2021
https://codelabs.developers.google.com/codelabs/openthread-simulation/#0Image Not Showing Possible ReasonsLearn More →
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
OpenThread released by Google is an open-source implementation of the Thread networking protocol. Google Nest has released OpenThread to make the technology used in Nest products broadly available to developers to accelerate the development of products for the connected home.
The Thread specification defines an IPv6-based reliable, secure and low-power wireless device-to-device communication protocol for home applications. OpenThread implements all Thread networking layers including IPv6, 6LoWPAN, IEEE 802.15.4 with MAC security, Mesh Link Establishment, and Mesh Routing.
To understand the terms: mesh, Thread, and OpenThread you have to first watch these videos:
A longer video is available here :)
This lab will walk you through simulating a Thread mesh network on emulated devices using Docker.
What you'll learn:
The openthread/codelab_otsim
Docker image features OpenThread and wpantund
pre-built and ready to use.
The example application you'll use demonstrates a minimal OpenThread application that exposes the OpenThread configuration and management interfaces via a basic command-line interface (CLI).
This exercise takes you through the minimal steps required to ping one emulated Thread device from another emulated Thread device.
This first exercise does not include any network parameter configuration, such as the IEEE 802.15.4 PAN ID or the Thread Master Key. OpenThread currently implements default values for network parameters (which can be changed later via the CLI).
The figure below describes a basic Thread network topology. For this exercise, we'll emulate the two nodes within the green circle: a Thread Leader and Thread Router with a single connection between them.
1. Start Node 1
In a terminal window, we start a Docker container from the image and connect to its bash shell:
Note the flags:
--sysctl net.ipv6.conf.all.disable_ipv6=0
: this enables IPv6 within the container--cap-add=net_admin
: enables the NET_ADMIN capability, which allows you to execute network-related operations, such as adding IP routesOnce in the container, prompt similar will look like this (c0f3912a74ff
is the Container ID):
In the Docker container, we navigate to the openthread
directory and spawn the CLI process for an emulated Thread device using the ot-cli-ftd binary; this binary implements an OpenThread device emulated on top of POSIX.
Remember: FTD -> Full Thread Device
IMPORTANT: If you don't see the > prompt after running this command, press enter.
The IEEE 802.15.4 radio driver is implemented on top of UDP (IEEE 802.15.4 frames are passed within UDP payloads).
The argument of 1 is a file descriptor that represents the least-significant bits of the "factory-assigned" IEEE EUI-64 for the emulated device. This value is also used when binding to a UDP port for IEEE 802.15.4 radio emulation (port = 9000 + file descriptor). Each instance of an emulated Thread device in this lab will use a different file descriptor.
Only file descriptors of 1 or greater can be used when spawning the process for an emulated device. A file descriptor of 0 is reserved for other use.
Creating a new Operational Dataset and commit it as the active one.
An Operational Dataset is the configuration for the Thread network we are creating.
Command dataset init new
creates a new Operational Dataset with random values.
you will get something like this
and finally:
IMPORTANT: note down the: Master Key (in this case e4344ca17d1dca2a33f064992f31f786) and the PAN ID (in this case 0xc169)
We bring up the IPv6 interface:
We start Thread protocol operation:
We wait a few seconds and verify that the device has become the Thread Leader. The Leader is the device responsible for managing router ID assignment.
View the IPv6 addresses assigned to Node 1's Thread interface:
Note the specific IPv6 address types:
Mesh-local address types are classified further:
The RLOC will change as the network topology changes and a Thread device switches between states. The EID is independent of topology changes and will remain static.
2. Start Node 2 Open a new terminal and execute a bash shell in the currently running Docker container to use for Node 2.
As before, we navigate to the openthread directory and spawn the CLI process. This is the second emulated Thread device:
We now configure the Thread Master Key and PAN ID, using the values of Node 1's Operational Dataset, for example (remember to use your own values):
The device will initialize itself as a Child. A Thread Child is equivalent to an End Device, which is a Thread device that transmits and receives unicast traffic only with a Parent device.
Within 2 minutes you should see the state switch from child to router. A Thread Router is capable of routing traffic between Thread devices. It is also referred to as a Parent.
An easy way to verify the mesh network is to look at the router table.
1. Check connectivity We get the RLOC16 of Node 2. The RLOC16 is the last 16 bits of the device's RLOC IPv6 address.
We check, on Node 1, the router table for Node 2's RLOC16. We have to be sure that Node 2 has switched to the router state first.
Node 2's RLOC of 0x5800 is found in the table, confirming that it is connected to the mesh.
2. Ping Node 1 from Node 2 Verify connectivity between the two emulated Thread devices. In Node 2, ping the EID assigned to Node 1:
Now that you can successfully ping between two emulated Thread devices, test the mesh network by taking one node offline.
Return to Node 1 and stop Thread:
Switch to Node 2 and check the state. Within two minutes, Node 2 detects that the leader (Node 1) is offline, and you should see Node 2 transition to be the leader of the network:
Once confirmed, stop Thread and factory reset Node 2 before exiting back to the Docker bash prompt. A factory reset is done to ensure that the Thread network credentials we used in this exercise are not carried over to the next exercise.
You may have to press enter a few times to bring the > prompt back after a factoryreset command.
Do not exit the Docker container.
Also factory reset and exit Node 1:
In the previous step we set up a Thread network with two simulated devices and verified connectivity. However, this only allows unauthenticated IPv6 link-local traffic to pass between devices. To route global IPv6 traffic between them (and the Internet via a Thread border router), nodes must be authenticated.
In order to authenticate, one device must act as a Commissioner. The Commissioner is the currently elected authentication server for new Thread devices, and the authorizer for providing the network credentials required for the devices to join the network.
In this step, we will use the same two-node topology as before. For authentication, the Thread Leader will act as the Commissioner, the Thread Router as a Joiner.
Devices without Thread interfaces may also perform the Commissioner role. For example, a cell phone or a server in the cloud can provide the interface by which a human administrator joins a new device to the Thread Network. These devices are called External Commissioners.
Continuing from the previous exercise we will use again the two bash prompts within the same Docker container.
In Node 1, spawn the CLI process:
Create a new Operational Dataset, commit it as the active one, and start Thread:
Wait a few seconds and verify that the device has become a Thread Leader:
While still on Node 1, start the Commissioner role:
We will now allow any Joiner (by using the *
wildcard) with the credential: J01NME
to commission onto the network by doing:
A Joiner is a device that is added by a human administrator to a commissioned Thread Network.
You can choose any Joiner Credential you wish in a different implementation of a Thread network.
Note: The Joiner Credential is a device-specific string of all uppercase alphanumeric characters (0-9 and AY, excluding I, O, Q, and Z for readability), between 6 and 32 characters long. For more information, see Thread Commissioning (https://openthread.io/guides/building/commissioning).
In a second terminal window, in the Docker container, spawn a new CLI process. This is Node 2.
On Node 2, enable the Joiner role using the J01NME Joiner Credential.
… wait a few seconds for confirmation …
As a Joiner, the device (Node 2) has successfully authenticated itself with the Commissioner (Node 1) and received the Thread Network credentials.
If you get a Join failed message, the Commissioner may have timed out waiting for a Join request. In that case, restart from the commissioner joiner command.
You may also receive error and/or log messages on both Nodes 1 and 2 after a successful join, like:
These are normal and can be ignored.
Now that Node 2 is authenticated, start Thread (on both nodes):
Check the state on Node 2, to validate that it has now joined the network. Within two minutes, Node 2 transitions from child to router:
To prepare for the next step, reset the configuration. On each Node, stop Thread, do a factory reset, and exit the emulated Thread device:
In this section we will implement a more complex network:
We will need 5 nodes: 1 leader, 2 routers and 2 child.
We will use the word child and childs, altough grammatically incorrect to indicate 1 or more child nodes
Executing the first node:
Activate Leader as commissioner:
Where 600 is the value of the joiner timeout in seconds (i.e., 10 minutes). If you are not fast enough in typing the following commands you can use an higher value
We now execute the other 2 routers (number 2 and 3):
Transition to state 'router' can take various seconds!
If you get a Join failed message, the Commissioner may have timed out waiting for a Join request. In that case, restart from the commissioner joiner command. Don't wait too long after starting the Commissioner to enable the Joiner role.
Now we have 1 Leader and 2 routers. from any node we can check the routing table or our neighbours:
From the Leader:
From router 3:
Creating the network
To create a desired topology and assign childs to the desired routers we use commands parentpriority x
and command childmax x
. For example:
Priority values can be 1 (highest), 0, -1, -2. To assign a priority we use:
The value parentpriority
can be changed at any time. Thanks to this, we will be able to assign a child to a specific router or to the leader.
The same for the maximum number of childs (the value must be set before launching any child):
Basically to assign a child to a router, we have to set parentpriority=1
to the router we want to assign the childs to and parentpriority=-2
to the others.
Assigning a child to router 3
To assign a child to router 3 we have to sewill set parentpriority 1
to it and parentpriority -2
to the leader and to router 2, and then:
It is important to note that we used ot-cli-mtd
and sequence number 4.
If executing the joiner start
you get a Join failed
you'll have to restart the commissioner joiner add * R3THREAD
in the leader node.
Now, from router 3:
And from the newly created child:
Assigning a child to the leader
We create now a child for the Leader by assigning to the Leader parentpriority 1
and parentpriority -2
to the router 2 and 3, and then, as usual:
It is important to note that we used ot-cli-mtd
and sequence number 5.
Now, from the Leader:
Another interesting command is:
Similar, but related to routers:
And finally:
Now we can ping from any node to any other node. For example: The IP address of client5 is:
From client 4:
Statistics
To get statistics about a router's work we can use:
and