]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bgpd: use L3NHG while installing EVPN host routes in zebra
authorAnuradha Karuppiah <anuradhak@cumulusnetworks.com>
Sat, 9 May 2020 02:44:35 +0000 (19:44 -0700)
committerAnuradha Karuppiah <anuradhak@nvidia.com>
Tue, 24 Nov 2020 19:06:08 +0000 (11:06 -0800)
Host routes imported into the VRF can have a destination ES (per-VRF)
which is set up as a L3NHG for efficient failover.

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

index ba43191ebf356fdb55040f8a31e606c3aa27c178..29d3d2c62f152fcd6d2972b7f0f874ceeaac8d41 100644 (file)
@@ -77,17 +77,16 @@ static inline int advertise_type5_routes(struct bgp *bgp_vrf,
 }
 
 /* Flag if the route's parent is a EVPN route. */
-static inline int is_route_parent_evpn(struct bgp_path_info *ri)
+static inline struct bgp_path_info *
+get_route_parent_evpn(struct bgp_path_info *ri)
 {
        struct bgp_path_info *parent_ri;
-       struct bgp_table *table;
-       struct bgp_dest *dest;
 
        /* If not imported (or doesn't have a parent), bail. */
        if (ri->sub_type != BGP_ROUTE_IMPORTED ||
            !ri->extra ||
            !ri->extra->parent)
-               return 0;
+               return NULL;
 
        /* Determine parent recursively */
        for (parent_ri = ri->extra->parent;
@@ -95,6 +94,20 @@ static inline int is_route_parent_evpn(struct bgp_path_info *ri)
             parent_ri = parent_ri->extra->parent)
                ;
 
+       return parent_ri;
+}
+
+/* Flag if the route's parent is a EVPN route. */
+static inline int is_route_parent_evpn(struct bgp_path_info *ri)
+{
+       struct bgp_path_info *parent_ri;
+       struct bgp_table *table;
+       struct bgp_dest *dest;
+
+       parent_ri = get_route_parent_evpn(ri);
+       if (!parent_ri)
+               return 0;
+
        /* See if of family L2VPN/EVPN */
        dest = parent_ri->net;
        if (!dest)
index 029c2e838e20d31bd60942cfba53fbe966ee5ae3..6a8799d4cd2b14ac972b0225c183f1ab419c6f0a 100644 (file)
@@ -49,6 +49,7 @@
 #include "bgpd/bgp_addpath.h"
 #include "bgpd/bgp_label.h"
 #include "bgpd/bgp_nht.h"
+#include "bgpd/bgp_mpath.h"
 
 static void bgp_evpn_local_es_down(struct bgp *bgp,
                struct bgp_evpn_es *es);
@@ -2396,6 +2397,72 @@ void bgp_evpn_es_evi_vrf_ref(struct bgpevpn *vpn)
                bgp_evpn_es_vrf_ref(es_evi, vpn->bgp_vrf);
 }
 
+/* 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_path_info *parent_pi;
+       struct bgp_node *rn;
+       struct prefix_evpn *evp;
+       struct bgp_path_info *mpinfo;
+
+       *nhg_p = 0;
+
+       parent_pi = get_route_parent_evpn(pi);
+       if (!parent_pi)
+               return false;
+
+       rn = parent_pi->net;
+       if (!rn)
+               return false;
+
+       evp = (struct prefix_evpn *)&rn->p;
+       if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
+               return false;
+
+       /* L3NHG support is disabled, use legacy-exploded multipath */
+       if (!bgp_mh_info->host_routes_use_l3nhg)
+               return false;
+
+       /* non-es path, use legacy-exploded multipath */
+       esi = bgp_evpn_attr_get_esi(parent_pi->attr);
+       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
+        */
+       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))
+               return true;
+
+       /* this needs to be set the v6NHG if v6route */
+       if (evp->family == AF_INET6)
+               *nhg_p = es_vrf->v6_nhg_id;
+       else
+               *nhg_p = es_vrf->nhg_id;
+
+       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
+                * the NHG associated with the ES. fallback to legacy-exploded
+                * multipath
+                */
+               if (memcmp(esi, bgp_evpn_attr_get_esi(mpinfo->attr),
+                          sizeof(*esi)))
+                       return false;
+       }
+
+       return true;
+}
+
 /*****************************************************************************/
 /* Ethernet Segment to EVI association -
  * 1. The ES-EVI entry is maintained as a RB tree per L2-VNI
index be4456828e6122b3736d0f4c71ea09025bdf5dba..f7aaf157c699aad9dd95ccc90dc0c2f7f6a50923 100644 (file)
@@ -172,6 +172,7 @@ struct bgp_evpn_es_vrf {
        struct listnode es_listnode;
 
        uint32_t nhg_id;
+       uint32_t v6_nhg_id;
 
        /* Number of ES-EVI entries associated with this ES-VRF */
        uint32_t ref_cnt;
