Skip to content
Switch branches/tags

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


Kernel image and instructions to deploy a virtual borderrouter test environment.


Install the needed dependencies


GNU EABI compiler will probably need few other dependencies, install accordingly:

sudo pacman -S base-devel qemu qemu-arch-extra
trizen -S aqemu
trizen -S arm-linux-gnueabihf-gcc
trizen -S ncurses5-compat-libs


sudo apt-get install bison flex build-essential qemu-system-arm gcc-arm-linux-gnueabihf

Kernel Build Instructions

In case you want it you can build your own kernel and tweak it to add support to more devices/functions. I always prefer to build it by my own as:

  • Contain the latest changes.
  • Is compatible with the last raspbian image available.

In the steps below I will be using the .config file from this repo, In addition to the versatile-pb configuration it contains the below modules built-in:

  • IPv6.
  • USB Serial Support (For the very popular FT232 transceivers, tweak this option in case you use some other) .
  • VirtIO drivers
  • iptables (netfilter)

Clone the Raspberry kernel tree:

git clone git://
cd linux/

For the next step I used the linux-arm.patch (As of May 2019) from dhruvvyas90, due changes in the files from the kernel tree the patch failed to be applied in my case so I opened the files and did the changes manually (Just 3 files...). Please refer to the patch file to apply the changes. It just be needed to be done just once. Linux tools from dhruvvyas90. Don't forget to thanks dhruvvyas90 for his help.

nano arch/arm/Kconfig
nano arch/arm/mach-versatile/Kconfig
nano drivers/mmc/host/Kconfig

Prepare the initial configuration for versatile:

make ARCH=arm versatile_defconfig 

In case you want to use the same .config file I used copy it into your location (The .config file I provided has all the IPv6, USB, etc stuff needed by OpenThread to work, modify for your own needs):

cp ../.config .

Start menuconfig and modify the kernel options to your taste, remember to save the .config file:

make -j 4 -k ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig

Compile the kernel and generate the device tree files:

make -j 4 -k ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bzImage dtbs

Once done copy the kernel and versatile-pb.dtb files where the script resides. (In case you want to use it).

cp arch/arm/boot/zImage ../
cp arch/arm/boot/dts/versatile-pb.dtb ../

Border Router Setup

To get a working test environment with a Raspbian we need some setup in the host computer:

  • Bridge configuration to permit the virtual Raspbian reach the internet
  • iptables rules to allow the traffic
  • An IPv6 and IPv4 free network segments to deploy the virtual Raspbian networking.

The steps below will use the script which takes care of the 2 first points above. You will need to choose a network segment for IPv4 and 2 for IPv6 and set it in the variables of the script. In my case I used:

  • 2001:dead:beef:cafe::/64 - Additional Local Mesh for the Thread network
  • 2001:db8:dead:beef:fe::/96 - IPv6 network between the virtual BR and your computer.
  • - IPv4 network for Internet access.

If you need more information about iptables, network routing in Linux I recommend you to read the below topics which I used while writting the script.

Raspbian image preparation

Download the raspbian image of your taste, my personal preference is the lite version. Then use qemu-image to add some necessary space.

sudo qemu-img resize 2018-10-09-raspbian-stretch-lite.img +10G

Modify the script variables to match your kernel files, network details and USB OpenThread NCP device:




# USB DETAILS - In this case is 

Run the script:

sudo ./

After this first boot lets configure and resize the filesystem to occupy the new size:

# Configure timezone, keyboard, password, etc.
sudo raspi-config 
# Work with the root filesystem.
sudo fdisk /dev/sda
# Print the partitions and take note of boot start of partition sda2 (e.g. 98304)
Type p
# Delete the second partition:
Type d
Type 2
# Create a new partition using the same start position as the partition erased:
Type n 
Type p : for Primary partition
Type 2 : for the partition number
Type 98304 : From the previous steps
Type N : Just if you are asked to remove the signature (NO).
# Write the changes
Type w
# Shutdown raspbian to reboot and the changes take effect.
sudo shutdown -h now

