From 643215ce4cd1a38d15fdce8ea44e48b325c63272 Mon Sep 17 00:00:00 2001 From: mitesh Date: Wed, 24 Jan 2018 15:25:03 -0800 Subject: [PATCH 1/5] zebra: optimize l3vni lookup in certain callflows Currently, while processing kernel messages related to VNIs we first check if VNI is L3 - this is a hash lookup later, we do the lookup again to find the L3-VNI. This is non-optimal. Made changed to make sure we only do the lookup once. Signed-off-by: Mitesh Kanjariya --- zebra/zebra_vxlan.c | 119 ++++++++++---------------------------------- 1 file changed, 25 insertions(+), 94 deletions(-) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 1690079f68..0054555e5a 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -126,7 +126,6 @@ static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac); /* l3-vni related APIs*/ -static int is_vni_l3(vni_t); static zebra_l3vni_t *zl3vni_lookup(vni_t vni); static void *zl3vni_alloc(void *p); static zebra_l3vni_t *zl3vni_add(vni_t vni, vrf_id_t vrf_id); @@ -2593,6 +2592,8 @@ static void zvni_build_hash_table() zns = zebra_ns_lookup(NS_DEFAULT); for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { vni_t vni; + zebra_vni_t *zvni = NULL; + zebra_l3vni_t *zl3vni = NULL; struct zebra_if *zif; struct zebra_l2info_vxlan *vxl; @@ -2606,21 +2607,14 @@ static void zvni_build_hash_table() vxl = &zif->l2info.vxl; vni = vxl->vni; - if (is_vni_l3(vni)) { - zebra_l3vni_t *zl3vni = NULL; + /* L3-VNI and L2-VNI are handled seperately */ + zl3vni = zl3vni_lookup(vni); + if (zl3vni) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug("create L3-VNI hash for Intf %s(%u) L3-VNI %u", ifp->name, ifp->ifindex, vni); - zl3vni = zl3vni_lookup(vni); - if (!zl3vni) { - zlog_err( - "Failed to locate L3-VNI hash at UP, IF %s(%u) VNI %u", - ifp->name, ifp->ifindex, vni); - return; - } - /* associate with vxlan_if */ zl3vni->local_vtep_ip = vxl->vtep_ip; zl3vni->vxlan_if = ifp; @@ -2636,8 +2630,6 @@ static void zvni_build_hash_table() zebra_vxlan_process_l3vni_oper_up(zl3vni); } else { - zebra_vni_t *zvni = NULL; - zebra_l3vni_t *zl3vni = NULL; struct interface *vlan_if = NULL; if (IS_ZEBRA_DEBUG_VXLAN) @@ -3387,16 +3379,6 @@ static int zl3vni_del(zebra_l3vni_t *zl3vni) return 0; } -static int is_vni_l3(vni_t vni) -{ - zebra_l3vni_t *zl3vni = NULL; - - zl3vni = zl3vni_lookup(vni); - if (zl3vni) - return 1; - return 0; -} - static struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni) { struct zebra_ns *zns = NULL; @@ -5815,6 +5797,8 @@ int zebra_vxlan_if_down(struct interface *ifp) vni_t vni; struct zebra_if *zif = NULL; struct zebra_l2info_vxlan *vxl = NULL; + zebra_l3vni_t *zl3vni = NULL; + zebra_vni_t *zvni; /* Check if EVPN is enabled. */ if (!is_evpn_enabled()) @@ -5825,30 +5809,16 @@ int zebra_vxlan_if_down(struct interface *ifp) vxl = &zif->l2info.vxl; vni = vxl->vni; - - if (is_vni_l3(vni)) { - + zl3vni = zl3vni_lookup(vni); + if (zl3vni) { /* process-if-down for l3-vni */ - zebra_l3vni_t *zl3vni = NULL; - if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug("Intf %s(%u) L3-VNI %u is DOWN", ifp->name, ifp->ifindex, vni); - zl3vni = zl3vni_lookup(vni); - if (!zl3vni) { - zlog_err( - "Failed to locate L3-VNI hash at DOWN, IF %s(%u) VNI %u", - ifp->name, ifp->ifindex, vni); - return -1; - } - zebra_vxlan_process_l3vni_oper_down(zl3vni); - } else { /* process if-down for l2-vni */ - zebra_vni_t *zvni; - if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug("Intf %s(%u) L2-VNI %u is DOWN", ifp->name, ifp->ifindex, vni); @@ -5885,6 +5855,8 @@ int zebra_vxlan_if_up(struct interface *ifp) vni_t vni; struct zebra_if *zif = NULL; struct zebra_l2info_vxlan *vxl = NULL; + zebra_vni_t *zvni = NULL; + zebra_l3vni_t *zl3vni = NULL; /* Check if EVPN is enabled. */ if (!is_evpn_enabled()) @@ -5895,7 +5867,8 @@ int zebra_vxlan_if_up(struct interface *ifp) vxl = &zif->l2info.vxl; vni = vxl->vni; - if (is_vni_l3(vni)) { + zl3vni = zl3vni_lookup(vni); + if (zl3vni) { /* Handle L3-VNI add */ zebra_l3vni_t *zl3vni = NULL; @@ -5904,14 +5877,6 @@ int zebra_vxlan_if_up(struct interface *ifp) zlog_debug("Intf %s(%u) L3-VNI %u is UP", ifp->name, ifp->ifindex, vni); - zl3vni = zl3vni_lookup(vni); - if (!zl3vni) { - zlog_err( - "Failed to locate L3-VNI hash at UP, IF %s(%u) VNI %u", - ifp->name, ifp->ifindex, vni); - return -1; - } - /* we need to associate with SVI, if any, we can associate with * svi-if only after association with vxlan-intf is complete */ @@ -5921,9 +5886,6 @@ int zebra_vxlan_if_up(struct interface *ifp) zebra_vxlan_process_l3vni_oper_up(zl3vni); } else { /* Handle L2-VNI add */ - - zebra_vni_t *zvni = NULL; - zebra_l3vni_t *zl3vni = NULL; struct interface *vlan_if = NULL; if (IS_ZEBRA_DEBUG_VXLAN) @@ -5969,6 +5931,8 @@ int zebra_vxlan_if_del(struct interface *ifp) vni_t vni; struct zebra_if *zif = NULL; struct zebra_l2info_vxlan *vxl = NULL; + zebra_vni_t *zvni = NULL; + zebra_l3vni_t *zl3vni = NULL; /* Check if EVPN is enabled. */ if (!is_evpn_enabled()) @@ -5979,7 +5943,8 @@ int zebra_vxlan_if_del(struct interface *ifp) vxl = &zif->l2info.vxl; vni = vxl->vni; - if (is_vni_l3(vni)) { + zl3vni = zl3vni_lookup(vni); + if (zl3vni) { /* process if-del for l3-vni */ zebra_l3vni_t *zl3vni = NULL; @@ -5988,14 +5953,6 @@ int zebra_vxlan_if_del(struct interface *ifp) zlog_debug("Del L3-VNI %u intf %s(%u)", vni, ifp->name, ifp->ifindex); - zl3vni = zl3vni_lookup(vni); - if (!zl3vni) { - zlog_err( - "Failed to locate L3-VNI hash at del, IF %s(%u) VNI %u", - ifp->name, ifp->ifindex, vni); - return 0; - } - /* process oper-down for l3-vni */ zebra_vxlan_process_l3vni_oper_down(zl3vni); @@ -6005,9 +5962,6 @@ int zebra_vxlan_if_del(struct interface *ifp) } else { /* process if-del for l2-vni*/ - zebra_vni_t *zvni = NULL; - zebra_l3vni_t *zl3vni = NULL; - if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug("Del L2-VNI %u intf %s(%u)", vni, ifp->name, ifp->ifindex); @@ -6043,7 +5997,6 @@ int zebra_vxlan_if_del(struct interface *ifp) return -1; } } - return 0; } @@ -6055,6 +6008,8 @@ int zebra_vxlan_if_update(struct interface *ifp, u_int16_t chgflags) vni_t vni; struct zebra_if *zif = NULL; struct zebra_l2info_vxlan *vxl = NULL; + zebra_vni_t *zvni = NULL; + zebra_l3vni_t *zl3vni = NULL; /* Check if EVPN is enabled. */ if (!is_evpn_enabled()) @@ -6065,16 +6020,8 @@ int zebra_vxlan_if_update(struct interface *ifp, u_int16_t chgflags) vxl = &zif->l2info.vxl; vni = vxl->vni; - if (is_vni_l3(vni)) { - zebra_l3vni_t *zl3vni = NULL; - - zl3vni = zl3vni_lookup(vni); - if (!zl3vni) { - zlog_err( - "Failed to find L3-VNI hash on update, IF %s(%u) VNI %u", - ifp->name, ifp->ifindex, vni); - return -1; - } + zl3vni = zl3vni_lookup(vni); + if (zl3vni) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( @@ -6110,7 +6057,6 @@ int zebra_vxlan_if_update(struct interface *ifp, u_int16_t chgflags) zebra_vxlan_process_l3vni_oper_up(zl3vni); } } else { - zebra_vni_t *zvni = NULL; /* Update VNI hash. */ zvni = zvni_lookup(vni); @@ -6201,6 +6147,8 @@ int zebra_vxlan_if_add(struct interface *ifp) vni_t vni; struct zebra_if *zif = NULL; struct zebra_l2info_vxlan *vxl = NULL; + zebra_vni_t *zvni = NULL; + zebra_l3vni_t *zl3vni = NULL; /* Check if EVPN is enabled. */ if (!is_evpn_enabled()) @@ -6211,11 +6159,10 @@ int zebra_vxlan_if_add(struct interface *ifp) vxl = &zif->l2info.vxl; vni = vxl->vni; - if (is_vni_l3(vni)) { + zl3vni = zl3vni_lookup(vni); + if (zl3vni) { /* process if-add for l3-vni*/ - zebra_l3vni_t *zl3vni = NULL; - if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( "Add L3-VNI %u intf %s(%u) VLAN %u local IP %s master %u", @@ -6223,20 +6170,6 @@ int zebra_vxlan_if_add(struct interface *ifp) vxl->access_vlan, inet_ntoa(vxl->vtep_ip), zif->brslave_info.bridge_ifindex); - /* - * we expect the l3-vni has entry to be present here. - * The only place l3-vni is created in zebra is vrf-vni mapping - * command. This might change when we have the switchd support - * for l3-vxlan interface. - */ - zl3vni = zl3vni_lookup(vni); - if (!zl3vni) { - zlog_err( - "Failed to locate L3-VNI hash at del, IF %s(%u) VNI %u", - ifp->name, ifp->ifindex, vni); - return 0; - } - /* associate with vxlan_if */ zl3vni->local_vtep_ip = vxl->vtep_ip; zl3vni->vxlan_if = ifp; @@ -6250,8 +6183,6 @@ int zebra_vxlan_if_add(struct interface *ifp) } else { /* process if-add for l2-vni */ - zebra_vni_t *zvni = NULL; - zebra_l3vni_t *zl3vni = NULL; struct interface *vlan_if = NULL; /* Create or update VNI hash. */ From 33c2ff625e0865a65713a81cc25cf8c8cc47d22f Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Fri, 26 Jan 2018 17:16:48 -0800 Subject: [PATCH 2/5] bgpd: support for filtering EVPN routes based on route-types. In many situations, it is desirable to only exchange EVPN routes of a particular type. For e.g., a common deployment scenario for large DCs is to sub-divide the DC into multiple PODs with full host mobility within a POD (i.e., all subnets provisioned on all leaf switches within the POD) but only do prefix-based routing across PODs. This can be achieved by only exchanging EVPN type-5 routes across PODs. Implement a policy to filter EVPN routes based on route type. Ticket: CM-19394 Review: CCR-7139 Testing: Manual Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_routemap.c | 85 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 8c9f9f65ca..f5edcf381d 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -696,6 +696,58 @@ struct route_map_rule_cmd route_match_evpn_vni_cmd = { "evpn vni", route_match_vni, route_match_vni_compile, route_match_vni_free}; +/* `match evpn route-type' */ + +/* Match function should return 1 if match is success else return + zero. */ +static route_map_result_t route_match_evpn_route_type(void *rule, + struct prefix *prefix, + route_map_object_t type, + void *object) +{ + u_char route_type = 0; + + if (type == RMAP_BGP) { + route_type = *((u_char *)rule); + + if (route_type == prefix->u.prefix_evpn.route_type) + return RMAP_MATCH; + } + + return RMAP_NOMATCH; +} + +/* Route map `route-type' match statement. */ +static void *route_match_evpn_route_type_compile(const char *arg) +{ + u_char *route_type = NULL; + + route_type = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(u_char)); + if (!route_type) + return NULL; + + if (strncmp(arg, "ma", 2) == 0) + *route_type = BGP_EVPN_MAC_IP_ROUTE; + else if (strncmp(arg, "mu", 2) == 0) + *route_type = BGP_EVPN_IMET_ROUTE; + else + *route_type = BGP_EVPN_IP_PREFIX_ROUTE; + + return route_type; +} + +/* Free route map's compiled `route-type' value. */ +static void route_match_evpn_route_type_free(void *rule) +{ + XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for evpn route-type matching. */ +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 local-preference LOCAL-PREF' */ /* Match function return 1 if match is success else return zero. */ @@ -3132,6 +3184,36 @@ DEFUN (no_match_mac_address, RMAP_EVENT_FILTER_DELETED); } +DEFUN (match_evpn_route_type, + match_evpn_route_type_cmd, + "match evpn route-type {macip | multicast | prefix}", + MATCH_STR + EVPN_HELP_STR + "Match route-type\n" + "mac-ip route\n" + "IMET route\n" + "prefix route\n") +{ + return bgp_route_match_add(vty, "evpn route-type", argv[3]->arg, + RMAP_EVENT_MATCH_ADDED); +} + +DEFUN (no_match_evpn_route_type, + no_match_evpn_route_type_cmd, + "no match evpn route-type {macip | multicast | prefix}", + NO_STR + MATCH_STR + EVPN_HELP_STR + "Match route-type\n" + "mac-ip route\n" + "IMET route\n" + "prefix route\n") +{ + return bgp_route_match_delete(vty, "evpn route-type", argv[4]->arg, + RMAP_EVENT_MATCH_DELETED); +} + + DEFUN (match_evpn_vni, match_evpn_vni_cmd, "match evpn vni (1-16777215)", @@ -4534,6 +4616,7 @@ void bgp_route_map_init(void) route_map_install_match(&route_match_tag_cmd); 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_set(&route_set_ip_nexthop_cmd); route_map_install_set(&route_set_local_pref_cmd); @@ -4568,6 +4651,8 @@ void bgp_route_map_init(void) install_element(RMAP_NODE, &no_match_mac_address_cmd); install_element(RMAP_NODE, &match_evpn_vni_cmd); 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_aspath_cmd); install_element(RMAP_NODE, &no_match_aspath_cmd); From 2aeb403d3750c1b5f41679a395e592c3371d84fa Mon Sep 17 00:00:00 2001 From: mitesh Date: Mon, 5 Feb 2018 13:51:45 -0800 Subject: [PATCH 3/5] zebra: fix SA issues Signed-off-by: Mitesh Kanjariya --- zebra/zebra_vxlan.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 0054555e5a..7f71f2a809 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -3415,6 +3415,9 @@ static struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni) struct zebra_if *zif = NULL; /* zebra_if for vxlan_if */ struct zebra_l2info_vxlan *vxl = NULL; /* l2 info for vxlan_if */ + if (!zl3vni) + return NULL; + if (!zl3vni->vxlan_if) return NULL; @@ -3587,6 +3590,9 @@ static int zl3vni_send_del_to_client(zebra_l3vni_t *zl3vni) static void zebra_vxlan_process_l3vni_oper_up(zebra_l3vni_t *zl3vni) { + if (!zl3vni) + return; + if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug("L3-VNI %u is UP - send add to BGP", zl3vni->vni); @@ -3597,6 +3603,9 @@ static void zebra_vxlan_process_l3vni_oper_up(zebra_l3vni_t *zl3vni) static void zebra_vxlan_process_l3vni_oper_down(zebra_l3vni_t *zl3vni) { + if (!zl3vni) + return; + if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug("L3-VNI %u is Down - Send del to BGP", zl3vni->vni); @@ -5946,9 +5955,6 @@ int zebra_vxlan_if_del(struct interface *ifp) zl3vni = zl3vni_lookup(vni); if (zl3vni) { - /* process if-del for l3-vni */ - zebra_l3vni_t *zl3vni = NULL; - if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug("Del L3-VNI %u intf %s(%u)", vni, ifp->name, ifp->ifindex); From d4ef18b6a797c568fc2d1de07b6984e497c4f0b5 Mon Sep 17 00:00:00 2001 From: mitesh Date: Mon, 5 Feb 2018 13:56:12 -0800 Subject: [PATCH 4/5] bgpd: match evpn route type command should use '<>' instead of '{}' Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_routemap.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index f5edcf381d..597a01842e 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -723,8 +723,6 @@ static void *route_match_evpn_route_type_compile(const char *arg) u_char *route_type = NULL; route_type = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(u_char)); - if (!route_type) - return NULL; if (strncmp(arg, "ma", 2) == 0) *route_type = BGP_EVPN_MAC_IP_ROUTE; @@ -3186,7 +3184,7 @@ DEFUN (no_match_mac_address, DEFUN (match_evpn_route_type, match_evpn_route_type_cmd, - "match evpn route-type {macip | multicast | prefix}", + "match evpn route-type ", MATCH_STR EVPN_HELP_STR "Match route-type\n" @@ -3200,7 +3198,7 @@ DEFUN (match_evpn_route_type, DEFUN (no_match_evpn_route_type, no_match_evpn_route_type_cmd, - "no match evpn route-type {macip | multicast | prefix}", + "no match evpn route-type ", NO_STR MATCH_STR EVPN_HELP_STR From eb474e7313f4a6cb990dd13559718d57ac3b8aba Mon Sep 17 00:00:00 2001 From: mitesh Date: Mon, 5 Feb 2018 16:21:00 -0800 Subject: [PATCH 5/5] zebra: fix SA issues Signed-off-by: Mitesh Kanjariya --- zebra/zebra_vxlan.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 7f71f2a809..6a08ab8f80 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -5879,9 +5879,6 @@ int zebra_vxlan_if_up(struct interface *ifp) zl3vni = zl3vni_lookup(vni); if (zl3vni) { - /* Handle L3-VNI add */ - zebra_l3vni_t *zl3vni = NULL; - if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug("Intf %s(%u) L3-VNI %u is UP", ifp->name, ifp->ifindex, vni);