]> git.puffer.fish Git - mirror/frr.git/commitdiff
bgpd: Handle ES VTEP add/del to a host route
authorAnuradha Karuppiah <anuradhak@cumulusnetworks.com>
Sat, 9 May 2020 02:36:47 +0000 (19:36 -0700)
committerAnuradha Karuppiah <anuradhak@nvidia.com>
Tue, 24 Nov 2020 19:06:08 +0000 (11:06 -0800)
1. MAC-IP routes in the VPN routing table are linked to the
destination ES for efficient handling for remote ES link flaps.
2. Only MAC-IP paths whose nexthops are active (added via EAD-ES)
are imported into the VRF routing table.

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

index 83c5dc534e958b92f6ea8af069834c00e5346c3e..2f1217945ea469a3d937065d53ee817903ec3c16 100644 (file)
@@ -1485,10 +1485,10 @@ static void update_evpn_route_entry_sync_info(struct bgp *bgp,
  * or the global route table.
  */
 static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
-                                  afi_t afi, safi_t safi, struct bgp_dest *dest,
-                                  struct attr *attr, int add,
-                                  struct bgp_path_info **pi, uint8_t flags,
-                                  uint32_t seq, bool setup_sync,
+                                  afi_t afi, safi_t safi,
+                                  struct bgp_dest *dest, struct attr *attr,
+                                  int add, struct bgp_path_info **pi,
+                                  uint8_t flags, uint32_t seq, bool vpn_rt,
                                   bool *old_is_sync)
 {
        struct bgp_path_info *tmp_pi;
@@ -1520,7 +1520,7 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
        /* if a local path is being added with a non-zero esi look
         * for SYNC paths from ES peers and bubble up the sync-info
         */
-       update_evpn_route_entry_sync_info(bgp, dest, attr, seq, setup_sync);
+       update_evpn_route_entry_sync_info(bgp, dest, attr, seq, vpn_rt);
 
        /* For non-GW MACs, update MAC mobility seq number, if needed. */
        if (seq && !CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW))
@@ -1612,6 +1612,14 @@ 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
+        */
+       if (route_change && vpn_rt
+           && (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE))
+               bgp_evpn_path_es_link(tmp_pi, vpn->vni,
+                                     bgp_evpn_attr_get_esi(tmp_pi->attr));
+
        /* Return back the route entry. */
        *pi = tmp_pi;
        return route_change;
