From 196c6b092d3f9d8a6ce037e778270aff231133c2 Mon Sep 17 00:00:00 2001 From: Lakshman Krishnamoorthy Date: Tue, 12 Nov 2019 16:51:24 -0800 Subject: [PATCH] bgpd: route-map support for evpn RD filter With this code change, we can now filter evpn routes based on RD using the match statement: "match evpn rd XX" Signed-off-by: Lakshman Krishnamoorthy --- bgpd/bgp_route.c | 10 +++-- bgpd/bgp_routemap.c | 91 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 96 insertions(+), 5 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 261fe77800..8e0a758259 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1244,7 +1244,7 @@ static int bgp_cluster_filter(struct peer *peer, struct attr *attr) static int bgp_input_modifier(struct peer *peer, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi, const char *rmap_name, mpls_label_t *label, - uint32_t num_labels) + uint32_t num_labels, struct bgp_node *rn) { struct bgp_filter *filter; struct bgp_path_info rmap_path = { 0 }; @@ -1279,6 +1279,8 @@ static int bgp_input_modifier(struct peer *peer, struct prefix *p, rmap_path.peer = peer; rmap_path.attr = attr; rmap_path.extra = &extra; + rmap_path.net = rn; + extra.num_labels = num_labels; if (label && num_labels && num_labels <= BGP_MAX_LABELS) memcpy(extra.label, label, @@ -1795,6 +1797,7 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, memset(&rmap_path, 0, sizeof(struct bgp_path_info)); rmap_path.peer = peer; rmap_path.attr = attr; + rmap_path.net = rn; if (pi->extra) { memcpy(&dummy_rmap_path_extra, pi->extra, @@ -3153,7 +3156,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, * intern * the attr (which takes over the memory references) */ if (bgp_input_modifier(peer, p, &new_attr, afi, safi, NULL, - label, num_labels) == RMAP_DENY) { + label, num_labels, rn) == RMAP_DENY) { peer->stat_pfx_filter++; reason = "route-map;"; bgp_attr_flush(&new_attr); @@ -11299,7 +11302,8 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, /* Filter prefix using route-map */ ret = bgp_input_modifier(peer, &rn->p, &attr, - afi, safi, rmap_name, NULL, 0); + afi, safi, rmap_name, NULL, 0, + NULL); if (type == bgp_show_adj_route_filtered && !route_filtered && ret != RMAP_DENY) { diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index d0cea547ec..4d73faa87c 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -969,6 +969,63 @@ struct route_map_rule_cmd route_match_evpn_route_type_cmd = { "evpn route-type", route_match_evpn_route_type, route_match_evpn_route_type_compile, route_match_evpn_route_type_free}; +/* `match rd' */ + +/* Match function should return 1 if match is success else return zero. */ +static enum route_map_cmd_result_t +route_match_rd(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct prefix_rd *prd_rule = NULL; + struct prefix_rd *prd_route = NULL; + struct bgp_path_info *path = NULL; + + if (type == RMAP_BGP) { + if (prefix->family != AF_EVPN) + return RMAP_NOMATCH; + + prd_rule = (struct prefix_rd *)rule; + path = (struct bgp_path_info *)object; + + if (path->net == NULL || path->net->prn == NULL) + return RMAP_NOMATCH; + + prd_route = (struct prefix_rd *)&path->net->prn->p; + if (memcmp(prd_route->val, prd_rule->val, ECOMMUNITY_SIZE) == 0) + return RMAP_MATCH; + } + + return RMAP_NOMATCH; +} + +/* Route map `rd' match statement. */ +static void *route_match_rd_compile(const char *arg) +{ + struct prefix_rd *prd; + int ret; + + prd = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct prefix_rd)); + + ret = str2prefix_rd(arg, prd); + if (!ret) { + XFREE(MTYPE_ROUTE_MAP_COMPILED, prd); + return NULL; + } + + return prd; +} + +/* Free route map's compiled `rd' value. */ +static void route_match_rd_free(void *rule) +{ + XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for rd matching. */ +struct route_map_rule_cmd route_match_evpn_rd_cmd = { + "evpn rd", route_match_rd, route_match_rd_compile, + route_match_rd_free}; + /* Route map commands for VRF route leak with source vrf matching */ static enum route_map_cmd_result_t route_match_vrl_source_vrf(void *rule, const struct prefix *prefix, @@ -1038,8 +1095,10 @@ route_match_local_pref(void *rule, const struct prefix *prefix, return RMAP_NOMATCH; } -/* Route map `match local-preference' match statement. - `arg' is local-pref value */ +/* + * Route map `match local-preference' match statement. + * `arg' is local-pref value + */ static void *route_match_local_pref_compile(const char *arg) { uint32_t *local_pref; @@ -3666,6 +3725,31 @@ DEFUN (no_match_evpn_default_route, RMAP_EVENT_MATCH_DELETED); } +DEFUN (match_evpn_rd, + match_evpn_rd_cmd, + "match evpn rd ASN:NN_OR_IP-ADDRESS:NN", + MATCH_STR + EVPN_HELP_STR + "Route Distinguisher\n" + "ASN:XX or A.B.C.D:XX\n") +{ + return bgp_route_match_add(vty, "evpn rd", argv[3]->arg, + RMAP_EVENT_MATCH_ADDED); +} + +DEFUN (no_match_evpn_rd, + no_match_evpn_rd_cmd, + "no match evpn rd ASN:NN_OR_IP-ADDRESS:NN", + NO_STR + MATCH_STR + EVPN_HELP_STR + "Route Distinguisher\n" + "ASN:XX or A.B.C.D:XX\n") +{ + return bgp_route_match_delete(vty, "evpn rd", argv[4]->arg, + RMAP_EVENT_MATCH_DELETED); +} + DEFPY(match_vrl_source_vrf, match_vrl_source_vrf_cmd, "match source-vrf NAME$vrf_name", @@ -5216,6 +5300,7 @@ void bgp_route_map_init(void) route_map_install_match(&route_match_mac_address_cmd); route_map_install_match(&route_match_evpn_vni_cmd); route_map_install_match(&route_match_evpn_route_type_cmd); + route_map_install_match(&route_match_evpn_rd_cmd); route_map_install_match(&route_match_evpn_default_route_cmd); route_map_install_match(&route_match_vrl_source_vrf_cmd); @@ -5256,6 +5341,8 @@ void bgp_route_map_init(void) install_element(RMAP_NODE, &no_match_evpn_vni_cmd); install_element(RMAP_NODE, &match_evpn_route_type_cmd); install_element(RMAP_NODE, &no_match_evpn_route_type_cmd); + install_element(RMAP_NODE, &match_evpn_rd_cmd); + install_element(RMAP_NODE, &no_match_evpn_rd_cmd); install_element(RMAP_NODE, &match_evpn_default_route_cmd); install_element(RMAP_NODE, &no_match_evpn_default_route_cmd); install_element(RMAP_NODE, &match_vrl_source_vrf_cmd);