]> 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>
Wed, 31 Jan 2024 13:31:33 +0000 (14:31 +0100)
conf/confbase.Y
lib/net.c
lib/net.h
nest/config.Y
nest/rt-fib.c

index 668ba413b2a820adcfef76553d5d491482fd29bd..f5bd5019ff8a4774167111dddb0a9747c1008557 100644 (file)
@@ -121,7 +121,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_
+%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_
 %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
@@ -143,7 +143,7 @@ CF_DECLS
 
 %start config
 
-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
@@ -299,6 +299,18 @@ net_roa6_: net_ip6_ MAX NUM AS NUM
     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 NUM
 {
   $$ = cfg_alloc(sizeof(net_addr_mpls));
@@ -355,6 +367,7 @@ net_:
  | net_roa_
  | net_flow_
  | net_ip6_sadr_
+ | net_eth_
  | net_mpls_
  | net_evpn_
  ;
index 25de9c2d6d885571864d1e3cb2764a2f6abd7117..b83b1a75a7e25b4ce3750f67c081aa46d4eaead2 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_EVPN]   = "evpn",
 };
@@ -29,6 +30,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_EVPN]   = 0,
 };
@@ -43,6 +45,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_EVPN]   = 0,
 };
@@ -57,6 +60,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_EVPN]   = 0,
 };
@@ -72,6 +76,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_evpn_ead)                == 32);
@@ -132,6 +137,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_EVPN:
@@ -159,6 +174,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_EVPN:
   default:
@@ -192,6 +208,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_EVPN:
@@ -216,6 +234,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_EVPN: return NET_HASH(n, evpn);
   default: bug("invalid type");
@@ -239,6 +258,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_EVPN: return NET_VALIDATE(n, evpn);
   default: return 0;
@@ -267,6 +287,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_EVPN:
     return;
@@ -295,6 +316,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_EVPN:       /* ?? */
     return IADDR_HOST | SCOPE_UNIVERSE;
@@ -329,6 +351,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_EVPN:
   default:
index 3cfeae18815926f65ad1dc0060aa7fbdbeb9c2a0..1fe9902bdd33208ff43b0a1d0b081d3d85bc5a34 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_EVPN       11
-#define NET_MAX                12
+#define NET_ETH                10
+#define NET_MPLS       11
+#define NET_EVPN       12
+#define NET_MAX                13
 
 #define NB_IP4         (1 << NET_IP4)
 #define NB_IP6         (1 << NET_IP6)
@@ -37,6 +38,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_EVPN                (1 << NET_EVPN)
 
@@ -44,7 +46,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
 
 
@@ -121,6 +123,14 @@ 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;
+} net_addr_eth;
+
 typedef struct net_addr_mpls {
   u8 type;
   u8 pxlen;
@@ -220,6 +230,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_evpn evpn;
 } net_addr_union;
@@ -260,6 +271,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 })
 
@@ -301,6 +315,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); }
 
@@ -405,6 +422,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_EVPN:
   default:
@@ -412,12 +430,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)
@@ -476,6 +498,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)); }
 
@@ -520,6 +545,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; }
 
@@ -555,6 +583,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); }
 
@@ -598,6 +629,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)); }
 
@@ -644,6 +678,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); }
 
@@ -696,6 +733,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 c413bf3d77b614e3bd19f2c984c9345114f9003c..c64a355ef9bb4aae87302e9d7db4cef8b986ca77 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)
+CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, SADR, ETH, MPLS)
 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)
@@ -203,6 +203,7 @@ net_type_base:
  | ROA6 { $$ = NET_ROA6; }
  | FLOW4{ $$ = NET_FLOW4; }
  | FLOW6{ $$ = NET_FLOW6; }
+ | ETH  { $$ = NET_ETH; }
  | EVPN { $$ = NET_EVPN; }
  ;
 
@@ -211,7 +212,7 @@ net_type:
  | MPLS { $$ = NET_MPLS; }
  ;
 
-CF_ENUM(T_ENUM_NETTYPE, NET_, IP4, IP6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, IP6_SADR, MPLS, EVPN)
+CF_ENUM(T_ENUM_NETTYPE, NET_, IP4, IP6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, IP6_SADR, ETH, MPLS, EVPN)
 
 
 /* Creation of routing tables */
index 6b333278a38cdd675d5173b74fbb0a5e00befefa..9a3fcf15dd1ad591b5149816ff4e35ddc14cb0f1 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_EVPN: return FIB_FIND(f, a, evpn);
   default: bug("invalid type");
@@ -300,6 +301,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_EVPN: FIB_INSERT(f, a, e, evpn); return;
   default: bug("invalid type");