]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bgpd: re-eval use-l3nhg when a remote ES is [de]activated in a VRF
authorAnuradha Karuppiah <anuradhak@cumulusnetworks.com>
Mon, 17 Aug 2020 23:24:50 +0000 (16:24 -0700)
committerAnuradha Karuppiah <anuradhak@nvidia.com>
Fri, 26 Mar 2021 00:09:53 +0000 (17:09 -0700)
There are two changes in this commit -

1. Maintain a list of global MAC-IP routes per-ES. This list is maintained
for quick processing on the following events -
a. When the first VTEP/PE becomes active in the ES-VRF, the L3 NHG is
activated and the route can be sent to zebra.
b. When there are no active PEs in the ES-VRF the L3 NHG is
de-activated and -
- If the ES is present in the VRF -
The route is not installed in zebra as there are no active PEs for
the ES-VRF
- If the ES is not present in the VRF -
The route is installed with a flat multi-path list i.e. without L3NHG.
This is to handle the case where there are no locally attached L2VNIs
on the ES (for that tenant VRF).

2. Reinstall VRF route when an ES is installed or uninstalled in a
tenant VRF (the global MAC-IP list in #1 is used for this purpose also).
If an ES is present in the VRF we use L3NHG to enable fast-failover of
routed traffic.

Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
bgpd/bgp_attr.h
bgpd/bgp_evpn.c
bgpd/bgp_evpn_mh.c
bgpd/bgp_evpn_mh.h
bgpd/bgp_evpn_private.h
bgpd/bgp_evpn_vty.c
bgpd/bgp_route.c

index 1b176f87164de2c55d408242a6fd1db5e2866216..a583581030845e74b6e17aebb5da763536de886e 100644 (file)
@@ -243,6 +243,15 @@ struct attr {
         */
 #define ATTR_ES_PEER_ROUTER (1 << 4)
 
+       /* These two flags are only set on L3 routes installed in a
+        * VRF as a result of EVPN MAC-IP route
+        * XXX - while splitting up per-family attrs these need to be
+        * classified as non-EVPN
+        */
+#define ATTR_ES_L3_NHG_USE (1 << 5)
+#define ATTR_ES_L3_NHG_ACTIVE (1 << 6)
+#define ATTR_ES_L3_NHG (ATTR_ES_L3_NHG_USE | ATTR_ES_L3_NHG_ACTIVE)
+
        /* route tag */
        route_tag_t tag;
 
index a4d4dbc20395a28a4b84d17682533bc224babbdd..26e880c0dd7561140def9e1b0bfb2933f2fa0ec6 100644 (file)
@@ -1597,8 +1597,8 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
                }
        }
 
-       /* MAC-IP routes in the VNI route table are linked to the
-        * destination ES
+       /* local MAC-IP routes in the VNI table are linked to
+        * the destination ES
         */
        if (route_change && vpn_rt
            && (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE))
@@ -2378,6 +2378,8 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
        afi_t afi = 0;
        safi_t safi = 0;
        bool new_pi = false;
+       bool use_l3nhg = false;
+       bool is_l3nhg_active = false;
 
        memset(pp, 0, sizeof(struct prefix));
        ip_prefix_from_evpn_prefix(evp, pp);
@@ -2413,6 +2415,13 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
        else
                attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
 
+       bgp_evpn_es_vrf_use_nhg(bgp_vrf, &parent_pi->attr->esi, &use_l3nhg,
+                               &is_l3nhg_active, NULL);
+       if (use_l3nhg)
+               attr.es_flags |= ATTR_ES_L3_NHG_USE;
+       if (is_l3nhg_active)
+               attr.es_flags |= ATTR_ES_L3_NHG_ACTIVE;
+
        /* Check if route entry is already present. */
        for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
                if (pi->extra
@@ -2532,11 +2541,6 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
                pi->uptime = bgp_clock();
        }
 
-       /* MAC-IP routes in the VNI table are linked to the destination ES */
-       if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
-               bgp_evpn_path_es_link(pi, vpn->vni,
-                                     bgp_evpn_attr_get_esi(pi->attr));
-
        /* Perform route selection and update zebra, if required. */
        ret = evpn_route_select_install(bgp, vpn, dest);
 
