# Simulating a Thread network using OpenThread
###### tags: `2021`
[](https://hackmd.io/sV7hqy70SwyQ1rMHpqMoBQ)
> :copyright: https://codelabs.developers.google.com/codelabs/openthread-simulation/#0
## Introduction
[OpenThread](https://github.com/openthread) released by Google is an open-source implementation of the [Thread](http://threadgroup.org/) 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](https://www.threadgroup.org/ThreadSpec) 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:
* in [this first video](https://www.youtube.com/watch?v=cV5ktpaJv5Y) (duration 5:14) Mesh Networking is explained
* then, [this video](https://www.youtube.com/watch?v=2-69-DcM2NA) (duration 4:58) offers a brief overview of the Thread Wireless Technology
* finally, [this video](https://www.youtube.com/watch?v=EUGI4fdY2JU) (duration 1:20) explains how OpenThread is used in Google/Nest products
A longer [video is available here](https://www.youtube.com/watch?v=JPXw5Hw--4M) :)
## Learning OpenThread using Docker
This lab will walk you through simulating a Thread mesh network on emulated devices using Docker.
What you'll learn:
* How to set up the OpenThread build toolchain
* How to simulate a Thread network
* How to authenticate Thread nodes
* How to manage a Thread network with OpenThread Daemon
### Pull the Docker image
The `openthread/codelab_otsim` Docker image features OpenThread and `wpantund` pre-built and ready to use.
```bash
$ docker pull openthread/codelab_otsim:latest
```
### Simulate a Thread network
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.
:::info
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.

#### Create the network
**1. Start Node 1**
In a terminal window, we start a Docker container from the image and connect to its bash shell:
```bash
$ docker run --name codelab_otsim_ctnr -it --rm \
--sysctl net.ipv6.conf.all.disable_ipv6=0 \
--cap-add=net_admin openthread/codelab_otsim bash
```
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 routes
Once in the container, prompt similar will look like this (`c0f3912a74ff` is the Container ID):
```
root@c0f3912a74ff:/#
```
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.
:::info
Remember: FTD -> Full Thread Device
:::
```
# cd /root/src/openthread
# ./output/simulation/bin/ot-cli-ftd 1
```
:::warning
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.
:::warning
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**.
```
> dataset init new
Done
> dataset
```
you will get something like this
```
Active Timestamp: 1
Channel: 20
Channel Mask: 07fff800
Ext PAN ID: d6263b6d857647da
Mesh Local Prefix: fd61:2344:9a52:ede0/64
Master Key: e4344ca17d1dca2a33f064992f31f786
Network Name: OpenThread-c169
PAN ID: 0xc169
PSKc: ebb4f2f8a68026fc55bcf3d7be3e6fe4
Security Policy: 0, onrcb
Done
```
and finally:
```
> dataset commit active
Done
```
:::info
IMPORTANT: note down the:
**Master Key** (in this case e4344ca17d1dca2a33f064992f31f786) and the
**PAN ID** (in this case 0xc169)
:::
:::danger
1. Indicate the data of the "Operation Dataset" that you have created:
- Master Key:
- Network Name:
- PAN ID:
:::
We bring up the IPv6 interface:
```
> ifconfig up
Done
```
We start Thread protocol operation:
```
> thread start
Done
```
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.
```
> state
leader
Done
```
View the IPv6 addresses assigned to Node 1's Thread interface:
```
> ipaddr
fd61:2344:9a52:ede0:0:ff:fe00:fc00
fd61:2344:9a52:ede0:0:ff:fe00:5000
fd61:2344:9a52:ede0:d041:c5ba:a7bc:5ce6
fe80:0:0:0:94da:92ea:1353:4f3b
Done
```
Note the specific IPv6 address types:
* Begins with fd = mesh-local
* Begins with fe80 = link-local
:::danger
2. Indicate the link-local address of your device
:::
Mesh-local address types are classified further:
* Contains ff:fe00 = Router Locator (RLOC)
* Does not contain ff:fe00 = Endpoint Identifier (EID) ⇢
in this case = **fd61:2344:9a52:ede0:d041:c5ba:a7bc:5ce6**
:::danger
3. Indicate the Endpoint Identifier (EID) of the first device.
:::
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.
```
$ docker exec -it codelab_otsim_ctnr bash
```
As before, we navigate to the openthread directory and spawn the CLI process. This is the second emulated Thread device:
```
# cd ~/src/openthread
# ./output/simulation/bin/ot-cli-ftd 2
```
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):
```
> dataset masterkey e4344ca17d1dca2a33f064992f31f786
Done
> dataset panid 0xc169
Done
> dataset commit active
Done
> ifconfig up
Done
> thread start
Done
```
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.
```
> state
child
Done
```
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.
```
> state
router
Done
```
#### Verify the network
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.
```
> rloc16
5800
Done
```
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.
```
> router table
| ID | RLOC16 | Next Hop | Path Cost | LQ In | LQ Out | Age | Extended MAC |
+----+--------+----------+-----------+--------+---------+-----+------------------+
| 20 | 0x5000 | 63 | 0 | 0 | 0 | 0 | 96da92ea13534f3b |
| 22 | 0x5800 | 63 | 0 | 3 | 3 | 23 | 5a4eb647eb6bc66c |
```
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:
```
> ping fd61:2344:9a52:ede0:d041:c5ba:a7bc:5ce6
> 16 bytes from fd61:2344:9a52:ede0:d041:c5ba:a7bc:5ce6: icmp_seq=1 hlim=64 time=12ms
```
:::danger
4. Note down the latency of the ping to node 1 from node 2.
:::
#### Test the network
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:
```
> thread stop
Done
```
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:
```
> state
router
Done
...
> state
leader
Done
```
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.
```
> thread stop
Done
> factoryreset
>
> exit
root@c0f3912a74ff:/#
```
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:
```
> factoryreset
>
> exit
root@c0f3912a74ff:/#
```
---
### Authenticate nodes with Commissioning
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.

:::info
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.
### Create a network
In Node 1, spawn the CLI process:
```
root@c0f3912a74ff:/# cd ~/src/openthread
root@c0f3912a74ff:/# ./output/simulation/bin/ot-cli-ftd 1
```
Create a new Operational Dataset, commit it as the active one, and start Thread:
```
> dataset init new
Done
> dataset
Active Timestamp: 1
Channel: 12
Channel Mask: 07fff800
Ext PAN ID: e68d05794bf13052
Mesh Local Prefix: fd7d:ddf7:877b:8756/64
Master Key: a77fe1d03b0e8028a4e13213de38080e
Network Name: OpenThread-8f37
PAN ID: 0x8f37
PSKc: f9debbc1532487984b17f92cd55b21fc
Security Policy: 0, onrcb
Done
> dataset commit active
Done
> ifconfig up
Done
> thread start
Done
```
Wait a few seconds and verify that the device has become a Thread Leader:
```
> state
leader
Done
```
#### Start the Commissioner role
While still on Node 1, start the Commissioner role:
```
> commissioner start
Commissioner: petitioning
Done
> Commissioner: active
```
We will now allow any Joiner (by using the `*` wildcard) with the credential: `J01NME` to *commission* onto the network by doing:
```
> commissioner joiner add * J01NME
Done
```
A Joiner is a device that is added by a human administrator to a commissioned Thread Network.
:::info
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).
:::
#### Start the Joiner role
In a second terminal window, in the Docker container, spawn a new CLI process. This is Node 2.
```
root@c0f3912a74ff:/# cd ~/src/openthread
root@c0f3912a74ff:/# ./output/simulation/bin/ot-cli-ftd 2
> ifconfig up
Done
```
On Node 2, enable the Joiner role using the J01NME Joiner Credential.
```
> joiner start J01NME
Done
```
... wait a few seconds for confirmation ...
```
Join success
```
As a Joiner, the device (Node 2) has successfully authenticated itself with the Commissioner (Node 1) and received the Thread Network credentials.
:::warning
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:
```
> joiner start J01NME
Done
> =========[[THCI] direction=send | type=JOIN_FIN.req | len=048]==========
| 10 01 01 21 0A 4F 50 45 | 4E 54 48 52 45 41 44 22 | ...!.OPENTHREAD"
| 05 50 4F 53 49 58 23 10 | 32 30 31 39 31 31 31 33 | .POSIX#.20191113
| 2D 30 30 32 30 32 2D 67 | 25 06 18 B4 30 00 00 10 | -00202-g%..40...
------------------------------------------------------------------------
=========[[THCI] direction=recv | type=JOIN_FIN.rsp | len=003]==========
| 10 01 01 .. .. .. .. .. | .. .. .. .. .. .. .. .. | ................
------------------------------------------------------------------------
[THCI] direction=recv | type=JOIN_ENT.ntf
[THCI] direction=send | type=JOIN_ENT.rsp
Join success
```
These are normal and can be ignored.
:::danger
5. Note down the message obtained on screen after Join; should be something like:
```
Commissioner: Joiner connect d65e64fa83f81cf7
[[NONE]]=========[[THCI] direction=recv | type=JOIN_FIN.req | len=053]==========
[[NONE]]| 10 01 01 21 0A 4F 50 45 | 4E 54 48 52 45 41 44 22 | ...!.OPENTHREAD"
[[NONE]]| 0A 53 49 4D 55 4C 41 54 | 49 4F 4E 23 10 32 30 31 | .SIMULATION#.201
...
```
:::
Now that Node 2 is authenticated, start Thread (**on both nodes**):
```
> thread start
Done
```
#### Validate network authentication
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:
```
> state
child
Done
...
> state
router
Done
```
#### Reset configuration
To prepare for the next step, reset the configuration. On each Node, stop Thread, do a factory reset, and exit the emulated Thread device:
```
> thread stop
Done
> factoryreset
>
> exit
root@c0f3912a74ff:/#
```
### Creating complex networks
In this section we will implement a more complex network:
```graphviz
digraph {
node [shape=box, color=red]; router2; router3;
node [shape=pentagon, color=green, style=filled]; leader;
node [shape=circle,fixedsize=true,style=filled,color=lightgrey; width=0.9]; client4; client5;
leader -> router2;
router2 -> router3;
router3 -> leader;
client4 -> router3;
client5 -> leader;
}
```
We will need 5 nodes: 1 leader, 2 routers and 2 child.
:::warning
We will use the word child and childs, altough grammatically incorrect to indicate 1 or more child nodes
:::
Executing the first node:
```
$ docker run --name codelab_otsim_ctnr -it --rm\
--sysctl net.ipv6.conf.all.disable_ipv6=0\
--cap-add=net_admin openthread/codelab_otsim bash
...
root@c9f1c6a8f32a:/# cd ~/src/openthread/
root@c9f1c6a8f32a:~/src/openthread# ./output/simulation/bin/ot-cli-ftd 1
> dataset init new
Done
> dataset
Active Timestamp: 1
Channel: 13
Channel Mask: 07fff800
Ext PAN ID: 2623047c61a34cc6
Mesh Local Prefix: fdaa:9c5c:5a7b:f781/64
Master Key: 3bfcc6271f185fe33d8fa6119caa3d6e
Network Name: OpenThread-84ee
PAN ID: 0x84ee
PSKc: 76c5920bb8a76192fb2f5b11b6f09aa5
Security Policy: 0, onrcb
Done
> dataset commit active
Done
> ifconfig up
Done
> thread start
Done
> state
leader
Done
>
```
Activate Leader as commissioner:
```
> commissioner start
Commissioner: petitioning
Done
> Commissioner: active
> commissioner joiner add * R3THREAD 600
Done
```
:::warning
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):
```
$ docker exec -it codelab_otsim_ctnr bash
root@c9f1c6a8f32a:/# cd ~/src/openthread/
root@c9f1c6a8f32a:~/src/openthread# ./output/simulation/bin/ot-cli-ftd 2
> ifconfig up
Done
> joiner start R3THREAD
Done
... some text ...
Join success
> thread start
Done
> state
router
Done
>
```
:::warning
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:
```
> router table
| ID | RLOC16 | Next Hop | Path Cost | LQ In | LQ Out | Age | Extended MAC |
+----+--------+----------+-----------+-------+--------+-----+------------------+
| 5 | 0x1400 | 12 | 1 | 3 | 3 | 26 | 1e7bfb6270c9eab6 |
| 8 | 0x2000 | 63 | 0 | 0 | 0 | 0 | 86c45e49822461c6 |
| 12 | 0x3000 | 5 | 1 | 3 | 3 | 29 | fe09fc7604b6f2d9 |
Done
> neighbor table
| Role | RLOC16 | Age | Avg RSSI | Last RSSI |R|S|D|N| Extended MAC |
+------+--------+-----+----------+-----------+-+-+-+-+------------------+
| R | 0x1400 | 16 | -20 | -20 |1|0|1|1| 1e7bfb6270c9eab6 |
| R | 0x3000 | 19 | -20 | -20 |1|0|1|1| fe09fc7604b6f2d9 |
Done
```
From router 3:
```
> router table
| ID | RLOC16 | Next Hop | Path Cost | LQ In | LQ Out | Age | Extended MAC |
+----+--------+----------+-----------+-------+--------+-----+------------------+
| 5 | 0x1400 | 8 | 1 | 3 | 3 | 0 | 1e7bfb6270c9eab6 |
| 8 | 0x2000 | 5 | 1 | 3 | 3 | 28 | 86c45e49822461c6 |
| 12 | 0x3000 | 63 | 0 | 0 | 0 | 0 | fe09fc7604b6f2d9 |
Done
> neighbor table
| Role | RLOC16 | Age | Avg RSSI | Last RSSI |R|S|D|N| Extended MAC |
+------+--------+-----+----------+-----------+-+-+-+-+------------------+
| R | 0x1400 | 32 | -20 | -20 |1|0|1|1| 1e7bfb6270c9eab6 |
| R | 0x2000 | 25 | -20 | -20 |1|0|1|1| 86c45e49822461c6 |
Done
>
```
**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:
```
> parentpriority
-2
Done
```
Priority values can be 1 (highest), 0, -1, -2. To assign a priority we use:
```
> parentpriority 0
Done
```
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):
```
> childmax
10
Done
> childmax 3
Done
```
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:
```
$ docker exec -it codelab_otsim_ctnr bash
root@c9f1c6a8f32a:/# cd ~/src/openthread/
root@c9f1c6a8f32a:~/src/openthread# ./output/simulation/bin/ot-cli-mtd 4
>
```
It is important to note that we used **`ot-cli-mtd`** and sequence number 4.
```
> ifconfig up
Done
> joiner start R3THREAD
Done
...
> thread start
Done
```
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:
```
> neighbor table
| Role | RLOC16 | Age | Avg RSSI | Last RSSI |R|S|D|N| Extended MAC |
+------+--------+-----+----------+-----------+-+-+-+-+------------------+
| C | 0x6001 | 109 | -20 | -20 |1|1|0|0| 1e0466ad64a8d6fd |
| R | 0x1800 | 6 | -20 | -20 |1|0|1|1| be3a9f9efb2d3931 |
| R | 0xf000 | 10 | -20 | -20 |1|0|1|1| 5a316d006cbba883 |
Done
>
```
And from the newly created child:
```
> parent
Ext Addr: aed7c5a4a3333f5b
Rloc: 6000
Link Quality In: 3
Link Quality Out: 3
Age: 7
Done
>
```
**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:
```
$ docker exec -it codelab_otsim_ctnr bash
root@c9f1c6a8f32a:/# cd ~/src/openthread/
root@c9f1c6a8f32a:~/src/openthread# ./output/simulation/bin/ot-cli-mtd 5
>
```
It is important to note that we used **`ot-cli-mtd`** and sequence number 5.
```
> ifconfig up
Done
> joiner start R3THREAD
Done
...
> thread start
Done
```
Now, from the Leader:
```
> neighbor table
| Role | RLOC16 | Age | Avg RSSI | Last RSSI |R|S|D|N| Extended MAC |
+------+--------+-----+----------+-----------+-+-+-+-+------------------+
| C | 0x1803 | 15 | -20 | -20 |1|1|0|0| 06eda04756c56f16 |
| R | 0x6000 | 16 | -20 | -20 |1|0|1|1| aed7c5a4a3333f5b |
| R | 0xf000 | 19 | -20 | -20 |1|0|1|1| 5a316d006cbba883 |
Done
> child table
| ID | RLOC16 | Timeout | Age | LQ In | C_VN |R|S|D|N| Extended MAC |
+-----+--------+------------+------------+-------+------+-+-+-+-+------------------+
| 3 | 0x1803 | 240 | 126 | 3 | 230 |1|1|0|0| 06eda04756c56f16 |
Done
>
```
Another interesting command is:
```
> child list
3
Done
> child 3
Child ID: 3
Rloc: 1803
Ext Addr: 06eda04756c56f16
Mode: rs
Net Data: 230
Timeout: 240
Age: 145
Link Quality In: 3
RSSI: -20
Done
>
```
Similar, but related to routers:
```
> router list
6 24 60
Done
> router 6
Alloc: 1
Router ID: 6
Rloc: 1800
Next Hop: fc00
Link: 0
Done
>
```
And finally:
```
> childip
1803: fdd9:d378:b10c:139a:ce0e:172d:cda3:a27d
Done
>
```
Now we can ping from any node to any other node. For example:
The IP address of client5 is:
```
> ipaddr
fdd9:d378:b10c:139a:0:ff:fe00:1803
fdd9:d378:b10c:139a:ce0e:172d:cda3:a27d
fe80:0:0:0:4ed:a047:56c5:6f16
Done
>
```
From client 4:
```
> ping fdd9:d378:b10c:139a:ce0e:172d:cda3:a27d
> 16 bytes from fdd9:d378:b10c:139a:ce0e:172d:cda3:a27d: icmp_seq=1 hlim=62 time=11ms
```
**Statistics**
To get statistics about a router's work we can use:
```
> counters mac
TxTotal: 335
TxUnicast: 95
TxBroadcast: 240
TxAckRequested: 95
TxAcked: 95
TxNoAckRequested: 240
TxData: 335
TxDataPoll: 0
TxBeacon: 0
TxBeaconRequest: 0
TxOther: 0
TxRetry: 0
TxErrCca: 0
TxErrBusyChannel: 0
RxTotal: 552
RxUnicast: 90
RxBroadcast: 462
RxData: 552
RxDataPoll: 0
RxBeacon: 0
RxBeaconRequest: 0
RxOther: 0
RxAddressFiltered: 0
RxDestAddrFiltered: 0
RxDuplicated: 0
RxErrNoFrame: 0
RxErrNoUnknownNeighbor: 0
RxErrInvalidSrcAddr: 0
RxErrSec: 0
RxErrFcs: 0
RxErrOther: 0
Done
>
```
and
```
> counters mle
Role Disabled: 0
Role Detached: 1
Role Child: 1
Role Router: 1
Role Leader: 0
Attach Attempts: 1
Partition Id Changes: 1
Better Partition Attach Attempts: 0
Parent Changes: 0
Done
>
```
:::danger
6. Report the operating statistics of the two network routers
:::