]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bgpd: allow routes to be imported if the ES/ES-VRF is not present
authorAnuradha Karuppiah <anuradhak@cumulusnetworks.com>
Sat, 15 Aug 2020 13:41:31 +0000 (06:41 -0700)
committerAnuradha Karuppiah <anuradhak@nvidia.com>
Fri, 26 Mar 2021 00:09:53 +0000 (17:09 -0700)
In a sym-IRB setup the remote ES may not be installed if the tenant
VRF is not present locally. To allow that case while retaining the
fast-failover benefits for the case where the tenant VRF is locally
present we use the following approach -
1. If ES is present in the tenant VRF we use the L3NHG for installing
the MAC-IP based tenant route. This allows for efficient failover via
L3NHG updates.
2. If the ES is not present locally in the corresponding tenant VRF we
fall back to a non-NHG multi-path based routing approach. In this
case individual routes are updated when the ES links flap.

PS: #1 can be turned off entirely by disabling use-l3-nhg in BGP.

Ticket: CM-30935

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

index bcf980d957c9e99894afae75107cd74fe4a70db5..a4d4dbc20395a28a4b84d17682533bc224babbdd 100644 (file)
@@ -2852,7 +2852,8 @@ static int bgp_evpn_route_rmac_self_check(struct bgp *bgp_vrf,
 
 /* don't import hosts that are locally attached */
 static inline bool
-bgp_evpn_skip_vrf_import_of_local_es(const struct prefix_evpn *evp,
+bgp_evpn_skip_vrf_import_of_local_es(struct bgp *bgp_vrf,
+                                    const struct prefix_evpn *evp,
                                     struct bgp_path_info *pi, int install)
 {
        esi_t *esi;
@@ -2875,19 +2876,20 @@ bgp_evpn_skip_vrf_import_of_local_es(const struct prefix_evpn *evp,
                        return true;
                }
 
-               /* Don't import routes with ES as destination if the nexthop
-                * has not been advertised via the EAD-ES
+               /* 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;
                else
                        nh.s_addr = INADDR_ANY;
-               if (install && !bgp_evpn_es_is_vtep_active(esi, nh)) {
+               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];
 
                                zlog_debug(
-                                       "vrf %s of evpn prefix %pFX skipped, nh %pI4 inactive in es %s",
+                                       "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,
@@ -2959,7 +2961,7 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install)
                                /* don't import hosts that are locally attached
                                 */
                                if (bgp_evpn_skip_vrf_import_of_local_es(
-                                           evp, pi, install))
+                                           bgp_vrf, evp, pi, install))
                                        continue;
 
                                if (is_route_matching_for_vrf(bgp_vrf, pi)) {
@@ -3168,13 +3170,14 @@ static int install_uninstall_route_in_vrfs(struct bgp *bgp_def, afi_t afi,
                 || is_evpn_prefix_ipaddr_v6(evp)))
                return 0;
 
-       /* don't import hosts that are locally attached */
-       if (bgp_evpn_skip_vrf_import_of_local_es(evp, pi, install))
-               return 0;
-
        for (ALL_LIST_ELEMENTS(vrfs, node, nnode, bgp_vrf)) {
                int ret;
 
+               /* don't import hosts that are locally attached */
+               if (bgp_evpn_skip_vrf_import_of_local_es(bgp_vrf, evp, pi,
+                                                        install))
+                       continue;
+
                if (install)
                        ret = install_evpn_route_entry_in_vrf(bgp_vrf, evp, pi);
                else
index 552225197fbb9cda400bad38876da19d0cef2cc8..41640efb34e6bccf3f32b651a7ce06fcb9df5cfb 100644 (file)
@@ -1489,6 +1489,15 @@ void bgp_evpn_path_es_link(struct bgp_path_info *pi, vni_t vni, esi_t *esi)
        listnode_add(es->macip_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
+ */
+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)
@@ -1499,6 +1508,9 @@ bgp_evpn_es_path_update_on_vtep_chg(struct bgp_evpn_es_vtep *es_vtep,
        struct bgp_path_info *parent_pi;
        struct bgp_evpn_es *es = es_vtep->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);
@@ -1714,7 +1726,7 @@ 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 vtep chg",
+                       zlog_debug("update path %s linked to es %s on oper chg",
                                   prefix2str(&pi->net->p, prefix_buf,
                                              sizeof(prefix_buf)),
                                   es->esi_str);
@@ -2546,6 +2558,11 @@ static struct bgp_evpn_es_vrf *bgp_evpn_es_vrf_create(struct bgp_evpn_es *es,
                           bgp_vrf->vrf_id, es_vrf->nhg_id, es_vrf->v6_nhg_id);
        bgp_evpn_l3nhg_activate(es_vrf, false /* update */);
 
+       /* 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);
+
        return es_vrf;
 }
 
@@ -2559,6 +2576,11 @@ static void bgp_evpn_es_vrf_delete(struct bgp_evpn_es_vrf *es_vrf)
                zlog_debug("es %s vrf %u nhg %u delete", es->esi_str,
                           bgp_vrf->vrf_id, es_vrf->nhg_id);
 
+       /* 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);
+
        /* Remove the NHG resources */
        bgp_evpn_l3nhg_deactivate(es_vrf);
        if (es_vrf->nhg_id)
@@ -2656,13 +2678,47 @@ 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)
+{
+       struct bgp_evpn_es *es;
+       struct bgp_evpn_es_vrf *es_vrf;
+
+       if (!bgp_mh_info->host_routes_use_l3nhg)
+               return false;
+
+       es = bgp_evpn_es_find(esi);
+       if (!es)
+               return false;
+       if (es_p)
+               *es_p = es;
+
+       es_vrf = bgp_evpn_es_vrf_find(es, bgp_vrf);
+       if (!es_vrf)
+               return false;
+       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 */
 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;
-       struct bgp_evpn_es_vrf *es_vrf;
+       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;
@@ -2670,10 +2726,6 @@ bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf, struct bgp_path_info *pi,
 
        *nhg_p = 0;
 
-       /* L3NHG support is disabled, use legacy-exploded multipath */
-       if (!bgp_mh_info->host_routes_use_l3nhg)
-               return false;
-
        parent_pi = get_route_parent_evpn(pi);
        if (!parent_pi)
                return false;
@@ -2691,15 +2743,14 @@ 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;
 
-       /* if the ES-VRF is not setup or if the NHG has not been installed
-        * we cannot install the route yet, return a 0-NHG to indicate
-        * that
+       /* L3NHG support is disabled, use legacy-exploded multipath */
+       if (!bgp_evpn_es_vrf_use_nhg(bgp_vrf, esi, &es, &es_vrf))
+               return false;
+
+       /* if the NHG has not been installed we cannot install the route yet,
+        * return a 0-NHG to indicate that
         */
-       es = bgp_evpn_es_find(esi);
-       if (!es)
-               return true;
-       es_vrf = bgp_evpn_es_vrf_find(es, bgp_vrf);
-       if (!es_vrf || !(es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE))
+       if (!(es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE))
                return true;
 
        /* this needs to be set the v6NHG if v6route */
@@ -2710,7 +2761,7 @@ bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf, struct bgp_path_info *pi,
 
        for (mpinfo = bgp_path_info_mpath_next(pi); mpinfo;
             mpinfo = bgp_path_info_mpath_next(mpinfo)) {
-               /* if any of the paths of have a different ESI we can't use
+               /* if any of the paths have a different ESI we can't use
                 * the NHG associated with the ES. fallback to legacy-exploded
                 * multipath
                 */
index 5008945156107192fb210303b1648784cf656e0f..f22a38e7b47157dd3b1309e960edfb6115e6e540 100644 (file)
@@ -389,5 +389,7 @@ 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);
 
 #endif /* _FRR_BGP_EVPN_MH_H */