Skip to content

RPL Routing

The IPv6 Routing Protocol for Low-Power and Lossy Networks (RPL) is a routing protocol for constrained networks. See RFC 6550 for more information on RPL.

This tutorial shows how to use the RPL shell command to configure routing in a RIOT multi-hop network. We will configure one node as the RPL root and verify that the other nodes have joined the RPL Destination Oriented Directed Acyclic Graph (DODAG) and can ping each other using ICMPv6 echo requests.

Please have a look at The Getting Started and Creating an Application.

For routing capabilities, it is necessary that the RPL implementation is compiled into your RIOT application. This can be achieved by adding gnrc_rpl to the USEMODULE variable in your application’s Makefile. You can consult this Makefile for a complete example.

For the following tutorials, the gnrc_networking example will be used. All commands listed here will be issued from within the examples/networking/gnrc/networking directory. You may use your own application after adjusting the Makefile as described above.

You can run the tutorial either on local hardware, native, or the FIT IoT-Lab.

If you have three or more hardware boards with IEEE 802.15.4 radio capabilities, you can run the tutorial on actual hardware. This allows you to experiment with different distances between the boards and, e.g., create multi-hop topologies.

This tutorial is based on the Adafruit Feather nRF52840 Sense board. If you are using different hardware, simply replace the BOARD value in the commands below with your board name.

A detailed description of development with multiple boards can be found in the build system guide. For the sake of simplicity, we are setting the PORT and DEBUG_ADAPTER_ID values for each board manually in this tutorial.

List all connected boards, their port, and serial number.

Terminal window
make list-ttys
path | driver | vendor | model | model_db | serial | ctime | iface_num
-------------|---------|-------------|---------------------------------|----------|------------------|----------|----------
/dev/ttyACM0 | cdc_acm | RIOT-os.org | adafruit-feather-nrf52840-sense | None | AD57F0199B27E0C5 | 14:27:03 | 0
/dev/ttyACM1 | cdc_acm | RIOT-os.org | adafruit-feather-nrf52840-sense | None | A595DD98EC28FB7C | 14:27:07 | 0
/dev/ttyACM2 | cdc_acm | RIOT-os.org | adafruit-feather-nrf52840-sense | None | A766F77F8FC7A4A4 | 14:27:13 | 0

Open one terminal window for each board and set the BOARD, PORT, and DEBUG_ADAPTER_ID for each board. Set the DEBUG_ADAPTER_ID to the printed serial value.

Terminal window
export BOARD=adafruit-feather-nrf52840-sense PORT=/dev/ttyACM0 DEBUG_ADAPTER_ID=AD57F0199B27E0C5

In each window, compile and flash RIOT. Please note that you can not have multiple compilations running at the same time in a RIOT directory, so you have to compile and flash one at a time.

Terminal window
make flash term

You will be greeted by RIOT’s shell in all three terminals.

In the following sections, the term node{0,1,2} will be used to refer to the RIOT instances running on the boards connected to /dev/ttyACM{0,1,2}, respectively.

Information about the native port of RIOT can be found in Family:-native.

Because all nodes are connected via the tapbr0 bridge, all nodes are reachable from each other within a single hop. Therefore, it is not possible to test real multi-hop communication with this method. Virtual-riot-network describes how native nodes can be deployed with a virtualized network topology using tap interfaces. See README.desvirt.md for more information.

The native RIOT instances communicate through tap interfaces. We provide a script that supports the setup and cleanup of such interfaces.

To set up tap interfaces and a bridge that connects each tap interface:

Terminal window
../../../../dist/tools/tapsetup/tapsetup -c 4

With the -c parameter, you can specify how many tap interfaces you want to create (default: 2). To delete all tap interfaces, you can execute:

Terminal window
../../../../dist/tools/tapsetup/tapsetup -d

See the help for further information about additional parameters:

Terminal window
../../../../dist/tools/tapsetup/tapsetup -h

You can verify that the tap interfaces have been created successfully by looking at the output of the ip l shell command. This list should include the new interfaces tapbr0, tap0, tap1, tap2, and tap3.

Terminal window
make clean all

Type the following command in three different terminals, using tap0, tap1, and tap2, respectively.

