]> git.proxmox.com Git - mirror_frr.git/blobdiff - zebra/zebra_vxlan.c
Merge pull request #4635 from AnuradhaKaruppiah/evpn-pim-replay
[mirror_frr.git] / zebra / zebra_vxlan.c
index abd076bc829242c8fec740d88f6af626802b93a2..dff50ceef4de9d64008b6db1738fcd6ac9353e61 100644 (file)
@@ -60,6 +60,9 @@ DEFINE_MTYPE_STATIC(ZEBRA, MAC, "VNI MAC");
 DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "VNI Neighbor");
 DEFINE_MTYPE_STATIC(ZEBRA, ZVXLAN_SG, "zebra VxLAN multicast group");
 
+DEFINE_HOOK(zebra_rmac_update, (zebra_mac_t *rmac, zebra_l3vni_t *zl3vni,
+           bool delete, const char *reason), (rmac, zl3vni, delete, reason))
+
 /* definitions */
 /* PMSI strings. */
 #define VXLAN_FLOOD_STR_NO_INFO "-"
@@ -143,8 +146,6 @@ static zebra_l3vni_t *zl3vni_lookup(vni_t vni);
 static void *zl3vni_alloc(void *p);
 static zebra_l3vni_t *zl3vni_add(vni_t vni, vrf_id_t vrf_id);
 static int zl3vni_del(zebra_l3vni_t *zl3vni);
-static struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni);
-static struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni);
 static void zebra_vxlan_process_l3vni_oper_up(zebra_l3vni_t *zl3vni);
 static void zebra_vxlan_process_l3vni_oper_down(zebra_l3vni_t *zl3vni);
 
@@ -224,6 +225,9 @@ static void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip,
                                struct in_addr mcast_grp);
 static void zebra_vxlan_sg_cleanup(struct hash_backet *backet, void *arg);
 
+static void zvni_send_mac_to_client(zebra_vni_t *zvn);
+static void zvni_send_neigh_to_client(zebra_vni_t *zvni);
+
 /* Private functions */
 static int host_rb_entry_compare(const struct host_rb_entry *hle1,
                                 const struct host_rb_entry *hle2)
@@ -728,6 +732,7 @@ static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json)
        bool flags_present = false;
        struct zebra_vrf *zvrf = NULL;
        struct timeval detect_start_time = {0, 0};
+       char timebuf[MONOTIME_STRLEN];
 
        zvrf = zebra_vrf_get_evpn();
        if (!zvrf)
@@ -782,19 +787,17 @@ static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json)
 
                if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE)) {
                        vty_out(vty, " Duplicate, detected at %s",
-                               time_to_string(n->dad_dup_detect_time));
+                               time_to_string(n->dad_dup_detect_time,
+                                              timebuf));
                } else if (n->dad_count) {
                        monotime_since(&n->detect_start_time,
                                       &detect_start_time);
                        if (detect_start_time.tv_sec <= zvrf->dad_time) {
-                               char *buf = time_to_string(
-                                               n->detect_start_time.tv_sec);
-                               char tmp_buf[30];
-
-                               strlcpy(tmp_buf, buf, sizeof(tmp_buf));
+                               time_to_string(n->detect_start_time.tv_sec,
+                                              timebuf);
                                vty_out(vty,
                                        " Duplicate detection started at %s, detection count %u\n",
-                                       tmp_buf, n->dad_count);
+                                       timebuf, n->dad_count);
                        }
                }
        } else {
@@ -871,10 +874,10 @@ static void zvni_print_neigh_hash(struct hash_bucket *bucket, void *ctxt)
                if (json_vni == NULL) {
                        if ((wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP) &&
                            (wctx->count == 0))
-                               vty_out(vty,
-                                       "%*s %-6s %-8s %-17s %-21s\n",
+                               vty_out(vty, "%*s %-6s %-8s %-17s %-21s %s\n",
                                        -wctx->addr_width, "Neighbor", "Type",
-                                       "State", "MAC", "Remote VTEP");
+                                       "State", "MAC", "Remote VTEP",
+                                       "Seq #'s");
                        vty_out(vty, "%*s %-6s %-8s %-17s %-21s %u/%u\n",
                                -wctx->addr_width, buf2, "remote", state_str,
                                buf1, inet_ntoa(n->r_vtep_ip), n->loc_seq, n->rem_seq);
@@ -1175,6 +1178,7 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json)
        char buf2[INET6_ADDRSTRLEN];
        struct zebra_vrf *zvrf;
        struct timeval detect_start_time = {0, 0};
+       char timebuf[MONOTIME_STRLEN];
 
        zvrf = zebra_vrf_get_evpn();
        if (!zvrf)
@@ -1305,19 +1309,17 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json)
 
                if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
                        vty_out(vty, " Duplicate, detected at %s",
-                               time_to_string(mac->dad_dup_detect_time));
+                               time_to_string(mac->dad_dup_detect_time,
+                                              timebuf));
                } else if (mac->dad_count) {
                        monotime_since(&mac->detect_start_time,
                               &detect_start_time);
                        if (detect_start_time.tv_sec <= zvrf->dad_time) {
-                               char *buf = time_to_string(
-                                               mac->detect_start_time.tv_sec);
-                               char tmp_buf[30];
-
-                               strlcpy(tmp_buf, buf, sizeof(tmp_buf));
+                               time_to_string(mac->detect_start_time.tv_sec,
+                                              timebuf);
                                vty_out(vty,
                                        " Duplicate detection started at %s, detection count %u\n",
-                                       tmp_buf, mac->dad_count);
+                                       timebuf, mac->dad_count);
                        }
                }
 