@@ -2513,7 +2521,7 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
 
        if (!pi) {
                /* Create an info */
-               (void)bgp_create_evpn_bgp_path_info(parent_pi, dest,
+               pi = bgp_create_evpn_bgp_path_info(parent_pi, dest,
                                                    parent_pi->attr);
        } else {
                if (attrhash_cmp(pi->attr, parent_pi->attr)
@@ -2539,6 +2547,11 @@ 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,20 +2870,46 @@ static inline bool
 bgp_evpn_skip_vrf_import_of_local_es(const struct prefix_evpn *evp,
                                     struct bgp_path_info *pi, int install)
 {
-       if ((evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
-           && bgp_evpn_attr_is_local_es(pi->attr)) {
-               if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) {
-                       char esi_buf[ESI_STR_LEN];
-                       char prefix_buf[PREFIX_STRLEN];
+       esi_t *esi;
+       struct in_addr nh;
 
-                       zlog_debug(
-                               "vrf %s of evpn prefix %s skipped, local es %s",
-                               install ? "import" : "unimport",
-                               prefix2str(evp, prefix_buf, sizeof(prefix_buf)),
-                               esi_to_str(bgp_evpn_attr_get_esi(pi->attr),
-                                          esi_buf, sizeof(esi_buf)));
+       if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
+               esi = bgp_evpn_attr_get_esi(pi->attr);
+
+               /* Don't import routes that point to a local destination */
+               if (bgp_evpn_attr_is_local_es(pi->attr)) {
+                       if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) {
+                               char esi_buf[ESI_STR_LEN];
+
+                               zlog_debug(
+                                       "vrf %s of evpn prefix %pFX skipped, local es %s",
+                                       install ? "import" : "unimport", evp,
+                                       esi_to_str(esi, esi_buf,
+                                                  sizeof(esi_buf)));
+                       }
+                       return true;
+               }
+
+               /* Don't import routes with ES as destination if the nexthop
+                * has not been advertised via the EAD-ES
+                */
+               if (pi->attr)
+                       nh = pi->attr->nexthop;
+               else
+                       nh.s_addr = 0;
+               if (!bgp_evpn_es_is_vtep_active(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",
+                                       install ? "import" : "unimport", evp,
+                                       &nh,
+                                       esi_to_str(esi, esi_buf,
+                                                  sizeof(esi_buf)));
+                       }
+                       return true;
                }
-               return true;
        }
        return false;
 }
@@ -3210,9 +3249,11 @@ static int install_uninstall_route_in_vnis(struct bgp *bgp, afi_t afi,
 /*
  * Install or uninstall route for appropriate VNIs/ESIs.
  */
-static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
-                                       const struct prefix *p,
-                                       struct bgp_path_info *pi, int import)
+static int bgp_evpn_install_uninstall_table(struct bgp *bgp, afi_t afi,
+                                           safi_t safi, const struct prefix *p,
+                                           struct bgp_path_info *pi,
+                                           int import, bool in_vni_rt,
+                                           bool in_vrf_rt)
 {
        struct prefix_evpn *evp = (struct prefix_evpn *)p;
        struct attr *attr = pi->attr;
@@ -3274,13 +3315,13 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
                    evp->prefix.route_type == BGP_EVPN_AD_ROUTE ||
                    evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE) {
 
-                       irt = lookup_import_rt(bgp, eval);
+                       irt = in_vni_rt ? lookup_import_rt(bgp, eval) : NULL;
                        if (irt)
                                install_uninstall_route_in_vnis(
                                        bgp, afi, safi, evp, pi, irt->vnis,
                                        import);
 
-                       vrf_irt = lookup_vrf_import_rt(eval);
+                       vrf_irt = in_vrf_rt ? lookup_vrf_import_rt(eval) : NULL;
                        if (vrf_irt)
                                install_uninstall_route_in_vrfs(
                                        bgp, afi, safi, evp, pi, vrf_irt->vrfs,
@@ -3299,8 +3340,11 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
                            || type == ECOMMUNITY_ENCODE_IP) {
                                memcpy(&eval_tmp, eval, ecom->unit_size);
                                mask_ecom_global_admin(&eval_tmp, eval);
-                               irt = lookup_import_rt(bgp, &eval_tmp);
-                               vrf_irt = lookup_vrf_import_rt(&eval_tmp);
+                               if (in_vni_rt)
+                                       irt = lookup_import_rt(bgp, &eval_tmp);
+                               if (in_vrf_rt)
+                                       vrf_irt =
+                                               lookup_vrf_import_rt(&eval_tmp);
                        }
 
                        if (irt)
@@ -3329,6 +3373,31 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
        return 0;
 }
 
+/*
+ * Install or uninstall route for appropriate VNIs/ESIs.
+ */
+static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
+                                       const struct prefix *p,
+                                       struct bgp_path_info *pi, int import)
+{
+       return bgp_evpn_install_uninstall_table(bgp, afi, safi, p, pi, import,
+                                               true, true);
+}
+
+/* Import the pi into vrf routing tables */
+void bgp_evpn_import_route_in_vrfs(struct bgp_path_info *pi, int import)
+{
+       struct bgp *bgp_evpn;
+
+       bgp_evpn = bgp_get_evpn();
+       if (!bgp_evpn)
+               return;
+
+       bgp_evpn_install_uninstall_table(bgp_evpn, AFI_L2VPN, SAFI_EVPN,
+                                        &pi->net->p, pi, import, false /*vpn*/,
+                                        true /*vrf*/);
+}
+
 /*
  * delete and withdraw all ipv4 and ipv6 routes in the vrf table as type-5
  * routes
index 39523ea206d669cf27a95752877e1dca84201db3..029c2e838e20d31bd60942cfba53fbe966ee5ae3 100644 (file)
@@ -66,6 +66,10 @@ static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es *es);
 static void bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi *es_evi);
 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_all_update(struct bgp_evpn_es_vtep *es_vtep,
+                                       bool active);
 
 esi_t zero_esi_buf, *zero_esi = &zero_esi_buf;
 
@@ -1231,8 +1235,19 @@ static void bgp_evpn_es_vtep_re_eval_active(struct bgp *bgp,
                /* send remote ES to zebra */
                bgp_zebra_send_remote_es_vtep(bgp, es_vtep, new_active);
 
-               /* update L3NHG associated with the ES */
-               bgp_evpn_l3nhg_update_on_vtep_chg(es_vtep->es);
+               /* If VTEP becomes active update the NHG first and then
+                * the exploded routes. If VTEP becomes inactive update
+                * routes first. This ordering is done to avoid deleting
+                * the NHG while there are dependent routes against
+                * it.
+                */
+               if (new_active) {
+                       bgp_evpn_l3nhg_update_on_vtep_chg(es_vtep->es);
+                       bgp_evpn_es_path_all_update(es_vtep, true /*active*/);
+               } else {
+                       bgp_evpn_es_path_all_update(es_vtep, false /*active*/);
+                       bgp_evpn_l3nhg_update_on_vtep_chg(es_vtep->es);
+               }
 
                /* queue up the es for background consistency checks */
                bgp_evpn_es_cons_checks_pend_add(es_vtep->es);
@@ -1309,6 +1324,167 @@ 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).
+ ****************************************************************************/
+void bgp_evpn_path_es_info_free(struct bgp_path_es_info *es_info)
+{
+       bgp_evpn_path_es_unlink(es_info);
+       XFREE(MTYPE_BGP_EVPN_PATH_ES_INFO, es_info);
+}
+
+static struct bgp_path_es_info *
+bgp_evpn_path_es_info_new(struct bgp_path_info *pi, vni_t vni)
+{
+       struct bgp_path_info_extra *e;
+
+       e = bgp_path_info_extra_get(pi);
+
+       /* If es_info doesn't exist allocate it */
+       if (!e->es_info) {
+               e->es_info = XCALLOC(MTYPE_BGP_EVPN_PATH_ES_INFO,
+                                    sizeof(struct bgp_path_es_info));
+               e->es_info->pi = pi;
+               e->es_info->vni = vni;
+       }
+
+       return e->es_info;
+}
+
+void bgp_evpn_path_es_unlink(struct bgp_path_es_info *es_info)
+{
+       struct bgp_evpn_es *es = es_info->es;
+       struct bgp_path_info *pi;
+       char prefix_buf[PREFIX_STRLEN];
+
+       if (!es)
+               return;
+
+       pi = es_info->pi;
+       if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
+               zlog_debug(
+                       "path %s unlinked from es %s",
+                       prefix2str(&pi->net->p, prefix_buf, sizeof(prefix_buf)),
+                       es->esi_str);
+
+       list_delete_node(es->macip_path_list, &es_info->es_listnode);
+       es_info->es = NULL;
+
+       /* if there are no other references against the ES it
+        * needs to be freed
+        */
+       bgp_evpn_es_free(es, __func__);
+
+       /* Note we don't free the path es_info on unlink; it will be freed up
+        * along with the path.
+        */
+}
+
+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();
+       char prefix_buf[PREFIX_STRLEN];
+
+       es_info = pi->extra ? pi->extra->es_info : NULL;
+       /* if the esi is zero just unlink the path from the old es */
+       if (!esi || !memcmp(esi, zero_esi, sizeof(*esi))) {
+               if (es_info)
+                       bgp_evpn_path_es_unlink(es_info);
+               return;
+       }
+
+       if (!bgp_evpn)
+               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);
+
+       /* find-create ES */
+       es = bgp_evpn_es_find(esi);
+       if (!es)
+               bgp_evpn_es_new(bgp_evpn, esi);
+
+       /* dup check */
+       if (es_info->es == es)
+               return;
+
+       /* unlink old ES if any */
+       bgp_evpn_path_es_unlink(es_info);
+
+       if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
+               zlog_debug(
+                       "path %s linked to es %s",
+                       prefix2str(&pi->net->p, prefix_buf, sizeof(prefix_buf)),
+                       es->esi_str);
+
+       /* link mac-ip path to the new destination ES */
+       es_info->es = es;
+       listnode_init(&es_info->es_listnode, es_info);
+       listnode_add_sort(es->macip_path_list, &es_info->es_listnode);
+}
+
+static void bgp_evpn_es_path_all_update(struct bgp_evpn_es_vtep *es_vtep,
+                                       bool active)
+{
+       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;
+       char prefix_buf[PREFIX_STRLEN];
+
+       if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
+               zlog_debug("update all paths linked to es %s", es->esi_str);
+
+       for (ALL_LIST_ELEMENTS_RO(es->macip_path_list, node, es_info)) {
+               pi = es_info->pi;
+               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 %s linked to es %s",
+                                  prefix2str(&parent_pi->net->p, prefix_buf,
+                                             sizeof(prefix_buf)),
+                                  es->esi_str);
+               bgp_evpn_import_route_in_vrfs(parent_pi, active ? 1 : 0);
+       }
+}
+
 /* compare ES-IDs for the global ES RB tree */
 static int bgp_es_rb_cmp(const struct bgp_evpn_es *es1,
                const struct bgp_evpn_es *es2)
