From: Ondrej Zajicek Date: Mon, 29 May 2023 03:36:40 +0000 (+0200) Subject: Nest: EVPN net type - preliminary support X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=52490faf96223a584c71d4a10d262a093d0c578e;p=thirdparty%2Fbird.git Nest: EVPN net type - preliminary support --- diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 0119e1f55..31e4757ca 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -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; diff --git a/conf/confbase.Y b/conf/confbase.Y index b2ba3cafb..c5844041b 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -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 NUM ENUM_TOKEN %token IP4 %token IP6 +%token MAC_ %token VPN_RD %token CF_SYM_KNOWN CF_SYM_UNDEFINED CF_SYM_METHOD_BARE CF_SYM_METHOD_ARGS %token TEXT @@ -147,7 +151,9 @@ CF_DECLS %type ipa %type net_ip4_ net_ip4 net_ip6_ net_ip6 net_ip_ net_ip net_or_ipa %type net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ net_ip6_sadr_ net_mpls_ net_aspa_ +%type net_evpn_ net_evpn_ead_ net_evpn_mac_ net_evpn_mac_ip_ net_evpn_imet_ net_evpn_es_ %type label_stack_start label_stack +%type evpn_esi %type text opttext %type 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_ ; diff --git a/filter/data.c b/filter/data.c index f5a9e5eec..bc6351cfe 100644 --- a/filter/data.c +++ b/filter/data.c @@ -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", diff --git a/filter/data.h b/filter/data.h index f36820cba..5e529748a 100644 --- a/filter/data.h +++ b/filter/data.h @@ -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 */ diff --git a/lib/Makefile b/lib/Makefile index 812f721cc..21aad3784 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -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 index 000000000..8f4be04f6 --- /dev/null +++ b/lib/evpn.c @@ -0,0 +1,38 @@ +/* + * BIRD Internet Routing Daemon -- EVPN Net Type + * + * (c) 2023 Ondrej Zajicek + * (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 index 000000000..c340c3856 --- /dev/null +++ b/lib/evpn.h @@ -0,0 +1,50 @@ +/* + * BIRD Internet Routing Daemon -- EVPN Net Type + * + * (c) 2023 Ondrej Zajicek + * (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 diff --git a/lib/net.c b/lib/net.c index 64cf9e047..b738a067a 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_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; } diff --git a/lib/net.h b/lib/net.h index a1fd0291e..ed12e985f 100644 --- 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) @@ -37,12 +40,13 @@ #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); } diff --git a/nest/config.Y b/nest/config.Y index 4a3b45b50..8e2ca3d74 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -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 imexport %type rtable @@ -192,6 +193,7 @@ net_type_base: | FLOW4{ $$ = NET_FLOW4; } | FLOW6{ $$ = NET_FLOW6; } | ASPA { $$ = NET_ASPA; } + | EVPN { $$ = NET_EVPN; } ; net_type: diff --git a/nest/rt-fib.c b/nest/rt-fib.c index 688d0b96e..fe8b72150 100644 --- a/nest/rt-fib.c +++ b/nest/rt-fib.c @@ -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"); } }