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

Reply via email to