]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Nest: EVPN net type - preliminary support
authorOndrej Zajicek <santiago@crfreenet.org>
Mon, 29 May 2023 03:36:40 +0000 (05:36 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Sat, 14 Jun 2025 20:09:32 +0000 (22:09 +0200)
conf/cf-lex.l
conf/confbase.Y
filter/data.c
filter/data.h
lib/Makefile
lib/evpn.c [new file with mode: 0644]
lib/evpn.h [new file with mode: 0644]
lib/net.c
lib/net.h
nest/config.Y
nest/rt-fib.c

index 0119e1f55435ef40c23d66db082768cfd154fc9a..31e4757ca731500939a8c133e78b94255d668565 100644 (file)
@@ -246,7 +246,19 @@ WHITE [ \t]
   return IP4;
 }
 
-({XIGIT}{2}){16,}|{XIGIT}{2}(:{XIGIT}{2}){15,}|hex:({XIGIT}{2}*|{XIGIT}{2}(:{XIGIT}{2})*) {
+{XIGIT}{2}(:{XIGIT}{2}){5} {
+  mac_addr mac;
+  char *s = yytext;
+
+  int len = bstrhextobin(s, mac.addr);
+  if (len != 6)
+    cf_error("Invalid MAC address");
+
+  cf_lval.mac = mac;
+  return MAC_;
+}
+
+({XIGIT}{2}){10,}|{XIGIT}{2}(:{XIGIT}{2}){9,}|hex:({XIGIT}{2}*|{XIGIT}{2}(:{XIGIT}{2})*) {
   char *s = yytext;
   struct adata *bs;
 
index b2ba3cafbfbb65a79727bfb2643c9a3536899fbe..c5844041b2810be904c5ceac2bb5f408e3e539a5 100644 (file)
@@ -16,6 +16,7 @@ CF_HDR
 #include "lib/socket.h"
 #include "lib/timer.h"
 #include "lib/string.h"
+#include "lib/evpn.h"
 #include "nest/protocol.h"
 #include "nest/iface.h"
 #include "nest/route.h"
@@ -86,7 +87,9 @@ CF_DECLS
   ip_addr a;
   ip4_addr ip4;
   ip6_addr ip6;
+  mac_addr mac;
   net_addr net;
+  evpn_esi esi;
   net_addr *net_ptr;
   struct symbol *s;
   struct keyword *kw;
@@ -135,6 +138,7 @@ CF_DECLS
 %token <i> NUM ENUM_TOKEN
 %token <ip4> IP4
 %token <ip6> IP6
+%token <mac> MAC_
 %token <rd> VPN_RD
 %token <s> CF_SYM_KNOWN CF_SYM_UNDEFINED CF_SYM_METHOD_BARE CF_SYM_METHOD_ARGS
 %token <t> TEXT
@@ -147,7 +151,9 @@ CF_DECLS
 %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_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
 
 %type <t> text opttext
 %type <bs> bytestring
@@ -169,6 +175,7 @@ CF_DECLS
 %expect 2
 
 CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN, MPLS, FROM, MAX, AS)
+CF_KEYWORDS(EVPN, EAD, MAC, IMET, ES)
 
 CF_GRAMMAR
 
@@ -372,6 +379,46 @@ net_aspa_: ASPA expr
   net_fill_aspa($$, $2);
 }
 
