diff options
| author | Russ White <russ@riw.us> | 2023-09-26 10:07:02 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-09-26 10:07:02 -0400 |
| commit | 8e755a03a3257644c0542a8ee658d2c08230c0ae (patch) | |
| tree | a4d58a1595c3884d9555d88d533fd2043a8de21d /lib/prefix.c | |
| parent | c0a681eed504398fc1fef11bd62b3667c93d8048 (diff) | |
| parent | 8074d6f438bfb6c0cc98626b54919ce10f190125 (diff) | |
Merge pull request #12649 from louis-6wind/bgp-link-state
bgpd: add basic support of BGP Link-State RFC7752
Diffstat (limited to 'lib/prefix.c')
| -rw-r--r-- | lib/prefix.c | 172 |
1 files changed, 152 insertions, 20 deletions
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); |