Once Raspbian is shutdown it will close the script. Even if you type sudo reboot the Raspbian will shutdown (Due the script is using -no-reboot flag. At this point the filesystem was modified but it is needed to run the below command to modify the usable space. Run again the script to boot up Raspbian and then:

sudo resize2fs /dev/sda2

Make sure the following rules are uncommented and set to 1 in the file /etc/sysctl.conf


Finally test the networking and update the OS (dnsmasq DHCP negotiation should do the routing job to reach internet):

sudo dhcpcd eth0
sudo apt-get update

You should have a working Raspbian ready to install OpenThread Border Router. Additionally upgrade and install git.

sudo apt-get upgrade
sudo apt-get install git

Install OpenThread Border Router

Clone the OTBR git in a local folder

git clone
cd ot-br-posix

In this case we will avoid the installation of NAT64, DNS64 and the AP (Due the fact that this Raspbian is lack of wifi interface (wlan0). Set the below variables to 0 from the file examples/platforms/raspbian/default.


Before building we need more RAM... the 256 MB assigned are not enough, for this reason we setup a SWAP file:

sudo su -c 'echo "CONF_SWAPSIZE=512" > /etc/dphys-swapfile'
sudo dphys-swapfile setup

Build and run wpantund and otbr-agent/web as mentioned in the OT guide:

cd ot-br-posix

Sit back and relax. The proces will take quite long time. After finishing the OT Border Router Build and Configuration guide you should have a working OpenThread networking we just need something else...

Connectivity from host to OT devices

Using the guest Raspbian with the NCP connected, form a Thread network and add your devices. In this case I'm using a custom board with a cc2538... chip that at this time has problems with commissioning (11/2018) but I made it to get a formed network of some devices just for testing purposes.

Guest NCP status

pi@raspivirtual:~$ sudo wpanctl status
wpan0 => [
        "NCP:State" => "associated"
        "Daemon:Enabled" => true
        "NCP:Version" => "OPENTHREAD/20170716-01079-g08747cf7-dirty; CC2538; Nov 13 2018 20:16:15"
        "Daemon:Version" => "0.08.00d (/47f3212; Nov  7 2018 16:10:04)"
        "Config:NCP:DriverName" => "spinel"
        "NCP:HardwareAddress" => [00124B0011F47F13]
        "NCP:Channel" => 11
        "Network:NodeType" => "router"
        "Network:Name" => "OpenThread"
        "Network:XPANID" => 0xDEAD00BEEF00CAFE
        "Network:PANID" => 0x0102
        "IPv6:LinkLocalAddress" => "fe80::30ac:123:29b9:74e8"
        "IPv6:MeshLocalAddress" => "fdde:ad00:beef:0:b8d4:da1a:5652:2239"
        "IPv6:MeshLocalPrefix" => "fdde:ad00:beef::/64"
        "com.nestlabs.internal:Network:AllowingJoin" => false

OT child device (

sudo screen /dev/ttyUSB0 115200,cs8

> state
> ipaddr
> neighbor table
| Role | RLOC16 | Age | Avg RSSI | Last RSSI |R|S|D|N| Extended MAC     |
|   R  | 0xbc00 |  41 |      -22 |       -23 |1|0|1|1| 32ac012329b974e8 |

We need to add a gateway and a route to advise the OT network of a route to outside the Thread network:

# Configure the gateway. Use a different network prefix from apart of the one from the Raspbian configuration In my case (2001:dead:beef:cafe::/64).
sudo wpanctl -I wpan0 config-gateway 2001:dead:beef:cafe:: -d

In this moment you will see that the OT devices and Border Router's wpan will configure a new IP:

Raspbian Border Router:
pi@raspivirtual:~$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff
    inet brd scope global eth0
       valid_lft forever preferred_lft forever
    inet6 2001:db8:dead:beef::7f/128 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::5054:ff:fe12:3456/64 scope link 
       valid_lft forever preferred_lft forever
3: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
    link/ipip brd
4: wpan0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1280 qdisc pfifo_fast state UNKNOWN group default qlen 500
    inet6 2001:dead:beef:cafe:30ac:123:29b9:74e8/64 scope global 
       valid_lft forever preferred_lft forever
    inet6 fdde:ad00:beef:0:b8d4:da1a:5652:2239/64 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::30ac:123:29b9:74e8/64 scope link 
       valid_lft forever preferred_lft forever
    inet6 fe80::30bc:8ea9:5584:c802/64 scope link flags 800 
       valid_lft forever preferred_lft forever

OT Child device:
> ipaddr

Add now a route to let the OT devices know what other networks are behind the Border Router:

sudo wpanctl -I wpan0 add-route 2001:db8:dead:beef::

You should be able to do ping from your host computer to your OT devices and viceversa:

From OT child to Host computer:
> ping 2001:db8:dead:beef::1
> 16 bytes from 2001:db8:dead:beef:0:0:0:1: icmp_seq=25 hlim=63 time=61ms

From Host computer to OT child
[ernestrc@homedell qemu_raspbian]$ ping -6 2001:dead:beef:cafe:9a0d:50:91ad:230
PING 2001:dead:beef:cafe:9a0d:50:91ad:230(2001:dead:beef:cafe:9a0d:50:91ad:230) 56 data bytes
64 bytes from 2001:dead:beef:cafe:9a0d:50:91ad:230: icmp_seq=1 ttl=63 time=73.5 ms
64 bytes from 2001:dead:beef:cafe:9a0d:50:91ad:230: icmp_seq=2 ttl=63 time=86.5 ms
64 bytes from 2001:dead:beef:cafe:9a0d:50:91ad:230: icmp_seq=3 ttl=63 time=94.10 ms
64 bytes from 2001:dead:beef:cafe:9a0d:50:91ad:230: icmp_seq=4 ttl=63 time=101 ms

Some troubleshooting

Refresh IP

The script is configured to provide the virtual Raspbian with the fixed IP you provide in the variables via dnsmasq. This same IP is configured as route via to reach the Thread network. If you have problems reaching the Thread network from your Host computer try the below in the virtual Raspbian:

# Remove the IPv6 from the ethernet interface
sudo ip -6 addr flush dev eth0
# Request again an IP (This hopefully will give the IP you provided to your Raspbian eth0 interface)
sudo dhcpcd eth0

Then check if you can reach now the Thread network.


If you are using Docker, you will probably have problems connecting the virtual raspbian to the network. This is due the fact hat Docker set several iptables rules for the containers. It is possible to

Memory constraints

If you run into problems while running the bootstrap or setup scripts and the error message stands for out of memory, reboot the virtual machine and retry the script. This is due the fact that the swap configured (512M) is not enough to handle the compilation process (As of May 2019, the build process works ok without hitting this issue).

Final thought

Despite is funny to have a virtual Raspbian with wpantund and OTBR recent achievements are being made with Docker OTBR Docker. Please check that solution and use the one of your taste.


Kernel image and instructions to deploy a virtual borderrouter test environment.



No releases published


No packages published