This implements [draft-ietf-babel-v4viav6] an IPv4 via IPv6 extension
to the Babel routing protocol that allows annoncing routes to an IPv4
prefix with an IPv6 next-hop, which makes it possible for IPv4 traffic
to flow through interfaces that have not been assigned an IPv4 address.
The implementation is compatible with the current Babeld version (the
relevant changes can be seen in the [babeld PR]). I've verified this
with a few VMs in the following setup:
Bird <- v4 only -> Bird <- v6 only -> Babeld <- v4 only -> Babeld
Each routing daemon was running on their own VM and had L2 connectivity
to only its direct neighbors. At the nodes at the edges v4 networks have
been announced and full end-to-end communication was possible over the
mixed AF network. The v6 only link between Babel and Bird (at the
"center" of the above setup) did transport the v4 packets via the v6
link-local next hop addresses just as expected.
Thanks to Toke Høiland-Jørgensen for early review on this work.
[draft-ietf-babel-v4viav6]:
https://datatracker.ietf.org/doc/draft-ietf-babel-v4viav6/
[babeld PR]: https://github.com/jech/babeld/pull/56
---
The draft has reached the "Proposed Standard" stage:
https://mailarchive.ietf.org/arch/msg/ietf-announce/oybMxQbud2RvpyBBn8hkMTKakm4/
The mentioned babeld PR has been merged and a new babel release has been
cut a few hours ago.
I've addressed the feedback gathered in 2020 when I posted this for the
first time. On the topic of "feature detection" I didn't invest any more
time. It seems like the conclusion was that the adminitrator has to
ensure that the host system provides the required capabilities. If it
doesn't then we don't try to disable features.
I've rebased this onto Bird 2.0.9 and rerun my test suite. Everything
looks fine.
doc/bird.sgml | 6 +++
proto/babel/babel.c | 26 --
proto/babel/babel.h | 3 ++
proto/babel/config.Y | 5 +-
proto/babel/packets.c | 114 ++
5 files changed, 116 insertions(+), 38 deletions(-)
diff --git a/doc/bird.sgml b/doc/bird.sgml
index 1d5ae056..14758627 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -1892,6 +1892,7 @@ protocol babel [] {
algorithm ( hmac sha1 | hmac sha256 | hmac sha384 |
hmac sha512 | blake2s128 | blake2s256 | blake2b256 | blake2b512 );
};
+ ipv4 via ipv6 ;
};
}
@@ -2000,6 +2001,11 @@ protocol babel [] {
protocol will only accept HMAC-based algorithms or one of the Blake
algorithms, and the length of the supplied password string must match the
key size used by the selected algorithm.
+
+ ipv4 via ipv6
+ If enabled, Bird will accept and emit IPv4-via-IPv6 routes when IPv4
+ addresses are absent from the interface as described in
draft-ietf-babel-v4viav6.
+ Default: yes.
Attributes
diff --git a/proto/babel/babel.c b/proto/babel/babel.c
index 174fc9e2..cba407e3 100644
--- a/proto/babel/babel.c
+++ b/proto/babel/babel.c
@@ -965,8 +965,17 @@ babel_send_update_(struct babel_iface *ifa, btime changed,
struct fib *rtable)
msg.update.router_id = e->router_id;
net_copy(&msg.update.net, e->n.addr);
-msg.update.next_hop = ((e->n.addr->type == NET_IP4) ?
- ifa->next_hop_ip4 : ifa->next_hop_ip6);
+if (e->n.addr->type == NET_IP4) {
+ /* Always prefer v4 nexthop if set */
+ if(!ipa_zero(ifa->next_hop_ip4))
+msg.update.next_hop = ifa->next_hop_ip4;
+
+ /* Only send v4-via-v6 if enabled */
+ else if (ifa->cf->ip4_via_ip6)
+msg.update.next_hop = ifa->next_hop_ip6;
+} else {
+ msg.update.next_hop = ifa->next_hop_ip6;
+}
/* Do not send route if next hop is unknown, e.g. no configured IPv4
address */
if (ipa_zero(msg.update.next_hop))
@@ -1261,6 +1270,12 @@ babel_handle_update(union babel_msg *m, struct
babel_iface *ifa)
return;
}
+ /* Reject IPv4 via IPv6 routes if disabled */
+ if (!ifa->cf->ip4_via_ip6 && msg->net.type == NET_IP4 &&
ipa_is_ip6(msg->next_hop)) {
+DBG("Babel: Ignoring disabled IPv4 via IPv6 route.\n");
+return;
+ }
+
/* Regular update */
e = babel_get_entry(p, &msg->net);
r = babel_get_route(p, e, nbr); /* the route entry indexed by neighbour */
@@ -1666,7 +1681,7 @@ babel_iface_update_addr4(struct babel_iface *ifa)
ip_addr addr4 = ifa->iface->addr4 ? ifa->iface->addr4->ip : IPA_NONE;
ifa->next_hop_ip4 = ipa_nonzero(ifa->cf->next_hop_ip4) ?
ifa->cf->next_hop_ip4 : addr4;
- if (ipa_zero(ifa->next_hop_ip4) && p->ip4_channel)
+ if (ipa_zero(ifa->next_hop_ip4) && p->ip4_channel && !ifa->cf->ip4_via_ip6)
log(L_WARN "%s: Missing IPv4 next hop address for %s", p->p.name,
ifa->ifname);
if (ifa->up)
@@ -2049,8 +2064,8 @@ babel_show_interfaces(struct proto *P, const char *iff)
}
cli_msg(-1023, "%s:", p->p.name);
- cli_msg(-1023, "%-10s %-6s %-5s %7s %6s %7s %-15s %s",
- "Interf