@@ -1361,6 +1537,10 @@ static struct bgp_evpn_es *bgp_evpn_es_new(struct bgp *bgp, const esi_t *esi)
        es->es_vrf_list = list_new();
        listset_app_node_mem(es->es_vrf_list);
 
+       /* Initialise the route list used for efficient event handling */
+       es->macip_path_list = list_new();
+       listset_app_node_mem(es->macip_path_list);
+
        QOBJ_REG(es, bgp_evpn_es);
 
        return es;
@@ -1372,7 +1552,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))
+       if ((es->flags & (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE))
+           || listcount(es->macip_path_list))
                return;
 
        if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
@@ -1382,6 +1563,7 @@ static void bgp_evpn_es_free(struct bgp_evpn_es *es, const char *caller)
        list_delete(&es->es_evi_list);
        list_delete(&es->es_vrf_list);
        list_delete(&es->es_vtep_list);
+       list_delete(&es->macip_path_list);
        bgp_table_unlock(es->route_table);
 
        /* remove the entry from various databases */
index bf957e581abd4d1cb11b54b079e8b49fba92ecd1..be4456828e6122b3736d0f4c71ea09025bdf5dba 100644 (file)
@@ -99,6 +99,11 @@ struct bgp_evpn_es {
        /* List of ES-VRFs associated with this ES */
        struct list *es_vrf_list;
 
+       /* List of MAC-IP global routes using this ES as destination -
+        * element is bgp_path_info_extra->es_info
+        */
+       struct list *macip_path_list;
+
        /* Number of remote VNIs referencing this ES */
        uint32_t remote_es_evi_cnt;
 
@@ -344,5 +349,10 @@ extern void bgp_evpn_vrf_es_init(struct bgp *bgp_vrf);
 extern void bgp_evpn_es_vrf_deref(struct bgp_evpn_es_evi *es_evi);
 extern void bgp_evpn_es_vrf_ref(struct bgp_evpn_es_evi *es_evi,
                                struct bgp *bgp_vrf);
+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);
 
 #endif /* _FRR_BGP_EVPN_MH_H */