@@ -2857,7 +2861,6 @@ bgp_evpn_skip_vrf_import_of_local_es(struct bgp *bgp_vrf,
                                     struct bgp_path_info *pi, int install)
 {
        esi_t *esi;
-       struct in_addr nh;
 
        if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
                esi = bgp_evpn_attr_get_esi(pi->attr);
@@ -2875,30 +2878,52 @@ bgp_evpn_skip_vrf_import_of_local_es(struct bgp *bgp_vrf,
                        }
                        return true;
                }
+       }
+       return false;
+}
 
-               /* Don't import routes with ES as destination if L3NHG is in
-                * use and the nexthop has not been advertised via the EAD-ES
-                */
-               if (pi->attr)
-                       nh = pi->attr->nexthop;
+/*
+ * Install or uninstall a mac-ip route in the provided vrf if
+ * there is a rt match
+ */
+int bgp_evpn_route_entry_install_if_vrf_match(struct bgp *bgp_vrf,
+                                             struct bgp_path_info *pi,
+                                             int install)
+{
+       int ret = 0;
+       const struct prefix_evpn *evp =
+               (const struct prefix_evpn *)bgp_dest_get_prefix(pi->net);
+
+       /* Consider "valid" remote routes applicable for
+        * this VRF.
+        */
+       if (!(CHECK_FLAG(pi->flags, BGP_PATH_VALID)
+             && pi->type == ZEBRA_ROUTE_BGP
+             && pi->sub_type == BGP_ROUTE_NORMAL))
+               return 0;
+
+       /* don't import hosts that are locally attached */
+       if (bgp_evpn_skip_vrf_import_of_local_es(bgp_vrf, evp, pi, install))
+               return 0;
+
+       if (is_route_matching_for_vrf(bgp_vrf, pi)) {
+               if (bgp_evpn_route_rmac_self_check(bgp_vrf, evp, pi))
+                       return 0;
+
+               if (install)
+                       ret = install_evpn_route_entry_in_vrf(bgp_vrf, evp, pi);
                else
-                       nh.s_addr = INADDR_ANY;
-               if (install && !bgp_evpn_es_vrf_import_ok(bgp_vrf, esi, nh)) {
-                       if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) {
-                               char esi_buf[ESI_STR_LEN];
+                       ret = uninstall_evpn_route_entry_in_vrf(bgp_vrf, evp,
+                                                               pi);
 
-                               zlog_debug(
-                                       "vrf %s %s of evpn prefix %pFX skipped, nh %pI4 inactive in es %s",
-                                       bgp_vrf->name,
-                                       install ? "import" : "unimport", evp,
-                                       &nh,
-                                       esi_to_str(esi, esi_buf,
-                                                  sizeof(esi_buf)));
-                       }
-                       return true;
-               }
+               if (ret)
+                       flog_err(EC_BGP_EVPN_FAIL,
+                                "Failed to %s EVPN %pFX route in VRF %s",
+                                install ? "install" : "uninstall", evp,
+                                vrf_id_to_name(bgp_vrf->vrf_id));
        }
-       return false;
+
+       return ret;
 }
 
 /*
@@ -2950,46 +2975,10 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install)
 
                        for (pi = bgp_dest_get_bgp_path_info(dest); pi;
                             pi = pi->next) {
-                               /* Consider "valid" remote routes applicable for
-                                * this VRF.
-                                */
-                               if (!(CHECK_FLAG(pi->flags, BGP_PATH_VALID)
-                                     && pi->type == ZEBRA_ROUTE_BGP
-                                     && pi->sub_type == BGP_ROUTE_NORMAL))
-                                       continue;
-
-                               /* don't import hosts that are locally attached
-                                */
-                               if (bgp_evpn_skip_vrf_import_of_local_es(
-                                           bgp_vrf, evp, pi, install))
-                                       continue;
-
-                               if (is_route_matching_for_vrf(bgp_vrf, pi)) {
-                                       if (bgp_evpn_route_rmac_self_check(
-                                                               bgp_vrf, evp, pi))
-                                               continue;
-
-                                       if (install)
-                                               ret = install_evpn_route_entry_in_vrf(
-                                                       bgp_vrf, evp, pi);
-                                       else
-                                               ret = uninstall_evpn_route_entry_in_vrf(
-                                                       bgp_vrf, evp, pi);
-
-                                       if (ret) {
-                                               flog_err(
-                                                       EC_BGP_EVPN_FAIL,
-                                                       "Failed to %s EVPN %pFX route in VRF %s",
-                                                       install ? "install"
-                                                               : "uninstall",
-                                                       evp,
-                                                       vrf_id_to_name(
-                                                               bgp_vrf->vrf_id));
-                                               bgp_dest_unlock_node(rd_dest);
-                                               bgp_dest_unlock_node(dest);
-                                               return ret;
-                                       }
-                               }
+                               ret = bgp_evpn_route_entry_install_if_vrf_match(
+                                       bgp_vrf, pi, install);
+                               if (ret)
+                                       return ret;
                        }
                }
        }
