[PATCH 1/4] Nest: Add net_peer route type to track discovered peers

Matteo Perin matteo.perin at canonical.com
Fri Dec 5 14:52:29 CET 2025


The definition and helper functions for a new route-like
object to track peers discovery data has been added.
It only contains the (v4 or v6) remote peer address for now.

The main intent of this is, currently, to enable BGP
unnumbered auto peer discovery via RAdv incoming
advertisments, but in the future the same data structure
could be used to allow discovery coming from different protocols.

Signed-off-by: Matteo Perin <matteo.perin at canonical.com>
---
 lib/net.c     | 16 ++++++++++++++++
 lib/net.h     | 31 ++++++++++++++++++++++++++++++-
 nest/config.Y |  3 ++-
 nest/proto.c  |  2 +-
 4 files changed, 49 insertions(+), 3 deletions(-)

diff --git a/lib/net.c b/lib/net.c
index 64cf9e04..3eae6605 100644
--- a/lib/net.c
+++ b/lib/net.c
@@ -17,6 +17,7 @@ const char * const net_label[] = {
   [NET_IP6_SADR]= "ipv6-sadr",
   [NET_MPLS]	= "mpls",
   [NET_ASPA]	= "aspa",
+  [NET_PEER]	= "peer",
 };
 
 const u16 net_addr_length[] = {
@@ -31,6 +32,7 @@ const u16 net_addr_length[] = {
   [NET_IP6_SADR]= sizeof(net_addr_ip6_sadr),
   [NET_MPLS]	= sizeof(net_addr_mpls),
   [NET_ASPA]	= sizeof(net_addr_aspa),
+  [NET_PEER]	= sizeof(net_addr_peer),
 };
 
 const u8 net_max_prefix_length[] = {
@@ -45,6 +47,7 @@ const u8 net_max_prefix_length[] = {
   [NET_IP6_SADR]= IP6_MAX_PREFIX_LENGTH,
   [NET_MPLS]	= 0,
   [NET_ASPA]	= 0,
+  [NET_PEER]	= IP6_MAX_PREFIX_LENGTH,
 };
 
 const u16 net_max_text_length[] = {
@@ -59,6 +62,7 @@ const u16 net_max_text_length[] = {
   [NET_IP6_SADR]= 92,	/* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128 from ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */
   [NET_MPLS]	= 7,	/* "1048575" */
   [NET_ASPA]	= 10,	/* "4294967295" */
+  [NET_PEER]	= 43,	/* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */
 };
 
 /* There should be no implicit padding in net_addr structures */
@@ -74,6 +78,7 @@ STATIC_ASSERT(sizeof(net_addr_flow6)	== 20);
 STATIC_ASSERT(sizeof(net_addr_ip6_sadr)	== 40);
 STATIC_ASSERT(sizeof(net_addr_mpls)	==  8);
 STATIC_ASSERT(sizeof(net_addr_aspa)	==  8);
+STATIC_ASSERT(sizeof(net_addr_peer)	== 20);
 
 /* Ensure that all net_addr structures have the same alignment */
 STATIC_ASSERT(alignof(net_addr_ip4)	== alignof(net_addr));
@@ -89,6 +94,7 @@ STATIC_ASSERT(alignof(net_addr_flow6)	== alignof(net_addr));
 STATIC_ASSERT(alignof(net_addr_ip6_sadr) == alignof(net_addr));
 STATIC_ASSERT(alignof(net_addr_mpls)	== alignof(net_addr));
 STATIC_ASSERT(alignof(net_addr_aspa)	== alignof(net_addr));
+STATIC_ASSERT(alignof(net_addr_peer)	== alignof(net_addr));
 
 
 int
@@ -147,6 +153,8 @@ net_format(const net_addr *N, char *buf, int buflen)
     return bsnprintf(buf, buflen, "%u", n->mpls.label);
   case NET_ASPA:
     return bsnprintf(buf, buflen, "%u", n->aspa.asn);
+  case NET_PEER:
+    return bsnprintf(buf, buflen, "%I", n->peer.addr);
   }
 
   bug("unknown network type");
@@ -172,6 +180,7 @@ net_pxmask(const net_addr *a)
 
   case NET_MPLS:
   case NET_ASPA:
+  case NET_PEER:
   default:
     return IPA_NONE;
   }
@@ -207,6 +216,8 @@ net_compare(const net_addr *a, const net_addr *b)
     return net_compare_mpls((const net_addr_mpls *) a, (const net_addr_mpls *) b);
   case NET_ASPA:
     return net_compare_aspa((const net_addr_aspa *) a, (const net_addr_aspa *) b);
+  case NET_PEER:
+    return net_compare_peer((const net_addr_peer *) a, (const net_addr_peer *) b);
   }
   return 0;
 }
