From c8172af6825ad4b10e68b33b8edc22e6e2dc1524 Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Fri, 6 Jan 2023 18:31:15 +0100 Subject: [PATCH] lib: add link-state prefixes Add to the library the link-state type of prefixes. Link-state prefixes contain much more data than the current prefixes and they only make sense for BGP Link-State. Storing all the data in "struct prefix" is not relevant because it would increase the memory usage of all daemons. Instead a pointer to a structure that contains all the information is used. Printing link-state prefixes can be delegated to a hook function. Signed-off-by: Louis Scalbert --- lib/prefix.c | 158 +++++++++++++++++++++++++++++++++++++++++++++------ lib/prefix.h | 34 +++++++++++ lib/table.c | 2 +- 3 files changed, 176 insertions(+), 18 deletions(-) diff --git a/lib/prefix.c b/lib/prefix.c index 5f24b0f780..59acc7c22e 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; } @@ -219,6 +240,21 @@ int prefix_match(union prefixconstptr unet, union prefixconstptr upfx) offset = n->u.prefix_flowspec.prefixlen; + while (offset--) + 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; @@ -324,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; @@ -342,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; @@ -355,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", @@ -444,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; } @@ -491,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; @@ -1080,6 +1147,22 @@ 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; @@ -1124,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; @@ -1147,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); } @@ -1181,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; @@ -1330,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); @@ -1348,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); diff --git a/lib/prefix.h b/lib/prefix.h index fc6e32dd54..dacdbf9059 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; @@ -376,6 +403,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 +432,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 +451,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..1910bd0427 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; -- 2.39.5