diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 14197791f808..57d4e2649312 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -5377,7 +5377,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 @@ -7770,6 +7771,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 c22f8e89dec2..110cbf2edc13 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -8030,7 +8030,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 8c99a6d039fd..2fbcc72df558 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -4590,6 +4590,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;