+evpn_esi: bytestring
+{
+  if ($1->length != 10)
+    cf_error("Invalid ESI length %u", (uint) $1->length);
+
+  memcpy(&$$, $1->data, 10);
+}
+
+net_evpn_ead_: EVPN EAD VPN_RD NUM evpn_esi
+{
+  $$ = cfg_alloc(sizeof(net_addr_evpn_ead));
+  net_fill_evpn_ead($$, $3, $4, $5);
+}
+
+net_evpn_mac_: EVPN MAC VPN_RD NUM MAC_ '*'
+{
+  $$ = cfg_alloc(sizeof(net_addr_evpn_mac));
+  net_fill_evpn_mac($$, $3, $4, $5);
+}
+
+net_evpn_mac_ip_: EVPN MAC VPN_RD NUM MAC_ ipa
+{
+  $$ = cfg_alloc(sizeof(net_addr_evpn_mac_ip));
+  net_fill_evpn_mac_ip($$, $3, $4, $5, $6);
+}
+
+net_evpn_imet_: EVPN IMET VPN_RD NUM ipa
+{
+  $$ = cfg_alloc(sizeof(net_addr_evpn_imet));
+  net_fill_evpn_imet($$, $3, $4, $5);
+}
+
+net_evpn_es_: EVPN ES VPN_RD evpn_esi ipa
+{
+  $$ = cfg_alloc(sizeof(net_addr_evpn_es));
+  net_fill_evpn_es($$, $3, $4, $5);
+}
+
+net_evpn_: net_evpn_ead_ | net_evpn_mac_ | net_evpn_mac_ip_ | net_evpn_imet_ | net_evpn_es_ ;
+
 net_ip_: net_ip4_ | net_ip6_ ;
 net_vpn_: net_vpn4_ | net_vpn6_ ;
 net_roa_: net_roa4_ | net_roa6_ ;
@@ -384,6 +431,7 @@ net_:
  | net_ip6_sadr_
  | net_mpls_
  | net_aspa_
+ | net_evpn_
  ;
 
 
index f5a9e5eecf5263290702f6a34179c59693339c7e..bc6351cfed7424e7df25958658f692178b9177bd 100644 (file)
@@ -44,6 +44,7 @@ static const char * const f_type_str[] = {
   [T_ENUM_RA_PREFERENCE] = "enum ra_preference",
   [T_ENUM_AF]  = "enum af",
   [T_ENUM_MPLS_POLICY] = "enum mpls_policy",
+  [T_ENUM_NET_EVPN_TYPE] = "enum net_evpn_type",
 
   [T_IP]       = "ip",
   [T_NET]      = "prefix",
index f36820cba4d20ab4a82449c4e99afe276e62ca60..5e529748af3a7ca2821ebef63f4dde599f557dbb 100644 (file)
@@ -43,6 +43,7 @@ enum f_type {
   T_ENUM_RA_PREFERENCE = 0x37,
   T_ENUM_AF = 0x38,
   T_ENUM_MPLS_POLICY = 0x39,
+  T_ENUM_NET_EVPN_TYPE = 0x3a,
 
 /* new enums go here */
   T_ENUM_EMPTY = 0x3f, /* Special hack for atomic_aggr */
index 812f721cc844f4c8fcd325b9c66089122010b566..21aad3784b22a20431a2bc9ca93c25f7dbadadc7 100644 (file)
@@ -1,4 +1,4 @@
-src := bitmap.c bitops.c blake2s.c blake2b.c checksum.c event.c flowspec.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c
+src := bitmap.c bitops.c blake2s.c blake2b.c checksum.c event.c evpn.c flowspec.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c
 obj := $(src-o-files)
 $(all-daemon)
 
diff --git a/lib/evpn.c b/lib/evpn.c
new file mode 100644 (file)
index 0000000..8f4be04
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *     BIRD Internet Routing Daemon -- EVPN Net Type
+ *
+ *     (c) 2023 Ondrej Zajicek <santiago@crfreenet.org>
+ *     (c) 2023 CZ.NIC z.s.p.o.
+ *
+ *     Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "nest/bird.h"
+#include "lib/net.h"
+
+uint
+evpn_format(char *buf, uint blen, const net_addr_evpn *n)
+{
+  char rds[32];
+  rd_format(n->rd, rds, 32);
+
+  switch (n->subtype)
+  {
+  case NET_EVPN_EAD:
+    return bsnprintf(buf, blen, "evpn ead %s %u %10b", rds, n->tag, &n->ead.esi);
+
+  case NET_EVPN_MAC:
+    if (n->length < sizeof(net_addr_evpn_mac_ip))
+      return bsnprintf(buf, blen, "evpn mac %s %u %6b *", rds, n->tag, &n->mac.mac);
+    else
+      return bsnprintf(buf, blen, "evpn mac %s %u %6b %I", rds, n->tag, &n->mac_ip.mac, n->mac_ip.ip);
+
+  case NET_EVPN_IMET:
+    return bsnprintf(buf, blen, "evpn imet %s %u %I", rds, n->tag, n->imet.rtr);
+
+  case NET_EVPN_ES:
+    return bsnprintf(buf, blen, "evpn es %s %10b %I", rds, &n->es.esi, n->es.rtr);
+  }
+
+  bug("unknown EVPN type %d", n->subtype);
+}
diff --git a/lib/evpn.h b/lib/evpn.h
new file mode 100644 (file)
index 0000000..c340c38
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *     BIRD Internet Routing Daemon -- EVPN Net Type
+ *
+ *     (c) 2023 Ondrej Zajicek <santiago@crfreenet.org>
+ *     (c) 2023 CZ.NIC z.s.p.o.
+ *
+ *     Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _BIRD_EVPN_NET_H_
+#define _BIRD_EVPN_NET_H_
+
+enum evpn_net_type {
+  NET_EVPN_EAD         =  1,
+  NET_EVPN_MAC         =  2,
+  NET_EVPN_IMET                =  3,
+  NET_EVPN_ES          =  4,
+  NET_EVPN_MAX
+};
+
+enum evpn_esi_type {
+  EVPN_ESI_MANUAL      = 0,
+  EVPN_ESI_LACP                = 1,
+  EVPN_ESI_MAX
+};
+
+typedef struct evpn_esi {
+  u8 type;
+  u8 value[9];
+} evpn_esi;
+
+typedef struct mac_addr {
+  u8 addr[6];
+} mac_addr;
+
+#define MAC_NONE ((mac_addr){ })
+
+static inline int mac_zero(mac_addr a)
+{ return !memcmp(&a, &MAC_NONE, sizeof(mac_addr)); }
+
+static inline int mac_nonzero(mac_addr a)
+{ return !mac_zero(a); }
+
+static inline int mac_compare(mac_addr a, mac_addr b)
+{ return memcmp(&a, &b, sizeof(mac_addr)); }
+
+union net_addr_evpn;
+uint evpn_format(char *buf, uint blen, const union net_addr_evpn *n);
+
+#endif
index 64cf9e047414c81073fedc7d65b7a970daf4dcd9..b738a067ab48419c09a79265c24912bfaa7a5a66 100644 (file)
--- 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_EVPN]   = "evpn",
 };
 
 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_EVPN]   = 0,
 };
 
 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_EVPN]   = 0,
 };
 
 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_EVPN]   = 0,
 };
 
 /* There should be no implicit padding in net_addr structures */
