summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/command.c10
-rw-r--r--lib/command.h2
-rw-r--r--lib/log.c3
-rw-r--r--lib/memory.c1
-rw-r--r--lib/memory.h1
-rw-r--r--lib/prefix.c88
-rw-r--r--lib/prefix.h19
-rw-r--r--lib/table.c12
-rw-r--r--lib/zclient.c162
-rw-r--r--lib/zclient.h9
-rw-r--r--lib/zebra.h10
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 */
};
diff --git a/lib/log.c b/lib/log.c
index 35298f1fa3..f5aff756dd 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -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(&copy, 0, sizeof(copy));
+ prefix_copy(&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;
}