@@ -1387,9 +1389,10 @@ static void zvni_print_mac_hash(struct hash_bucket *bucket, void *ctxt)
                        else
                                json_object_int_add(json_mac, "vlan", vid);
                } else /* No vid? fill out the space */
-                       vty_out(vty, " %-5s", "");
-               vty_out(vty, " %u/%u", mac->loc_seq, mac->rem_seq);
+                       if (json_mac_hdr == NULL)
+                               vty_out(vty, " %-5s", "");
                if (json_mac_hdr == NULL) {
+                       vty_out(vty, " %u/%u", mac->loc_seq, mac->rem_seq);
                        vty_out(vty, "\n");
                } else {
                        json_object_int_add(json_mac, "localSequence",
@@ -2873,6 +2876,16 @@ static void zvni_gw_macip_del_for_vni_hash(struct hash_bucket *bucket,
        /* Add primary SVI MAC*/
        zvni = (zebra_vni_t *)bucket->data;
 
+       /* Global (Zvrf) advertise-default-gw is disabled,
+        * but zvni advertise-default-gw is enabled
+        */
+       if (zvni->advertise_gw_macip) {
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug("VNI: %u GW-MACIP enabled, retain gw-macip",
+                                  zvni->vni);
+               return;
+       }
+
        ifp = zvni->vxlan_if;
        if (!ifp)
                return;
@@ -2954,6 +2967,16 @@ static void zvni_svi_macip_del_for_vni_hash(struct hash_bucket *bucket,
        if (!zvni)
                return;
 
+       /* Global(vrf) advertise-svi-ip disabled, but zvni advertise-svi-ip
+        * enabled
+        */
+       if (zvni->advertise_svi_macip) {
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug("VNI: %u SVI-MACIP enabled, retain svi-macip",
+                                  zvni->vni);
+               return;
+       }
+
        ifp = zvni->vxlan_if;
        if (!ifp)
                return;
@@ -4060,46 +4083,67 @@ static void zvni_build_hash_table(void)
                                        ifp->name, ifp->ifindex, vni,
                                        inet_ntoa(vxl->vtep_ip));
 
-                       /* VNI hash entry is not expected to exist. */
+                       /* VNI hash entry is expected to exist, if the BGP process is killed */
                        zvni = zvni_lookup(vni);
                        if (zvni) {
                                zlog_debug(
                                        "VNI hash already present for IF %s(%u) L2-VNI %u",
                                        ifp->name, ifp->ifindex, vni);
-                               continue;
-                       }
 
-                       zvni = zvni_add(vni);
-                       if (!zvni) {
-                               zlog_debug(
-                                       "Failed to add VNI hash, IF %s(%u) L2-VNI %u",
-                                       ifp->name, ifp->ifindex, vni);
-                               return;
-                       }
+                               /*
+                                * Inform BGP if intf is up and mapped to
+                                * bridge.
+                                */
+                               if (if_is_operative(ifp) &&
+                                       zif->brslave_info.br_if)
+                                       zvni_send_add_to_client(zvni);
 
-                       if (zvni->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr ||
-                               zvni->mcast_grp.s_addr != vxl->mcast_grp.s_addr) {
-                               zebra_vxlan_sg_deref(zvni->local_vtep_ip,
-                                       zvni->mcast_grp);
-                               zebra_vxlan_sg_ref(vxl->vtep_ip,
-                                       vxl->mcast_grp);
-                               zvni->local_vtep_ip = vxl->vtep_ip;
-                               zvni->mcast_grp = vxl->mcast_grp;
-                       }
-                       zvni->vxlan_if = ifp;
-                       vlan_if = zvni_map_to_svi(vxl->access_vlan,
-                                                 zif->brslave_info.br_if);
-                       if (vlan_if) {
-                               zvni->vrf_id = vlan_if->vrf_id;
-                               zl3vni = zl3vni_from_vrf(vlan_if->vrf_id);
-                               if (zl3vni)
-                                       listnode_add_sort(zl3vni->l2vnis, zvni);
-                       }
+                               /* Send Local MAC-entries to client */
+                               zvni_send_mac_to_client(zvni);
 
+                               /* Send Loval Neighbor entries to client */
+                               zvni_send_neigh_to_client(zvni);
+                       } else {
+                               zvni = zvni_add(vni);
+                               if (!zvni) {
+                                       zlog_debug(
+                                               "Failed to add VNI hash, IF %s(%u) L2-VNI %u",
+                                               ifp->name, ifp->ifindex, vni);
+                                       return;
+                               }
 
-                       /* Inform BGP if intf is up and mapped to bridge. */
-                       if (if_is_operative(ifp) && zif->brslave_info.br_if)
-                               zvni_send_add_to_client(zvni);
+                               if (zvni->local_vtep_ip.s_addr !=
+                                       vxl->vtep_ip.s_addr ||
+                                       zvni->mcast_grp.s_addr !=
+                                       vxl->mcast_grp.s_addr) {
+                                       zebra_vxlan_sg_deref(
+                                               zvni->local_vtep_ip,
+                                               zvni->mcast_grp);
+                                       zebra_vxlan_sg_ref(vxl->vtep_ip,
+                                               vxl->mcast_grp);
+                                       zvni->local_vtep_ip = vxl->vtep_ip;
+                                       zvni->mcast_grp = vxl->mcast_grp;
+                               }
+                               zvni->vxlan_if = ifp;
+                               vlan_if = zvni_map_to_svi(vxl->access_vlan,
+                                               zif->brslave_info.br_if);
+                               if (vlan_if) {
+                                       zvni->vrf_id = vlan_if->vrf_id;
+                                       zl3vni = zl3vni_from_vrf(
+                                                       vlan_if->vrf_id);
+                                       if (zl3vni)
+                                               listnode_add_sort(
+                                                       zl3vni->l2vnis, zvni);
+                               }
+
+                               /*
+                                * Inform BGP if intf is up and mapped to
+                                * bridge.
+                                */
+                               if (if_is_operative(ifp) &&
+                                       zif->brslave_info.br_if)
+                                       zvni_send_add_to_client(zvni);
+                       }
                }
        }
 }