@@ -256,6 +257,7 @@ struct bgp_evpn_mh_info {
        bool ead_evi_adv_for_down_links;
        /* Enable ES consistency checking */
        bool consistency_checking;
+       bool host_routes_use_l3nhg;
 };
 
 /****************************************************************************/
@@ -354,5 +356,7 @@ 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);
 
 #endif /* _FRR_BGP_EVPN_MH_H */
index 5d43645c6e546ed13c1fffd54de62a5969be3b1a..eb0883f775d56b2b9d08c2fae0a41cf073815f62 100644 (file)
@@ -1179,6 +1179,8 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
        int nh_updated;
        bool do_wt_ecmp;
        uint64_t cum_bw = 0;
+       uint32_t nhg_id = 0;
+       bool is_add;
 
        /* Don't try to install if we're not connected to Zebra or Zebra doesn't
         * know of this instance.
@@ -1257,7 +1259,13 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
        if (do_wt_ecmp)
                cum_bw = bgp_path_info_mpath_cumbw(info);
 
-       for (mpinfo = info; mpinfo; mpinfo = bgp_path_info_mpath_next(mpinfo)) {
+       /* EVPN MAC-IP routes are installed with a L3 NHG id */
+       if (bgp_evpn_path_es_use_nhg(bgp, info, &nhg_id))
+               mpinfo = NULL;
+       else
+               mpinfo = info;
+
+       for (; mpinfo; mpinfo = bgp_path_info_mpath_next(mpinfo)) {
                uint32_t nh_weight;
 
                if (valid_nh_count >= multipath_num)
@@ -1395,6 +1403,8 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
                valid_nh_count++;
        }
 
+       is_add = (valid_nh_count || nhg_id) ? true : false;
+
        /*
         * When we create an aggregate route we must also
         * install a Null0 route in the RIB, so overwrite
@@ -1428,9 +1438,10 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
 
                zlog_debug(
                        "Tx route %s VRF %u %pFX metric %u tag %" ROUTE_TAG_PRI
-                       " count %d",
+                       " count %d nhg %d",
                        valid_nh_count ? "add" : "delete", bgp->vrf_id,
-                       &api.prefix, api.metric, api.tag, api.nexthop_num);
+                       &api.prefix, api.metric, api.tag, api.nexthop_num,
+                       nhg_id);
                for (i = 0; i < api.nexthop_num; i++) {
                        api_nh = &api.nexthops[i];
 
@@ -1487,8 +1498,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
                        __func__, buf_prefix,
                        (recursion_flag ? "" : "NOT "));
        }
-       zclient_route_send(valid_nh_count ? ZEBRA_ROUTE_ADD
-                                         : ZEBRA_ROUTE_DELETE,
+       zclient_route_send(is_add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE,
                           zclient, &api);
 }
 
@@ -1820,7 +1830,6 @@ int bgp_redistribute_unreg(struct bgp *bgp, afi_t afi, int type,
                vrf_bitmap_unset(zclient->redist[afi][type], bgp->vrf_id);
        }
 
-
        if (bgp_install_info_to_zebra(bgp)) {
                /* Send distribute delete message to zebra. */
                if (BGP_DEBUG(zebra, ZEBRA))