@@ -75,6 +79,13 @@ 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_evpn_ead)                == 32);
+STATIC_ASSERT(sizeof(net_addr_evpn_mac)                == 24);
+STATIC_ASSERT(sizeof(net_addr_evpn_mac_ip)     == 40);
+STATIC_ASSERT(sizeof(net_addr_evpn_imet)       == 32);
+STATIC_ASSERT(sizeof(net_addr_evpn_es)         == 48);
+STATIC_ASSERT(sizeof(net_addr_evpn)            == 48);
+
 /* Ensure that all net_addr structures have the same alignment */
 STATIC_ASSERT(alignof(net_addr_ip4)    == alignof(net_addr));
 STATIC_ASSERT(alignof(net_addr_ip6)    == alignof(net_addr));
@@ -90,6 +101,13 @@ 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_evpn_ead)       == alignof(net_addr));
+STATIC_ASSERT(alignof(net_addr_evpn_mac)       == alignof(net_addr));
+STATIC_ASSERT(alignof(net_addr_evpn_mac_ip)    == alignof(net_addr));
+STATIC_ASSERT(alignof(net_addr_evpn_imet)      == alignof(net_addr));
+STATIC_ASSERT(alignof(net_addr_evpn_es)                == alignof(net_addr));
+STATIC_ASSERT(alignof(net_addr_evpn)           == alignof(net_addr));
+
 
 int
 rd_format(const vpn_rd rd_, char *buf, int buflen)
@@ -147,6 +165,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_EVPN:
+    return evpn_format(buf, buflen, &n->evpn);;
   }
 
   bug("unknown network type");
@@ -172,6 +192,7 @@ net_pxmask(const net_addr *a)
 
   case NET_MPLS:
   case NET_ASPA:
+  case NET_EVPN:
   default:
     return IPA_NONE;
   }
