Table Of Contents
Table Of Contents

Testing a Linux Routing Daemon in a Simulated Environment

Goals

Testing routing protocols with simulation is often easier than building a test setup in the real world. INET’s emulation features make it possible to use a real-world routing protocol implementation in a simulated environment, where the simulated environment and multiple instances of the real-world routing protocol implementation can run on the same computer.

This showcase demonstrates such a test scenario with the Linux implementation of the Babel routing protocol (Babel daemon). We’ll run a simulation of a mobile ad hoc network, where mobility and wireless connectivity will be simulated using INET, and the routes will be managed by multiple instances of the Babel daemon.

Note that the emulation example only runs on Linux. For a comprehensive understanding of emulation in INET, read the Emulation section in the User’s Guide.

INET version: 4.1
Source files location: inet/showcases/emulation/babel

The Model

Babel is a reactive distance-vector routing protocol, similar to AODV or DSDV. It is a robust and efficient routing protocol, suitable for both wired networks and wireless mesh networks. It works over IPv4/IPv6 and UDP. The protocol’s reference implementation is available for Linux as the Babel daemon (babeld).

Note

The Babel daemon can be installed in Ubuntu and derivates with the following command:

sudo apt install babeld

We’ll use INET’s emulation support, namely Ext interfaces and RealTimeScheduler, to interface the simulation with services running on the host OS.

We test the Babel routing protocol in a simulated scenario. We build a wireless ad hoc network, where one of the hosts pings another. The position and movement of the nodes, and the physical medium carrying the wireless signals between them are simulated. The Ping requests are generated by a real Ping application, the Ping replies by the real ICMP protocol, and the routing protocol messages come from isolated instances of the real Babel daemon, all running on the host OS. The protocol instances are separated by running them in network namespaces on the host OS (network namespaces contain a complete virtualized network protocol stack, independent from the real protocol stack in the host OS). Each namespace has its IPv4 routing table that is managed by a Babel daemon instance.

Configuration

The network contains one stationary and two mobile AdhocHost’s. The mobile hosts are host[0] and host[2]; they are configured to move around in circles, going in and out of communication range with each other and the stationary host, host[1]. The Babel daemons will update the routes as connectivity changes between the three hosts. The network is shown on the following image; the communication ranges are indicated with blue circles, and the green movement trail circles show the path of the nodes.

The simulation and the real world is split at the wlan Ext interfaces in the hosts. The following figure illustrates the emulation setup:

../../../../_images/setup__.png

Each host has an ExtUpperIeee80211Interface. The interface contains an ExtEthernetTapDevice module that has a corresponding TAP device created in the host OS. The 802.11 radio, MAC and LLC are simulated; packets enter and exit the TAP device above the LLC:

../../../../_images/extinterface.png

In the host OS, we set up three network namespaces for the three hosts so that the babeld instances can run isolated from each other. Each network namespace has a TAP device, and an IPv4 routing table. We use a real Ping application in host0 to ping host2. The Ping response is generated by the ICMP protocol in the host2 network namespace.

Three shell scripts in showcase’s folder configure and control the emulation in the host OS: Setup.sh, Run.sh and Teardown.sh.

Setup.sh needs to be run first to create the network namespaces and the TAP devices for the three hosts. It also brings up the TAP interfaces, and assigns IP addresses to them:

# create network namespaces
sudo ip netns add host0
sudo ip netns add host1
sudo ip netns add host2

# create TAP interfaces
sudo ip netns exec host0 ip tuntap add mode tap dev tap0
sudo ip netns exec host1 ip tuntap add mode tap dev tap1
sudo ip netns exec host2 ip tuntap add mode tap dev tap2

# bring up TAP interfaces
sudo ip netns exec host0 ip link set dev tap0 up
sudo ip netns exec host1 ip link set dev tap1 up
sudo ip netns exec host2 ip link set dev tap2 up

# assign IP addresses to interface
sudo ip netns exec host0 ip addr add 192.168.2.1/32 dev tap0
sudo ip netns exec host1 ip addr add 192.168.3.1/32 dev tap1
sudo ip netns exec host2 ip addr add 192.168.4.1/32 dev tap2

The script assigns the following IP addresses:

host0

192.168.2.1

host1

192.168.3.1

host2

192.168.4.1

The TAP devices are assigned random MAC addresses by the host OS when they are created.

Run.sh runs the emulation example; it starts the babeld instances, runs a ping command in host0’s network namespace each second, and opens the simulation in qtenv. The user is expected to run the simulation in express mode. After qtenv is closed, the script stops the Ping loop and the babeld instances:

# start babel routing daemons
sudo ip netns exec host0 babeld -I babel0.pid -S babel-state0 -r -w -h 2 -M 0 -C 'reflect-kernel-metric true' -C 'interface tap0 channel 1 link-quality false' &
sudo ip netns exec host1 babeld -I babel1.pid -S babel-state1 -r -w -h 2 -M 0 -C 'reflect-kernel-metric true' -C 'interface tap1 channel 1 link-quality false' &
sudo ip netns exec host2 babeld -I babel2.pid -S babel-state2 -r -w -h 2 -M 0 -C 'reflect-kernel-metric true' -C 'interface tap2 channel 1 link-quality false' &

# start ping loop to avoid exiting early and to wait for the simulation to start
sudo ip netns exec host0 bash -c 'while ! ping 192.168.4.1; do sleep 1; done' &

# start simulation and wait for the user to exit
inet

# stop ping loop
ps -fe | grep -v awk | awk '/ping 192.168.4.1/ {print $2}' | xargs sudo kill

# stop babel routing deamons
sudo killall babeld

The Teardown.sh script can be run to destroy the TAP interfaces and the network namespaces when they are not needed anymore:

# destroy TAP interfaces
sudo ip netns exec host0 ip tuntap del mode tap dev tap0
sudo ip netns exec host1 ip tuntap del mode tap dev tap1
sudo ip netns exec host2 ip tuntap del mode tap dev tap2

# destroy network namespaces
sudo ip netns del host0
sudo ip netns del host1
sudo ip netns del host2

Note that commands involving network namespaces (netns) require root privileges.

Here is the Ext interface configuration in omnetpp.ini:

*.host[*].wlan[0].typename = "ExtUpperIeee80211Interface"
*.host[*].wlan[0].copyConfiguration = "copyFromExt"
*.host[0].wlan[0].device = "tap0"
*.host[0].wlan[0].namespace = "host0"
*.host[1].wlan[0].device = "tap1"
*.host[1].wlan[0].namespace = "host1"
*.host[2].wlan[0].device = "tap2"
*.host[2].wlan[0].namespace = "host2"

For each host, the configuration selects the corresponding TAP interface from the network namespaces of the host OS, and copies its configuration, such as assigned IP address and MAC address. Having matching addresses of the corresponding simulated and real network interface parts is important because packets will contain and be handled according to these addresses (the MAC might silently drop packets if the addresses don’t match).

It is also important to ensure synchronization between the host OS and the simulation with RealTimeScheduler:

[General]
network = BabelShowcase
scheduler-class = "inet::RealTimeScheduler"
sim-time-limit = 3600s

For compatibility with the host OS’s babeld and ping applications, the FCS mode in the hosts’ MAC module is configured to compute the FCS (as opposed to assuming it to be correct):

*.*.wlan[*].mac.fcsMode = "computed"

Also, for the sake of simplicity, we turn off everything that’s not strictly required, such as loopback interfaces and unused protocols:

*.*.numLoInterfaces = 0
*.*.hasTcp = false
*.*.hasUdp = false
*.*.hasIpv4 = false
*.*.hasIpv6 = false

Results

Here is a video of the simulation running:

The simulation is shown running in qtenv on the left. The first three terminals on the right display the routing tables of the three hosts in the three network namespaces; the fourth terminal displays the Ping output.

Successful link-layer transmissions are visualized with arrows; green for Babel messages, and red for Ping.

At first, the routing tables are empty. When the nodes move into communication range with each other, the babel messages can be exchanged, and each babeld instance adds routes to its routing table. The following route topologies occur between host[0] and host[2] during the simulation:

  • There is no connectivity between host[0] and host[2]

  • host[0] can reach host[2] in one hop (via host[1])

  • host[0] can reach host[2] directly

As the connectivity changes, the babel protocols adapts the routes. Note that the route metric is 256/hop (256 when the address is reachable in one hop; 512 when two hops). The metric is a very large number when unreachable.

The routes take a few seconds (and several babel message exchanges) to form. They also expire after some time when there is no connectivity.

A Babel message opened in Wireshark is shown on the following image. It is sent by host[0] at the beginning of the simulation when the route between host[0] and host[2] forms for the first time:

../../../../_images/babelmessage3.png

This Babel message broadcasts a route; it contains several type-length-value elements (TLVs). The nh and update messages indicate that 192.168.4.1 (host2) can be reached via 192.168.3.1 (host1), in one hop (metric=256).

Sources: omnetpp.ini, BabelShowcase.ned

Discussion

Use this page in the GitHub issue tracker for commenting on this showcase.