Babel Redux: Easy to use as RIPng, but with wireless support

Traffic

For those who have been following my articles, they will know I am a fan of RIPng routing protocol for IPv6 in small networks. It requires little to no configuration, turn it on, and it just works.

Recently, I was exchanging emails with the bird package maintainer for Openwrt, and he suggested I give Babel another look. I looked at the bird implementation of Babel about five years ago, and found the convergence time to be slow. That was back when bird was at version 1.6.3. bird has improved since then and is now at version 3.01.

I set up a small IPv6 test lab to see how the new bird (with Babel support) would perform. In this article I will be making comparisons to RIPng, as to features, and convergence performance.

What is Babel

Babel is a loop-avoiding distance-vector routing protocol that is robust and efficient both in ordinary wired networks and in wireless mesh networks. Based on the loss of hellos the cost of wireless links can be increased, making sketchy wireless links less preferred.

RFC 8966 standardizes the routing protocol. There are two implementations which are supported on OpenWrt routers, babeld and bird

Although I did try babeld on one of my routers as a test, this lab is using the bird implementation of the babel protocol.

Creating a network with redundant paths

Like anything in networking, it starts with the physical layer (wireless is a form of physical layer). I setup a lab with 4 nodes, AA, BB, CC,and DD, with a redundant path from AA to CC via BB.

Network Diagram

In this lab, I used different versions of OpenWrt and bird. I wanted to ensure that the different versions would work together using the Babel Protocol.

Node Name Device OpenWrt Bird
AA Waihee TP-Link AX23 24.10.0 v3.01
BB Waimanu MX6 24.10.0-rc7 v2.15
CC Malmo BT Home Hub 51 23.05.5 v2.15
DD Makiki GL-iNET AR750 18.06.2 v1.6.8

Babel Lab in the home

Babel lab on the dining room table

Running BIRD with Babel

As of version 2, bird supports both IPv4 and IPv6 in the same configuration file: /etc/bird.conf. I used the IPv6-only config in node DD with bird 1.6.8

The Bird Documentation provides an example. The following is a basic Babel IPv6 configuration (/etc/bird.conf) to just plug and play, without any wireless link additions, which will run similar to RIPng (but converge faster).

# Basic bird.conf for Babel

# Use Source Address Dependent Routing Routing (SADR)
ipv6 sadr table sadr6;

protocol kernel {
    ipv6 sadr {
       export all;    # Default is export none
       table sadr6;
    };
}

# Required to get info about Net Interfaces from Kernel
protocol device {
}

#advertises directly connected interfaces
protocol direct {
    ipv6 sadr {
         table sadr6;
    };
    interface "*";
}


protocol babel {
    # duplicate interface line to add additional interfaces
    interface "*";

    ipv6 sadr {
        import all;
        export all;
        table sadr6;
    };
    # prevent stale routes staying in the network on restart
    randomize router id yes;
}

In the example (above), the interface "*"; could be more specific and list several interfaces, where eth0 is the WAN interface, such as:

    interface "br-lan";
    interface "eth0";

However, your router may have a different interface than eth0 for the WAN, and the example config is more universal.

Firewall Configuration for Babel

Similar to RIPng, a firewall rule is required to allow Babel routes in on the WAN interface. Not surprisingly, Babel uses a different port from RIPng, 6696.

Place the following rule in /etc/config/firewall for Babel, and reload the firewall: fw4 reload

   config rule
       option name 'Babel'
       option family 'ipv6'
       list proto 'udp'
       option src 'wan'
       option dest_port '6696'
       option target 'ACCEPT'

Checking the path of connectivity

When determining the connectivity path, traceroute6 (the IPv6 version) is your friend. Checking between Node DD and Node AA, the path is (showing the wireless link):

root@makiki:~# traceroute6 aa
traceroute to aa (fdaa::1) from fdcc::e695:6eff:fe01:aa01, 30 hops max, 16 byte packets
 1  cc (fdcc::1)  0.849 ms  0.78 ms  0.657 ms
 2  fdaa::e255:3dff:fe75:70af (fdaa::e255:3dff:fe75:70af)  1.861 ms  1.525 ms  1.437 ms
 3  fdaa::e255:3dff:fe75:70af (fdaa::e255:3dff:fe75:70af)  1.592 ms  1.598 ms  1.437 ms

