]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bgpd,lib: route-map/plist matching via type-2/5 routes
authorStephen Worley <sworley@nvidia.com>
Tue, 9 Mar 2021 23:59:09 +0000 (18:59 -0500)
committerStephen Worley <sworley@nvidia.com>
Tue, 23 Aug 2022 16:41:25 +0000 (12:41 -0400)
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>
bgpd/bgp_routemap.c
lib/prefix.c
lib/prefix.h

index 33f68c9e8811107426d58ecf849d5307176e36b0..3d7442f45cb6a90edcf5d69e0f62724524478515 100644 (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);
 }
index e64b10bf24787452081c01262c3ff839b0a632ed..a3b8e5c82302a23ad16dba27920cfa797a6995d0 100644 (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)
index 7b2f889874982d744b921e1a114d762c8c1dce16..026e525f610fb0949edb10617a0829ee0cb9a41f 100644 (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)
 {