Hi bird users,
I recently came across the following thread [1] when trying to build an
IP-in-IP overlay network with bird. Unfortunately, those patches where
never merged upstream. Calico still uses a very old fork of bird with
those patches applied [2].
I decided to try the path that Ondrej proposed in the thread from 2016.
I made the small change from the attached patch and it worked
wonderfully for building a dynamically routed IP-in-IP overlay network.
Do you think it will take a lot of work to pass, from this proof of
concept, to a patch which could be accepted into bird? Is setting
"onlink" this way a good idea? I'd be happy to work on improving the patch.
Regards,
Radu
[1] https://bird.network.cz/pipermail/bird-users/2016-September/010633.html
[2] https://github.com/projectcalico/bird
From 91ca4ac5620d18c940c108f49fc2cdaf60f159f1 Mon Sep 17 00:00:00 2001
From: Radu Carpa <radu.ca...@cern.ch>
Date: Mon, 16 Jan 2023 17:50:07 +0100
Subject: [PATCH] allow setting the 'onlink' route attribute in filters
The main use-case is to build IP-IP overlay networks on linux.
Two routers (1.1.1.1 and 2.2.2.2) can peer directly over their
public interface, but be configured to program received routes
on the overlay IP-IP network.
This is achieved by using an export filter on the kernel protocol:
ifname = "tunl0";
onlink = true;
gw = from;
the routes will be programmed on the tunl0 interface with a gateway
from the outer network. This relies on a linux-specific behavior of
the tunl0 interface. For example, on the node 1.1.1.1, the following
route:
10.254.0.0/26 via 2.2.2.2 dev tunl0 proto bird metric 32 onlink
results in packets towards 10.254.0.0/26 to be encapsulated in
another IP packet with destination 2.2.2.2 and be sent via the
outer network.
---
doc/bird.sgml | 24 ++++++++++++++++++++++++
filter/config.Y | 1 +
filter/data.h | 1 +
filter/f-inst.c | 14 ++++++++++++--
4 files changed, 38 insertions(+), 2 deletions(-)
diff --git a/doc/bird.sgml b/doc/bird.sgml
index 50657ebf..f89eff45 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -1839,6 +1839,30 @@ Common route attributes are:
network for routes that do not have a native protocol metric attribute
(like <cf/ospf_metric1/ for OSPF routes). It is used mainly by BGP to
compare internal distances to boundary routers (see below).
+
+ <tag><label id="rta-onlink"><m/bool/ onlink</tag>
+ Onlink flag means that the specified nexthop is accessible on the
+ interface regardless of IP prefixes configured on the interface.
+ A possible use-case for setting this flag is to automatically build
+ overlay IP-IP networks on linux.
+<code>
+protocol kernel {
+ merge paths on limit 32;
+ ipv4 {
+ table master4;
+ import all;
+ export filter {
+ if ( net ~ 10.254.0.0/16 ) then {
+ ifname = "tunl0";
+ onlink = true;
+ gw = from;
+ accept;
+ }
+ reject;
+ };
+ };
+}
+</code>
</descrip>
<p>Protocol-specific route attributes are described in the corresponding
diff --git a/filter/config.Y b/filter/config.Y
index 1d9d9aa9..fa7a637e 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -795,6 +795,7 @@ static_attr:
| WEIGHT { $$ = f_new_static_attr(T_INT, SA_WEIGHT, 0); }
| PREFERENCE { $$ = f_new_static_attr(T_INT, SA_PREF, 0); }
| GW_MPLS { $$ = f_new_static_attr(T_INT, SA_GW_MPLS, 0); }
+ | ONLINK { $$ = f_new_static_attr(T_BOOL, SA_ONLINK, 0); }
;
term:
diff --git a/filter/data.h b/filter/data.h
index 700609e9..b3767f7b 100644
--- a/filter/data.h
+++ b/filter/data.h
@@ -102,6 +102,7 @@ enum f_sa_code {
SA_WEIGHT,
SA_PREF,
SA_GW_MPLS,
+ SA_ONLINK,
} PACKED;
/* Static attribute definition (members of struct rta) */
diff --git a/filter/f-inst.c b/filter/f-inst.c
index 2d2a30e4..ccc34f24 100644
--- a/filter/f-inst.c
+++ b/filter/f-inst.c
@@ -694,6 +694,7 @@
case SA_WEIGHT: RESULT(sa.f_type, i, rta->nh.weight + 1); break;
case SA_PREF: RESULT(sa.f_type, i, rta->pref); break;
case SA_GW_MPLS: RESULT(sa.f_type, i, rta->nh.labels ? rta->nh.label[0] : MPLS_NULL); break;
+ case SA_ONLINK: RESULT(sa.f_type, i, rta->nh.flags & RNF_ONLINK ? 1 : 0); break;
default:
bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code);
@@ -720,8 +721,8 @@
case SA_GW:
{
ip_addr ip = v1.val.ip;
- struct iface *ifa = ipa_is_link_local(ip) ? rta->nh.iface : NULL;
- neighbor *n = neigh_find((*fs->rte)->src->proto, ip, ifa, 0);
+ struct iface *ifa = ipa_is_link_local(ip) || (rta->nh.flags & RNF_ONLINK) ? rta->nh.iface : NULL;
+ neighbor *n = neigh_find((*fs->rte)->src->proto, ip, ifa, (rta->nh.flags & RNF_ONLINK) ? NEF_ONLINK : 0);
if (!n || (n->scope == SCOPE_HOST))
runtime( "Invalid gw address" );
@@ -801,6 +802,15 @@
rta->pref = v1.val.i;
break;
+ case SA_ONLINK:
+ {
+ if (v1.val.i)
+ rta->nh.flags |= RNF_ONLINK;
+ else
+ rta->nh.flags &= ~RNF_ONLINK;
+ }
+ break;
+
default:
bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code);
}
--
2.39.0