@@ -207,6 +228,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_EVPN:
+    return net_compare_evpn((const net_addr_evpn *) a, (const net_addr_evpn *) b);
   }
   return 0;
 }
@@ -229,6 +252,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_EVPN: return NET_HASH(n, evpn);
   default: bug("invalid type");
   }
 }
@@ -252,6 +276,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_EVPN: return NET_VALIDATE(n, evpn);
   default: return 0;
   }
 }
@@ -280,6 +305,7 @@ net_normalize(net_addr *N)
 
   case NET_MPLS:
   case NET_ASPA:
+  case NET_EVPN:
     return;
   }
 }
@@ -308,6 +334,7 @@ net_classify(const net_addr *N)
 
   case NET_MPLS:
   case NET_ASPA:
+  case NET_EVPN:       /* ?? */
     return IADDR_HOST | SCOPE_UNIVERSE;
   }
 
@@ -342,6 +369,7 @@ ipa_in_netX(const ip_addr a, const net_addr *n)
 
   case NET_MPLS:
   case NET_ASPA:
+  case NET_EVPN:
   default:
     return 0;
   }
index a1fd0291e445b9f50115e0df68b0022f5205e6d6..ed12e985feea0bc529185058b143f34e710f7358 100644 (file)
--- a/lib/net.h
+++ b/lib/net.h
@@ -11,6 +11,8 @@
 #define _BIRD_NET_H_
 
 #include "lib/ip.h"
+#include "lib/evpn.h"
+#include "lib/hash.h"
 
 
 #define NET_IP4                1
@@ -24,7 +26,8 @@
 #define NET_IP6_SADR   9
 #define NET_MPLS       10
 #define NET_ASPA       11
-#define NET_MAX                12
+#define NET_EVPN       12
+#define NET_MAX                13
 
 #define NB_IP4         (1 << NET_IP4)
 #define NB_IP6         (1 << NET_IP6)
 #define NB_IP6_SADR    (1 << NET_IP6_SADR)
 #define NB_MPLS                (1 << NET_MPLS)
 #define NB_ASPA                (1 << NET_ASPA)
+#define NB_EVPN                (1 << NET_EVPN)
 
 #define NB_IP          (NB_IP4 | NB_IP6)
 #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)
+#define NB_DEST                (NB_IP | NB_IP6_SADR | NB_VPN | NB_MPLS | NB_EVPN)
 #define NB_ANY         0xffffffff
 
 
@@ -142,6 +146,78 @@ typedef struct net_addr_ip6_sadr {
   ip6_addr src_prefix;
 } net_addr_ip6_sadr;
 
