From: Stephen Worley Date: Tue, 9 Mar 2021 23:59:09 +0000 (-0500) Subject: bgpd,lib: route-map/plist matching via type-2/5 routes X-Git-Tag: frr-8.4-rc~1^2~5 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=6eb8350586c7eb2afa1ed20381c1febd296e38ed;p=matthieu%2Ffrr.git 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 --- diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 33f68c9e88..3d7442f45c 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -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); } diff --git a/lib/prefix.c b/lib/prefix.c index e64b10bf24..a3b8e5c823 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -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) diff --git a/lib/prefix.h b/lib/prefix.h index 7b2f889874..026e525f61 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -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) {