@@ -229,6 +240,7 @@ net_hash(const net_addr *n)
   case NET_IP6_SADR: return NET_HASH(n, ip6_sadr);
   case NET_MPLS: return NET_HASH(n, mpls);
   case NET_ASPA: return NET_HASH(n, aspa);
+  case NET_PEER: return NET_HASH(n, peer);
   default: bug("invalid type");
   }
 }
@@ -252,6 +264,7 @@ net_validate(const net_addr *n)
   case NET_IP6_SADR: return NET_VALIDATE(n, ip6_sadr);
   case NET_MPLS: return NET_VALIDATE(n, mpls);
   case NET_ASPA: return NET_VALIDATE(n, aspa);
+  case NET_PEER: return NET_VALIDATE(n, peer);
   default: return 0;
   }
 }
@@ -280,6 +293,7 @@ net_normalize(net_addr *N)
 
   case NET_MPLS:
   case NET_ASPA:
+  case NET_PEER:
     return;
   }
 }
@@ -308,6 +322,7 @@ net_classify(const net_addr *N)
 
   case NET_MPLS:
   case NET_ASPA:
+  case NET_PEER:
     return IADDR_HOST | SCOPE_UNIVERSE;
   }
 
@@ -342,6 +357,7 @@ ipa_in_netX(const ip_addr a, const net_addr *n)
 
   case NET_MPLS:
   case NET_ASPA:
+  case NET_PEER:
   default:
     return 0;
   }
diff --git a/lib/net.h b/lib/net.h
index 24aae87d..c301c803 100644
--- a/lib/net.h
+++ b/lib/net.h
@@ -24,7 +24,8 @@
 #define NET_IP6_SADR	9
 #define NET_MPLS	10
 #define NET_ASPA	11
-#define NET_MAX		12
+#define NET_PEER	12
+#define NET_MAX		13
 
 #define NB_IP4		(1 << NET_IP4)
 #define NB_IP6		(1 << NET_IP6)
@@ -37,6 +38,7 @@
 #define NB_IP6_SADR	(1 << NET_IP6_SADR)
 #define NB_MPLS		(1 << NET_MPLS)
 #define NB_ASPA		(1 << NET_ASPA)
+#define NB_PEER		(1 << NET_PEER)
 
 #define NB_IP		(NB_IP4 | NB_IP6)
 #define NB_VPN		(NB_VPN4 | NB_VPN6)
@@ -133,6 +135,13 @@ typedef struct net_addr_aspa {
   u32 asn;
 } net_addr_aspa;
 
