From e241544469ab880da97db8edbc9d21e9cb000257 Mon Sep 17 00:00:00 2001 From: Lakshman Krishnamoorthy Date: Fri, 31 May 2019 10:22:11 -0700 Subject: [PATCH] bgpd: Filtering received EVPN routes based on VNI does not work Issue1: When "neighbor X.X.X.X route-map RM-VNI-FILTER in" is configured under evpn address-family, all the received routes are dropped regardless of whether the route has a matching vni or not. Issue2: Routes with 2 labels are not filtered correctly Issue3: Interpreting the label based on tunnel type, vxlan was not done correctly. Vxlan label has 24 bits, whereas, MPLS label is 20 bits long Fix1: The handler bgp_update() that services the received route ignored the route's label while deciding whether to filter it or not. As part of the fix, the handler now uses the label info to make the decision about whether to filter the route or not. Fix2: route_match_vni() now tries to match both the labels within the route, not just the one. Signed-off-by: Lakshman Krishnamoorthy --- bgpd/bgp_route.c | 17 ++++++++++++----- bgpd/bgp_routemap.c | 36 ++++++++++++++++++++++++++++++------ 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index edaab88286..543df2b048 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1236,10 +1236,12 @@ 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) + const char *rmap_name, mpls_label_t *label, + uint32_t num_labels) { struct bgp_filter *filter; - struct bgp_path_info rmap_path; + struct bgp_path_info rmap_path = { 0 }; + struct bgp_path_info_extra extra = { 0 }; route_map_result_t ret; struct route_map *rmap = NULL; @@ -1269,6 +1271,11 @@ static int bgp_input_modifier(struct peer *peer, struct prefix *p, /* Duplicate current value to new strucutre for modification. */ rmap_path.peer = peer; rmap_path.attr = attr; + rmap_path.extra = &extra; + extra.num_labels = num_labels; + if (label && num_labels && num_labels <= BGP_MAX_LABELS) + memcpy(extra.label, label, + num_labels * sizeof(mpls_label_t)); SET_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN); @@ -3124,8 +3131,8 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, * commands, so we need bgp_attr_flush in the error paths, until we * intern * the attr (which takes over the memory references) */ - if (bgp_input_modifier(peer, p, &new_attr, afi, safi, NULL) - == RMAP_DENY) { + if (bgp_input_modifier(peer, p, &new_attr, afi, safi, NULL, + label, num_labels) == RMAP_DENY) { reason = "route-map;"; bgp_attr_flush(&new_attr); goto filtered; @@ -11191,7 +11198,7 @@ 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); + afi, safi, rmap_name, NULL, 0); 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 85cab0d59f..790b2f7995 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -60,6 +60,7 @@ #include "bgpd/bgp_evpn_private.h" #include "bgpd/bgp_evpn_vty.h" #include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_encap_types.h" #if ENABLE_BGP_VNC #include "bgpd/rfapi/bgp_rfapi_cfg.h" @@ -795,26 +796,49 @@ struct route_map_rule_cmd route_match_mac_address_cmd = { "mac address", route_match_mac_address, route_match_mac_address_compile, route_match_mac_address_free}; -/* `match vni' */ - -/* Match function should return 1 if match is success else return - zero. */ +/* + * Match function returns: + * ...RMAP_MATCH if match is found. + * ...RMAP_NOMATCH if match is not found. + * ...RMAP_NOOP to ignore this match check. + */ static enum route_map_match_result_t route_match_vni(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { vni_t vni = 0; + unsigned int label_cnt = 0; struct bgp_path_info *path = NULL; + struct prefix_evpn *evp = (struct prefix_evpn *) prefix; if (type == RMAP_BGP) { vni = *((vni_t *)rule); path = (struct bgp_path_info *)object; + /* + * This rmap filter is valid for vxlan tunnel type only. + * For any other tunnel type, return noop to ignore + * this check. + */ + if (path->attr && path->attr->encap_tunneltype != + BGP_ENCAP_TYPE_VXLAN) + return RMAP_NOOP; + + /* + * We do not want to filter type 3 routes because + * they do not have vni associated with them. + */ + if (evp && evp->prefix.route_type == BGP_EVPN_IMET_ROUTE) + return RMAP_NOOP; + if (path->extra == NULL) return RMAP_NOMATCH; - if (vni == label2vni(&path->extra->label[0])) - return RMAP_MATCH; + for ( ; label_cnt < BGP_MAX_LABELS && + label_cnt < path->extra->num_labels; label_cnt++) { + if (vni == label2vni(&path->extra->label[label_cnt])) + return RMAP_MATCH; + } } return RMAP_NOMATCH; -- 2.39.5