@@ -3293,6 +3282,13 @@ static int bgp_evpn_install_uninstall_table(struct bgp *bgp, afi_t afi,
                if (sub_type != ECOMMUNITY_ROUTE_TARGET)
                        continue;
 
+               /* non-local MAC-IP routes in the global route table are linked
+                * to the destination ES
+                */
+               if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
+                       bgp_evpn_path_es_link(pi, 0,
+                                             bgp_evpn_attr_get_esi(pi->attr));
+
                /*
                 * macip routes (type-2) are imported into VNI and VRF tables.
                 * IMET route is imported into VNI table.
index c7e6c01758c8f0624631307e1874185467413568..9a5fe7aecbbd9e488709923ada56c81d058d927c 100644 (file)
@@ -69,9 +69,6 @@ static uint32_t bgp_evpn_es_get_active_vtep_cnt(struct bgp_evpn_es *es);
 static void bgp_evpn_l3nhg_update_on_vtep_chg(struct bgp_evpn_es *es);
 static struct bgp_evpn_es *bgp_evpn_es_new(struct bgp *bgp, const esi_t *esi);
 static void bgp_evpn_es_free(struct bgp_evpn_es *es, const char *caller);
-static void
-bgp_evpn_es_path_update_on_vtep_chg(struct bgp_evpn_es_vtep *es_vtep,
-                                   bool active);
 
 esi_t zero_esi_buf, *zero_esi = &zero_esi_buf;
 static int bgp_evpn_run_consistency_checks(struct thread *t);
@@ -1291,8 +1288,6 @@ static void bgp_evpn_es_vtep_re_eval_active(struct bgp *bgp,
                 * removed.
                 */
                bgp_evpn_l3nhg_update_on_vtep_chg(es_vtep->es);
-               bgp_evpn_es_path_update_on_vtep_chg(es_vtep, new_active);
-
                /* queue up the es for background consistency checks */
                bgp_evpn_es_cons_checks_pend_add(es_vtep->es);
        }
@@ -1368,33 +1363,15 @@ static void bgp_evpn_es_vtep_del(struct bgp *bgp,
                bgp_evpn_es_vtep_do_del(bgp, es_vtep, esr);
 }
 
-bool bgp_evpn_es_is_vtep_active(esi_t *esi, struct in_addr nh)
-{
-       struct bgp_evpn_es *es;
-       struct bgp_evpn_es_vtep *es_vtep;
-       struct listnode *node = NULL;
-       bool rc = false;
-
-       if (!memcmp(esi, zero_esi, sizeof(*esi)) || !nh.s_addr)
-               return true;
-
-       es = bgp_evpn_es_find(esi);
-       if (!es)
-               return false;
-
-       for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
-               if (es_vtep->vtep_ip.s_addr == nh.s_addr) {
-                       if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE))
-                               rc = true;
-                       break;
-               }
-       }
-       return rc;
-}
-
 /********************** ES MAC-IP paths *************************************
- * MAC-IP routes in the VNI routing table are linked to the destination
- * ES for efficient updates on ES changes (such as VTEP add/del).
+ * 1. Local MAC-IP routes in the VNI routing table are linked to the
+ * destination ES (macip_evi_path_list) for efficient updates on ES oper
+ * state changes.
+ * 2. Non-local MAC-IP routes in the global routing table are linked to
+ * the detination for efficient updates on -
+ * a. VTEP add/del - this results in a L3NHG update.
+ * b. ES-VRF add/del - this may result in the host route being migrated to
+ *    L3NHG or vice versa (flat multipath list).
  ****************************************************************************/
 void bgp_evpn_path_es_info_free(struct bgp_path_es_info *es_info)
 {
@@ -1433,7 +1410,12 @@ void bgp_evpn_path_es_unlink(struct bgp_path_es_info *es_info)
                zlog_debug("vni %u path %pFX unlinked from es %s", es_info->vni,
                           &pi->net->p, es->esi_str);
 
-       list_delete_node(es->macip_evi_path_list, &es_info->es_listnode);
+       if (es_info->vni)
+               list_delete_node(es->macip_evi_path_list,
+                                &es_info->es_listnode);
+       else
+               list_delete_node(es->macip_global_path_list,
+                                &es_info->es_listnode);
        es_info->es = NULL;
 
        /* if there are no other references against the ES it
@@ -1450,7 +1432,8 @@ void bgp_evpn_path_es_link(struct bgp_path_info *pi, vni_t vni, esi_t *esi)
 {
        struct bgp_path_es_info *es_info;
        struct bgp_evpn_es *es;
-       struct bgp *bgp_evpn = bgp_get_evpn();
+       struct bgp *bgp_evpn;
+       struct prefix_evpn *evp;
 
        es_info = pi->extra ? pi->extra->es_info : NULL;
        /* if the esi is zero just unlink the path from the old es */
@@ -1460,9 +1443,18 @@ void bgp_evpn_path_es_link(struct bgp_path_info *pi, vni_t vni, esi_t *esi)
                return;
        }
 
