summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitesh Kanjariya <mitesh@cumulusnetworks.com>2017-10-09 18:12:05 -0700
committerMitesh Kanjariya <mitesh@marvel-07.cumulusnetworks.com>2017-12-14 10:57:05 -0800
commit10ebe1ab5417af8760a05fb2edd3306847f7e4ba (patch)
treef8d0580444564cc626c4ac54f3dad20ddc2d5276
parentbc59a6720c51482ff41f0f1f903ef9370dcd01cf (diff)
bgpd: import rt to vrf mapping
Signed-off-by: Mitesh Kanjariya <mitesh@cumulusnetworks.com>
-rw-r--r--bgpd/bgp_evpn.c281
-rw-r--r--bgpd/bgp_evpn.h1
-rw-r--r--bgpd/bgp_evpn_private.h15
-rw-r--r--bgpd/bgp_evpn_vty.c167
-rw-r--r--bgpd/bgp_memory.c1
-rw-r--r--bgpd/bgp_memory.h1
-rw-r--r--bgpd/bgpd.c3
-rw-r--r--bgpd/bgpd.h3
8 files changed, 466 insertions, 6 deletions
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index 64b2501705..326748bb47 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -93,6 +93,131 @@ static int vni_hash_cmp(const void *p1, const void *p2)
}
/*
+ * Make vrf import route target hash key.
+ */
+static unsigned int vrf_import_rt_hash_key_make(void *p)
+{
+ struct vrf_irt_node *irt = p;
+ char *pnt = irt->rt.val;
+ unsigned int key = 0;
+ int c = 0;
+
+ key += pnt[c];
+ key += pnt[c + 1];
+ key += pnt[c + 2];
+ key += pnt[c + 3];
+ key += pnt[c + 4];
+ key += pnt[c + 5];
+ key += pnt[c + 6];
+ key += pnt[c + 7];
+
+ return key;
+}
+
+/*
+ * Comparison function for vrf import rt hash
+ */
+static int vrf_import_rt_hash_cmp(const void *p1, const void *p2)
+{
+ const struct vrf_irt_node *irt1 = p1;
+ const struct vrf_irt_node *irt2 = p2;
+
+ if (irt1 == NULL && irt2 == NULL)
+ return 1;
+
+ if (irt1 == NULL || irt2 == NULL)
+ return 0;
+
+ return (memcmp(irt1->rt.val, irt2->rt.val, ECOMMUNITY_SIZE) == 0);
+}
+
+/*
+ * Create a new vrf import_rt in default instance
+ */
+static struct vrf_irt_node *vrf_import_rt_new(struct ecommunity_val *rt)
+{
+ struct bgp *bgp_def = NULL;
+ struct vrf_irt_node *irt;
+
+ bgp_def = bgp_get_default();
+ if (!bgp_def) {
+ zlog_err("vrf import rt new - def instance not created yet");
+ return NULL;
+ }
+
+ irt = XCALLOC(MTYPE_BGP_EVPN_VRF_IMPORT_RT,
+ sizeof(struct vrf_irt_node));
+ if (!irt)
+ return NULL;
+
+ irt->rt = *rt;
+ irt->vrfs = list_new();
+
+ /* Add to hash */
+ if (!hash_get(bgp_def->vrf_import_rt_hash, irt, hash_alloc_intern)) {
+ XFREE(MTYPE_BGP_EVPN_VRF_IMPORT_RT, irt);
+ return NULL;
+ }
+
+ return irt;
+}
+
+/*
+ * Free the vrf import rt node
+ */
+static void vrf_import_rt_free(struct vrf_irt_node *irt)
+{
+ struct bgp *bgp_def = NULL;
+
+ bgp_def = bgp_get_default();
+ if (!bgp_def) {
+ zlog_err("vrf import rt free - def instance not created yet");
+ return;
+ }
+
+ hash_release(bgp_def->vrf_import_rt_hash, irt);
+ XFREE(MTYPE_BGP_EVPN_VRF_IMPORT_RT, irt);
+}
+
+/*
+ * Function to lookup Import RT node - used to map a RT to set of
+ * VNIs importing routes with that RT.
+ */
+static struct vrf_irt_node *lookup_vrf_import_rt(struct ecommunity_val *rt)
+{
+ struct bgp *bgp_def = NULL;
+ struct vrf_irt_node *irt;
+ struct vrf_irt_node tmp;
+
+ bgp_def = bgp_get_default();
+ if (!bgp_def) {
+ zlog_err("vrf import rt lookup - def instance not created yet");
+ return NULL;
+ }
+
+ memset(&tmp, 0, sizeof(struct vrf_irt_node));
+ memcpy(&tmp.rt, rt, ECOMMUNITY_SIZE);
+ irt = hash_lookup(bgp_def->vrf_import_rt_hash, &tmp);
+ return irt;
+}
+
+/*
+ * Is specified VRF present on the RT's list of "importing" VRFs?
+ */
+static int is_vrf_present_in_irt_vrfs(struct list *vrfs,
+ struct bgp *bgp_vrf)
+{
+ struct listnode *node = NULL, *nnode = NULL;
+ struct bgp *tmp_bgp_vrf = NULL;
+
+ for (ALL_LIST_ELEMENTS(vrfs, node, nnode, tmp_bgp_vrf)) {
+ if (tmp_bgp_vrf == bgp_vrf)
+ return 1;
+ }
+ return 0;
+}
+
+/*
* Make import route target hash key.
*/
static unsigned int import_rt_hash_key_make(void *p)
@@ -247,6 +372,57 @@ static inline void mask_ecom_global_admin(struct ecommunity_val *dst,
}
/*
+ * Map one RT to specified VRF.
+ * bgp_vrf = BGP vrf instance
+ */
+static void map_vrf_to_rt(struct bgp *bgp_vrf,
+ struct ecommunity_val *eval)
+{
+ struct vrf_irt_node *irt = NULL;
+ struct ecommunity_val eval_tmp;
+
+ /* If using "automatic" RT,
+ * we only care about the local-admin sub-field.
+ * This is to facilitate using L3VNI(VRF-VNI)
+ * as the RT for EBGP peering too.
+ */
+ memcpy(&eval_tmp, eval, ECOMMUNITY_SIZE);
+ if (!CHECK_FLAG(bgp_vrf->vrf_flags,
+ BGP_VRF_IMPORT_RT_CFGD))
+ mask_ecom_global_admin(&eval_tmp, eval);
+
+ irt = lookup_vrf_import_rt(&eval_tmp);
+ if (irt && irt->vrfs)
+ if (is_vrf_present_in_irt_vrfs(irt->vrfs, bgp_vrf))
+ /* Already mapped. */
+ return;
+
+ if (!irt) {
+ irt = vrf_import_rt_new(&eval_tmp);
+ assert(irt);
+ }
+
+ /* Add VRF to the list for this RT. */
+ listnode_add(irt->vrfs, bgp_vrf);
+}
+
+/*
+ * Unmap specified VRF from specified RT. If there are no other
+ * VRFs for this RT, then the RT hash is deleted.
+ * bgp_vrf: BGP VRF specific instance
+ */
+static void unmap_vrf_from_rt(struct bgp *bgp_vrf,
+ struct vrf_irt_node *irt)
+{
+ /* Delete VRF from list for this RT. */
+ listnode_delete(irt->vrfs, bgp_vrf);
+ if (!listnode_head(irt->vrfs)) {
+ list_free(irt->vrfs);
+ vrf_import_rt_free(irt);
+ }
+}
+
+/*
* Map one RT to specified VNI.
*/
static void map_vni_to_rt(struct bgp *bgp, struct bgpevpn *vpn,
@@ -2135,8 +2311,16 @@ static void free_vni_entry(struct hash_backet *backet, struct bgp *bgp)
*/
static void evpn_auto_rt_import_add_for_vrf(struct bgp *bgp_vrf)
{
- UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD);
+ struct bgp *bgp_def = NULL;
+
form_auto_rt(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_import_rtl);
+ UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD);
+
+ /* Map RT to VRF */
+ bgp_def = bgp_get_default();
+ if (!bgp_def)
+ return;
+ bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
}
/*
@@ -2209,8 +2393,13 @@ void evpn_rt_delete_auto(struct bgp *bgp, vni_t vni,
}
void bgp_evpn_configure_import_rt_for_vrf(struct bgp *bgp_vrf,
- struct ecommunity *ecomadd)
+ struct ecommunity *ecomadd)
{
+ //TODO_MITESH: uninstall routes from VRF
+
+ /* Cleanup the RT to VRF mapping */
+ bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
+
/* Remove auto generated RT */
evpn_auto_rt_import_delete_for_vrf(bgp_vrf);
@@ -2218,8 +2407,10 @@ void bgp_evpn_configure_import_rt_for_vrf(struct bgp *bgp_vrf,
listnode_add_sort(bgp_vrf->vrf_import_rtl, ecomadd);
SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD);
- //TODO_MITESH: handle RT change (uninstall old routes and install new
- //routes matching this RT)
+ /* map VRF to its RTs */
+ bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
+
+ //TODO_MITESH: install routes matching the new VRF
}
void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp *bgp_vrf,
@@ -2228,6 +2419,11 @@ void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp *bgp_vrf,
struct listnode *node = NULL, *nnode = NULL, *node_to_del = NULL;
struct ecommunity *ecom = NULL;
+ //TODO_MITESH: uninstall routes from VRF
+
+ /* Cleanup the RT to VRF mapping */
+ bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
+
/* remove the RT from the RT list */
for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, ecom)) {
if (ecommunity_match(ecom, ecomdel)) {
@@ -2246,8 +2442,10 @@ void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp *bgp_vrf,
evpn_auto_rt_import_add_for_vrf(bgp_vrf);
}
- //TODO_MITESH: handle import RT change
- //uninstall old routes, install new routes matching this RT
+ /* map VRFs to its RTs */
+ bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
+
+ //TODO_MITESH: install routes matching this new RT
}
void bgp_evpn_configure_export_rt_for_vrf(struct bgp *bgp_vrf,
@@ -2632,6 +2830,65 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
return 0;
}
+/*
+ * Map the RTs (configured or automatically derived) of a VRF to the VRF.
+ * The mapping will be used during route processing.
+ * bgp_def: default bgp instance
+ * bgp_vrf: specific bgp vrf instance on which RT is configured
+ */
+void bgp_evpn_map_vrf_to_its_rts(struct bgp *bgp_vrf)
+{
+ int i = 0;
+ struct ecommunity_val *eval = NULL;
+ struct listnode *node = NULL, *nnode = NULL;
+ struct ecommunity *ecom = NULL;
+
+ for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, ecom)) {
+ for (i = 0; i < ecom->size; i++) {
+ eval = (struct ecommunity_val *)(ecom->val
+ + (i
+ * ECOMMUNITY_SIZE));
+ map_vrf_to_rt(bgp_vrf, eval);
+ }
+ }
+}
+
+/*
+ * Unmap the RTs (configured or automatically derived) of a VRF from the VRF.
+ */
+void bgp_evpn_unmap_vrf_from_its_rts(struct bgp *bgp_vrf)
+{
+ int i;
+ struct ecommunity_val *eval;
+ struct listnode *node, *nnode;
+ struct ecommunity *ecom;
+
+ for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, ecom)) {
+ for (i = 0; i < ecom->size; i++) {
+ struct vrf_irt_node *irt;
+ struct ecommunity_val eval_tmp;
+
+ eval = (struct ecommunity_val *)(ecom->val
+ + (i
+ * ECOMMUNITY_SIZE));
+ /* If using "automatic" RT, we only care about the
+ * local-admin sub-field.
+ * This is to facilitate using VNI as the RT for EBGP
+ * peering too.
+ */
+ memcpy(&eval_tmp, eval, ECOMMUNITY_SIZE);
+ if (!CHECK_FLAG(bgp_vrf->vrf_flags,
+ BGP_VRF_IMPORT_RT_CFGD))
+ mask_ecom_global_admin(&eval_tmp, eval);
+
+ irt = lookup_vrf_import_rt(&eval_tmp);
+ if (irt)
+ unmap_vrf_from_rt(bgp_vrf, irt);
+ }
+ }
+}
+
+
/*
* Map the RTs (configured or automatically derived) of a VNI to the VNI.
@@ -3071,6 +3328,7 @@ int bgp_evpn_local_l3vni_del(vni_t l3vni,
/* delete RD/RT */
if (bgp_vrf->vrf_import_rtl && !list_isempty(bgp_vrf->vrf_import_rtl)) {
+ bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
list_delete(bgp_vrf->vrf_import_rtl);
bgp_vrf->vrf_import_rtl = NULL;
}
@@ -3236,6 +3494,9 @@ void bgp_evpn_cleanup(struct bgp *bgp)
if (bgp->import_rt_hash)
hash_free(bgp->import_rt_hash);
bgp->import_rt_hash = NULL;
+ if (bgp->vrf_import_rt_hash)
+ hash_free(bgp->vrf_import_rt_hash);
+ bgp->vrf_import_rt_hash = NULL;
if (bgp->vnihash)
hash_free(bgp->vnihash);
bgp->vnihash = NULL;
@@ -3265,6 +3526,9 @@ void bgp_evpn_init(struct bgp *bgp)
bgp->import_rt_hash =
hash_create(import_rt_hash_key_make, import_rt_hash_cmp,
"BGP Import RT Hash");
+ bgp->vrf_import_rt_hash =
+ hash_create(vrf_import_rt_hash_key_make, vrf_import_rt_hash_cmp,
+ "BGP VRF Import RT Hash");
bgp->vrf_import_rtl = list_new();
bgp->vrf_import_rtl->cmp =
(int (*)(void *, void *))evpn_route_target_cmp;
@@ -3279,3 +3543,8 @@ void bgp_evpn_init(struct bgp *bgp)
/*assign 0th index in the bitfield, so that we start with id 1*/
bf_assign_zero_index(bgp->rd_idspace);
}
+
+void bgp_evpn_vrf_delete(struct bgp *bgp_vrf)
+{
+ bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
+}
diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h
index 42b9ebc5c5..14de479007 100644
--- a/bgpd/bgp_evpn.h
+++ b/bgpd/bgp_evpn.h
@@ -25,6 +25,7 @@
#define EVPN_ROUTE_STRLEN 200 /* Must be >> MAC + IPv6 strings. */
+extern void bgp_evpn_vrf_delete(struct bgp *);
extern void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw);
extern char *bgp_evpn_label2str(mpls_label_t *label, char *buf, int len);
extern char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len);
diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h
index b983a00a76..f8594394ef 100644
--- a/bgpd/bgp_evpn_private.h
+++ b/bgpd/bgp_evpn_private.h
@@ -97,6 +97,19 @@ struct irt_node {
struct list *vnis;
};
+/* Mapping of Import RT to VRFs.
+ * The Import RTs of all VRFss are maintained in a hash table with each
+ * RT linking to all VRFs that will import routes matching this RT.
+ */
+struct vrf_irt_node {
+ /* RT */
+ struct ecommunity_val rt;
+
+ /* List of VNIs importing routes matching this RT. */
+ struct list *vrfs;
+};
+
+
#define RT_TYPE_IMPORT 1
#define RT_TYPE_EXPORT 2
#define RT_TYPE_BOTH 3
@@ -285,6 +298,8 @@ extern void bgp_evpn_handle_rd_change(struct bgp *bgp, struct bgpevpn *vpn,
int withdraw);
extern int bgp_evpn_install_routes(struct bgp *bgp, struct bgpevpn *vpn);
extern int bgp_evpn_uninstall_routes(struct bgp *bgp, struct bgpevpn *vpn);
+extern void bgp_evpn_map_vrf_to_its_rts(struct bgp *);
+extern void bgp_evpn_unmap_vrf_from_its_rts(struct bgp *);
extern void bgp_evpn_map_vni_to_its_rts(struct bgp *bgp, struct bgpevpn *vpn);
extern void bgp_evpn_unmap_vni_from_its_rts(struct bgp *bgp,
struct bgpevpn *vpn);
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index fce887df2e..86b50db581 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -53,6 +53,117 @@ struct vni_walk_ctx {
};
#if defined(HAVE_CUMULUS)
+static void display_vrf_import_rt(struct vty *vty,
+ struct vrf_irt_node *irt,
+ json_object *json)
+{
+ u_char *pnt;
+ u_char type, sub_type;
+ struct ecommunity_as eas;
+ struct ecommunity_ip eip;
+ struct listnode *node, *nnode;
+ struct bgp *tmp_bgp_vrf = NULL;
+ json_object *json_rt = NULL;
+ json_object *json_vrfs = NULL;
+ char rt_buf[RT_ADDRSTRLEN];
+
+ if (json) {
+ json_rt = json_object_new_object();
+ json_vrfs = json_object_new_array();
+ }
+
+ pnt = (u_char *)&irt->rt.val;
+ type = *pnt++;
+ sub_type = *pnt++;
+ if (sub_type != ECOMMUNITY_ROUTE_TARGET)
+ return;
+
+ memset(&eas, 0, sizeof(eas));
+ switch (type) {
+ case ECOMMUNITY_ENCODE_AS:
+ eas.as = (*pnt++ << 8);
+ eas.as |= (*pnt++);
+ pnt = ptr_get_be32(pnt, &eas.val);
+
+ snprintf(rt_buf, RT_ADDRSTRLEN, "%u:%u", eas.as, eas.val);
+
+ if (json)
+ json_object_string_add(json_rt, "rt", rt_buf);
+ else
+ vty_out(vty, "Route-target: %s", rt_buf);
+
+ break;
+
+ case ECOMMUNITY_ENCODE_IP:
+ memcpy(&eip.ip, pnt, 4);
+ pnt += 4;
+ eip.val = (*pnt++ << 8);
+ eip.val |= (*pnt++);
+
+ snprintf(rt_buf, RT_ADDRSTRLEN, "%s:%u", inet_ntoa(eip.ip),
+ eip.val);
+
+ if (json)
+ json_object_string_add(json_rt, "rt", rt_buf);
+ else
+ vty_out(vty, "Route-target: %s", rt_buf);
+
+ break;
+
+ case ECOMMUNITY_ENCODE_AS4:
+ pnt = ptr_get_be32(pnt, &eas.val);
+ eas.val = (*pnt++ << 8);
+ eas.val |= (*pnt++);
+
+ snprintf(rt_buf, RT_ADDRSTRLEN, "%u:%u", eas.as, eas.val);
+
+ if (json)
+ json_object_string_add(json_rt, "rt", rt_buf);
+ else
+ vty_out(vty, "Route-target: %s", rt_buf);
+
+ break;
+
+ default:
+ return;
+ }
+
+ if (!json) {
+ vty_out(vty,
+ "\nList of VRFs importing routes with this route-target:\n");
+ }
+
+ for (ALL_LIST_ELEMENTS(irt->vrfs, node, nnode, tmp_bgp_vrf)) {
+ if (json)
+ json_object_array_add(
+ json_vrfs,
+ json_object_new_string(
+ vrf_id_to_name(
+ tmp_bgp_vrf->vrf_id)));
+ else
+ vty_out(vty, " %s\n",
+ vrf_id_to_name(tmp_bgp_vrf->vrf_id));
+ }
+
+ if (json) {
+ json_object_object_add(json_rt, "vrfs", json_vrfs);
+ json_object_object_add(json, rt_buf, json_rt);
+ }
+}
+
+static void show_vrf_import_rt_entry(struct hash_backet *backet,
+ void *args[])
+{
+ json_object *json = NULL;
+ struct vty *vty = NULL;
+ struct vrf_irt_node *irt = (struct vrf_irt_node *)backet->data;
+
+ vty = args[0];
+ json = args[1];
+
+ display_vrf_import_rt(vty, irt, json);
+}
+
static void display_import_rt(struct vty *vty, struct irt_node *irt,
json_object *json)
{
@@ -1433,6 +1544,25 @@ static int evpn_delete_vni(struct bgp *bgp, struct bgpevpn *vpn)
}
/*
+ * Display import RT mapping to VRFs (vty handler)
+ * bgp_def: default bgp instance
+ */
+static void evpn_show_vrf_import_rts(struct vty *vty,
+ struct bgp *bgp_def,
+ json_object *json)
+{
+ void *args[2];
+
+ args[0] = vty;
+ args[1] = json;
+
+ hash_iterate(bgp_def->vrf_import_rt_hash,
+ (void (*)(struct hash_backet *, void *))
+ show_vrf_import_rt_entry,
+ args);
+}
+
+/*
* Display import RT mapping to VNIs (vty handler)
*/
static void evpn_show_import_rts(struct vty *vty, struct bgp *bgp,
@@ -2768,6 +2898,42 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni_all,
/*
* Display EVPN import route-target hash table
*/
+DEFUN(show_bgp_l2vpn_evpn_vrf_import_rt,
+ show_bgp_l2vpn_evpn_vrf_import_rt_cmd,
+ "show bgp l2vpn evpn vrf-import-rt [json]",
+ SHOW_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "Show vrf import route target\n"
+ JSON_STR)
+{
+ u_char uj = 0;
+ struct bgp *bgp_def;
+ json_object *json = NULL;
+
+ bgp_def = bgp_get_default();
+ if (!bgp_def)
+ return CMD_WARNING;
+
+ uj = use_json(argc, argv);
+ if (uj)
+ json = json_object_new_object();
+
+ evpn_show_vrf_import_rts(vty, bgp_def, json);
+
+ 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
+ */
DEFUN(show_bgp_l2vpn_evpn_import_rt,
show_bgp_l2vpn_evpn_import_rt_cmd,
"show bgp l2vpn evpn import-rt [json]",
@@ -3536,6 +3702,7 @@ void bgp_ethernetvpn_init(void)
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_macip_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_all_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_import_rt_cmd);
+ install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vrf_import_rt_cmd);
/* "show bgp evpn" commands. */
install_element(VIEW_NODE, &show_bgp_evpn_vni_cmd);
diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c
index 37054ce425..64543ff019 100644
--- a/bgpd/bgp_memory.c
+++ b/bgpd/bgp_memory.c
@@ -117,4 +117,5 @@ DEFINE_MTYPE(BGPD, LCOMMUNITY_VAL, "Large Community value")
DEFINE_MTYPE(BGPD, BGP_EVPN, "BGP EVPN Information")
DEFINE_MTYPE(BGPD, BGP_EVPN_IMPORT_RT, "BGP EVPN Import RT")
+DEFINE_MTYPE(BGPD, BGP_EVPN_VRF_IMPORT_RT, "BGP EVPN VRF Import RT")
DEFINE_MTYPE(BGPD, BGP_EVPN_MACIP, "BGP EVPN MAC IP")
diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h
index 35b83a0401..fae98329c6 100644
--- a/bgpd/bgp_memory.h
+++ b/bgpd/bgp_memory.h
@@ -113,5 +113,6 @@ DECLARE_MTYPE(LCOMMUNITY_VAL)
DECLARE_MTYPE(BGP_EVPN)
DECLARE_MTYPE(BGP_EVPN_IMPORT_RT)
+DECLARE_MTYPE(BGP_EVPN_VRF_IMPORT_RT)
DECLARE_MTYPE(BGP_EVPN_MACIP)
#endif /* _QUAGGA_BGP_MEMORY_H */
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 56e18db311..de1e3b8959 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -3139,6 +3139,9 @@ int bgp_delete(struct bgp *bgp)
bgp->name);
}
+ /* unmap from RT list */
+ bgp_evpn_vrf_delete(bgp);
+
/* Stop timers. */
if (bgp->t_rmap_def_originate_eval) {
BGP_TIMER_OFF(bgp->t_rmap_def_originate_eval);
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index c49e2b56b2..927056bd48 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -406,6 +406,9 @@ struct bgp {
/* Hash table of Import RTs to EVIs */
struct hash *import_rt_hash;
+ /* Hash table of VRF import RTs to VRFs */
+ struct hash *vrf_import_rt_hash;
+
/* Id space for automatic RD derivation for an EVI */
bitfield_t rd_idspace;