diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index ef9e607abeed..2c09792e7c60 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -5328,7 +5328,8 @@ static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p, * * NOTE: NO need to pop the VPN routes in two cases * 1) In free_vni_entry - * - Called by bgp_free()->bgp_evpn_cleanup(). + * - Called by bgp_free()->bgp_evpn_cleanup() or + * bgp_delete()->bgp_evpn_cleanup() when terminating. * - Since bgp_delete is called before bgp_free and we pop all the dest * pertaining to bgp under delete. * 2) evpn_delete_vni() when user configures "no vni" since the withdraw @@ -7587,6 +7588,10 @@ void bgp_evpn_cleanup_on_disable(struct bgp *bgp) */ void bgp_evpn_cleanup(struct bgp *bgp) { + /* Guard against double-call during termination */ + if (!bgp->vnihash) + return; + hash_iterate(bgp->vnihash, (void (*)(struct hash_bucket *, void *))free_vni_entry, bgp); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 415a21d9897d..d393563aeade 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -7252,7 +7252,7 @@ void bgp_cleanup_routes(struct bgp *bgp) /* * VPN and ENCAP and EVPN tables are two-level (RD is top level) */ - if (safi != SAFI_MPLS_VPN && IS_BGP_INSTANCE_HIDDEN(bgp)) + if (safi != SAFI_MPLS_VPN && IS_BGP_INSTANCE_HIDDEN(bgp) && !bm->terminating) continue; for (dest = bgp_table_top(bgp->rib[afi][safi]); dest; dest = bgp_route_next(dest)) { diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 6153889994f9..04c8f76d7f37 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -4348,6 +4348,14 @@ int bgp_delete(struct bgp *bgp) bgp_cleanup_routes(bgp); + if (bm->terminating) + /* + * Release EVPN VNI bgp_lock references so the + * subsequent bgp_unlock() can drive refcount to + * zero and trigger bgp_free(). + */ + bgp_evpn_cleanup(bgp); + for (afi = 0; afi < AFI_MAX; ++afi) { if (!bgp->vpn_policy[afi].import_redirect_rtlist) continue;