+       bgp_evpn = bgp_get_evpn();
        if (!bgp_evpn)
                return;
 
+       /* Only MAC-IP routes need to be linked (MAC-only routes can be
+        * skipped) as these lists are maintained for managing
+        * host routes in the tenant VRF
+        */
+       evp = (struct prefix_evpn *)&pi->net->p;
+       if (!(is_evpn_prefix_ipaddr_v4(evp) || is_evpn_prefix_ipaddr_v6(evp)))
+               return;
+
        /* setup es_info against the path if it doesn't aleady exist */
        if (!es_info)
                es_info = bgp_evpn_path_es_info_new(pi, vni);
@@ -1486,55 +1478,44 @@ void bgp_evpn_path_es_link(struct bgp_path_info *pi, vni_t vni, esi_t *esi)
        /* link mac-ip path to the new destination ES */
        es_info->es = es;
        listnode_init(&es_info->es_listnode, es_info);
-       listnode_add(es->macip_evi_path_list, &es_info->es_listnode);
+       if (es_info->vni)
+               listnode_add(es->macip_evi_path_list, &es_info->es_listnode);
+       else
+               listnode_add(es->macip_global_path_list, &es_info->es_listnode);
 }
 
-/* XXX - When a remote ES is added to a VRF, routes using that as
- * a destination need to be migrated to a L2NHG and viceversa
+/* When a remote ES is added to a VRF, routes using that as
+ * a destination need to be migrated to a L3NHG or viceversa.
+ * This is done indirectly by re-attempting an install of the
+ * route in the associated VRFs. As a part of the VRF install use
+ * of l3 NHG is evaluated and this results in the
+ * attr.es_flag ATTR_ES_USE_L3_NHG being set or cleared.
  */
 static void
 bgp_evpn_es_path_update_on_es_vrf_chg(struct bgp_evpn_es_vrf *es_vrf,
-                                     bool active)
-{
-}
-
-static void
-bgp_evpn_es_path_update_on_vtep_chg(struct bgp_evpn_es_vtep *es_vtep,
-                                   bool active)
+                                     const char *reason)
 {
        struct listnode *node;
        struct bgp_path_es_info *es_info;
        struct bgp_path_info *pi;
-       struct bgp_path_info *parent_pi;
-       struct bgp_evpn_es *es = es_vtep->es;
+       struct bgp_evpn_es *es = es_vrf->es;
 
        if (!bgp_mh_info->host_routes_use_l3nhg)
                return;
 
        if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
-               zlog_debug("update paths linked to es %s on vtep chg",
-                          es->esi_str);
+               zlog_debug("update paths linked to es %s on es-vrf %s %s",
+                          es->esi_str, es_vrf->bgp_vrf->name, reason);
 
-       for (ALL_LIST_ELEMENTS_RO(es->macip_evi_path_list, node, es_info)) {
+       for (ALL_LIST_ELEMENTS_RO(es->macip_global_path_list, node, es_info)) {
                pi = es_info->pi;
-               if (!CHECK_FLAG(pi->flags, BGP_PATH_VALID))
-                       continue;
-
-               if (pi->sub_type != BGP_ROUTE_IMPORTED)
-                       continue;
-
-               parent_pi = pi->extra ? pi->extra->parent : NULL;
-               if (!parent_pi || !parent_pi->attr)
-                       continue;
-
-               if (es_vtep->vtep_ip.s_addr != parent_pi->attr->nexthop.s_addr)
-                       continue;
 
                if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
                        zlog_debug(
-                               "update path %pFX linked to es %s on vtep chg",
-                               &parent_pi->net->p, es->esi_str);
-               bgp_evpn_import_route_in_vrfs(parent_pi, active ? 1 : 0);
+                               "update path %pFX linked to es %s on vrf chg",
+                               &pi->net->p, es->esi_str);
+               bgp_evpn_route_entry_install_if_vrf_match(es_vrf->bgp_vrf, pi,
+                                                         1);
        }
 }
 