index e8e68c8387223d16ed4414f2e5cd64c01786eaa3..cd4920e3d087b6e52003a8266316d6b6978c0844 100644 (file)
@@ -630,4 +630,13 @@ extern struct bgp_dest *
 bgp_global_evpn_node_lookup(struct bgp_table *table, afi_t afi, safi_t safi,
                            const struct prefix_evpn *evp,
                            struct prefix_rd *prd);
+extern struct bgp_node *bgp_global_evpn_node_get(struct bgp_table *table,
+                                                afi_t afi, safi_t safi,
+                                                const struct prefix_evpn *evp,
+                                                struct prefix_rd *prd);
+extern struct bgp_node *
+bgp_global_evpn_node_lookup(struct bgp_table *table, afi_t afi, safi_t safi,
+                           const struct prefix_evpn *evp,
+                           struct prefix_rd *prd);
+extern void bgp_evpn_import_route_in_vrfs(struct bgp_path_info *pi, int import);
 #endif /* _BGP_EVPN_PRIVATE_H */
index 1582b90a2e7f36c6abc6916faf905752a3bffc94..f9aac35d057a65e4be2d130235d783a0cce30ac1 100644 (file)
@@ -118,6 +118,7 @@ DEFINE_MTYPE(BGPD, LCOMMUNITY_VAL, "Large Community value")
 DEFINE_MTYPE(BGPD, BGP_EVPN, "BGP EVPN Information")
 DEFINE_MTYPE(BGPD, BGP_EVPN_MH_INFO, "BGP EVPN MH Information")
 DEFINE_MTYPE(BGPD, BGP_EVPN_ES_VTEP, "BGP EVPN ES VTEP")