And below traceroute is showing the the path via the wired link (between Node DD & AA):

root@makiki:~# traceroute6 aa
traceroute to aa (fdaa::1) from fdaa:0:0:6::d7b, 30 hops max, 16 byte packets
 1  fdaa:0:0:6::1 (fdaa:0:0:6::1)  0.74 ms  0.726 ms  0.679 ms
 2  fdaa:0:0:4::1 (fdaa:0:0:4::1)  0.917 ms  0.764 ms  0.747 ms
 3  aa (fdaa::1)  1.437 ms  1.099 ms  1.02 ms

Network Failure!

To test how well Babel can automatically route around failed links, I started a ping from Node DD to Node AA and unplugged the disabled the wifi on Node CC, thus blocking the link the pings were using, and waited...

...
64 bytes from fdaa::1: seq=15 ttl=63 time=2.263 ms
64 bytes from fdaa::1: seq=16 ttl=63 time=2.168 ms
64 bytes from fdaa::1: seq=17 ttl=63 time=2.078 ms
64 bytes from fdaa::1: seq=92 ttl=62 time=1.461 ms
64 bytes from fdaa::1: seq=93 ttl=62 time=1.756 ms
64 bytes from fdaa::1: seq=94 ttl=62 time=1.268 ms
64 bytes from fdaa::1: seq=95 ttl=62 time=1.337 ms
64 bytes from fdaa::1: seq=96 ttl=62 time=1.265 ms
64 bytes from fdaa::1: seq=97 ttl=62 time=1.269 ms
64 bytes from fdaa::1: seq=98 ttl=62 time=1.302 ms
64 bytes from fdaa::1: seq=99 ttl=62 time=1.293 ms
64 bytes from fdaa::1: seq=100 ttl=62 time=1.256 ms
64 bytes from fdaa::1: seq=101 ttl=62 time=1.363 ms
^C
--- aa ping statistics ---
103 packets transmitted, 28 packets received, 72% packet loss
round-trip min/avg/max = 1.256/1.837/2.966 ms

As you can see the outage was 75 seconds (103-287). Not particularly faster than RIPng, and it did fix itself (called convergence) without human intervention.

Restoring the Network

Starting a ping6 again from node DD to AA, and enabling the 5 Ghz radio, one can measure the time of the outage while Babel recalculates the shortest path. And there was no outage.

Restoring the Node CC to AA wireless link, I noticed that the network would continue to use the path DD->CC->BB->AA, and would not flip to the DD->CC->AA path. This is because the example bird.conf above has no specific wireless link configuration.

So I tried again, to see how fast the wireless link would take up the traffic. Starting the ping again from Node DD to AA, I pulled the ethernet cable between Node CC & BB.

...
64 bytes from fdaa::1: seq=9 ttl=63 time=2.144 ms
64 bytes from fdaa::1: seq=10 ttl=63 time=2.390 ms
64 bytes from fdaa::1: seq=11 ttl=63 time=2.287 ms
64 bytes from fdaa::1: seq=12 ttl=63 time=2.150 ms
64 bytes from fdaa::1: seq=13 ttl=63 time=2.271 ms
64 bytes from fdaa::1: seq=14 ttl=63 time=2.011 ms
64 bytes from fdaa::1: seq=15 ttl=63 time=1.970 ms
64 bytes from fdaa::1: seq=16 ttl=63 time=2.075 ms
64 bytes from fdaa::1: seq=17 ttl=63 time=1.978 ms
64 bytes from fdaa::1: seq=18 ttl=63 time=2.137 ms
64 bytes from fdaa::1: seq=19 ttl=63 time=3.590 ms
^C
--- aa ping statistics ---
20 packets transmitted, 19 packets received, 5% packet loss
round-trip min/avg/max = 1.619/2.221/4.438 ms