@@ -1593,6 +1574,8 @@ static struct bgp_evpn_es *bgp_evpn_es_new(struct bgp *bgp, const esi_t *esi)
        /* Initialise the route list used for efficient event handling */
        es->macip_evi_path_list = list_new();
        listset_app_node_mem(es->macip_evi_path_list);
+       es->macip_global_path_list = list_new();
+       listset_app_node_mem(es->macip_global_path_list);
 
        QOBJ_REG(es, bgp_evpn_es);
 
@@ -1606,7 +1589,8 @@ static struct bgp_evpn_es *bgp_evpn_es_new(struct bgp *bgp, const esi_t *esi)
 static void bgp_evpn_es_free(struct bgp_evpn_es *es, const char *caller)
 {
        if ((es->flags & (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE))
-           || listcount(es->macip_evi_path_list))
+           || listcount(es->macip_evi_path_list)
+           || listcount(es->macip_global_path_list))
                return;
 
        if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
@@ -1617,6 +1601,7 @@ static void bgp_evpn_es_free(struct bgp_evpn_es *es, const char *caller)
        list_delete(&es->es_vrf_list);
        list_delete(&es->es_vtep_list);
        list_delete(&es->macip_evi_path_list);
+       list_delete(&es->macip_global_path_list);
        bgp_table_unlock(es->route_table);
 
        /* remove the entry from various databases */
@@ -1727,10 +1712,12 @@ static void bgp_evpn_mac_update_on_es_oper_chg(struct bgp_evpn_es *es)
                        continue;
 
                if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
-                       zlog_debug("update path %s linked to es %s on oper chg",
-                                  prefix2str(&pi->net->p, prefix_buf,
-                                             sizeof(prefix_buf)),
-                                  es->esi_str);
+                       zlog_debug(
+                               "update path %d %s linked to es %s on oper chg",
+                               es_info->vni,
+                               prefix2str(&pi->net->p, prefix_buf,
+                                          sizeof(prefix_buf)),
+                               es->esi_str);
 
                bgp_evpn_update_type2_route_entry(bgp, vpn, pi->net, pi,
                                                  __func__);
@@ -2186,6 +2173,8 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty,
                                    listcount(es->es_vrf_list));
                json_object_int_add(json, "macipPathCount",
                                    listcount(es->macip_evi_path_list));
+               json_object_int_add(json, "macipGlobalPathCount",
+                                   listcount(es->macip_global_path_list));
                json_object_int_add(json, "inconsistentVniVtepCount",
                                es->incons_evi_vtep_cnt);
                if (listcount(es->es_vtep_list)) {
@@ -2233,8 +2222,10 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty,
                vty_out(vty, " Remote VNI Count: %d\n",
                                es->remote_es_evi_cnt);
                vty_out(vty, " VRF Count: %d\n", listcount(es->es_vrf_list));
-               vty_out(vty, " MACIP Path Count: %d\n",
+               vty_out(vty, " MACIP EVI Path Count: %d\n",
                        listcount(es->macip_evi_path_list));
+               vty_out(vty, " MACIP Global Path Count: %d\n",
+                       listcount(es->macip_global_path_list));
                vty_out(vty, " Inconsistent VNI VTEP Count: %d\n",
                                es->incons_evi_vtep_cnt);
                if (es->inconsistencies) {
@@ -2465,6 +2456,8 @@ static void bgp_evpn_l3nhg_deactivate(struct bgp_evpn_es_vrf *es_vrf)
                           es_vrf->nhg_id);
        bgp_evpn_l3nhg_zebra_del(es_vrf);
        es_vrf->flags &= ~BGP_EVPNES_VRF_NHG_ACTIVE;
+       /* MAC-IPs can now be installed via the L3NHG */
+       bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf, "l3nhg-deactivate");
 }
 
 static void bgp_evpn_l3nhg_activate(struct bgp_evpn_es_vrf *es_vrf, bool update)