+DEFINE_MTYPE(BGPD, BGP_EVPN_PATH_ES_INFO, "BGP EVPN PATH ES Information")
 DEFINE_MTYPE(BGPD, BGP_EVPN_ES_EVI_VTEP, "BGP EVPN ES-EVI VTEP")
 DEFINE_MTYPE(BGPD, BGP_EVPN_ES, "BGP EVPN ESI Information")
 DEFINE_MTYPE(BGPD, BGP_EVPN_ES_EVI, "BGP EVPN ES-per-EVI Information")
index 058fa4b29599e9803b6e9e34c3047cc6e6ecff6a..a95d9ef931f1743d045ef2f80d1e473fb3013c39 100644 (file)
@@ -116,6 +116,7 @@ DECLARE_MTYPE(BGP_EVPN_ES)
 DECLARE_MTYPE(BGP_EVPN_ES_EVI)
 DECLARE_MTYPE(BGP_EVPN_ES_VRF)
 DECLARE_MTYPE(BGP_EVPN_ES_VTEP)
+DECLARE_MTYPE(BGP_EVPN_PATH_ES_INFO)
 DECLARE_MTYPE(BGP_EVPN_ES_EVI_VTEP)
 
 DECLARE_MTYPE(BGP_EVPN)
index df30897dc6a5e6dca12f0109b39604447c5d6929..29dbdbad897944406c89c3e0ba0d598b184c8289 100644 (file)
@@ -244,6 +244,9 @@ void bgp_path_info_extra_free(struct bgp_path_info_extra **extra)
        if (e->aggr_suppressors)
                list_delete(&e->aggr_suppressors);
 
+       if (e->es_info)
+               bgp_evpn_path_es_info_free(e->es_info);
+
        if ((*extra)->bgp_fs_iprule)
                list_delete(&((*extra)->bgp_fs_iprule));
        if ((*extra)->bgp_fs_pbr)
index 0b76d7504b5f10eaef3fd477f8eb34f018ebb74e..17ca3f8b38470df209dd7255ed78457969ec09cf 100644 (file)
@@ -102,6 +102,19 @@ enum bgp_show_adj_route_type {
 #define BGP_NLRI_PARSE_ERROR_EVPN_TYPE1_SIZE -15
 #define BGP_NLRI_PARSE_ERROR -32
 
+/* MAC-IP/type-2 path_info in the global routing table is linked to the
+ * destination ES
+ */
+struct bgp_path_es_info {
+       /* back pointer to the route */
+       struct bgp_path_info *pi;
+       vni_t vni;
+       /* destination ES */
+       struct bgp_evpn_es *es;
+       /* memory used for linking the path to the destination ES */
+       struct listnode es_listnode;
+};
+
 /* Ancillary information to struct bgp_path_info,
  * used for uncommonly used data (aggregation, MPLS, etc.)
  * and lazily allocated to save memory.
@@ -188,6 +201,8 @@ struct bgp_path_info_extra {
        struct list *bgp_fs_pbr;
        /* presence of FS pbr iprule based entry */
        struct list *bgp_fs_iprule;
+       /* Destination Ethernet Segment links for EVPN MH */
+       struct bgp_path_es_info *es_info;
 };
 
 struct bgp_path_info {