bgpd,lib: route-map/plist matching via type-2/5 routes

Implement the ability to match type-2 and type-5 routes
via a route-map and a prefix-list.

Add some library code to convert an evpn prefix into
a general ipv4/ipv6 prefix for type-2 and type-5 routes.
evpn prefix is really just another subtype of prefix so all
the info needed can be extracted right there.

Add a special handler to bgp_routemap for evpn type routes
when applying the outbound route-map. This calls the library
code to convert the evpn_prefix to a ipv4/ipv6 prefix and
run it through the plist code. In this we assume type-2 routes
are a /32.

Signed-off-by: Stephen Worley <sworley@nvidia.com>
This commit is contained in:
Stephen Worley 2021-03-09 18:59:09 -05:00
parent 24df337988
commit 6eb8350586
3 changed files with 76 additions and 0 deletions

View File

@ -642,6 +642,20 @@ route_match_prefix_list_flowspec(afi_t afi, struct prefix_list *plist,
return RMAP_NOMATCH;
}
static enum route_map_cmd_result_t
route_match_prefix_list_evpn(afi_t afi, struct prefix_list *plist,
const struct prefix *p)
{
/* Convert to match a general plist */
struct prefix new;
if (evpn_prefix2prefix(p, &new))
return RMAP_NOMATCH;
return (prefix_list_apply(plist, &new) == PREFIX_DENY ? RMAP_NOMATCH
: RMAP_MATCH);
}
static enum route_map_cmd_result_t
route_match_address_prefix_list(void *rule, afi_t afi,
const struct prefix *prefix, void *object)
@ -655,6 +669,10 @@ route_match_address_prefix_list(void *rule, afi_t afi,
if (prefix->family == AF_FLOWSPEC)
return route_match_prefix_list_flowspec(afi, plist,
prefix);
else if (prefix->family == AF_EVPN)
return route_match_prefix_list_evpn(afi, plist, prefix);
return (prefix_list_apply(plist, prefix) == PREFIX_DENY ? RMAP_NOMATCH
: RMAP_MATCH);
}

View File

@ -1404,6 +1404,63 @@ bool ipv4_unicast_valid(const struct in_addr *addr)
return true;
}
static int ipaddr2prefix(const struct ipaddr *ip, uint16_t prefixlen,
struct prefix *p)
{
switch (ip->ipa_type) {
case (IPADDR_V4):
p->family = AF_INET;
p->u.prefix4 = ip->ipaddr_v4;
p->prefixlen = prefixlen;
break;
case (IPADDR_V6):
p->family = AF_INET6;
p->u.prefix6 = ip->ipaddr_v6;
p->prefixlen = prefixlen;
break;
case (IPADDR_NONE):
p->family = AF_UNSPEC;
break;
}
return 0;
}
/*
* Convert type-2 and type-5 evpn route prefixes into the more
* general ipv4/ipv6 prefix types so we can match prefix lists
* and such.
*/
int evpn_prefix2prefix(const struct prefix *evpn, struct prefix *to)
{
const struct evpn_addr *addr;
if (evpn->family != AF_EVPN)
return -1;
addr = &evpn->u.prefix_evpn;
switch (addr->route_type) {
case (2):
if (IS_IPADDR_V4(&addr->macip_addr.ip))
ipaddr2prefix(&addr->macip_addr.ip, 32, to);
else if (IS_IPADDR_V6(&addr->macip_addr.ip))
ipaddr2prefix(&addr->macip_addr.ip, 128, to);
else
return -1; /* mac only? */
break;
case (5):
ipaddr2prefix(&addr->prefix_addr.ip,
addr->prefix_addr.ip_prefix_length, to);
break;
default:
return -1;
}
return 0;
}
printfrr_ext_autoreg_p("EA", printfrr_ea);
static ssize_t printfrr_ea(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)

View File

@ -510,6 +510,7 @@ extern char *esi_to_str(const esi_t *esi, char *buf, int size);
extern char *evpn_es_df_alg2str(uint8_t df_alg, char *buf, int buf_len);
extern void prefix_evpn_hexdump(const struct prefix_evpn *p);
extern bool ipv4_unicast_valid(const struct in_addr *addr);
extern int evpn_prefix2prefix(const struct prefix *evpn, struct prefix *to);
static inline int ipv6_martian(const struct in6_addr *addr)
{