Terminal window
make term PORT=tap{0,1,2}
RIOT native interrupts/signals initialized.
TZ not set, setting UTC
RIOT native board initialized.
RIOT native hardware initialization complete.
main(): This is RIOT! (Version: XXX)
RIOT network stack example application
All up, running the shell now
>

You will be greeted by RIOT’s shell in all three terminals.

In the following sections, the term node{0,1,2} will be used to refer to the nodes at tap{0,1,2}.

Basic information about the IoT-Lab Testbed can be found in their wiki. This tutorial will cover only the iotlab-m3 nodes, but the following commands should also be applicable to the wsn430 nodes.

To compile the gnrc_networking example for the iotlab-m3, the following command can be executed.

Terminal window
BOARD=iotlab-m3 make all

An experiment can be started either by using the IoT-Lab dashboard or by using a Makefile provided by RIOT. In this tutorial, the Makefile method will be used.

Add the iotlab Makefile to your own Makefile:

include $(RIOTBASE)/dist/testbed-support/Makefile.iotlab

To start an experiment and directly flash the reserved nodes, execute:

Terminal window
IOTLAB_USER=<iotlab_user> IOTLAB_PHY_NODES=10-12+14-16 IOTLAB_EXP_NAME=test IOTLAB_DURATION=60 BOARD=iotlab-m3 make iotlab-exp

This command may prompt for a password to authenticate your IoT-Lab account. You will need to use the same password that you use for the IoT-Lab dashboard.

Parameter Description
IOTLAB_USER Specify your IoT-Lab account name. The same name used for the dashboard
IOTLAB_PHY_NODES Choose the nodes for the experiment. If a node is not available, the Makefile will return an error specifying which nodes are busy
IOTLAB_EXP_NAME Name of the experiment
IOTLAB_DURATION Duration in minutes
BOARD The board to use: iotlab-m3

More information and further parameters can be found in the README.

Assuming the experiment started successfully, you can then communicate with the nodes directly from the command line like this:

Terminal window
IOTLAB_USER=<iotlab_user> BOARD=iotlab-m3 make iotlab-term

Once you are connected, the serial aggregator of the IoT-Lab testbed will be started, and you will have a console from which you can control every node.

If you want to flash the nodes again at a later point in time, use the iotlab-flash command:

Terminal window
IOTLAB_USER=<iotlab_user> BOARD=iotlab-m3 make iotlab-flash

Alternatively, you can flash individual nodes or get their serial I/O by setting IOTLAB_NODE and using the usual make flash / make term commands, e.g.:

Terminal window
IOTLAB_NODE=m3-10.grenoble.iot-lab.info BOARD=iotlab-m3 make flash term

Each command issued in the serial aggregator will be transmitted to all nodes used for the current experiment. To direct a command specifically to a single node, the node ID must be prepended to the command.

E.g., start RPL on interface 5 for all nodes:

Terminal window
rpl init 5
m3-10;> rpl init 5
m3-10;successfully initialized RPL on interface 5
m3-11;> rpl init 5
m3-11;successfully initialized RPL on interface 5
m3-12;> rpl init 5
m3-12;successfully initialized RPL on interface 5
m3-14;> rpl init 5
m3-14;successfully initialized RPL on interface 5
m3-15;> rpl init 5
m3-15;successfully initialized RPL on interface 5
m3-16;> rpl init 5
m3-16;successfully initialized RPL on interface 5

Start RPL only on one node:

Terminal window
m3-10; rpl init 5
m3-10;successfully initialized RPL on interface 5

In the tutorial below we use node{0,1,2} to refer to specific nodes. These commands should be prepended with the node ids, e.g., m3-10;, m3-11;, and m3-12; for node0, node1, and node2, respectively.

In order to use RPL, we have to choose a RPL root node. We will choose node0 as the RPL root.

With the ifconfig command, we can get the configured interfaces for a particular RIOT node. An example output for node0 is shown below. It may look slightly different if you are using different hardware or are running on native.

Terminal window
ifconfig
Iface 6 HWaddr: 68:C5 Channel: 26 NID: 0x23 PHY: O-QPSK
Long HWaddr: AE:57:F0:19:9B:27:E8:C5
TX-Power: 0dBm State: IDLE
ACK_REQ L2-PDU:102 MTU:1280 HL:64 RTR
RTR_ADV 6LO IPHC
Source address length: 8
Link type: wireless
inet6 addr: fe80::ac57:f019:9b27:e8c5 scope: link VAL
inet6 group: ff02::2
inet6 group: ff02::1
inet6 group: ff02::1:ff27:e8c5
inet6 group: ff02::1a

