diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/command.h | 1 | ||||
| -rw-r--r-- | lib/iana_afi.h | 15 | ||||
| -rw-r--r-- | lib/prefix.c | 172 | ||||
| -rw-r--r-- | lib/prefix.h | 39 | ||||
| -rw-r--r-- | lib/table.c | 16 | ||||
| -rw-r--r-- | lib/vty.c | 7 | ||||
| -rw-r--r-- | lib/zebra.h | 9 |
7 files changed, 232 insertions, 27 deletions
diff --git a/lib/command.h b/lib/command.h index 718d34b007..36640c493f 100644 --- a/lib/command.h +++ b/lib/command.h @@ -174,6 +174,7 @@ enum node_type { BMP_NODE, /* BMP config under router bgp */ ISIS_SRV6_NODE, /* ISIS SRv6 node */ ISIS_SRV6_NODE_MSD_NODE, /* ISIS SRv6 Node MSDs node */ + BGP_LS_NODE, /* BGP-LS configuration node */ NODE_TYPE_MAX, /* maximum */ }; /* clang-format on */ diff --git a/lib/iana_afi.h b/lib/iana_afi.h index b9c19cc3d5..9b4d33fa4d 100644 --- a/lib/iana_afi.h +++ b/lib/iana_afi.h @@ -26,6 +26,7 @@ typedef enum { IANA_AFI_IPV4 = 1, IANA_AFI_IPV6 = 2, IANA_AFI_L2VPN = 25, + IANA_AFI_LINKSTATE = 16388, /* BGP-LS RFC 7752 */ } iana_afi_t; typedef enum { @@ -35,6 +36,8 @@ typedef enum { IANA_SAFI_LABELED_UNICAST = 4, IANA_SAFI_ENCAP = 7, IANA_SAFI_EVPN = 70, + IANA_SAFI_LINKSTATE = 71, /* BGP-LS RFC 7752 */ + IANA_SAFI_LINKSTATE_VPN = 72, /* BGP-LS RFC 7752 */ IANA_SAFI_MPLS_VPN = 128, IANA_SAFI_FLOWSPEC = 133 } iana_safi_t; @@ -48,6 +51,8 @@ static inline afi_t afi_iana2int(iana_afi_t afi) return AFI_IP6; case IANA_AFI_L2VPN: return AFI_L2VPN; + case IANA_AFI_LINKSTATE: + return AFI_LINKSTATE; case IANA_AFI_RESERVED: return AFI_MAX; } @@ -64,6 +69,8 @@ static inline iana_afi_t afi_int2iana(afi_t afi) return IANA_AFI_IPV6; case AFI_L2VPN: return IANA_AFI_L2VPN; + case AFI_LINKSTATE: + return IANA_AFI_LINKSTATE; case AFI_UNSPEC: case AFI_MAX: return IANA_AFI_RESERVED; @@ -94,6 +101,10 @@ static inline safi_t safi_iana2int(iana_safi_t safi) return SAFI_LABELED_UNICAST; case IANA_SAFI_FLOWSPEC: return SAFI_FLOWSPEC; + case IANA_SAFI_LINKSTATE: + return SAFI_LINKSTATE; + case IANA_SAFI_LINKSTATE_VPN: + return SAFI_LINKSTATE_VPN; case IANA_SAFI_RESERVED: return SAFI_MAX; } @@ -118,6 +129,10 @@ static inline iana_safi_t safi_int2iana(safi_t safi) return IANA_SAFI_LABELED_UNICAST; case SAFI_FLOWSPEC: return IANA_SAFI_FLOWSPEC; + case SAFI_LINKSTATE: + return IANA_SAFI_LINKSTATE; + case SAFI_LINKSTATE_VPN: + return IANA_SAFI_LINKSTATE_VPN; case SAFI_UNSPEC: case SAFI_MAX: return IANA_SAFI_RESERVED; diff --git a/lib/prefix.c b/lib/prefix.c index f342c4c1db..cde8677cf0 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -20,6 +20,7 @@ DEFINE_MTYPE_STATIC(LIB, PREFIX, "Prefix"); DEFINE_MTYPE_STATIC(LIB, PREFIX_FLOWSPEC, "Prefix Flowspec"); +DEFINE_MTYPE_STATIC(LIB, PREFIX_LINKSTATE, "Prefix Link-State"); /* Maskbit. */ static const uint8_t maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, @@ -32,6 +33,18 @@ static const uint8_t maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, #define MASKBIT(offset) ((0xff << (PNBBY - (offset))) & 0xff) +char *(*prefix_linkstate_display_hook)(char *buf, size_t size, + uint16_t nlri_type, uintptr_t ptr, + uint16_t len) = NULL; + +void prefix_set_linkstate_display_hook(char *(*func)(char *buf, size_t size, + uint16_t nlri_type, + uintptr_t ptr, + uint16_t len)) +{ + prefix_linkstate_display_hook = func; +} + int is_zero_mac(const struct ethaddr *mac) { int i = 0; @@ -81,6 +94,8 @@ int str2family(const char *string) return AF_ETHERNET; else if (!strcmp("evpn", string)) return AF_EVPN; + else if (!strcmp("link-state", string)) + return AF_LINKSTATE; return -1; } @@ -95,6 +110,8 @@ const char *family2str(int family) return "Ethernet"; case AF_EVPN: return "Evpn"; + case AF_LINKSTATE: + return "Link-State"; } return "?"; } @@ -109,6 +126,8 @@ int afi2family(afi_t afi) else if (afi == AFI_L2VPN) return AF_ETHERNET; /* NOTE: EVPN code should NOT use this interface. */ + else if (afi == AFI_LINKSTATE) + return AF_LINKSTATE; return 0; } @@ -120,6 +139,8 @@ afi_t family2afi(int family) return AFI_IP6; else if (family == AF_ETHERNET || family == AF_EVPN) return AFI_L2VPN; + else if (family == AF_LINKSTATE) + return AFI_LINKSTATE; return 0; } @@ -132,6 +153,8 @@ const char *afi2str_lower(afi_t afi) return "ipv6"; case AFI_L2VPN: return "l2vpn"; + case AFI_LINKSTATE: + return "link-state"; case AFI_MAX: case AFI_UNSPEC: return "bad-value"; @@ -149,6 +172,8 @@ const char *afi2str(afi_t afi) return "IPv6"; case AFI_L2VPN: return "l2vpn"; + case AFI_LINKSTATE: + return "link-state"; case AFI_MAX: case AFI_UNSPEC: return "bad-value"; @@ -174,6 +199,10 @@ const char *safi2str(safi_t safi) return "labeled-unicast"; case SAFI_FLOWSPEC: return "flowspec"; + case SAFI_LINKSTATE: + return "link-state"; + case SAFI_LINKSTATE_VPN: + return "link-state-vpn"; case SAFI_UNSPEC: case SAFI_MAX: return "unknown"; @@ -215,6 +244,21 @@ int prefix_match(union prefixconstptr unet, union prefixconstptr upfx) if (np[offset] != pp[offset]) return 0; return 1; + } else if (n->family == AF_LINKSTATE) { + if (n->u.prefix_linkstate.nlri_type != + p->u.prefix_linkstate.nlri_type) + return 0; + + /* Set both prefix's head pointer. */ + np = (const uint8_t *)&n->u.prefix_linkstate.ptr; + pp = (const uint8_t *)&p->u.prefix_linkstate.ptr; + + offset = n->prefixlen; /* length is checked above */ + + while (offset--) + if (np[offset] != pp[offset]) + return 0; + return 1; } /* Set both prefix's head pointer. */ @@ -316,6 +360,8 @@ void prefix_copy(union prefixptr udest, union prefixconstptr usrc) { struct prefix *dest = udest.p; const struct prefix *src = usrc.p; + void *temp; + int len; dest->family = src->family; dest->prefixlen = src->prefixlen; @@ -334,9 +380,6 @@ void prefix_copy(union prefixptr udest, union prefixconstptr usrc) dest->u.lp.id = src->u.lp.id; dest->u.lp.adv_router = src->u.lp.adv_router; } else if (src->family == AF_FLOWSPEC) { - void *temp; - int len; - len = src->u.prefix_flowspec.prefixlen; dest->u.prefix_flowspec.prefixlen = src->u.prefix_flowspec.prefixlen; @@ -347,6 +390,14 @@ void prefix_copy(union prefixptr udest, union prefixconstptr usrc) dest->u.prefix_flowspec.ptr = (uintptr_t)temp; memcpy((void *)dest->u.prefix_flowspec.ptr, (void *)src->u.prefix_flowspec.ptr, len); + } else if (src->family == AF_LINKSTATE) { + len = src->prefixlen; + dest->u.prefix_linkstate.nlri_type = + src->u.prefix_linkstate.nlri_type; + temp = XCALLOC(MTYPE_PREFIX_LINKSTATE, len); + dest->u.prefix_linkstate.ptr = (uintptr_t)temp; + memcpy((void *)dest->u.prefix_linkstate.ptr, + (void *)src->u.prefix_linkstate.ptr, len); } else { flog_err(EC_LIB_DEVELOPMENT, "prefix_copy(): Unknown address family %d", @@ -436,6 +487,14 @@ int prefix_same(union prefixconstptr up1, union prefixconstptr up2) p2->u.prefix_flowspec.prefixlen)) return 1; } + if (p1->family == AF_LINKSTATE) { + if (p1->u.prefix_linkstate.nlri_type != + p2->u.prefix_linkstate.nlri_type) + return 0; + if (!memcmp(&p1->u.prefix_linkstate.ptr, + &p2->u.prefix_linkstate.ptr, p2->prefixlen)) + return 1; + } } return 0; } @@ -483,6 +542,22 @@ int prefix_cmp(union prefixconstptr up1, union prefixconstptr up2) if (pp1[offset] != pp2[offset]) return numcmp(pp1[offset], pp2[offset]); return 0; + } else if (p1->family == AF_LINKSTATE) { + pp1 = (const uint8_t *)p1->u.prefix_linkstate.ptr; + pp2 = (const uint8_t *)p2->u.prefix_linkstate.ptr; + + if (p1->u.prefix_linkstate.nlri_type != + p2->u.prefix_linkstate.nlri_type) + return 1; + + if (p1->prefixlen != p2->prefixlen) + return numcmp(p1->prefixlen, p2->prefixlen); + + offset = p1->prefixlen; + while (offset--) + if (pp1[offset] != pp2[offset]) + return numcmp(pp1[offset], pp2[offset]); + return 0; } pp1 = p1->u.val; pp2 = p2->u.val; @@ -1072,10 +1147,26 @@ static const char *prefixevpn2str(const struct prefix_evpn *p, char *str, return str; } +const char *bgp_linkstate_nlri_type_2str(uint16_t nlri_type) +{ + switch (nlri_type) { + case BGP_LINKSTATE_NODE: + return "Node"; + case BGP_LINKSTATE_LINK: + return "Link"; + case BGP_LINKSTATE_PREFIX4: + return "IPv4-Prefix"; + case BGP_LINKSTATE_PREFIX6: + return "IPv6-Prefix"; + } + + return "Unknown"; +} + const char *prefix2str(union prefixconstptr pu, char *str, int size) { const struct prefix *p = pu.p; - char buf[PREFIX2STR_BUFFER]; + char buf[PREFIX_STRLEN_EXTENDED]; int byte, tmp, a, b; bool z = false; size_t l; @@ -1116,6 +1207,22 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size) strlcpy(str, "FS prefix", size); break; + case AF_LINKSTATE: + if (prefix_linkstate_display_hook) + snprintf(str, size, "%s/%d", + prefix_linkstate_display_hook( + buf, sizeof(buf), + p->u.prefix_linkstate.nlri_type, + p->u.prefix_linkstate.ptr, + p->prefixlen), + p->prefixlen); + else + snprintf(str, size, "%s/%d", + bgp_linkstate_nlri_type_2str( + p->u.prefix_linkstate.nlri_type), + p->prefixlen); + break; + default: strlcpy(str, "UNK prefix", size); break; @@ -1127,7 +1234,7 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size) static ssize_t prefixhost2str(struct fbuf *fbuf, union prefixconstptr pu) { const struct prefix *p = pu.p; - char buf[PREFIX2STR_BUFFER]; + char buf[PREFIX_STRLEN_EXTENDED]; switch (p->family) { case AF_INET: @@ -1139,6 +1246,17 @@ static ssize_t prefixhost2str(struct fbuf *fbuf, union prefixconstptr pu) prefix_mac2str(&p->u.prefix_eth, buf, sizeof(buf)); return bputs(fbuf, buf); + case AF_LINKSTATE: + if (prefix_linkstate_display_hook) + prefix_linkstate_display_hook( + buf, sizeof(buf), + p->u.prefix_linkstate.nlri_type, + p->u.prefix_linkstate.ptr, p->prefixlen); + else + snprintf(buf, sizeof(buf), "%s", + bgp_linkstate_nlri_type_2str( + p->u.prefix_linkstate.nlri_type)); + return bputs(fbuf, buf); default: return bprintfrr(fbuf, "{prefix.af=%dPF}", p->family); } @@ -1173,6 +1291,20 @@ const char *prefix_sg2str(const struct prefix_sg *sg, char *sg_str) return sg_str; } + +void prefix_linkstate_ptr_free(struct prefix *p) +{ + void *temp; + + if (!p || p->family != AF_LINKSTATE || !p->u.prefix_linkstate.ptr) + return; + + temp = (void *)p->u.prefix_linkstate.ptr; + XFREE(MTYPE_PREFIX_LINKSTATE, temp); + p->u.prefix_linkstate.ptr = (uintptr_t)NULL; +} + + struct prefix *prefix_new(void) { struct prefix *p; @@ -1322,17 +1454,16 @@ char *prefix_mac2str(const struct ethaddr *mac, char *buf, int size) unsigned prefix_hash_key(const void *pp) { struct prefix copy; + uint32_t len; + void *temp; - if (((struct prefix *)pp)->family == AF_FLOWSPEC) { - uint32_t len; - void *temp; + /* make sure *all* unused bits are zero, particularly including + * alignment / + * padding and unused prefix bytes. */ + memset(©, 0, sizeof(copy)); + prefix_copy(©, (struct prefix *)pp); - /* make sure *all* unused bits are zero, - * particularly including alignment / - * padding and unused prefix bytes. - */ - memset(©, 0, sizeof(copy)); - prefix_copy(©, (struct prefix *)pp); + if (((struct prefix *)pp)->family == AF_FLOWSPEC) { len = jhash((void *)copy.u.prefix_flowspec.ptr, copy.u.prefix_flowspec.prefixlen, 0x55aa5a5a); @@ -1340,12 +1471,13 @@ unsigned prefix_hash_key(const void *pp) XFREE(MTYPE_PREFIX_FLOWSPEC, temp); copy.u.prefix_flowspec.ptr = (uintptr_t)NULL; return len; + } else if (((struct prefix *)pp)->family == AF_LINKSTATE) { + len = jhash((void *)copy.u.prefix_linkstate.ptr, copy.prefixlen, + 0x55aa5a5a); + prefix_linkstate_ptr_free(©); + return len; } - /* make sure *all* unused bits are zero, particularly including - * alignment / - * padding and unused prefix bytes. */ - memset(©, 0, sizeof(copy)); - prefix_copy(©, (struct prefix *)pp); + return jhash(©, offsetof(struct prefix, u.prefix) + PSIZE(copy.prefixlen), 0x55aa5a5a); @@ -1620,7 +1752,7 @@ static ssize_t printfrr_pfx(struct fbuf *buf, struct printfrr_eargs *ea, if (host_only) return prefixhost2str(buf, (struct prefix *)ptr); else { - char cbuf[PREFIX_STRLEN]; + char cbuf[PREFIX_STRLEN_EXTENDED]; prefix2str(ptr, cbuf, sizeof(cbuf)); return bputs(buf, cbuf); diff --git a/lib/prefix.h b/lib/prefix.h index fc6e32dd54..f1aff43689 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -125,6 +125,15 @@ struct evpn_addr { #define prefix_addr u._prefix_addr }; +/* BGP Link-State NRLI types*/ +enum bgp_linkstate_nlri_type { + /* RFC7752 Table 1 */ + BGP_LINKSTATE_NODE = 1, + BGP_LINKSTATE_LINK = 2, + BGP_LINKSTATE_PREFIX4 = 3, /* IPv4 Topology Prefix */ + BGP_LINKSTATE_PREFIX6 = 4, /* IPv6 Topology Prefix */ +}; + /* * A struct prefix contains an address family, a prefix length, and an * address. This can represent either a 'network prefix' as defined @@ -158,12 +167,21 @@ struct evpn_addr { #define AF_FLOWSPEC (AF_MAX + 2) #endif +#if !defined(AF_LINKSTATE) +#define AF_LINKSTATE (AF_MAX + 3) +#endif + struct flowspec_prefix { uint8_t family; uint16_t prefixlen; /* length in bytes */ uintptr_t ptr; }; +struct linkstate_prefix { + uint16_t nlri_type; + uintptr_t ptr; +}; + /* FRR generic prefix structure. */ struct prefix { uint8_t family; @@ -182,6 +200,7 @@ struct prefix { uintptr_t ptr; struct evpn_addr prefix_evpn; /* AF_EVPN */ struct flowspec_prefix prefix_flowspec; /* AF_FLOWSPEC */ + struct linkstate_prefix prefix_linkstate; /* AF_LINKSTATE */ } u __attribute__((aligned(8))); }; @@ -279,6 +298,14 @@ struct prefix_fs { struct flowspec_prefix prefix __attribute__((aligned(8))); }; + +/* Prefix for a BGP-LS entry */ +struct prefix_bgpls { + uint8_t family; + uint16_t prefixlen; + struct linkstate_prefix prefix __attribute__((aligned(8))); +}; + struct prefix_sg { uint8_t family; uint16_t prefixlen; @@ -320,6 +347,11 @@ union prefixconstptr { /* Maximum string length of the result of prefix2str */ #define PREFIX_STRLEN 80 +/* Maximum string length of the result of prefix2str for + * long string prefixes (eg. BGP Link-State) + */ +#define PREFIX_STRLEN_EXTENDED 512 + /* * Longest possible length of a (S,G) string is 34 bytes * 123.123.123.123 = 15 * 2 @@ -376,6 +408,10 @@ static inline void ipv4_addr_copy(struct in_addr *dst, #define s6_addr32 __u6_addr.__u6_addr32 #endif /*s6_addr32*/ +extern void prefix_set_linkstate_display_hook( + char *(*func)(char *buf, size_t size, uint16_t nlri_type, uintptr_t ptr, + uint16_t len)); + /* Prototypes. */ extern int str2family(const char *string); extern int afi2family(afi_t afi); @@ -401,6 +437,8 @@ static inline afi_t prefix_afi(union prefixconstptr pu) */ extern unsigned int prefix_bit(const uint8_t *prefix, const uint16_t bit_index); +extern void prefix_linkstate_ptr_free(struct prefix *p); + extern struct prefix *prefix_new(void); extern void prefix_free(struct prefix **p); /* @@ -418,6 +456,7 @@ extern void prefix_mcast_inet4_dump(const char *onfail, struct in_addr addr, extern const char *prefix_sg2str(const struct prefix_sg *sg, char *str); extern const char *prefix2str(union prefixconstptr upfx, char *buffer, int size); +extern const char *bgp_linkstate_nlri_type_2str(uint16_t nlri_type); extern int evpn_type5_prefix_match(const struct prefix *evpn_pfx, const struct prefix *match_pfx); extern int prefix_match(union prefixconstptr unet, union prefixconstptr upfx); diff --git a/lib/table.c b/lib/table.c index 3bf93894ec..dbfc3f8b91 100644 --- a/lib/table.c +++ b/lib/table.c @@ -142,7 +142,7 @@ static void route_common(const struct prefix *n, const struct prefix *p, const uint8_t *pp; uint8_t *newp; - if (n->family == AF_FLOWSPEC) + if (n->family == AF_FLOWSPEC || n->family == AF_LINKSTATE) return prefix_copy(new, p); np = (const uint8_t *)&n->u.prefix; pp = (const uint8_t *)&p->u.prefix; @@ -281,15 +281,22 @@ struct route_node *route_node_get(struct route_table *table, const uint8_t *prefix = &p->u.prefix; node = rn_hash_node_find(&table->hash, &search); - if (node && node->info) + if (node && node->info) { + if (family2afi(p->family) == AFI_LINKSTATE) + prefix_linkstate_ptr_free(p); + return route_lock_node(node); + } match = NULL; node = table->top; while (node && node->p.prefixlen <= prefixlen && prefix_match(&node->p, p)) { - if (node->p.prefixlen == prefixlen) + if (node->p.prefixlen == prefixlen) { + if (family2afi(p->family) == AFI_LINKSTATE) + prefix_linkstate_ptr_free(p); return route_lock_node(node); + } match = node; node = node->link[prefix_bit(prefix, node->p.prefixlen)]; @@ -324,6 +331,9 @@ struct route_node *route_node_get(struct route_table *table, table->count++; route_lock_node(new); + if (family2afi(p->family) == AFI_LINKSTATE) + prefix_linkstate_ptr_free(p); + return new; } @@ -2386,9 +2386,14 @@ static void vtysh_read(struct event *thread) * => skip vty_event(VTYSH_READ, vty)! */ return; - } else + } else { + assertf(vty->status != VTY_PASSFD, + "%p address=%s passfd=%d", vty, + vty->address, vty->pass_fd); + /* normalize other invalid values */ vty->pass_fd = -1; + } /* hack for asynchronous "write integrated" * - other commands in "buf" will be ditched diff --git a/lib/zebra.h b/lib/zebra.h index ecc87f58f1..cd0b72834c 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -326,13 +326,14 @@ struct in_pktinfo { #define INADDR_LOOPBACK 0x7f000001 /* Internet address 127.0.0.1. */ #endif -/* Address family numbers from RFC1700. */ +/* Address family numbers. */ typedef enum { AFI_UNSPEC = 0, AFI_IP = 1, AFI_IP6 = 2, AFI_L2VPN = 3, - AFI_MAX = 4 + AFI_LINKSTATE = 4, /* BGP-LS RFC 7752 */ + AFI_MAX = 5, } afi_t; #define IS_VALID_AFI(a) ((a) > AFI_UNSPEC && (a) < AFI_MAX) @@ -347,7 +348,9 @@ typedef enum { SAFI_EVPN = 5, SAFI_LABELED_UNICAST = 6, SAFI_FLOWSPEC = 7, - SAFI_MAX = 8 + SAFI_LINKSTATE = 8, /* BGP-LS RFC 7752 */ + SAFI_LINKSTATE_VPN = 9, /* BGP-LS RFC 7752 */ + SAFI_MAX = 10, } safi_t; #define FOREACH_AFI_SAFI(afi, safi) \ |
