diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/command.c | 10 | ||||
| -rw-r--r-- | lib/command.h | 2 | ||||
| -rw-r--r-- | lib/log.c | 3 | ||||
| -rw-r--r-- | lib/memory.c | 1 | ||||
| -rw-r--r-- | lib/memory.h | 1 | ||||
| -rw-r--r-- | lib/prefix.c | 88 | ||||
| -rw-r--r-- | lib/prefix.h | 19 | ||||
| -rw-r--r-- | lib/table.c | 12 | ||||
| -rw-r--r-- | lib/zclient.c | 162 | ||||
| -rw-r--r-- | lib/zclient.h | 9 | ||||
| -rw-r--r-- | lib/zebra.h | 10 |
11 files changed, 308 insertions, 9 deletions
diff --git a/lib/command.c b/lib/command.c index 5697c1d812..7c7fddeea5 100644 --- a/lib/command.c +++ b/lib/command.c @@ -118,6 +118,10 @@ const char *node_names[] = { "link-params", // LINK_PARAMS_NODE, "bgp evpn vni", // BGP_EVPN_VNI_NODE, "rpki", // RPKI_NODE + "bgp ipv4 flowspec", /* BGP_FLOWSPECV4_NODE + */ + "bgp ipv6 flowspec", /* BGP_FLOWSPECV6_NODE + */ }; /* Command vector which includes some level of command lists. Normally @@ -948,6 +952,8 @@ enum node_type node_parent(enum node_type node) switch (node) { case BGP_VPNV4_NODE: case BGP_VPNV6_NODE: + case BGP_FLOWSPECV4_NODE: + case BGP_FLOWSPECV6_NODE: case BGP_VRF_POLICY_NODE: case BGP_VNC_DEFAULTS_NODE: case BGP_VNC_NVE_GROUP_NODE: @@ -1318,6 +1324,8 @@ void cmd_exit(struct vty *vty) case BGP_IPV4L_NODE: case BGP_VPNV4_NODE: case BGP_VPNV6_NODE: + case BGP_FLOWSPECV4_NODE: + case BGP_FLOWSPECV6_NODE: case BGP_VRF_POLICY_NODE: case BGP_VNC_DEFAULTS_NODE: case BGP_VNC_NVE_GROUP_NODE: @@ -1394,6 +1402,8 @@ DEFUN (config_end, case BGP_VNC_L2_GROUP_NODE: case BGP_VPNV4_NODE: case BGP_VPNV6_NODE: + case BGP_FLOWSPECV4_NODE: + case BGP_FLOWSPECV6_NODE: case BGP_IPV4_NODE: case BGP_IPV4M_NODE: case BGP_IPV4L_NODE: diff --git a/lib/command.h b/lib/command.h index 95d8ee99df..a7fa3a1692 100644 --- a/lib/command.h +++ b/lib/command.h @@ -142,6 +142,8 @@ enum node_type { BGP_EVPN_VNI_NODE, /* BGP EVPN VNI */ RPKI_NODE, /* RPKI node for configuration of RPKI cache server connections.*/ + BGP_FLOWSPECV4_NODE, /* BGP IPv4 FLOWSPEC Address-Family */ + BGP_FLOWSPECV6_NODE, /* BGP IPv6 FLOWSPEC Address-Family */ NODE_TYPE_MAX, /* maximum */ }; @@ -965,6 +965,9 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_RULE_ADD), DESC_ENTRY(ZEBRA_RULE_DELETE), DESC_ENTRY(ZEBRA_RULE_NOTIFY_OWNER), + DESC_ENTRY(ZEBRA_TABLE_MANAGER_CONNECT), + DESC_ENTRY(ZEBRA_GET_TABLE_CHUNK), + DESC_ENTRY(ZEBRA_RELEASE_TABLE_CHUNK), }; #undef DESC_ENTRY diff --git a/lib/memory.c b/lib/memory.c index 90d7d420a9..be8b100ba7 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -26,6 +26,7 @@ struct memgroup **mg_insert = &mg_first; DEFINE_MGROUP(LIB, "libfrr") DEFINE_MTYPE(LIB, TMP, "Temporary memory") +DEFINE_MTYPE(LIB, PREFIX_FLOWSPEC, "Prefix Flowspec") static inline void mt_count_alloc(struct memtype *mt, size_t size) { diff --git a/lib/memory.h b/lib/memory.h index 6de370514a..1fbbbe4231 100644 --- a/lib/memory.h +++ b/lib/memory.h @@ -127,6 +127,7 @@ struct memgroup { DECLARE_MGROUP(LIB) DECLARE_MTYPE(TMP) +DECLARE_MTYPE(PREFIX_FLOWSPEC) extern void *qmalloc(struct memtype *mt, size_t size) diff --git a/lib/prefix.c b/lib/prefix.c index 003ce992b4..ed55fac883 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -523,6 +523,8 @@ const char *safi2str(safi_t safi) return "evpn"; case SAFI_LABELED_UNICAST: return "labeled-unicast"; + case SAFI_FLOWSPEC: + return "flowspec"; default: return "unknown"; } @@ -539,6 +541,24 @@ int prefix_match(const struct prefix *n, const struct prefix *p) if (n->prefixlen > p->prefixlen) return 0; + if (n->family == AF_FLOWSPEC) { + /* prefixlen is unused. look at fs prefix len */ + if (n->u.prefix_flowspec.prefixlen > + p->u.prefix_flowspec.prefixlen) + return 0; + + /* Set both prefix's head pointer. */ + np = (const uint8_t *)&n->u.prefix_flowspec.ptr; + pp = (const uint8_t *)&p->u.prefix_flowspec.ptr; + + offset = n->u.prefix_flowspec.prefixlen; + + while (offset--) + if (np[offset] != pp[offset]) + return 0; + return 1; + } + /* Set both prefix's head pointer. */ np = (const uint8_t *)&n->u.prefix; pp = (const uint8_t *)&p->u.prefix; @@ -581,7 +601,6 @@ int prefix_match_network_statement(const struct prefix *n, return 1; } -/* Copy prefix from src to dest. */ void prefix_copy(struct prefix *dest, const struct prefix *src) { dest->family = src->family; @@ -600,6 +619,18 @@ void prefix_copy(struct prefix *dest, const struct prefix *src) } else if (src->family == AF_UNSPEC) { 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; + dest->family = src->family; + temp = XCALLOC(MTYPE_PREFIX_FLOWSPEC, len); + dest->u.prefix_flowspec.ptr = (uintptr_t)temp; + memcpy((void *)dest->u.prefix_flowspec.ptr, + (void *)src->u.prefix_flowspec.ptr, len); } else { zlog_err("prefix_copy(): Unknown address family %d", src->family); @@ -639,6 +670,15 @@ int prefix_same(const struct prefix *p1, const struct prefix *p2) if (!memcmp(&p1->u.prefix_evpn, &p2->u.prefix_evpn, sizeof(struct evpn_addr))) return 1; + if (p1->family == AF_FLOWSPEC) { + if (p1->u.prefix_flowspec.prefixlen != + p2->u.prefix_flowspec.prefixlen) + return 0; + if (!memcmp(&p1->u.prefix_flowspec.ptr, + &p2->u.prefix_flowspec.ptr, + p2->u.prefix_flowspec.prefixlen)) + return 1; + } } return 0; } @@ -659,12 +699,30 @@ int prefix_cmp(const struct prefix *p1, const struct prefix *p2) int shift; /* Set both prefix's head pointer. */ - const uint8_t *pp1 = (const uint8_t *)&p1->u.prefix; - const uint8_t *pp2 = (const uint8_t *)&p2->u.prefix; + const uint8_t *pp1; + const uint8_t *pp2; - if (p1->family != p2->family || p1->prefixlen != p2->prefixlen) + if (p1->family != p2->family) return 1; + if (p1->family == AF_FLOWSPEC) { + pp1 = (const uint8_t *)p1->u.prefix_flowspec.ptr; + pp2 = (const uint8_t *)p2->u.prefix_flowspec.ptr; + if (p1->u.prefix_flowspec.prefixlen != + p2->u.prefix_flowspec.prefixlen) + return 1; + + offset = p1->u.prefix_flowspec.prefixlen; + while (offset--) + if (pp1[offset] != pp2[offset]) + return 1; + return 0; + } + pp1 = (const uint8_t *)&p1->u.prefix; + pp2 = (const uint8_t *)&p2->u.prefix; + + if (p1->prefixlen != p2->prefixlen) + return 1; offset = p1->prefixlen / PNBBY; shift = p1->prefixlen % PNBBY; @@ -1207,6 +1265,10 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size) prefixevpn2str(p, str, size); break; + case AF_FLOWSPEC: + sprintf(str, "FS prefix"); + break; + default: sprintf(str, "UNK prefix"); break; @@ -1386,6 +1448,24 @@ unsigned prefix_hash_key(void *pp) { struct prefix copy; + 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); + len = jhash((void *)copy.u.prefix_flowspec.ptr, + copy.u.prefix_flowspec.prefixlen, + 0x55aa5a5a); + temp = (void *)copy.u.prefix_flowspec.ptr; + XFREE(MTYPE_PREFIX_FLOWSPEC, temp); + copy.u.prefix_flowspec.ptr = (uintptr_t)NULL; + return len; + } /* make sure *all* unused bits are zero, particularly including * alignment / * padding and unused prefix bytes. */ diff --git a/lib/prefix.h b/lib/prefix.h index 133264f999..4efbc5a95c 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -106,6 +106,15 @@ struct evpn_addr { #define AF_EVPN (AF_MAX + 1) #endif +#if !defined(AF_FLOWSPEC) +#define AF_FLOWSPEC (AF_MAX + 2) +#endif + +struct flowspec_prefix { + uint16_t prefixlen; /* length in bytes */ + uintptr_t ptr; +}; + /* FRR generic prefix structure. */ struct prefix { uint8_t family; @@ -122,6 +131,7 @@ struct prefix { uint8_t val[16]; uintptr_t ptr; struct evpn_addr prefix_evpn; /* AF_EVPN */ + struct flowspec_prefix prefix_flowspec; /* AF_FLOWSPEC */ } u __attribute__((aligned(8))); }; @@ -174,6 +184,13 @@ struct prefix_ptr { uintptr_t prefix __attribute__((aligned(8))); }; +/* Prefix for a Flowspec entry */ +struct prefix_fs { + uint8_t family; + uint8_t prefixlen; /* unused */ + struct flowspec_prefix prefix __attribute__((aligned(8))); +}; + struct prefix_sg { uint8_t family; uint8_t prefixlen; @@ -191,6 +208,7 @@ union prefixptr { struct prefix_ipv4 *p4; struct prefix_ipv6 *p6; struct prefix_evpn *evp; + const struct prefix_fs *fs; } __attribute__((transparent_union)); union prefixconstptr { @@ -198,6 +216,7 @@ union prefixconstptr { const struct prefix_ipv4 *p4; const struct prefix_ipv6 *p6; const struct prefix_evpn *evp; + const struct prefix_fs *fs; } __attribute__((transparent_union)); #ifndef INET_ADDRSTRLEN diff --git a/lib/table.c b/lib/table.c index bf63609bc3..3adb793891 100644 --- a/lib/table.c +++ b/lib/table.c @@ -152,10 +152,16 @@ static void route_common(const struct prefix *n, const struct prefix *p, int i; uint8_t diff; uint8_t mask; + const uint8_t *np; + const uint8_t *pp; + uint8_t *newp; - const uint8_t *np = (const uint8_t *)&n->u.prefix; - const uint8_t *pp = (const uint8_t *)&p->u.prefix; - uint8_t *newp = (uint8_t *)&new->u.prefix; + if (n->family == AF_FLOWSPEC) + return prefix_copy(new, p); + np = (const uint8_t *)&n->u.prefix; + pp = (const uint8_t *)&p->u.prefix; + + newp = (uint8_t *)&new->u.prefix; for (i = 0; i < p->prefixlen / 8; i++) { if (np[i] == pp[i]) diff --git a/lib/zclient.c b/lib/zclient.c index 4659bce1b1..7308beaaf2 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2123,6 +2123,168 @@ int lm_release_label_chunk(struct zclient *zclient, uint32_t start, return 0; } +/** + * Connect to table manager in a syncronous way + * + * It first writes the request to zcient output buffer and then + * immediately reads the answer from the input buffer. + * + * @param zclient Zclient used to connect to table manager (zebra) + * @result Result of response + */ +int tm_table_manager_connect(struct zclient *zclient) +{ + int ret; + struct stream *s; + uint8_t result; + + if (zclient_debug) + zlog_debug("Connecting to Table Manager"); + + if (zclient->sock < 0) + return -1; + + /* send request */ + s = zclient->obuf; + stream_reset(s); + zclient_create_header(s, ZEBRA_TABLE_MANAGER_CONNECT, VRF_DEFAULT); + + /* proto */ + stream_putc(s, zclient->redist_default); + /* instance */ + stream_putw(s, zclient->instance); + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + ret = zclient_send_message(zclient); + if (ret < 0) + return -1; + + if (zclient_debug) + zlog_debug("%s: Table manager connect request sent", + __func__); + + /* read response */ + if (zclient_read_sync_response(zclient, ZEBRA_TABLE_MANAGER_CONNECT) + != 0) + return -1; + + /* result */ + s = zclient->ibuf; + STREAM_GETC(s, result); + if (zclient_debug) + zlog_debug( + "%s: Table Manager connect response received, result %u", + __func__, result); + + return (int)result; +stream_failure: + return 0; +} + +/** + * Function to request a table chunk in a syncronous way + * + * It first writes the request to zclient output buffer and then + * immediately reads the answer from the input buffer. + * + * @param zclient Zclient used to connect to table manager (zebra) + * @param chunk_size Amount of table requested + * @param start to write first assigned chunk table RT ID to + * @param end To write last assigned chunk table RT ID to + * @result 0 on success, -1 otherwise + */ +int tm_get_table_chunk(struct zclient *zclient, uint32_t chunk_size, + uint32_t *start, uint32_t *end) +{ + int ret; + struct stream *s; + + if (zclient_debug) + zlog_debug("Getting Table Chunk"); + + if (zclient->sock < 0) + return -1; + + /* send request */ + s = zclient->obuf; + stream_reset(s); + zclient_create_header(s, ZEBRA_GET_TABLE_CHUNK, VRF_DEFAULT); + /* chunk size */ + stream_putl(s, chunk_size); + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + ret = writen(zclient->sock, s->data, stream_get_endp(s)); + if (ret < 0) { + zlog_err("%s: can't write to zclient->sock", __func__); + close(zclient->sock); + zclient->sock = -1; + return -1; + } + if (ret == 0) { + zlog_err("%s: zclient->sock connection closed", __func__); + close(zclient->sock); + zclient->sock = -1; + return -1; + } + if (zclient_debug) + zlog_debug("%s: Table chunk request (%d bytes) sent", __func__, + ret); + + /* read response */ + if (zclient_read_sync_response(zclient, ZEBRA_GET_TABLE_CHUNK) != 0) + return -1; + + s = zclient->ibuf; + /* start and end table IDs */ + STREAM_GETL(s, *start); + STREAM_GETL(s, *end); + + if (zclient_debug) + zlog_debug("Table Chunk assign: %u - %u ", *start, *end); + +stream_failure: + return 0; +} + +/** + * Function to release a table chunk + * + * @param zclient Zclient used to connect to table manager (zebra) + * @param start First label of table + * @param end Last label of chunk + * @result 0 on success, -1 otherwise + */ +int tm_release_table_chunk(struct zclient *zclient, uint32_t start, + uint32_t end) +{ + struct stream *s; + + if (zclient_debug) + zlog_debug("Releasing Table Chunk"); + + if (zclient->sock < 0) + return -1; + + /* send request */ + s = zclient->obuf; + stream_reset(s); + zclient_create_header(s, ZEBRA_RELEASE_TABLE_CHUNK, VRF_DEFAULT); + + /* start */ + stream_putl(s, start); + /* end */ + stream_putl(s, end); + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + return zclient_send_message(zclient); +} + + int zebra_send_pw(struct zclient *zclient, int command, struct zapi_pw *pw) { struct stream *s; diff --git a/lib/zclient.h b/lib/zclient.h index b51c518463..04f2a5c178 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -132,6 +132,9 @@ typedef enum { ZEBRA_RULE_ADD, ZEBRA_RULE_DELETE, ZEBRA_RULE_NOTIFY_OWNER, + ZEBRA_TABLE_MANAGER_CONNECT, + ZEBRA_GET_TABLE_CHUNK, + ZEBRA_RELEASE_TABLE_CHUNK, } zebra_message_types_t; struct redist_proto { @@ -538,6 +541,12 @@ extern int lm_get_label_chunk(struct zclient *zclient, uint8_t keep, uint32_t *end); extern int lm_release_label_chunk(struct zclient *zclient, uint32_t start, uint32_t end); +extern int tm_table_manager_connect(struct zclient *zclient); +extern int tm_get_table_chunk(struct zclient *zclient, uint32_t chunk_size, + uint32_t *start, uint32_t *end); +extern int tm_release_table_chunk(struct zclient *zclient, uint32_t start, + uint32_t end); + extern int zebra_send_pw(struct zclient *zclient, int command, struct zapi_pw *pw); extern void zebra_read_pw_status_update(int command, struct zclient *zclient, diff --git a/lib/zebra.h b/lib/zebra.h index ec530397be..f4f104299d 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -433,7 +433,8 @@ typedef enum { SAFI_ENCAP = 4, SAFI_EVPN = 5, SAFI_LABELED_UNICAST = 6, - SAFI_MAX = 7 + SAFI_FLOWSPEC = 7, + SAFI_MAX = 8 } safi_t; /* @@ -461,7 +462,8 @@ typedef enum { IANA_SAFI_LABELED_UNICAST = 4, IANA_SAFI_ENCAP = 7, IANA_SAFI_EVPN = 70, - IANA_SAFI_MPLS_VPN = 128 + IANA_SAFI_MPLS_VPN = 128, + IANA_SAFI_FLOWSPEC = 133 } iana_safi_t; /* Default Administrative Distance of each protocol. */ @@ -547,6 +549,8 @@ static inline safi_t safi_iana2int(iana_safi_t safi) return SAFI_EVPN; case IANA_SAFI_LABELED_UNICAST: return SAFI_LABELED_UNICAST; + case IANA_SAFI_FLOWSPEC: + return SAFI_FLOWSPEC; default: return SAFI_MAX; } @@ -567,6 +571,8 @@ static inline iana_safi_t safi_int2iana(safi_t safi) return IANA_SAFI_EVPN; case SAFI_LABELED_UNICAST: return IANA_SAFI_LABELED_UNICAST; + case SAFI_FLOWSPEC: + return IANA_SAFI_FLOWSPEC; default: return IANA_SAFI_RESERVED; } |