+typedef struct net_addr_evpn_ead {
+  u8 type;
+  u8 subtype;
+  u16 length;
+  u32 tag;
+  vpn_rd rd;
+
+  evpn_esi esi;
+  u8 padding[6];
+} net_addr_evpn_ead;
+
+typedef struct net_addr_evpn_mac {
+  u8 type;
+  u8 subtype;
+  u16 length;
+  u32 tag;
+  vpn_rd rd;
+
+  mac_addr mac;
+  u16 padding;
+} net_addr_evpn_mac;
+
+typedef struct net_addr_evpn_mac_ip {
+  u8 type;
+  u8 subtype;
+  u16 length;
+  u32 tag;
+  vpn_rd rd;
+
+  mac_addr mac;
+  u16 padding0;
+  ip_addr ip;
+} net_addr_evpn_mac_ip;
+
+typedef struct net_addr_evpn_imet {
+  u8 type;
+  u8 subtype;
+  u16 length;
+  u32 tag;
+  vpn_rd rd;
+
+  ip_addr rtr;
+} net_addr_evpn_imet;
+
+typedef struct net_addr_evpn_es {
+  u8 type;
+  u8 subtype;
+  u16 length;
+  u32 tag;     /* unused */
+  vpn_rd rd;
+
+  evpn_esi esi;
+  u8 padding[6];
+  ip_addr rtr;
+} net_addr_evpn_es;
+
+typedef union net_addr_evpn {
+  struct {
+    u8 type;
+    u8 subtype;
+    u16 length;
+    u32 tag;
+    vpn_rd rd;
+    byte data[0];
+  };
+  net_addr_evpn_ead ead;
+  net_addr_evpn_mac mac;
+  net_addr_evpn_mac_ip mac_ip;
+  net_addr_evpn_imet imet;
+  net_addr_evpn_es es;
+} net_addr_evpn;
+
 typedef union net_addr_union {
   net_addr n;
   net_addr_ip4 ip4;
@@ -155,6 +231,7 @@ typedef union net_addr_union {
   net_addr_ip6_sadr ip6_sadr;
   net_addr_mpls mpls;
   net_addr_aspa aspa;
+  net_addr_evpn evpn;
 } net_addr_union;
 
 
@@ -193,11 +270,26 @@ 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_MPLS(label) \
+  ((net_addr_mpls) { NET_MPLS, 20, sizeof(net_addr_mpls), label })
+
 #define NET_ADDR_ASPA(asn) \
   ((net_addr_aspa) { NET_ASPA, 32, sizeof(net_addr_aspa), asn })
 
-#define NET_ADDR_MPLS(label) \
-  ((net_addr_mpls) { NET_MPLS, 20, sizeof(net_addr_mpls), label })
+#define NET_ADDR_EVPN_EAD(rd, tag, esi) \
+  ((net_addr_evpn_ead) { NET_EVPN, NET_EVPN_EAD, sizeof(net_addr_evpn_ead), tag, rd, .esi = esi })
+
+#define NET_ADDR_EVPN_MAC(rd, tag, mac) \
+  ((net_addr_evpn_mac) { NET_EVPN, NET_EVPN_MAC, sizeof(net_addr_evpn_mac), tag, rd, .mac = mac })
+
+#define NET_ADDR_EVPN_MAC_IP(rd, tag, mac, ip) \
+  ((net_addr_evpn_mac_ip) { NET_EVPN, NET_EVPN_MAC, sizeof(net_addr_evpn_mac_ip), tag, rd, .mac = mac, .ip = ip })
+
+#define NET_ADDR_EVPN_IMET(rd, tag, rtr) \
+  ((net_addr_evpn_imet) { NET_EVPN, NET_EVPN_IMET, sizeof(net_addr_evpn_imet), tag, rd, .rtr = rtr })
+
+#define NET_ADDR_EVPN_ES(rd, esi, rtr) \
+  ((net_addr_evpn_es) { NET_EVPN, NET_EVPN_ES, sizeof(net_addr_evpn_es), 0, rd, .esi = esi, .rtr = rtr })
 
 
 static inline void net_fill_ip4(net_addr *a, ip4_addr prefix, uint pxlen)
@@ -227,6 +319,21 @@ 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_evpn_ead(net_addr *a, vpn_rd rd, u32 tag, evpn_esi esi)
+{ *(net_addr_evpn_ead *)a = NET_ADDR_EVPN_EAD(rd, tag, esi); }
+
+static inline void net_fill_evpn_mac(net_addr *a, vpn_rd rd, u32 tag, mac_addr mac)
+{ *(net_addr_evpn_mac *)a = NET_ADDR_EVPN_MAC(rd, tag, mac); }
+
+static inline void net_fill_evpn_mac_ip(net_addr *a, vpn_rd rd, u32 tag, mac_addr mac, ip_addr ip)
+{ *(net_addr_evpn_mac_ip *)a = NET_ADDR_EVPN_MAC_IP(rd, tag, mac, ip); }
+
+static inline void net_fill_evpn_imet(net_addr *a, vpn_rd rd, u32 tag, ip_addr rtr)
+{ *(net_addr_evpn_imet *)a = NET_ADDR_EVPN_IMET(rd, tag, rtr); }
+
+static inline void net_fill_evpn_es(net_addr *a, vpn_rd rd, evpn_esi esi, ip_addr rtr)
+{ *(net_addr_evpn_es *)a = NET_ADDR_EVPN_ES(rd, esi, rtr); }
+
 static inline void net_fill_ipa(net_addr *a, ip_addr prefix, uint pxlen)
 {
   if (ipa_is_ip4(prefix))
@@ -316,6 +423,7 @@ static inline ip_addr net_prefix(const net_addr *a)
 
   case NET_MPLS:
   case NET_ASPA:
+  case NET_EVPN:
   default:
     return IPA_NONE;
   }
@@ -348,6 +456,8 @@ static inline vpn_rd net_rd(const net_addr *a)
     return ((net_addr_vpn4 *)a)->rd;
   case NET_VPN6:
     return ((net_addr_vpn6 *)a)->rd;
+  case NET_EVPN:
+    return ((net_addr_evpn *)a)->rd;
   }
   return RD_NONE;
 }