@@ -4463,6 +4507,10 @@ static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac,
                memset(&zrmac->fwd_info, 0, sizeof(zrmac->fwd_info));
                zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4;
 
+               /* Send RMAC for FPM processing */
+               hook_call(zebra_rmac_update, zrmac, zl3vni, false,
+                         "new RMAC added");
+
                /* install rmac in kernel */
                zl3vni_rmac_install(zl3vni, zrmac);
        }
@@ -4483,6 +4531,10 @@ static void zl3vni_remote_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac,
                /* uninstall from kernel */
                zl3vni_rmac_uninstall(zl3vni, zrmac);
 
+               /* Send RMAC for FPM processing */
+               hook_call(zebra_rmac_update, zrmac, zl3vni, true,
+                         "RMAC deleted");
+
                /* del the rmac entry */
                zl3vni_rmac_del(zl3vni, zrmac);
        }
@@ -4794,7 +4846,7 @@ static int zl3vni_del(zebra_l3vni_t *zl3vni)
        return 0;
 }
 
-static struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni)
+struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni)
 {
        struct zebra_ns *zns = NULL;
        struct route_node *rn = NULL;
@@ -4825,7 +4877,7 @@ static struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni)
        return NULL;
 }
 
-static struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni)
+struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni)
 {
        struct zebra_if *zif = NULL;       /* zebra_if for vxlan_if */
        struct zebra_l2info_vxlan *vxl = NULL; /* l2 info for vxlan_if */
@@ -5093,6 +5145,10 @@ static void zl3vni_del_rmac_hash_entry(struct hash_bucket *bucket, void *ctx)
        zrmac = (zebra_mac_t *)bucket->data;
        zl3vni = (zebra_l3vni_t *)ctx;
        zl3vni_rmac_uninstall(zl3vni, zrmac);
+
+       /* Send RMAC for FPM processing */
+       hook_call(zebra_rmac_update, zrmac, zl3vni, true, "RMAC deleted");
+
        zl3vni_rmac_del(zl3vni, zrmac);
 }
 