@@ -2483,6 +2476,8 @@ static void bgp_evpn_l3nhg_activate(struct bgp_evpn_es_vrf *es_vrf, bool update)
                                   es_vrf->es->esi_str, es_vrf->bgp_vrf->vrf_id,
                                   es_vrf->nhg_id);
                es_vrf->flags |= BGP_EVPNES_VRF_NHG_ACTIVE;
+               /* MAC-IPs can now be installed via the L3NHG */
+               bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf, "l3nhg_activate");
        }
 
        bgp_evpn_l3nhg_zebra_add(es_vrf);
@@ -2562,7 +2557,7 @@ static struct bgp_evpn_es_vrf *bgp_evpn_es_vrf_create(struct bgp_evpn_es *es,
        /* update paths in the VRF that may already be associated with
         * this destination ES
         */
-       bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf, true);
+       bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf, "es-vrf-create");
 
        return es_vrf;
 }
@@ -2595,7 +2590,7 @@ static void bgp_evpn_es_vrf_delete(struct bgp_evpn_es_vrf *es_vrf)
        /* update paths in the VRF that may already be associated with
         * this destination ES
         */
-       bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf, false);
+       bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf, "es-vrf-delete");
 
        XFREE(MTYPE_BGP_EVPN_ES_VRF, es_vrf);
 }
@@ -2679,38 +2674,37 @@ void bgp_evpn_es_evi_vrf_ref(struct bgpevpn *vpn)
                bgp_evpn_es_vrf_ref(es_evi, vpn->bgp_vrf);
 }
 
-static bool bgp_evpn_es_vrf_use_nhg(struct bgp *bgp_vrf, esi_t *esi,
-                                   struct bgp_evpn_es **es_p,
-                                   struct bgp_evpn_es_vrf **es_vrf_p)
+/* 1. If ES-VRF is not present install the host route with the exploded/flat
+ * multi-path list.
+ * 2. If ES-VRF is present -
+ * - if L3NHG has not been activated for the ES-VRF (this could be because
+ *   all the PEs attached to the VRF are down) do not install the route
+ *   in zebra.
+ * - if L3NHG has been activated install the route via that L3NHG
+ */
+void bgp_evpn_es_vrf_use_nhg(struct bgp *bgp_vrf, esi_t *esi, bool *use_l3nhg,
+                            bool *is_l3nhg_active,
+                            struct bgp_evpn_es_vrf **es_vrf_p)
 {
        struct bgp_evpn_es *es;
        struct bgp_evpn_es_vrf *es_vrf;
 
        if (!bgp_mh_info->host_routes_use_l3nhg)
-               return false;
+               return;
 
        es = bgp_evpn_es_find(esi);
        if (!es)
-               return false;
-       if (es_p)
-               *es_p = es;
+               return;
 
        es_vrf = bgp_evpn_es_vrf_find(es, bgp_vrf);
        if (!es_vrf)
-               return false;
+               return;
+
+       *use_l3nhg = true;
+       if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE)
+               *is_l3nhg_active = true;
        if (es_vrf_p)
                *es_vrf_p = es_vrf;
-
-       return true;
-}
-
-bool bgp_evpn_es_vrf_import_ok(struct bgp *bgp_vrf, esi_t *esi,
-                              struct in_addr nh)
-{
-       if (!bgp_evpn_es_vrf_use_nhg(bgp_vrf, esi, NULL, NULL))
-               return true;
-
-       return bgp_evpn_es_is_vtep_active(esi, nh);
 }
 
 /* returns false if legacy-exploded mp needs to be used for route install */