@@ -389,6 +499,9 @@ static inline int net_equal_mpls(const net_addr_mpls *a, const net_addr_mpls *b)
 static inline int net_equal_aspa(const net_addr_aspa *a, const net_addr_aspa *b)
 { return !memcmp(a, b, sizeof(net_addr_aspa)); }
 
+static inline int net_equal_evpn(const net_addr_evpn *a, const net_addr_evpn *b)
+{ return net_equal((const net_addr *) a, (const net_addr *) b); }
+
 
 static inline int net_equal_prefix_roa4(const net_addr_roa4 *a, const net_addr_roa4 *b)
 { return ip4_equal(a->prefix, b->prefix) && (a->pxlen == b->pxlen); }
@@ -471,6 +584,13 @@ 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_evpn(const net_addr_evpn *a, const net_addr_evpn *b)
+{
+  return
+    uint_cmp(a->subtype, b->subtype) ?: rd_compare(a->rd, b->rd) ?: uint_cmp(a->tag, b->tag) ?:
+    uint_cmp(a->length, b->length) ?: memcmp(a->data, b->data, a->length - OFFSETOF(net_addr_evpn, data));
+}
+
 int net_compare(const net_addr *a, const net_addr *b);
 
 
@@ -510,6 +630,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_evpn(net_addr_evpn *dst, const net_addr_evpn *src)
+{ memcpy(dst, src, src->length); }
+
 
 static inline u32 px4_hash(ip4_addr prefix, u32 pxlen)
 { return ip4_hash(prefix) ^ (pxlen << 26); }
@@ -556,6 +679,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_evpn(const net_addr_evpn *n)
+{ return mem_hash(&n->tag, n->length - OFFSETOF(net_addr_evpn, tag)); }
+
 u32 net_hash(const net_addr *a);
 
 
@@ -608,6 +734,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_evpn(const net_addr_evpn *n UNUSED)
+{ return 1; /* XXX */ }
+
 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); }
 
index 4a3b45b507c60dbdcfe868a358a768187f17ded1..8e2ca3d743d2025929b220594865653a8173672c 100644 (file)
@@ -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)
+CF_ENUM(T_ENUM_NET_TYPE, NET_, IP4, IP6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, IP6_SADR, 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)
@@ -142,6 +142,7 @@ CF_ENUM(T_ENUM_ROA, ROA_, UNKNOWN, VALID, INVALID)
 CF_ENUM(T_ENUM_ASPA, ASPA_, UNKNOWN, VALID, INVALID)
 CF_ENUM_PX(T_ENUM_AF, AF_, AFI_, IPV4, IPV6)
 CF_ENUM(T_ENUM_MPLS_POLICY, MPLS_POLICY_, NONE, STATIC, PREFIX, AGGREGATE, VRF)
+CF_ENUM(T_ENUM_NET_EVPN_TYPE, NET_EVPN_, EAD, MAC, IMET, ES)
 
 %type <f> imexport
 %type <r> rtable
@@ -192,6 +193,7 @@ net_type_base:
  | FLOW4{ $$ = NET_FLOW4; }
  | FLOW6{ $$ = NET_FLOW6; }
  | ASPA { $$ = NET_ASPA; }
+ | EVPN { $$ = NET_EVPN; }
  ;
 
 net_type:
index 688d0b96e83776c544a7bf67e87b74815197aee9..fe8b721504638dca6ed0a317bfa3874c4399b579 100644 (file)
@@ -280,6 +280,7 @@ fib_find(struct fib *f, const net_addr *a)
   case NET_IP6_SADR: return FIB_FIND(f, a, ip6_sadr);
   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);
   default: bug("invalid type");
   }
 }
@@ -302,6 +303,7 @@ fib_insert(struct fib *f, const net_addr *a, struct fib_node *e)
   case NET_IP6_SADR: FIB_INSERT(f, a, e, ip6_sadr); 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;
   default: bug("invalid type");
   }
 }