]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Nest: Ethernet net type - preliminary support
authorOndrej Zajicek <santiago@crfreenet.org>
Wed, 25 Oct 2023 17:16:40 +0000 (19:16 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Sat, 14 Jun 2025 20:55:32 +0000 (22:55 +0200)
conf/confbase.Y
lib/net.c
lib/net.h
nest/config.Y
nest/rt-fib.c

index c5844041b2810be904c5ceac2bb5f408e3e539a5..f6a09dd50588234dbe58f40715aa649314e04081 100644 (file)
@@ -150,7 +150,7 @@ CF_DECLS
 %type <time> expr_us time
 %type <a> ipa
 %type <net> net_ip4_ net_ip4 net_ip6_ net_ip6 net_ip_ net_ip net_or_ipa
-%type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ net_ip6_sadr_ net_mpls_ net_aspa_
+%type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ net_ip6_sadr_ net_eth_ net_mpls_ net_aspa_
 %type <net_ptr> net_evpn_ net_evpn_ead_ net_evpn_mac_ net_evpn_mac_ip_ net_evpn_imet_ net_evpn_es_
 %type <mls> label_stack_start label_stack
 %type <esi> evpn_esi
@@ -174,7 +174,7 @@ CF_DECLS
 /* See r_args */
 %expect 2
 
-CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN, MPLS, FROM, MAX, AS)
+CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN, ETH, VLAN, MPLS, FROM, MAX, AS)
 CF_KEYWORDS(EVPN, EAD, MAC, IMET, ES)
 
 CF_GRAMMAR
@@ -367,6 +367,18 @@ net_roa6_: net_ip6_ MAX expr AS expr
     cf_error("Invalid max prefix length %u", $3);
 };
 
