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 <philippe.guibert@6wind.com>
This commit is contained in:
Philippe Guibert 2018-01-10 19:13:27 +01:00
parent 46f1e1ee96
commit 9a14899b0a
5 changed files with 112 additions and 7 deletions

View File

@ -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)
{

View File

@ -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)

View File

@ -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(&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. */

View File

@ -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

View File

@ -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])