Convergence was 1 second, much faster than RIPng!

Adjusting bird.conf for Wireless Links

In order to tell Babel that there is a wireless link (between Node AA & CC) one must change the Babel configuration in /etc/bird.conf a bit:

...
protocol babel {
    # duplicate interface line to add additional interfaces
    interface `"phy0-sta0" {
        type wireless;
    };
    interface "*";
    ipv6 sadr {
        import all;
        export all;
        table sadr6;
    };
    # prevent stale routes staying in the network on restart
    randomize router id yes;
}

Because I wanted to change the config as little as possible, I called out the one interface (phy0-sta0) as wireless first, then all other interfaces (indicated as *) would be treated as wired. If you reverse the interface lines, phy0-sta0 will be included in the "*" and won't be treated as wireless. Order is important.

By defining the phy0-sta0 interface as wireless, the default cost will be increased to 256, and therefore the wireless link will be less preferred than wired links (default cost is 96).

Bird CLI

On OpenWrt there is also a Bird CLI package called birdc. It offers a nice view of what Bird is doing under the covers. Since I was keeping things simple, only Babel was enabled, but bird can certainly redistribute routes between differing routing protocols such as RIPng, OSPF and Babel.

bird has a nice CLI, which can be invoked with the birdc command, and get a bird> prompt. That said, it can also be run on the shell command line, and output can be piped to grep or even a file. I tend to use the shell method.

Looking at Babel running in bird, one can see the interfaces, neighbours, and route table entries. Looking at node CC.

root@Malmo:/etc# birdc show babel interface
BIRD 2.15.1 ready.
babel1:
Interface  State  Auth  RX cost   Nbrs   Timer Next hop (v4)   Next hop (v6)
eth0       Up     No         96      0   1.910 ::              fe80::3897:38ff:fef5:4167
wan        Up     No         96      1   3.367 192.168.174.214 fe80::3897:38ff:fef5:4167
br-lan     Up     No         96      1   0.409 192.168.116.1   fe80::1a62:2cff:fe07:a474
phy0-sta0  Up     No        256      2   1.999 192.168.117.206 fe80::1a62:2cff:fe07:a477

Since this is IPv6, not surprisingly, the neighbours command displays the link-local addresses of the Babel peers. And this is where vanity link-local addressing really comes in handy. Sadly, I didn't use it in this small lab.

root@Malmo:~# birdc show babel neighbor
BIRD 2.15.1 ready.
babel1:
IP address                Interface  Metric Routes Hellos Expires Auth  RTT (ms)
fe80::e255:3dff:fe75:70ae wan            96      9     16   3.866 No       0.674
fe80::e695:6eff:fe01:aa01 br-lan         96      9     16   4.557 No       0.000
fe80::7ef1:7eff:fe11:bc75 phy0-sta0      96      9     16   2.671 No       2.026
fe80::e255:3dff:fe75:70af phy0-sta0      96      9     16   4.990 No       1.938

The routes show the routing entries which it will use to calculate paths:

root@Waimanu:~# birdc show babel route
BIRD 2.16.1 ready.
babel1:
Prefix                                                 Nexthop                   Interface Metric F Seqno Expires
fdaa:0:0:6::d7b/128 from ::/0                          fe80::3897:38ff:fef5:4167 br-lan       192 *    68  51.657
fdaa:0:0:6::d7b/128 from ::/0                          fe80::7ef1:7eff:fe11:bc75 br-wan       384      68  53.645
fdaa:0:0:6::d7b/128 from ::/0                          fe80::1a62:2cff:fe07:a477 br-wan       388 +    68  49.096
fdaa:0:0:4::/64 from ::/0                              fe80::3897:38ff:fef5:4167 br-lan        96 *     9  51.657
fdaa:0:0:4::/64 from ::/0                              fe80::7ef1:7eff:fe11:bc75 br-wan       288       9  53.645
fdaa:0:0:4::/64 from ::/0                              fe80::1a62:2cff:fe07:a477 br-wan       292 +     9  49.096
fdbb::/64 from ::/0                                    fe80::3897:38ff:fef5:4167 br-lan        96 *     9  51.657
fdbb::/64 from ::/0                                    fe80::7ef1:7eff:fe11:bc75 br-wan       288       9  53.645
fdbb::/64 from ::/0                                    fe80::1a62:2cff:fe07:a477 br-wan       292 +     9  49.096
fdaa:0:0:6::/63 from ::/0                              fe80::7ef1:7eff:fe11:bc75 br-wan       288       9  53.645
fdaa:0:0:6::/63 from ::/0                              fe80::3897:38ff:fef5:4167 br-lan        96 *     9  51.657
fdaa:0:0:6::/63 from ::/0                              fe80::1a62:2cff:fe07:a477 br-wan       292 +     9  49.096
fd8d:54d4:73fa::/60 from ::/0                          fe80::7ef1:7eff:fe11:bc75 br-wan       288       9  53.645
fd8d:54d4:73fa::/60 from ::/0                          fe80::3897:38ff:fef5:4167 br-lan        96 *     9  51.657
fd8d:54d4:73fa::/60 from ::/0                          fe80::1a62:2cff:fe07:a477 br-wan       292 +     9  49.096
fd93:7f97:8ab8:6::/63 from ::/0                        fe80::7ef1:7eff:fe11:bc75 br-wan       288       9  53.645
fd93:7f97:8ab8:6::/63 from ::/0                        fe80::3897:38ff:fef5:4167 br-lan        96 *     9  51.657
fd93:7f97:8ab8:6::/63 from ::/0                        fe80::1a62:2cff:fe07:a477 br-wan       292 +     9  49.096
fdbb:0:0:2::/63 from ::/0                              fe80::7ef1:7eff:fe11:bc75 br-wan       288       9  53.645
fdbb:0:0:2::/63 from ::/0                              fe80::3897:38ff:fef5:4167 br-lan        96 *     9  51.657
fdbb:0:0:2::/63 from ::/0                              fe80::1a62:2cff:fe07:a477 br-wan       292 +     9  49.096
fd8d:54d4:73fa::/64 from ::/0                          fe80::7ef1:7eff:fe11:bc75 br-wan       384      68  53.645
fd8d:54d4:73fa::/64 from ::/0                          fe80::3897:38ff:fef5:4167 br-lan       192 *    68  51.657
fd8d:54d4:73fa::/64 from ::/0                          fe80::1a62:2cff:fe07:a477 br-wan       388 +    68  49.096
fd93:7f97:8ab8::/60 from ::/0                          fe80::7ef1:7eff:fe11:bc75 br-wan        96 *     9  53.645
fd93:7f97:8ab8::/60 from ::/0                          fe80::3897:38ff:fef5:4167 br-lan       192       9  51.657
fd93:7f97:8ab8::/60 from ::/0                          fe80::1a62:2cff:fe07:a477 br-wan       388       9  49.096
fdbb::c9c/128 from ::/0                                fe80::3897:38ff:fef5:4167 br-lan        96 *     9  51.657
fdbb::c9c/128 from ::/0                                fe80::7ef1:7eff:fe11:bc75 br-wan       288       9  53.645
fdbb::c9c/128 from ::/0                                fe80::1a62:2cff:fe07:a477 br-wan       292 +     9  49.096
fdcc::/60 from ::/0                                    fe80::7ef1:7eff:fe11:bc75 br-wan       288       9  53.645
fdcc::/60 from ::/0                                    fe80::3897:38ff:fef5:4167 br-lan        96 *     9  51.657
fdcc::/60 from ::/0                                    fe80::1a62:2cff:fe07:a477 br-wan       292 +     9  49.096
fd93:7f97:8ab8:4::/64 from ::/0                        fe80::3897:38ff:fef5:4167 br-lan        96 *     9  51.657
fd93:7f97:8ab8:4::/64 from ::/0                        fe80::7ef1:7eff:fe11:bc75 br-wan       288       9  53.645
fd93:7f97:8ab8:4::/64 from ::/0                        fe80::1a62:2cff:fe07:a477 br-wan       292 +     9  49.096
fdaa::/60 from ::/0                                    fe80::7ef1:7eff:fe11:bc75 br-wan        96 *     9  53.645
fdaa::/60 from ::/0                                    fe80::3897:38ff:fef5:4167 br-lan       192       9  51.657
fdaa::/60 from ::/0                                    fe80::1a62:2cff:fe07:a477 br-wan       388       9  49.096
fd68:7aa9:9d9a::/64 from ::/0                          fe80::3897:38ff:fef5:4167 br-lan        96 *     9  51.657
fd68:7aa9:9d9a::/64 from ::/0                          fe80::7ef1:7eff:fe11:bc75 br-wan       288       9  53.645
fd68:7aa9:9d9a::/64 from ::/0                          fe80::1a62:2cff:fe07:a477 br-wan       292 +     9  49.096
fdaa:0:0:4::c9c/128 from ::/0                          fe80::3897:38ff:fef5:4167 br-lan        96 *     9  51.657
fdaa:0:0:4::c9c/128 from ::/0                          fe80::7ef1:7eff:fe11:bc75 br-wan       288       9  53.645
fdaa:0:0:4::c9c/128 from ::/0                          fe80::1a62:2cff:fe07:a477 br-wan       292 +     9  49.096

As you can see four (4) nodes with only four links (one is wireless) can create quite the routing table. That said, 18 of the routes are due to ULAs being set on each router (a default in OpenWrt). RIPng also creates a lot of routes as well.

A note about RouterIDs

Unlike RIPng which has no concept of RouterID, Babel uses RouterID to identify the source of routes and avoid loops. Using wireshark to sniff the Babel packets (UDP port 6696), it can be seen that the RouterIDs are being transmitted. The line in at the bottom of the config file helps flush old routes from the other routers when restarting bird (or reloading a config)

# prevent stale routes staying in the network on restart
randomize router id yes;

Comparing Babel to RIPng

Babel is still being actively developed, and has a more modern approach to wireless links (something that was near non-existent when RIPng was being standardized back in 1997). There are more controls that can be applied to Babel for wireless links. Refer to the Babel Doc for more info.

Additionally, Babel has support for authentication between neighbours (something OSPF has had since the 1990s). Sadly, RIPng does not have this feature, as the IPv6 team was enamored with IPSec over IPv6 at the time. Authentication can be passwords, or even encrypted hashes (hmac sha1 | hmac sha256 | hmac sha384 | hmac sha512| blake2s128 | blake2s256 | blake2b256 | blake2b512), so that even your router jocks won't know the passwords by looking at the bird.conf file.

Babel also has the concept of Round Trip Time (RTT), as you will note in the show babel neighbors command. The config file can be further adjusted to handle variable (read: wireless links) RTT time, and take action if the RTT exceeds a configured value.

Network Convergence with Babel's wireless option

I did configure the phy0-sta0 (on node CC) as wireless. This caused the network to prefer the ethernet-only path (DD->CC->BB->AA). By removing the ethernet cable between nodes CC & BB, the reconvegence to the wireless link was quite fast (about 5 seconds). However, when restoring the ethernet cable, I noted that the network would reconverge again in about 5 seconds, but then after another 30 seconds or so there would be nearly a full minute of outage.

This second outage may be a result of my lab setup. Even with the second minute long outage, the total convergence time is much less than RIPng. Looking back at my old RIPng notes, where the outages were closer to three (3) minutes.

Of course some of that delay is that RIPng only sends updates every 30 seconds. Babel on the other hand send hello messages out every two (2) seconds.

Wrapping up Babel

Like RIPng, Babel is easy to set up without having to understand the complexities of more enterprise-level routing protocols such as OSPF or IS-IS. It has been the choice of mesh-networks where radio links are variable. It is easy to setup on OpenWrt routers and provides redundancy in your SOHO network with wired and wireless links. I think I'll be converting my SOHO network from RIPng to Babel soon.


Notes:

Craig Miller -- 11 Februay 2025