At first, we need to configure a global IPv6 address for one node, the root node.

Terminal window
ifconfig 6 add 2001:db8::1
success: added 2001:db8::1/64 to interface 6
Terminal window
ifconfig
Iface 6 HWaddr: 68:C5 Channel: 26 NID: 0x23 PHY: O-QPSK
Long HWaddr: AE:57:F0:19:9B:27:E8:C5
TX-Power: 0dBm State: IDLE
ACK_REQ L2-PDU:102 MTU:1280 HL:64 RTR
RTR_ADV 6LO IPHC
Source address length: 8
Link type: wireless
inet6 addr: fe80::ac57:f019:9b27:e8c5 scope: link VAL
inet6 addr: 2001:db8::1 scope: global VAL
inet6 group: ff02::2
inet6 group: ff02::1
inet6 group: ff02::1:ff27:e8c5
inet6 group: ff02::1a

Now, RPL must be initialized on that particular interface for all nodes:

Terminal window
rpl init 6
successfully initialized RPL on interface 6

On the root node (node0 in this tutorial), type:

Terminal window
rpl root 1 2001:db8::1
successfully added a new RPL DODAG

Note, however, that the DODAG ID 2001:db8::1 matches a global IPv6 address configured on an interface, as done in Initializing RPL. The 1 before 2001:db8::1 is the Instance ID and can be adjusted if desired.

To see the RPL status, type rpl.

Terminal window
rpl
instance table: [X]
parent table: [ ] [ ] [ ]
instance [1 | Iface: 5 | mop: 2 | ocp: 0 | mhri: 256 | mri 0]
dodag [2001:db8::1 | R: 256 | OP: Router | PIO: on | TR(I=[8,20], k=10, c=1)] rpl

The root node has a rank of R: 256.

Now type rpl in the other terminals (here is an example for node1):

Terminal window
rpl
instance table: [X]
parent table: [X] [ ] [ ]
instance [1 | Iface: 5 | mop: 2 | ocp: 0 | mhri: 256 | mri 0]
dodag [2001:db8::1 | R: 512 | OP: Router | PIO: on | TR(I=[8,20], k=10, c=1)]
parent [addr: fe80::ac57:f019:9b27:e8c5 | rank: 256]

This node is part of the RPL DODAG with the DODAG ID 2001:db8::1 and Instance ID 1. Furthermore, this node’s rank is R: 512, and the preferred parent has the link-local IPv6 address fe80::d069:49ff:fede:b38c. This parent’s rank is 256, therefore we know that this parent must be the root of this RPL DODAG.

Note that all participating nodes in the RPL DODAG automatically configure a global IPv6 address matching the prefix from the DODAG ID. Verify this with ifconfig.

RPL should now start to fill the NIB (Neighbor Information Base) table, which is consulted when forwarding packets. On the root node (node0):

Terminal window
nib route
2001:db8::/64 dev #6
2001:db8::14f3:36ff:fe6f:6395/128 via fe80::14f3:36ff:fe6f:6395 dev #6
2001:db8::d8bc:8aff:feaa:7c46/128 via fe80::d8bc:8aff:feaa:7c46 dev #6

and on the participating node (node1):

Terminal window
nib route
2001:db8::/64 dev #6
default* via fe80::ac57:f019:9b27:e8c5 dev #6

The nodes can now ping each other using the public IP addresses (replace the destination IP):

Terminal window
ping 2001:db8::14f3:36ff:fe6f:6395
12 bytes from 2001:db8::14f3:36ff:fe6f:6395: icmp_seq=0 ttl=64 time=1.728 ms
12 bytes from 2001:db8::14f3:36ff:fe6f:6395: icmp_seq=1 ttl=64 time=1.070 ms
12 bytes from 2001:db8::14f3:36ff:fe6f:6395: icmp_seq=2 ttl=64 time=1.010 ms
--- 2001:db8::14f3:36ff:fe6f:6395 PING statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 1.010/1.269/1.728 ms