+typedef struct net_addr_peer {
+  u8 type;
+  u8 pxlen;
+  u16 length;
+  ip_addr addr;			/* Peer IP address (IPv6 or IPv4) */
+} net_addr_peer;
+
 typedef struct net_addr_ip6_sadr {
   u8 type;
   u8 dst_pxlen;
@@ -155,6 +164,7 @@ typedef union net_addr_union {
   net_addr_ip6_sadr ip6_sadr;
   net_addr_mpls mpls;
   net_addr_aspa aspa;
+  net_addr_peer peer;
 } net_addr_union;
 
 
@@ -182,6 +192,7 @@ extern const u16 net_max_text_length[];
 #define NET_PTR_FLOW6(_n)	NET_PTR_GEN((_n), NET_FLOW6, flow6)
 #define NET_PTR_IP6_SADR(_n)	NET_PTR_GEN((_n), NET_IP6_SADR, ip6_sadr)
 #define NET_PTR_MPLS(_n)	NET_PTR_GEN((_n), NET_MPLS, mpls)
+#define NET_PTR_PEER(_n)	NET_PTR_GEN((_n), NET_PEER, peer)
 
 
 #define NET_ADDR_IP4(prefix,pxlen) \
@@ -217,6 +228,9 @@ extern const u16 net_max_text_length[];
 #define NET_ADDR_MPLS(label) \
   ((net_addr_mpls) { NET_MPLS, 20, sizeof(net_addr_mpls), label })
 
+#define NET_ADDR_PEER(addr) \
+  ((net_addr_peer) { NET_PEER, ipa_is_ip4(addr) ? 32 : 128, sizeof(net_addr_peer), addr })
+
 
 static inline void net_fill_ip4(net_addr *a, ip4_addr prefix, uint pxlen)
 { *(net_addr_ip4 *)a = NET_ADDR_IP4(prefix, pxlen); }
@@ -245,6 +259,9 @@ static inline void net_fill_mpls(net_addr *a, u32 label)
 static inline void net_fill_aspa(net_addr *a, u32 asn)
 { *(net_addr_aspa *)a = NET_ADDR_ASPA(asn); }
 
+static inline void net_fill_peer(net_addr *a, ip_addr addr)
+{ *(net_addr_peer *)a = NET_ADDR_PEER(addr); }
+
 static inline void net_fill_ipa(net_addr *a, ip_addr prefix, uint pxlen)
 {
   if (ipa_is_ip4(prefix))
@@ -489,6 +506,9 @@ static inline int net_compare_mpls(const net_addr_mpls *a, const net_addr_mpls *
 static inline int net_compare_aspa(const net_addr_aspa *a, const net_addr_aspa *b)
 { return uint_cmp(a->asn, b->asn); }
 
+static inline int net_compare_peer(const net_addr_peer *a, const net_addr_peer *b)
+{ return ipa_compare(a->addr, b->addr); }
+
 int net_compare(const net_addr *a, const net_addr *b);
 
 
@@ -528,6 +548,9 @@ static inline void net_copy_mpls(net_addr_mpls *dst, const net_addr_mpls *src)
 static inline void net_copy_aspa(net_addr_aspa *dst, const net_addr_aspa *src)
 { memcpy(dst, src, sizeof(net_addr_aspa)); }
 
+static inline void net_copy_peer(net_addr_peer *dst, const net_addr_peer *src)
+{ memcpy(dst, src, sizeof(net_addr_peer)); }
+
 
 static inline u32 px4_hash(ip4_addr prefix, u32 pxlen)
 { return ip4_hash(prefix) ^ (pxlen << 26); }
@@ -574,6 +597,9 @@ static inline u32 net_hash_mpls(const net_addr_mpls *n)
 static inline u32 net_hash_aspa(const net_addr_aspa *n)
 { return u32_hash(n->asn); }
 
+static inline u32 net_hash_peer(const net_addr_peer *n)
+{ return ipa_hash(n->addr); }
+
 u32 net_hash(const net_addr *a);
 
 
@@ -626,6 +652,9 @@ static inline int net_validate_mpls(const net_addr_mpls *n)
 static inline int net_validate_aspa(const net_addr_aspa *n)
 { return n->asn > 0; }
 
+static inline int net_validate_peer(const net_addr_peer *n)
+{ return ipa_nonzero(n->addr); }
+
 static inline int net_validate_ip6_sadr(const net_addr_ip6_sadr *n)
 { return net_validate_px6(n->dst_prefix, n->dst_pxlen) && net_validate_px6(n->src_prefix, n->src_pxlen); }
 
diff --git a/nest/config.Y b/nest/config.Y
index 681d0edd..f12103d9 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -153,7 +153,7 @@ CF_DECLS
 
 CF_KEYWORDS(ROUTER, ID, HOSTNAME, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT, PIPE)
 CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, VRF, DEFAULT, TABLE, TABLES, STATES, ROUTES, FILTERS)
-CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, SADR, MPLS, ASPA)
+CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, SADR, MPLS, ASPA, PEER)
 CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED, RPKI)
 CF_KEYWORDS(PASSWORD, KEY, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, CHANNELS, INTERFACES)
 CF_KEYWORDS(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512, BLAKE2S128, BLAKE2S256, BLAKE2B256, BLAKE2B512)
@@ -231,6 +231,7 @@ net_type_base:
  | FLOW4{ $$ = NET_FLOW4; }
  | FLOW6{ $$ = NET_FLOW6; }
  | ASPA { $$ = NET_ASPA; }
+ | PEER { $$ = NET_PEER; }
  ;
 
 net_type:
diff --git a/nest/proto.c b/nest/proto.c
index d6620065..e8d0021f 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -1168,7 +1168,7 @@ channel_config_new(const struct channel_class *cc, const char *name, uint net_ty
     if (!net_val_match(net_type, proto->protocol->channel_mask))
       cf_error("Unsupported channel type");
 
-    if (proto->net_type && (net_type != proto->net_type) && (net_type != NET_MPLS))
+    if (proto->net_type && (net_type != proto->net_type) && (net_type != NET_MPLS) && (net_type != NET_PEER))
       cf_error("Different channel type");
 
     tab = rt_get_default_table(new_config, net_type);
-- 
2.43.0



More information about the Bird-users mailing list