From 9a14899b0ac8f3d9d0ce077127568f215c301f6a Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 10 Jan 2018 19:13:27 +0100 Subject: [PATCH] lib: prefix support for flowspec prefix structure is used to handle flowspec prefixes. A new AFI is introduced: AF_FLOWSPEC. A sub structure named flowspec_prefix is used in prefix to host the flowspec entry. Reason to introduce that new kind is that prefixlen from prefix structure is too short to all the flowspec needs, since NLRI can go over 0xff bytes. Signed-off-by: Philippe Guibert --- lib/memory.c | 1 + lib/memory.h | 1 + lib/prefix.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++--- lib/prefix.h | 19 ++++++++++++ lib/table.c | 12 ++++++-- 5 files changed, 112 insertions(+), 7 deletions(-) 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..515b4dcb5e 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -539,6 +539,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 +599,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 +617,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 +668,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 +697,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 +1263,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 +1446,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])