+net_eth_: ETH MAC_
+{
+  $$ = cfg_alloc(sizeof(net_addr_eth));
+  net_fill_eth($$, $2, 0);
+}
+
+net_eth_: ETH MAC_ VLAN NUM
+{
+  $$ = cfg_alloc(sizeof(net_addr_eth));
+  net_fill_eth($$, $2, $4);
+}
+
 net_mpls_: MPLS expr
 {
   $$ = cfg_alloc(sizeof(net_addr_mpls));
@@ -429,6 +441,7 @@ net_:
  | net_roa_
  | net_flow_
  | net_ip6_sadr_
+ | net_eth_
  | net_mpls_
  | net_aspa_
  | net_evpn_
index b738a067ab48419c09a79265c24912bfaa7a5a66..319abb71f6f952cb918b94e08f3687e4b9926c06 100644 (file)
--- a/lib/net.c
+++ b/lib/net.c
@@ -15,6 +15,7 @@ const char * const net_label[] = {
   [NET_FLOW4]  = "flow4",
   [NET_FLOW6]  = "flow6",
   [NET_IP6_SADR]= "ipv6-sadr",
+  [NET_ETH]    = "eth",
   [NET_MPLS]   = "mpls",
   [NET_ASPA]   = "aspa",
   [NET_EVPN]   = "evpn",
@@ -30,6 +31,7 @@ const u16 net_addr_length[] = {
   [NET_FLOW4]  = 0,
   [NET_FLOW6]  = 0,
   [NET_IP6_SADR]= sizeof(net_addr_ip6_sadr),
+  [NET_ETH]    = sizeof(net_addr_eth),
   [NET_MPLS]   = sizeof(net_addr_mpls),
   [NET_ASPA]   = sizeof(net_addr_aspa),
   [NET_EVPN]   = 0,
@@ -45,6 +47,7 @@ const u8 net_max_prefix_length[] = {
   [NET_FLOW4]  = IP4_MAX_PREFIX_LENGTH,
   [NET_FLOW6]  = IP6_MAX_PREFIX_LENGTH,
   [NET_IP6_SADR]= IP6_MAX_PREFIX_LENGTH,
+  [NET_ETH]    = 0,
   [NET_MPLS]   = 0,
   [NET_ASPA]   = 0,
   [NET_EVPN]   = 0,
@@ -60,6 +63,7 @@ const u16 net_max_text_length[] = {
   [NET_FLOW4]  = 0,    /* "flow4 { ... }" */
   [NET_FLOW6]  = 0,    /* "flow6 { ... }" */
   [NET_IP6_SADR]= 92,  /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128 from ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */
+  [NET_ETH]    = 28,   /* "11:22:33:44:55:66 vlan 65535" */
   [NET_MPLS]   = 7,    /* "1048575" */
   [NET_ASPA]   = 10,   /* "4294967295" */
   [NET_EVPN]   = 0,
@@ -76,6 +80,7 @@ STATIC_ASSERT(sizeof(net_addr_roa6)   == 28);
 STATIC_ASSERT(sizeof(net_addr_flow4)   ==  8);
 STATIC_ASSERT(sizeof(net_addr_flow6)   == 20);
 STATIC_ASSERT(sizeof(net_addr_ip6_sadr)        == 40);
+STATIC_ASSERT(sizeof(net_addr_eth)     == 12);
 STATIC_ASSERT(sizeof(net_addr_mpls)    ==  8);
 STATIC_ASSERT(sizeof(net_addr_aspa)    ==  8);
 
@@ -98,6 +103,7 @@ STATIC_ASSERT(alignof(net_addr_flow6)        == alignof(net_addr));
 STATIC_ASSERT(alignof(net_addr_flow4)  == alignof(net_addr));
 STATIC_ASSERT(alignof(net_addr_flow6)  == alignof(net_addr));
 STATIC_ASSERT(alignof(net_addr_ip6_sadr) == alignof(net_addr));
+STATIC_ASSERT(alignof(net_addr_eth)    == alignof(net_addr));
 STATIC_ASSERT(alignof(net_addr_mpls)   == alignof(net_addr));
 STATIC_ASSERT(alignof(net_addr_aspa)   == alignof(net_addr));
 
@@ -161,6 +167,16 @@ net_format(const net_addr *N, char *buf, int buflen)
     return flow6_net_format(buf, buflen, &n->flow6);
   case NET_IP6_SADR:
     return bsnprintf(buf, buflen, "%I6/%d from %I6/%d", n->ip6_sadr.dst_prefix, n->ip6_sadr.dst_pxlen, n->ip6_sadr.src_prefix, n->ip6_sadr.src_pxlen);
+  case NET_ETH:
+  {
+    int c = bsnprintf(buf, buflen, "%6b", &n->eth.mac);
+    ADVANCE(buf, buflen, c);
+
+    if (n->eth.vid)
+      c += bsnprintf(buf, buflen, " vlan %d", (int) n->eth.vid);
+
+    return c;
+  }
   case NET_MPLS:
     return bsnprintf(buf, buflen, "%u", n->mpls.label);
   case NET_ASPA:
@@ -190,6 +206,7 @@ net_pxmask(const net_addr *a)
   case NET_IP6_SADR:
     return ipa_from_ip6(ip6_mkmask(net6_pxlen(a)));
 
+  case NET_ETH:
   case NET_MPLS:
   case NET_ASPA:
   case NET_EVPN:
@@ -224,6 +241,8 @@ net_compare(const net_addr *a, const net_addr *b)
     return net_compare_flow6((const net_addr_flow6 *) a, (const net_addr_flow6 *) b);
   case NET_IP6_SADR:
     return net_compare_ip6_sadr((const net_addr_ip6_sadr *) a, (const net_addr_ip6_sadr *) b);
+  case NET_ETH:
+    return net_compare_eth((const net_addr_eth *) a, (const net_addr_eth *) b);
   case NET_MPLS:
     return net_compare_mpls((const net_addr_mpls *) a, (const net_addr_mpls *) b);
   case NET_ASPA:
@@ -250,6 +269,7 @@ net_hash(const net_addr *n)
   case NET_FLOW4: return NET_HASH(n, flow4);
   case NET_FLOW6: return NET_HASH(n, flow6);
   case NET_IP6_SADR: return NET_HASH(n, ip6_sadr);
+  case NET_ETH: return NET_HASH(n, eth);
   case NET_MPLS: return NET_HASH(n, mpls);
   case NET_ASPA: return NET_HASH(n, aspa);
   case NET_EVPN: return NET_HASH(n, evpn);
@@ -274,6 +294,7 @@ net_validate(const net_addr *n)
   case NET_FLOW4: return NET_VALIDATE(n, flow4);
   case NET_FLOW6: return NET_VALIDATE(n, flow6);
   case NET_IP6_SADR: return NET_VALIDATE(n, ip6_sadr);
+  case NET_ETH: return NET_VALIDATE(n, eth);
   case NET_MPLS: return NET_VALIDATE(n, mpls);
   case NET_ASPA: return NET_VALIDATE(n, aspa);
   case NET_EVPN: return NET_VALIDATE(n, evpn);
@@ -303,6 +324,7 @@ net_normalize(net_addr *N)
   case NET_IP6_SADR:
     return net_normalize_ip6_sadr(&n->ip6_sadr);
 
+  case NET_ETH:
   case NET_MPLS:
   case NET_ASPA:
   case NET_EVPN:
@@ -332,6 +354,7 @@ net_classify(const net_addr *N)
   case NET_IP6_SADR:
     return ip6_zero(n->ip6_sadr.dst_prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(&n->ip6_sadr.dst_prefix);
 
+  case NET_ETH:
   case NET_MPLS:
   case NET_ASPA:
   case NET_EVPN:       /* ?? */
@@ -367,6 +390,7 @@ ipa_in_netX(const ip_addr a, const net_addr *n)
     return ip6_zero(ip6_and(ip6_xor(ipa_to_ip6(a), net6_prefix(n)),
                            ip6_mkmask(net6_pxlen(n))));
 
+  case NET_ETH:
   case NET_MPLS:
   case NET_ASPA:
   case NET_EVPN:
index ed12e985feea0bc529185058b143f34e710f7358..7dee52dec6649fe044a64cfc7302935550697b41 100644 (file)
--- a/lib/net.h
+++ b/lib/net.h
 #define NET_FLOW4      7
 #define NET_FLOW6      8
 #define NET_IP6_SADR   9
-#define NET_MPLS       10
-#define NET_ASPA       11
-#define NET_EVPN       12
-#define NET_MAX                13
+#define NET_ETH                10
+#define NET_MPLS       11
+#define NET_ASPA       12
+#define NET_EVPN       13
+#define NET_MAX                14
 
 #define NB_IP4         (1 << NET_IP4)
 #define NB_IP6         (1 << NET_IP6)
@@ -38,6 +39,7 @@
 #define NB_FLOW4       (1 << NET_FLOW4)
 #define NB_FLOW6       (1 << NET_FLOW6)
 #define NB_IP6_SADR    (1 << NET_IP6_SADR)
+#define NB_ETH         (1 << NET_ETH)
 #define NB_MPLS                (1 << NET_MPLS)
 #define NB_ASPA                (1 << NET_ASPA)
 #define NB_EVPN                (1 << NET_EVPN)
@@ -46,7 +48,7 @@
 #define NB_VPN         (NB_VPN4 | NB_VPN6)
 #define NB_ROA         (NB_ROA4 | NB_ROA6)
 #define NB_FLOW                (NB_FLOW4 | NB_FLOW6)
-#define NB_DEST                (NB_IP | NB_IP6_SADR | NB_VPN | NB_MPLS | NB_EVPN)
+#define NB_DEST                (NB_IP | NB_IP6_SADR | NB_VPN | NB_ETH | NB_MPLS | NB_EVPN)
 #define NB_ANY         0xffffffff
 
 
@@ -123,6 +125,15 @@ typedef struct net_addr_flow6 {
   byte data[0];
 } net_addr_flow6;
 
+typedef struct net_addr_eth {
+  u8 type;
+  u8 pxlen;
+  u16 length;
+  mac_addr mac;
+  u16 vid;
+  u32 align[0];
+} net_addr_eth;
+
 typedef struct net_addr_mpls {
   u8 type;
   u8 pxlen;
@@ -229,6 +240,7 @@ typedef union net_addr_union {
   net_addr_flow4 flow4;
   net_addr_flow6 flow6;
   net_addr_ip6_sadr ip6_sadr;
+  net_addr_eth eth;
   net_addr_mpls mpls;
   net_addr_aspa aspa;
   net_addr_evpn evpn;
@@ -270,6 +282,9 @@ extern const u16 net_max_text_length[];
 #define NET_ADDR_IP6_SADR(dst_prefix,dst_pxlen,src_prefix,src_pxlen) \
   ((net_addr_ip6_sadr) { NET_IP6_SADR, dst_pxlen, sizeof(net_addr_ip6_sadr), dst_prefix, src_pxlen, src_prefix })
 
+#define NET_ADDR_ETH(mac, vid) \
+  ((net_addr_eth) { NET_ETH, 48, sizeof(net_addr_eth), mac, vid })
+
 #define NET_ADDR_MPLS(label) \
   ((net_addr_mpls) { NET_MPLS, 20, sizeof(net_addr_mpls), label })
 
@@ -313,6 +328,9 @@ static inline void net_fill_roa6(net_addr *a, ip6_addr prefix, uint pxlen, uint
 static inline void net_fill_ip6_sadr(net_addr *a, ip6_addr dst_prefix, uint dst_pxlen, ip6_addr src_prefix, uint src_pxlen)
 { *(net_addr_ip6_sadr *)a = NET_ADDR_IP6_SADR(dst_prefix, dst_pxlen, src_prefix, src_pxlen); }
 
+static inline void net_fill_eth(net_addr *a, mac_addr mac, u16 vid)
+{ *(net_addr_eth *)a = NET_ADDR_ETH(mac, vid); }
+
 static inline void net_fill_mpls(net_addr *a, u32 label)
 { *(net_addr_mpls *)a = NET_ADDR_MPLS(label); }
 
@@ -421,6 +439,7 @@ static inline ip_addr net_prefix(const net_addr *a)
   case NET_IP6_SADR:
     return ipa_from_ip6(net6_prefix(a));
 
+  case NET_ETH:
   case NET_MPLS:
   case NET_ASPA:
   case NET_EVPN:
@@ -429,12 +448,16 @@ static inline ip_addr net_prefix(const net_addr *a)
   }
 }
 
-static inline u32 net_mpls(const net_addr *a)
+static inline mac_addr net_mac_addr(const net_addr *a)
 {
-  if (a->type == NET_MPLS)
-    return ((net_addr_mpls *) a)->label;
+  ASSERT_DIE(a->type == NET_ETH);
+  return ((net_addr_eth *) a)->mac;
+}
 
-  bug("Can't call net_mpls on non-mpls net_addr");
+static inline u32 net_mpls(const net_addr *a)
+{
+  ASSERT_DIE(a->type == NET_MPLS);
+  return ((net_addr_mpls *) a)->label;
 }
 
 static inline uint net4_pxlen(const net_addr *a)
@@ -493,6 +516,9 @@ static inline int net_equal_flow6(const net_addr_flow6 *a, const net_addr_flow6
 static inline int net_equal_ip6_sadr(const net_addr_ip6_sadr *a, const net_addr_ip6_sadr *b)
 { return !memcmp(a, b, sizeof(net_addr_ip6_sadr)); }
 
+static inline int net_equal_eth(const net_addr_eth *a, const net_addr_eth *b)
+{ return !memcmp(a, b, sizeof(net_addr_eth)); }
+
 static inline int net_equal_mpls(const net_addr_mpls *a, const net_addr_mpls *b)
 { return !memcmp(a, b, sizeof(net_addr_mpls)); }
 
@@ -540,6 +566,9 @@ static inline int net_zero_flow4(const net_addr_flow4 *a)
 static inline int net_zero_flow6(const net_addr_flow6 *a)
 { return !a->pxlen && ip6_zero(a->prefix) && (a->length == sizeof(net_addr_flow6)); }
 
+static inline int net_zero_eth(const net_addr_eth *a)
+{ return mac_zero(a->mac) && !a->vid; }
+
 static inline int net_zero_mpls(const net_addr_mpls *a)
 { return !a->label; }
 
@@ -578,6 +607,9 @@ static inline int net_compare_ip6_sadr(const net_addr_ip6_sadr *a, const net_add
     ip6_compare(a->src_prefix, b->src_prefix) ?: uint_cmp(a->src_pxlen, b->src_pxlen);
 }
 
+static inline int net_compare_eth(const net_addr_eth *a, const net_addr_eth *b)
+{ return uint_cmp(a->vid, b->vid) ?: mac_compare(a->mac, b->mac); }
+
 static inline int net_compare_mpls(const net_addr_mpls *a, const net_addr_mpls *b)
 { return uint_cmp(a->label, b->label); }
 
@@ -624,6 +656,9 @@ static inline void net_copy_flow6(net_addr_flow6 *dst, const net_addr_flow6 *src
 static inline void net_copy_ip6_sadr(net_addr_ip6_sadr *dst, const net_addr_ip6_sadr *src)
 { memcpy(dst, src, sizeof(net_addr_ip6_sadr)); }
 
+static inline void net_copy_eth(net_addr_eth *dst, const net_addr_eth *src)
+{ memcpy(dst, src, sizeof(net_addr_eth)); }
+
 static inline void net_copy_mpls(net_addr_mpls *dst, const net_addr_mpls *src)
 { memcpy(dst, src, sizeof(net_addr_mpls)); }
 
@@ -673,6 +708,9 @@ static inline u32 net_hash_flow6(const net_addr_flow6 *n)
 static inline u32 net_hash_ip6_sadr(const net_addr_ip6_sadr *n)
 { return px6_hash(n->dst_prefix, n->dst_pxlen); }
 
+static inline u32 net_hash_eth(const net_addr_eth *n)
+{ u64 x = 0; memcpy(&x, (char *) n + OFFSETOF(net_addr_eth, mac), 8); return u64_hash(x); }
+
 static inline u32 net_hash_mpls(const net_addr_mpls *n)
 { return u32_hash(n->label); }
 
@@ -728,6 +766,9 @@ static inline int net_validate_flow4(const net_addr_flow4 *n)
 static inline int net_validate_flow6(const net_addr_flow6 *n)
 { return net_validate_px6(n->prefix, n->pxlen); }
 
+static inline int net_validate_eth(const net_addr_eth *n)
+{ return n->vid < (1 << 12); }
+
 static inline int net_validate_mpls(const net_addr_mpls *n)
 { return n->label < (1 << 20); }
 
index 8e2ca3d743d2025929b220594865653a8173672c..7f7fc4b21a32b52ea50e0b83d48c64ba61ad613c 100644 (file)
@@ -115,7 +115,7 @@ CF_DECLS
 
 CF_KEYWORDS(ROUTER, ID, HOSTNAME, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
 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, ETH, MPLS, ASPA)
 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)
@@ -132,7 +132,7 @@ CF_KEYWORDS(ASPA_PROVIDERS)
 /* For r_args_channel */
 CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, IPV6_SADR, VPN4, VPN4_MC, VPN4_MPLS, VPN6, VPN6_MC, VPN6_MPLS, ROA4, ROA6, FLOW4, FLOW6, MPLS, PRI, SEC, ASPA)
 
-CF_ENUM(T_ENUM_NET_TYPE, NET_, IP4, IP6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, IP6_SADR, MPLS, ASPA, EVPN)
+CF_ENUM(T_ENUM_NET_TYPE, NET_, IP4, IP6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, IP6_SADR, ETH, MPLS, ASPA, EVPN)
 CF_ENUM(T_ENUM_RTS, RTS_, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
        RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE, BABEL, RPKI, L3VPN,
        AGGREGATED)
@@ -192,6 +192,7 @@ net_type_base:
  | ROA6 { $$ = NET_ROA6; }
  | FLOW4{ $$ = NET_FLOW4; }
  | FLOW6{ $$ = NET_FLOW6; }
+ | ETH  { $$ = NET_ETH; }
  | ASPA { $$ = NET_ASPA; }
  | EVPN { $$ = NET_EVPN; }
  ;
index fe8b721504638dca6ed0a317bfa3874c4399b579..1eb5cc7f8e948206d76b0c2835c8d46c324268e7 100644 (file)
@@ -278,6 +278,7 @@ fib_find(struct fib *f, const net_addr *a)
   case NET_FLOW4: return FIB_FIND(f, a, flow4);
   case NET_FLOW6: return FIB_FIND(f, a, flow6);
   case NET_IP6_SADR: return FIB_FIND(f, a, ip6_sadr);
+  case NET_ETH: return FIB_FIND(f, a, eth);
   case NET_MPLS: return FIB_FIND(f, a, mpls);
   case NET_ASPA: return FIB_FIND(f, a, aspa);
   case NET_EVPN: return FIB_FIND(f, a, evpn);
@@ -301,6 +302,7 @@ fib_insert(struct fib *f, const net_addr *a, struct fib_node *e)
   case NET_FLOW4: FIB_INSERT(f, a, e, flow4); return;
   case NET_FLOW6: FIB_INSERT(f, a, e, flow6); return;
   case NET_IP6_SADR: FIB_INSERT(f, a, e, ip6_sadr); return;
+  case NET_ETH: FIB_INSERT(f, a, e, eth); return;
   case NET_MPLS: FIB_INSERT(f, a, e, mpls); return;
   case NET_ASPA: FIB_INSERT(f, a, e, aspa); return;
   case NET_EVPN: FIB_INSERT(f, a, e, evpn); return;