@@ -6093,9 +6149,8 @@ void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf,
                vty_out(vty,
                        "Number of ARPs (local and remote) known for this VNI: %u\n",
                        num_neigh);
-               vty_out(vty, "%*s %-6s %-8s %-17s %-21s\n",
-                       -wctx.addr_width, "IP", "Type",
-                       "State", "MAC", "Remote VTEP");
+               vty_out(vty, "%*s %-6s %-8s %-17s %-21s %s\n", -wctx.addr_width,
+                       "IP", "Type", "State", "MAC", "Remote VTEP", "Seq #'s");
        } else
                json_object_int_add(json, "numArpNd", num_neigh);
 
@@ -6357,8 +6412,8 @@ void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf,
                vty_out(vty,
                        "Number of MACs (local and remote) known for this VNI: %u\n",
                        num_macs);
-               vty_out(vty, "%-17s %-6s %-21s %-5s\n", "MAC", "Type",
-                       "Intf/Remote VTEP", "VLAN");
+               vty_out(vty, "%-17s %-6s %-21s %-5s %s\n", "MAC", "Type",
+                       "Intf/Remote VTEP", "VLAN", "Seq #'s");
        } else
                json_object_int_add(json, "numMacs", num_macs);
 
@@ -8920,7 +8975,7 @@ void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS)
        struct interface *ifp = NULL;
 
        if (!EVPN_ENABLED(zvrf)) {
-               zlog_debug("EVPN GW-MACIP Adv for non-EVPN VRF %u",
+               zlog_debug("EVPN SVI-MACIP Adv for non-EVPN VRF %u",
                          zvrf_id(zvrf));
                return;
        }
@@ -8931,7 +8986,7 @@ void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS)
 
        if (!vni) {
                if (IS_ZEBRA_DEBUG_VXLAN)
-                       zlog_debug("EVPN gateway macip Adv %s, currently %s",
+                       zlog_debug("EVPN SVI-MACIP Adv %s, currently %s",
                                   advertise ? "enabled" : "disabled",
                                   advertise_gw_macip_enabled(NULL)
                                           ? "enabled"
@@ -9426,8 +9481,9 @@ static int zebra_vxlan_dad_mac_auto_recovery_exp(struct thread *t)
 
 /************************** vxlan SG cache management ************************/
 /* Inform PIM about the mcast group */
-static int zebra_vxlan_sg_send(struct prefix_sg *sg,
-                       char *sg_str, uint16_t cmd)
+static int zebra_vxlan_sg_send(struct zebra_vrf *zvrf,
+               struct prefix_sg *sg,
+               char *sg_str, uint16_t cmd)
 {
        struct zserv *client = NULL;
        struct stream *s = NULL;
@@ -9436,6 +9492,9 @@ static int zebra_vxlan_sg_send(struct prefix_sg *sg,
        if (!client)
                return 0;
 
+       if (!CHECK_FLAG(zvrf->flags, ZEBRA_PIM_SEND_VXLAN_SG))
+               return 0;
+
        s = stream_new(ZEBRA_MAX_PACKET_SIZ);
 
        zclient_create_header(s, cmd, VRF_DEFAULT);
@@ -9535,7 +9594,8 @@ static zebra_vxlan_sg_t *zebra_vxlan_sg_add(struct zebra_vrf *zvrf,
                return vxlan_sg;
        }
 
-       zebra_vxlan_sg_send(sg, vxlan_sg->sg_str, ZEBRA_VXLAN_SG_ADD);
+       zebra_vxlan_sg_send(zvrf, sg, vxlan_sg->sg_str,
+                       ZEBRA_VXLAN_SG_ADD);
 
        return vxlan_sg;
 }
@@ -9557,8 +9617,8 @@ static void zebra_vxlan_sg_del(zebra_vxlan_sg_t *vxlan_sg)
                zebra_vxlan_sg_do_deref(zvrf, sip, vxlan_sg->sg.grp);
        }
 
-       zebra_vxlan_sg_send(&vxlan_sg->sg, vxlan_sg->sg_str,
-               ZEBRA_VXLAN_SG_DEL);
+       zebra_vxlan_sg_send(zvrf, &vxlan_sg->sg,
+                       vxlan_sg->sg_str, ZEBRA_VXLAN_SG_DEL);
 
        hash_release(vxlan_sg->zvrf->vxlan_sg_table, vxlan_sg);
 
@@ -9641,3 +9701,179 @@ static void zebra_vxlan_sg_cleanup(struct hash_backet *backet, void *arg)
 
        zebra_vxlan_sg_del(vxlan_sg);
 }
+
+static void zebra_vxlan_sg_replay_send(struct hash_backet *backet, void *arg)
+{
+       zebra_vxlan_sg_t *vxlan_sg = (zebra_vxlan_sg_t *)backet->data;
+
+       zebra_vxlan_sg_send(vxlan_sg->zvrf, &vxlan_sg->sg,
+                       vxlan_sg->sg_str, ZEBRA_VXLAN_SG_ADD);
+}
+
+/* Handle message from client to replay vxlan SG entries */
+void zebra_vxlan_sg_replay(ZAPI_HANDLER_ARGS)
+{
+       if (IS_ZEBRA_DEBUG_VXLAN)
+               zlog_debug("VxLAN SG updates to PIM, start");
+
+       SET_FLAG(zvrf->flags, ZEBRA_PIM_SEND_VXLAN_SG);
+
+       if (!EVPN_ENABLED(zvrf)) {
+               zlog_debug("VxLAN SG replay request on unexpected vrf %d",
+                       zvrf->vrf->vrf_id);
+               return;
+       }
+
+       hash_iterate(zvrf->vxlan_sg_table, zebra_vxlan_sg_replay_send, NULL);
+}
+
+/************************** EVPN BGP config management ************************/
+/* Notify Local MACs to the clienti, skips GW MAC */
+static void zvni_send_mac_hash_entry_to_client(struct hash_bucket *bucket,
+                                              void *arg)
+{
+       struct mac_walk_ctx *wctx = arg;
+       zebra_mac_t *zmac = bucket->data;
+
+       if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_DEF_GW))
+               return;
+
+       if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL))
+               zvni_mac_send_add_to_client(wctx->zvni->vni, &zmac->macaddr,
+                                               zmac->flags, zmac->loc_seq);
+}
+
+/* Iterator to Notify Local MACs of a L2VNI */
+static void zvni_send_mac_to_client(zebra_vni_t *zvni)
+{
+       struct mac_walk_ctx wctx;
+
+       if (!zvni->mac_table)
+               return;
+
+       memset(&wctx, 0, sizeof(struct mac_walk_ctx));
+       wctx.zvni = zvni;
+
+       hash_iterate(zvni->mac_table, zvni_send_mac_hash_entry_to_client,
+                       &wctx);
+}
+
+/* Notify Neighbor entries to the Client, skips the GW entry */
+static void zvni_send_neigh_hash_entry_to_client(struct hash_bucket *bucket,
+                                                void *arg)
+{
+       struct mac_walk_ctx *wctx = arg;
+       zebra_neigh_t *zn = bucket->data;
+       zebra_mac_t *zmac = NULL;
+
+       if (CHECK_FLAG(zn->flags, ZEBRA_NEIGH_DEF_GW))
+               return;
+
+       if (CHECK_FLAG(zn->flags, ZEBRA_NEIGH_LOCAL) &&
+               IS_ZEBRA_NEIGH_ACTIVE(zn)) {
+               zmac = zvni_mac_lookup(wctx->zvni, &zn->emac);
+               if (!zmac)
+                       return;
+
+               zvni_neigh_send_add_to_client(wctx->zvni->vni, &zn->ip,
+                                               &zn->emac, zn->flags,
+                                               zn->loc_seq);
+       }
+}
+
+/* Iterator of a specific L2VNI */
+static void zvni_send_neigh_to_client(zebra_vni_t *zvni)
+{
+       struct neigh_walk_ctx wctx;
+
+       memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
+       wctx.zvni = zvni;
+
+       hash_iterate(zvni->neigh_table, zvni_send_neigh_hash_entry_to_client,
+                       &wctx);
+}
+
+static void zvni_evpn_cfg_cleanup(struct hash_bucket *bucket, void *ctxt)
+{
+       zebra_vni_t *zvni = NULL;
+
+       zvni = (zebra_vni_t *)bucket->data;
+       zvni->advertise_gw_macip = 0;
+       zvni->advertise_svi_macip = 0;
+       zvni->advertise_subnet = 0;
+
+       zvni_neigh_del_all(zvni, 1, 0,
+                          DEL_REMOTE_NEIGH | DEL_REMOTE_NEIGH_FROM_VTEP);
+       zvni_mac_del_all(zvni, 1, 0,
+                        DEL_REMOTE_MAC | DEL_REMOTE_MAC_FROM_VTEP);
+       zvni_vtep_del_all(zvni, 1);
+}
+
+/* Cleanup EVPN configuration of a specific VRF */
+static void zebra_evpn_vrf_cfg_cleanup(struct zebra_vrf *zvrf)
+{
+       zebra_l3vni_t *zl3vni = NULL;
+
+       zvrf->advertise_all_vni = 0;
+       zvrf->advertise_gw_macip = 0;
+       zvrf->advertise_svi_macip = 0;
+       zvrf->vxlan_flood_ctrl = VXLAN_FLOOD_HEAD_END_REPL;
+
+       hash_iterate(zvrf->vni_table, zvni_evpn_cfg_cleanup, NULL);
+
+       if (zvrf->l3vni)
+               zl3vni = zl3vni_lookup(zvrf->l3vni);
+       if (zl3vni) {
+               /* delete and uninstall all rmacs */
+               hash_iterate(zl3vni->rmac_table, zl3vni_del_rmac_hash_entry,
+                            zl3vni);
+               /* delete and uninstall all next-hops */
+               hash_iterate(zl3vni->nh_table, zl3vni_del_nh_hash_entry,
+                            zl3vni);
+       }
+}
+
+/* Cleanup BGP EVPN configuration upon client disconnect */
+static int zebra_evpn_bgp_cfg_clean_up(struct zserv *client)
+{
+       struct vrf *vrf;
+       struct zebra_vrf *zvrf;
+
+       RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
+               zvrf = vrf->info;
+               if (zvrf)
+                       zebra_evpn_vrf_cfg_cleanup(zvrf);
+       }
+
+       return 0;
+}
+
+static int zebra_evpn_pim_cfg_clean_up(struct zserv *client)
+{
+       struct zebra_vrf *zvrf = zebra_vrf_get_evpn();
+
+       if (CHECK_FLAG(zvrf->flags, ZEBRA_PIM_SEND_VXLAN_SG)) {
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug("VxLAN SG updates to PIM, stop");
+               UNSET_FLAG(zvrf->flags, ZEBRA_PIM_SEND_VXLAN_SG);
+       }
+
+       return 0;
+}
+
+static int zebra_evpn_cfg_clean_up(struct zserv *client)
+{
+       if (client->proto == ZEBRA_ROUTE_BGP)
+               return zebra_evpn_bgp_cfg_clean_up(client);
+
+       if (client->proto == ZEBRA_ROUTE_PIM)
+               return zebra_evpn_pim_cfg_clean_up(client);
+
+       return 0;
+}
+
+/* Cleanup BGP EVPN configuration upon client disconnect */
+extern void zebra_evpn_init(void)
+{
+       hook_register(zserv_client_close, zebra_evpn_cfg_clean_up);
+}