@@ -2718,12 +2712,13 @@ bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf, struct bgp_path_info *pi,
                              uint32_t *nhg_p)
 {
        esi_t *esi;
-       struct bgp_evpn_es *es = NULL;
        struct bgp_evpn_es_vrf *es_vrf = NULL;
        struct bgp_path_info *parent_pi;
        struct bgp_node *rn;
        struct prefix_evpn *evp;
        struct bgp_path_info *mpinfo;
+       bool use_l3nhg = false;
+       bool is_l3nhg_active = false;
 
        *nhg_p = 0;
 
@@ -2744,14 +2739,17 @@ bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf, struct bgp_path_info *pi,
        if (!memcmp(esi, zero_esi, sizeof(*esi)))
                return false;
 
+       bgp_evpn_es_vrf_use_nhg(bgp_vrf, esi, &use_l3nhg, &is_l3nhg_active,
+                               &es_vrf);
+
        /* L3NHG support is disabled, use legacy-exploded multipath */
-       if (!bgp_evpn_es_vrf_use_nhg(bgp_vrf, esi, &es, &es_vrf))
+       if (!use_l3nhg)
                return false;
 
        /* if the NHG has not been installed we cannot install the route yet,
         * return a 0-NHG to indicate that
         */
-       if (!(es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE))
+       if (!is_l3nhg_active)
                return true;
 
        /* this needs to be set the v6NHG if v6route */
index 62414994b6de24a10ab9db41885a7128c9ab22c1..508766496f9a1a3b7b8e1b8eae8de49efc06f130 100644 (file)
@@ -105,9 +105,18 @@ struct bgp_evpn_es {
 
        /* List of MAC-IP VNI paths using this ES as destination -
         * element is bgp_path_info_extra->es_info
+        * Note: Only local/zebra-added MACIP paths in the VNI
+        * routing table are linked to this list
         */
        struct list *macip_evi_path_list;
 
+       /* List of MAC-IP paths in the global routing table using this
+        * ES as destination - data is bgp_path_info_extra->es_info
+        * Note: Only non-local/imported MACIP paths in the global
+        * routing table are linked to this list
+        */
+       struct list *macip_global_path_list;
+
        /* Number of remote VNIs referencing this ES */
        uint32_t remote_es_evi_cnt;
 
@@ -381,7 +390,6 @@ extern void bgp_evpn_path_es_info_free(struct bgp_path_es_info *es_info);
 extern void bgp_evpn_path_es_unlink(struct bgp_path_es_info *es_info);
 extern void bgp_evpn_path_es_link(struct bgp_path_info *pi, vni_t vni,
                                  esi_t *esi);
-extern bool bgp_evpn_es_is_vtep_active(esi_t *esi, struct in_addr nh);
 extern bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf,
                                     struct bgp_path_info *pi, uint32_t *nhg_p);
 extern void bgp_evpn_es_vrf_show(struct vty *vty, bool uj,
@@ -389,7 +397,8 @@ extern void bgp_evpn_es_vrf_show(struct vty *vty, bool uj,
 extern void bgp_evpn_es_vrf_show_esi(struct vty *vty, esi_t *esi, bool uj);
 extern void bgp_evpn_switch_ead_evi_rx(void);
 extern bool bgp_evpn_es_add_l3_ecomm_ok(esi_t *esi);
-extern bool bgp_evpn_es_vrf_import_ok(struct bgp *bgp_vrf, esi_t *esi,
-                                     struct in_addr nh);
+extern void bgp_evpn_es_vrf_use_nhg(struct bgp *bgp_vrf, esi_t *esi,
+                                   bool *use_l3nhg, bool *is_l3nhg_active,
+                                   struct bgp_evpn_es_vrf **es_vrf_p);
 
 #endif /* _FRR_BGP_EVPN_MH_H */
index 9a7a47751698524d5696b08bfd43b03f9b02e8bf..dfaac76f02877e033f942217ac1646e12276f4d5 100644 (file)
@@ -636,4 +636,7 @@ extern void bgp_evpn_update_type2_route_entry(struct bgp *bgp,
                                              struct bgp_node *rn,
                                              struct bgp_path_info *local_pi,
                                              const char *caller);
+extern int bgp_evpn_route_entry_install_if_vrf_match(struct bgp *bgp_vrf,
+                                                    struct bgp_path_info *pi,
+                                                    int install);
 #endif /* _BGP_EVPN_PRIVATE_H */
index 8f030067052e19900953706f3e3607a2a637aea1..43516dadad92f392c9f6e2341e9e2652252d4139 100644 (file)
@@ -687,8 +687,9 @@ static void show_esi_routes(struct bgp *bgp,
 }
 
 /* Display all MAC-IP VNI routes linked to an ES */
-static void bgp_evpn_show_routes_mac_ip_evi_es(struct vty *vty, esi_t *esi,
-                                              json_object *json, int detail)
+static void bgp_evpn_show_routes_mac_ip_es(struct vty *vty, esi_t *esi,
+                                          json_object *json, int detail,
+                                          bool global_table)
 {
        struct bgp_node *rn;
        struct bgp_path_info *pi;
@@ -709,12 +710,17 @@ static void bgp_evpn_show_routes_mac_ip_evi_es(struct vty *vty, esi_t *esi,
                json_paths = json_object_new_array();
 
        RB_FOREACH (es, bgp_es_rb_head, &bgp_mh_info->es_rb_tree) {
+               struct list *es_list;
 
                if (esi && memcmp(esi, &es->esi, sizeof(*esi)))
                        continue;
 
-               for (ALL_LIST_ELEMENTS_RO(es->macip_evi_path_list, node,
-                                         es_info)) {
+               if (global_table)
+                       es_list = es->macip_global_path_list;
+               else
+                       es_list = es->macip_evi_path_list;
+
+               for (ALL_LIST_ELEMENTS_RO(es_list, node, es_info)) {
                        json_object *json_path = NULL;
 
                        pi = es_info->pi;
@@ -759,6 +765,18 @@ static void bgp_evpn_show_routes_mac_ip_evi_es(struct vty *vty, esi_t *esi,
        }
 }
 
+static void bgp_evpn_show_routes_mac_ip_evi_es(struct vty *vty, esi_t *esi,
+                                              json_object *json, int detail)
+{
+       return bgp_evpn_show_routes_mac_ip_es(vty, esi, json, detail, false);
+}
+
+static void bgp_evpn_show_routes_mac_ip_global_es(struct vty *vty, esi_t *esi,
+                                                 json_object *json, int detail)
+{
+       return bgp_evpn_show_routes_mac_ip_es(vty, esi, json, detail, true);
+}
+
 static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
                            struct vty *vty, struct in_addr vtep_ip,
                            json_object *json, int detail)
@@ -4695,6 +4713,43 @@ DEFPY_HIDDEN(
        return CMD_SUCCESS;
 }
 
+DEFPY_HIDDEN(
+       show_bgp_l2vpn_evpn_route_mac_ip_global_es,
+       show_bgp_l2vpn_evpn_route_mac_ip_global_es_cmd,
+       "show bgp l2vpn evpn route mac-ip-global-es [NAME$esi_str|detail$detail] [json$uj]",
+       SHOW_STR BGP_STR L2VPN_HELP_STR EVPN_HELP_STR
+       "EVPN route information\n"
+       "MAC IP routes in the global table linked to the ES\n"
+       "ES ID\n"
+       "Detailed information\n" JSON_STR)
+{
+       esi_t esi;
+       esi_t *esi_p;
+       json_object *json = NULL;
+
+       if (esi_str) {
+               if (!str_to_esi(esi_str, &esi)) {
+                       vty_out(vty, "%%Malformed ESI\n");
+                       return CMD_WARNING;
+               }
+               esi_p = &esi;
+       } else {
+               esi_p = NULL;
+       }
+
+       if (uj)
+               json = json_object_new_object();
+       bgp_evpn_show_routes_mac_ip_global_es(vty, esi_p, json, !!detail);
+       if (uj) {
+               vty_out(vty, "%s\n",
+                       json_object_to_json_string_ext(
+                               json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+
+       return CMD_SUCCESS;
+}
+
 /*
  * Display EVPN import route-target hash table
  */
@@ -5971,6 +6026,8 @@ void bgp_ethernetvpn_init(void)
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_all_cmd);
        install_element(VIEW_NODE,
                        &show_bgp_l2vpn_evpn_route_mac_ip_evi_es_cmd);
+       install_element(VIEW_NODE,
+                       &show_bgp_l2vpn_evpn_route_mac_ip_global_es_cmd);
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_import_rt_cmd);
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vrf_import_rt_cmd);
 
index 124a477248ea233c068b9e6c10a4cf556de22194..6f8e2536dff920baa23d1f6d6d71d5c7bb6ab19a 100644 (file)
@@ -9626,12 +9626,20 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
                                        buf1, sizeof(buf1));
                                if (is_pi_family_evpn(parent_ri)) {
                                        vty_out(vty,
-                                               "  Imported from %s:%pFX, VNI %s\n",
+                                               "  Imported from %s:%pFX, VNI %s",
                                                buf1,
                                                (struct prefix_evpn *)
                                                        bgp_dest_get_prefix(
                                                                dest),
                                                tag_buf);
+                                       if (attr->es_flags & ATTR_ES_L3_NHG)
+                                               vty_out(vty, ", L3NHG %s",
+                                                       (attr->es_flags
+                                                        & ATTR_ES_L3_NHG_ACTIVE)
+                                                               ? "active"
+                                                               : "inactive");
+                                       vty_out(vty, "\n");
+
                                } else
                                        vty_out(vty,
                                                "  Imported from %s:%pFX\n",