* [PATCH frr v2 0/3] Backport FRR EVPN local RT2 leaking fixes
@ 2026-05-15 12:03 Gabriel Goller
2026-05-15 12:03 ` [PATCH frr v2 1/3] frr: backport "bgpd: fix valgrind memory leaks on daemon shutdown" (#21511) Gabriel Goller
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Gabriel Goller @ 2026-05-15 12:03 UTC (permalink / raw)
To: pve-devel
Since packaging 10.6.1, we also pull in the EVPN local RT2 leaking patches
(which are applied on upstream master).
The RT2 route leaking PR seems to have some race-condition-related problems,
namely a crash at bgp router shutdown and one case in which the rt2 route is not
leaked (see the last comment at #20005 [1]).
I was not able to reproduce both of these issues, but they seem to be fixed in
the upstream CI with #21844 [2], which solves multiple memory-related issues in
multiple dameons. This PR also needs the #21511 [3] PR as a prerequisite.
In order to be on the safe side, pull these in.
The backporting was a bit of a struggle, because frr-10.6.1..master now also
contains the new BGP-LS address-family (again, after it was reverted out of 10.5
:)) which changes a lot of core bgp structures.
[1]: https://github.com/FRRouting/frr/pull/20005
[2]: https://github.com/FRRouting/frr/pull/21844
[3]: https://github.com/FRRouting/frr/pull/21511
Changelog:
v2:
* instead of absorbing the fix into the commits of #20005, cherry pick the
fixing commit from #21511
frr:
Gabriel Goller (3):
frr: backport "bgpd: fix valgrind memory leaks on daemon shutdown"
(#21511)
frr: backport the "Memory leak problems." (#21844) upstream PR
bump to version 10.6.1-1+pve2
debian/changelog | 6 +
debian/patches/series | 21 +
...rind-memory-leaks-on-daemon-shutdown.patch | 89 ++
...nup-complaint-about-unneeded-destroy.patch | 77 ++
...p-termination-cleanup-of-memory-leak.patch | 47 +
.../0008-lib-ferr-memory-leaked.patch | 48 +
...fpm_listener-has-signal-handlers-now.patch | 55 ++
...g-file-isisd.log-from-all-isis-tests.patch | 883 ++++++++++++++++++
...-tests-Tell-fpm_listener-to-shutdown.patch | 52 ++
...sd-Clean-up-and-memory-leaks-in-isis.patch | 324 +++++++
...gpd-Cleanup-memory-leaks-on-shutdown.patch | 608 ++++++++++++
...ipd-Cleanup-memory-leaks-on-shutdown.patch | 58 ++
...-termination-cleanup-of-memory-leaks.patch | 126 +++
...eanup-nhrpd-termination-memory-leaks.patch | 105 +++
...rpd-memory-leaks-on-shutdown-cleanup.patch | 80 ++
.../0018-ospfd-memory-leaks-on-shutdown.patch | 38 +
...ry-leaks-in-shutdown-in-affinitymaps.patch | 32 +
...bra-cleanup-memory-leaks-on-shutdown.patch | 175 ++++
...-ldpd-Fixup-memory-leaks-on-shutdown.patch | 207 ++++
.../0022-Cleanup-snmp-memory-leaks.patch | 121 +++
...cleanup-of-leaked-memory-on-shutdown.patch | 41 +
...opotest-fail-if-a-memory-leak-is-det.patch | 126 +++
...hash_clean_and_free-remove-hash_free.patch | 480 ++++++++++
23 files changed, 3799 insertions(+)
create mode 100644 debian/patches/upstream/0005-bgpd-fix-valgrind-memory-leaks-on-daemon-shutdown.patch
create mode 100644 debian/patches/upstream/0006-pim6d-cleanup-complaint-about-unneeded-destroy.patch
create mode 100644 debian/patches/upstream/0007-lib-nexthop-group-termination-cleanup-of-memory-leak.patch
create mode 100644 debian/patches/upstream/0008-lib-ferr-memory-leaked.patch
create mode 100644 debian/patches/upstream/0009-zebra-fpm_listener-has-signal-handlers-now.patch
create mode 100644 debian/patches/upstream/0010-tests-Remove-log-file-isisd.log-from-all-isis-tests.patch
create mode 100644 debian/patches/upstream/0011-tests-Tell-fpm_listener-to-shutdown.patch
create mode 100644 debian/patches/upstream/0012-isisd-Clean-up-and-memory-leaks-in-isis.patch
create mode 100644 debian/patches/upstream/0013-bgpd-Cleanup-memory-leaks-on-shutdown.patch
create mode 100644 debian/patches/upstream/0014-ripd-Cleanup-memory-leaks-on-shutdown.patch
create mode 100644 debian/patches/upstream/0015-pbrd-termination-cleanup-of-memory-leaks.patch
create mode 100644 debian/patches/upstream/0016-nhrpd-Cleanup-nhrpd-termination-memory-leaks.patch
create mode 100644 debian/patches/upstream/0017-sharpd-memory-leaks-on-shutdown-cleanup.patch
create mode 100644 debian/patches/upstream/0018-ospfd-memory-leaks-on-shutdown.patch
create mode 100644 debian/patches/upstream/0019-lib-Cleanup-memory-leaks-in-shutdown-in-affinitymaps.patch
create mode 100644 debian/patches/upstream/0020-zebra-cleanup-memory-leaks-on-shutdown.patch
create mode 100644 debian/patches/upstream/0021-ldpd-Fixup-memory-leaks-on-shutdown.patch
create mode 100644 debian/patches/upstream/0022-Cleanup-snmp-memory-leaks.patch
create mode 100644 debian/patches/upstream/0023-pimd-cleanup-of-leaked-memory-on-shutdown.patch
create mode 100644 debian/patches/upstream/0024-tests-make-the-topotest-fail-if-a-memory-leak-is-det.patch
create mode 100644 debian/patches/upstream/0025-Use-hash_clean_and_free-remove-hash_free.patch
Summary over all repositories:
23 files changed, 3799 insertions(+), 0 deletions(-)
--
Generated by murpp 0.11.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH frr v2 1/3] frr: backport "bgpd: fix valgrind memory leaks on daemon shutdown" (#21511)
2026-05-15 12:03 [PATCH frr v2 0/3] Backport FRR EVPN local RT2 leaking fixes Gabriel Goller
@ 2026-05-15 12:03 ` Gabriel Goller
2026-05-15 12:03 ` [PATCH frr v2 2/3] frr: backport the "Memory leak problems." (#21844) upstream PR Gabriel Goller
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Gabriel Goller @ 2026-05-15 12:03 UTC (permalink / raw)
To: pve-devel
Backport the "bgpd: fix valgrind memory leaks on daemon shutdown"
(#21511) PR [1], which is a prerequisite for the PR [2] that fixes the
EVPN local RT2 leaking data-races.
[1]: https://github.com/FRRouting/frr/pull/21511
[2]: https://github.com/FRRouting/frr/pull/21844
Signed-off-by: Gabriel Goller <g.goller@proxmox.com>
---
debian/patches/series | 1 +
...rind-memory-leaks-on-daemon-shutdown.patch | 89 +++++++++++++++++++
2 files changed, 90 insertions(+)
create mode 100644 debian/patches/upstream/0005-bgpd-fix-valgrind-memory-leaks-on-daemon-shutdown.patch
diff --git a/debian/patches/series b/debian/patches/series
index fed297922f2d..89587e528948 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -2,6 +2,7 @@ upstream/0001-bgpd-fix-EVPN-VRF-auto-RT-deletion-collision.patch
upstream/0002-bgpd-export-local-rt2-mac-ip-entries-to-unicast.patch
upstream/0003-bgpd-do-not-add-local-vtep-as-remote.patch
upstream/0004-topotests-add-bgp_evpn_rt2_local_leak.patch
+upstream/0005-bgpd-fix-valgrind-memory-leaks-on-daemon-shutdown.patch
pve/0001-enable-bgp-bfd-daemons.patch
pve/0002-bgpd-add-an-option-for-RT-auto-derivation-to-force-A.patch
pve/0003-tests-add-bgp-evpn-autort-test.patch
diff --git a/debian/patches/upstream/0005-bgpd-fix-valgrind-memory-leaks-on-daemon-shutdown.patch b/debian/patches/upstream/0005-bgpd-fix-valgrind-memory-leaks-on-daemon-shutdown.patch
new file mode 100644
index 000000000000..12eb4e2b3b16
--- /dev/null
+++ b/debian/patches/upstream/0005-bgpd-fix-valgrind-memory-leaks-on-daemon-shutdown.patch
@@ -0,0 +1,89 @@
+From 3e5d7c3b53175b8ce44bc4e34d217e745a1d5e32 Mon Sep 17 00:00:00 2001
+From: souroy <souroy@nvidia.com>
+Date: Fri, 10 Apr 2026 22:11:51 -0700
+Subject: [PATCH 01/21] bgpd: fix valgrind memory leaks on daemon shutdown
+
+During daemon termination, the default BGP instance leaks due to
+two issues:
+
+First, bgp_cleanup_routes() skips EVPN and ENCAP two-level table
+cleanup for hidden instances, leaving route entries. Add a terminating
+check so these tables are always cleaned during shutdown.
+
+Second, a circular dependency exists between bgp_free() and VNI lock
+release: each L2VNI holds a bgp_lock on the default instance via
+bgpevpn_link_to_l3vni(), but the only code that releases these locks
+(bgp_evpn_cleanup -> free_vni_entry -> bgpevpn_unlink_from_l3vni) lives
+inside bgp_free(), which only runs when the lock count reaches zero.
+Break this cycle by calling bgp_evpn_cleanup() from bgp_delete() during
+termination, before the final bgp_unlock(). This releases VNI-held
+locks so the refcount can reach zero and bgp_free() actually executes.
+
+Signed-off-by: Soumya Roy <souroy@nvidia.com>
+---
+ bgpd/bgp_evpn.c | 7 ++++++-
+ bgpd/bgp_route.c | 2 +-
+ bgpd/bgpd.c | 9 +++++++++
+ 3 files changed, 16 insertions(+), 2 deletions(-)
+
+diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
+index 4e5bd96c5b54..5d1122e34554 100644
+--- a/bgpd/bgp_evpn.c
++++ b/bgpd/bgp_evpn.c
+@@ -5370,7 +5370,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
+@@ -7741,6 +7742,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 351f01ef4077..778b1ce214c8 100644
+--- a/bgpd/bgp_route.c
++++ b/bgpd/bgp_route.c
+@@ -7973,7 +7973,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 116bef933995..ef8ebea216d6 100644
+--- a/bgpd/bgpd.c
++++ b/bgpd/bgpd.c
+@@ -4418,6 +4418,15 @@ 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;
+--
+2.47.3
+
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH frr v2 2/3] frr: backport the "Memory leak problems." (#21844) upstream PR
2026-05-15 12:03 [PATCH frr v2 0/3] Backport FRR EVPN local RT2 leaking fixes Gabriel Goller
2026-05-15 12:03 ` [PATCH frr v2 1/3] frr: backport "bgpd: fix valgrind memory leaks on daemon shutdown" (#21511) Gabriel Goller
@ 2026-05-15 12:03 ` Gabriel Goller
2026-05-15 12:03 ` [PATCH frr v2 3/3] bump to version 10.6.1-1+pve2 Gabriel Goller
2026-05-16 23:59 ` [PATCH frr v2 0/3] Backport FRR EVPN local RT2 leaking fixes Thomas Lamprecht
3 siblings, 0 replies; 5+ messages in thread
From: Gabriel Goller @ 2026-05-15 12:03 UTC (permalink / raw)
To: pve-devel
The RT2 route leaking PR looks to have some race-condition-related
problems, namely a crash at bgp router shutdown and one case in which
the rt2 route is not leaked (see the last comment at #20005 [1]).
I was not able to reproduce both of these issues, but they seem to
be fixed in the upstream CI with #21844 [2], which solves multiple
memory-related issues in multiple dameons.
In order to be on the safe side, pull these in.
The backporting was a bit of a struggle, because frr-10.6.1::master now
also contains the new BGP-LS address-family (again, after it was
reverted out of 10.5 :)) which changes a lot of core bgp structures.
[1]: https://github.com/FRRouting/frr/pull/20005
[2]: https://github.com/FRRouting/frr/pull/21844
Signed-off-by: Gabriel Goller <g.goller@proxmox.com>
---
debian/patches/series | 20 +
...nup-complaint-about-unneeded-destroy.patch | 77 ++
...p-termination-cleanup-of-memory-leak.patch | 47 +
.../0008-lib-ferr-memory-leaked.patch | 48 +
...fpm_listener-has-signal-handlers-now.patch | 55 ++
...g-file-isisd.log-from-all-isis-tests.patch | 883 ++++++++++++++++++
...-tests-Tell-fpm_listener-to-shutdown.patch | 52 ++
...sd-Clean-up-and-memory-leaks-in-isis.patch | 324 +++++++
...gpd-Cleanup-memory-leaks-on-shutdown.patch | 608 ++++++++++++
...ipd-Cleanup-memory-leaks-on-shutdown.patch | 58 ++
...-termination-cleanup-of-memory-leaks.patch | 126 +++
...eanup-nhrpd-termination-memory-leaks.patch | 105 +++
...rpd-memory-leaks-on-shutdown-cleanup.patch | 80 ++
.../0018-ospfd-memory-leaks-on-shutdown.patch | 38 +
...ry-leaks-in-shutdown-in-affinitymaps.patch | 32 +
...bra-cleanup-memory-leaks-on-shutdown.patch | 175 ++++
...-ldpd-Fixup-memory-leaks-on-shutdown.patch | 207 ++++
.../0022-Cleanup-snmp-memory-leaks.patch | 121 +++
...cleanup-of-leaked-memory-on-shutdown.patch | 41 +
...opotest-fail-if-a-memory-leak-is-det.patch | 126 +++
...hash_clean_and_free-remove-hash_free.patch | 480 ++++++++++
21 files changed, 3703 insertions(+)
create mode 100644 debian/patches/upstream/0006-pim6d-cleanup-complaint-about-unneeded-destroy.patch
create mode 100644 debian/patches/upstream/0007-lib-nexthop-group-termination-cleanup-of-memory-leak.patch
create mode 100644 debian/patches/upstream/0008-lib-ferr-memory-leaked.patch
create mode 100644 debian/patches/upstream/0009-zebra-fpm_listener-has-signal-handlers-now.patch
create mode 100644 debian/patches/upstream/0010-tests-Remove-log-file-isisd.log-from-all-isis-tests.patch
create mode 100644 debian/patches/upstream/0011-tests-Tell-fpm_listener-to-shutdown.patch
create mode 100644 debian/patches/upstream/0012-isisd-Clean-up-and-memory-leaks-in-isis.patch
create mode 100644 debian/patches/upstream/0013-bgpd-Cleanup-memory-leaks-on-shutdown.patch
create mode 100644 debian/patches/upstream/0014-ripd-Cleanup-memory-leaks-on-shutdown.patch
create mode 100644 debian/patches/upstream/0015-pbrd-termination-cleanup-of-memory-leaks.patch
create mode 100644 debian/patches/upstream/0016-nhrpd-Cleanup-nhrpd-termination-memory-leaks.patch
create mode 100644 debian/patches/upstream/0017-sharpd-memory-leaks-on-shutdown-cleanup.patch
create mode 100644 debian/patches/upstream/0018-ospfd-memory-leaks-on-shutdown.patch
create mode 100644 debian/patches/upstream/0019-lib-Cleanup-memory-leaks-in-shutdown-in-affinitymaps.patch
create mode 100644 debian/patches/upstream/0020-zebra-cleanup-memory-leaks-on-shutdown.patch
create mode 100644 debian/patches/upstream/0021-ldpd-Fixup-memory-leaks-on-shutdown.patch
create mode 100644 debian/patches/upstream/0022-Cleanup-snmp-memory-leaks.patch
create mode 100644 debian/patches/upstream/0023-pimd-cleanup-of-leaked-memory-on-shutdown.patch
create mode 100644 debian/patches/upstream/0024-tests-make-the-topotest-fail-if-a-memory-leak-is-det.patch
create mode 100644 debian/patches/upstream/0025-Use-hash_clean_and_free-remove-hash_free.patch
diff --git a/debian/patches/series b/debian/patches/series
index 89587e528948..a6af3bcdc3c4 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -3,6 +3,26 @@ upstream/0002-bgpd-export-local-rt2-mac-ip-entries-to-unicast.patch
upstream/0003-bgpd-do-not-add-local-vtep-as-remote.patch
upstream/0004-topotests-add-bgp_evpn_rt2_local_leak.patch
upstream/0005-bgpd-fix-valgrind-memory-leaks-on-daemon-shutdown.patch
+upstream/0006-pim6d-cleanup-complaint-about-unneeded-destroy.patch
+upstream/0007-lib-nexthop-group-termination-cleanup-of-memory-leak.patch
+upstream/0008-lib-ferr-memory-leaked.patch
+upstream/0009-zebra-fpm_listener-has-signal-handlers-now.patch
+upstream/0010-tests-Remove-log-file-isisd.log-from-all-isis-tests.patch
+upstream/0011-tests-Tell-fpm_listener-to-shutdown.patch
+upstream/0012-isisd-Clean-up-and-memory-leaks-in-isis.patch
+upstream/0013-bgpd-Cleanup-memory-leaks-on-shutdown.patch
+upstream/0014-ripd-Cleanup-memory-leaks-on-shutdown.patch
+upstream/0015-pbrd-termination-cleanup-of-memory-leaks.patch
+upstream/0016-nhrpd-Cleanup-nhrpd-termination-memory-leaks.patch
+upstream/0017-sharpd-memory-leaks-on-shutdown-cleanup.patch
+upstream/0018-ospfd-memory-leaks-on-shutdown.patch
+upstream/0019-lib-Cleanup-memory-leaks-in-shutdown-in-affinitymaps.patch
+upstream/0020-zebra-cleanup-memory-leaks-on-shutdown.patch
+upstream/0021-ldpd-Fixup-memory-leaks-on-shutdown.patch
+upstream/0022-Cleanup-snmp-memory-leaks.patch
+upstream/0023-pimd-cleanup-of-leaked-memory-on-shutdown.patch
+upstream/0024-tests-make-the-topotest-fail-if-a-memory-leak-is-det.patch
+upstream/0025-Use-hash_clean_and_free-remove-hash_free.patch
pve/0001-enable-bgp-bfd-daemons.patch
pve/0002-bgpd-add-an-option-for-RT-auto-derivation-to-force-A.patch
pve/0003-tests-add-bgp-evpn-autort-test.patch
diff --git a/debian/patches/upstream/0006-pim6d-cleanup-complaint-about-unneeded-destroy.patch b/debian/patches/upstream/0006-pim6d-cleanup-complaint-about-unneeded-destroy.patch
new file mode 100644
index 000000000000..a9415984caec
--- /dev/null
+++ b/debian/patches/upstream/0006-pim6d-cleanup-complaint-about-unneeded-destroy.patch
@@ -0,0 +1,77 @@
+From b08277dc7820b3621e4ecf360f75acb8334c3e19 Mon Sep 17 00:00:00 2001
+From: Donald Sharp <sharpd@nvidia.com>
+Date: Fri, 1 May 2026 16:41:26 -0400
+Subject: [PATCH 02/21] pim6d: cleanup complaint about unneeded destroy
+
+Make the complaint about a unneeded destroy in nb code go away.
+
+Signed-off-by: Donald Sharp <sharpd@nvidia.com>
+---
+ pimd/pim_nb.c | 6 ++++++
+ pimd/pim_nb.h | 1 +
+ pimd/pim_nb_config.c | 20 ++++++++++++++++++++
+ 3 files changed, 27 insertions(+)
+
+diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c
+index 4770536d654f..d76c97623b6a 100644
+--- a/pimd/pim_nb.c
++++ b/pimd/pim_nb.c
+@@ -370,6 +370,12 @@ const struct frr_yang_module_info frr_pim_info = {
+ }
+ },
+ {
++ .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/override-interval",
++ .cbs = {
++ .modify = lib_interface_pim_override_interval_modify,
++ }
++ },
++ {
+ .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/bfd",
+ .cbs = {
+ .create = lib_interface_pim_address_family_bfd_create,
+diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h
+index 287d5ff7cf0c..20e86af769f4 100644
+--- a/pimd/pim_nb.h
++++ b/pimd/pim_nb.h
+@@ -124,6 +124,7 @@ int lib_interface_pim_address_family_nbr_plist_destroy(struct nb_cb_destroy_args
+ int lib_interface_pim_assert_interval_modify(struct nb_cb_modify_args *args);
+ int lib_interface_pim_assert_override_interval_modify(struct nb_cb_modify_args *args);
+ int lib_interface_pim_assert_override_interval_destroy(struct nb_cb_destroy_args *args);
++int lib_interface_pim_override_interval_modify(struct nb_cb_modify_args *args);
+ int lib_interface_pim_address_family_create(struct nb_cb_create_args *args);
+ int lib_interface_pim_address_family_destroy(struct nb_cb_destroy_args *args);
+ int lib_interface_pim_address_family_pim_enable_modify(
+diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c
+index 46417be87e29..ceeaa0802ad2 100644
+--- a/pimd/pim_nb_config.c
++++ b/pimd/pim_nb_config.c
+@@ -2505,6 +2505,26 @@ int lib_interface_pim_assert_override_interval_destroy(struct nb_cb_destroy_args
+ return NB_OK;
+ }
+
++int lib_interface_pim_override_interval_modify(struct nb_cb_modify_args *args)
++{
++ struct interface *ifp;
++ struct pim_interface *pim_ifp;
++
++ switch (args->event) {
++ case NB_EV_VALIDATE:
++ case NB_EV_ABORT:
++ case NB_EV_PREPARE:
++ break;
++ case NB_EV_APPLY:
++ ifp = nb_running_get_entry(args->dnode, NULL, true);
++ pim_ifp = ifp->info;
++ pim_ifp->pim_override_interval_msec = yang_dnode_get_uint16(args->dnode, NULL);
++ break;
++ }
++
++ return NB_OK;
++}
++
+ /*
+ * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/bfd
+ */
+--
+2.47.3
+
diff --git a/debian/patches/upstream/0007-lib-nexthop-group-termination-cleanup-of-memory-leak.patch b/debian/patches/upstream/0007-lib-nexthop-group-termination-cleanup-of-memory-leak.patch
new file mode 100644
index 000000000000..8bd2b2edfb39
--- /dev/null
+++ b/debian/patches/upstream/0007-lib-nexthop-group-termination-cleanup-of-memory-leak.patch
@@ -0,0 +1,47 @@
+From e543bae815e264ee75bbe9dd7b53a6c9ff1965d5 Mon Sep 17 00:00:00 2001
+From: Donald Sharp <sharpd@nvidia.com>
+Date: Fri, 1 May 2026 14:11:23 -0400
+Subject: [PATCH 03/21] lib: nexthop-group termination cleanup of memory leaks
+
+Nexthop groups were leaking memory on shutdown. Add the
+ability to cleanup memory leaks from a using daemon.
+
+Signed-off-by: Donald Sharp <sharpd@nvidia.com>
+---
+ lib/nexthop_group.c | 10 ++++++++++
+ lib/nexthop_group.h | 1 +
+ 2 files changed, 11 insertions(+)
+
+diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c
+index 7ee12079aaa6..5c6a02ae1bcc 100644
+--- a/lib/nexthop_group.c
++++ b/lib/nexthop_group.c
+@@ -1397,3 +1397,13 @@ void nexthop_group_init(void (*new)(const char *name),
+ if (delete)
+ nhg_hooks.delete = delete;
+ }
++
++void nexthop_group_terminate(void)
++{
++ struct nexthop_group_cmd *nhgc;
++
++ while ((nhgc = RB_ROOT(nhgc_entry_head, &nhgc_entries)))
++ nhgc_delete(nhgc);
++
++ memset(&nhg_hooks, 0, sizeof(nhg_hooks));
++}
+diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h
+index e12e341be88d..f96e5780063f 100644
+--- a/lib/nexthop_group.h
++++ b/lib/nexthop_group.h
+@@ -120,6 +120,7 @@ void nexthop_group_init(
+ void (*del_nexthop)(const struct nexthop_group_cmd *nhgc,
+ const struct nexthop *nhop),
+ void (*destroy)(const char *name));
++void nexthop_group_terminate(void);
+
+ void nexthop_group_enable_vrf(struct vrf *vrf);
+ void nexthop_group_disable_vrf(struct vrf *vrf);
+--
+2.47.3
+
diff --git a/debian/patches/upstream/0008-lib-ferr-memory-leaked.patch b/debian/patches/upstream/0008-lib-ferr-memory-leaked.patch
new file mode 100644
index 000000000000..ae03b2f54faf
--- /dev/null
+++ b/debian/patches/upstream/0008-lib-ferr-memory-leaked.patch
@@ -0,0 +1,48 @@
+From 80b48927045505951641df6eeccd357b7b814611 Mon Sep 17 00:00:00 2001
+From: Donald Sharp <sharpd@nvidia.com>
+Date: Sat, 2 May 2026 17:46:17 -0400
+Subject: [PATCH 04/21] lib: ferr memory leaked
+
+Usage of the frr pthread specific error messages were not being
+cleaned up. Make it so.
+
+Signed-off-by: Donald Sharp <sharpd@nvidia.com>
+---
+ lib/ferr.c | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+diff --git a/lib/ferr.c b/lib/ferr.c
+index 33bcb075fa5f..5cfc011fac34 100644
+--- a/lib/ferr.c
++++ b/lib/ferr.c
+@@ -179,9 +179,27 @@ void log_ref_init(void)
+
+ void log_ref_fini(void)
+ {
++ struct ferr *error;
++
+ frr_with_mutex (&refs_mtx) {
+ hash_clean_and_free(&refs, NULL);
+ }
++
++ /*
++ * Worker threads that called any ferr_*() macro have their per-thread
++ * struct ferr freed by ferr_free() through pthread_key_create()'s
++ * destructor when they exit (frr_pthread_finish() joins them earlier
++ * in frr_fini()). The main thread, however, is *itself* the thread
++ * driving shutdown and does not exit through pthread teardown until
++ * after log_memstats() has already dumped active allocations. Free
++ * its slot explicitly here so the lazily-allocated struct ferr (~4512
++ * bytes) is not reported as an "error information" leak.
++ */
++ error = pthread_getspecific(errkey);
++ if (error) {
++ pthread_setspecific(errkey, NULL);
++ ferr_free(error);
++ }
+ }
+
+ void log_ref_vty_init(void)
+--
+2.47.3
+
diff --git a/debian/patches/upstream/0009-zebra-fpm_listener-has-signal-handlers-now.patch b/debian/patches/upstream/0009-zebra-fpm_listener-has-signal-handlers-now.patch
new file mode 100644
index 000000000000..b6be07f97893
--- /dev/null
+++ b/debian/patches/upstream/0009-zebra-fpm_listener-has-signal-handlers-now.patch
@@ -0,0 +1,55 @@
+From 9c445535ae1712e4bf0f153c06a92145c3309d70 Mon Sep 17 00:00:00 2001
+From: Donald Sharp <sharpd@nvidia.com>
+Date: Sun, 3 May 2026 12:22:33 -0400
+Subject: [PATCH 05/21] zebra: fpm_listener has signal handlers now
+
+Add signal handlers for fpm_listener.c. This will allow
+it to be shutdown cleanly, such that gcoverage can work.
+
+Signed-off-by: Donald Sharp <sharpd@nvidia.com>
+---
+ zebra/fpm_listener.c | 21 +++++++++++++++++++++
+ 1 file changed, 21 insertions(+)
+
+diff --git a/zebra/fpm_listener.c b/zebra/fpm_listener.c
+index 491062001e7f..098421a9fb33 100644
+--- a/zebra/fpm_listener.c
++++ b/zebra/fpm_listener.c
+@@ -1120,6 +1120,11 @@ static void fpm_serve(void)
+ }
+ }
+
++static void sigterm_handler(int signum)
++{
++ exit(0);
++}
++
+ /* Signal handler for SIGUSR1 */
+ static void sigusr1_handler(int signum)
+ {
+@@ -1214,6 +1219,22 @@ int main(int argc, char **argv)
+ exit(1);
+ }
+
++ memset(&sa, 0, sizeof(sa));
++ sa.sa_handler = sigterm_handler;
++ sigemptyset(&sa.sa_mask);
++ if (sigaction(SIGTERM, &sa, NULL) < 0) {
++ fprintf(stderr, "Failed to set up SIGTERM handler: %s\n", strerror(errno));
++ exit(1);
++ }
++ if (sigaction(SIGINT, &sa, NULL) < 0) {
++ fprintf(stderr, "Failed to set up SIGINT handler: %s\n", strerror(errno));
++ exit(1);
++ }
++ if (sigaction(SIGHUP, &sa, NULL) < 0) {
++ fprintf(stderr, "Failed to set up SIGHUP handler: %s\n", strerror(errno));
++ exit(1);
++ }
++
+ while ((r = getopt(argc, argv, "rfdvo:z:")) != -1) {
+ switch (r) {
+ case 'r':
+--
+2.47.3
+
diff --git a/debian/patches/upstream/0010-tests-Remove-log-file-isisd.log-from-all-isis-tests.patch b/debian/patches/upstream/0010-tests-Remove-log-file-isisd.log-from-all-isis-tests.patch
new file mode 100644
index 000000000000..e9ceee277599
--- /dev/null
+++ b/debian/patches/upstream/0010-tests-Remove-log-file-isisd.log-from-all-isis-tests.patch
@@ -0,0 +1,883 @@
+From 08f033dc1813d8ab237c8716d1520052fa23438a Mon Sep 17 00:00:00 2001
+From: Donald Sharp <sharpd@nvidia.com>
+Date: Fri, 1 May 2026 12:52:10 -0400
+Subject: [PATCH 06/21] tests: Remove `log file isisd.log` from all isis tests
+
+This is not necessary, remove.
+
+Signed-off-by: Donald Sharp <sharpd@nvidia.com>
+---
+ tests/topotests/all_protocol_startup/r1/isisd.conf | 1 -
+ tests/topotests/isis_lfa_topo1/rt1/isisd.conf | 1 -
+ tests/topotests/isis_lfa_topo1/rt2/isisd.conf | 1 -
+ tests/topotests/isis_lfa_topo1/rt3/isisd.conf | 1 -
+ tests/topotests/isis_lfa_topo1/rt4/isisd.conf | 1 -
+ tests/topotests/isis_lfa_topo1/rt5/isisd.conf | 1 -
+ tests/topotests/isis_lfa_topo1/rt6/isisd.conf | 1 -
+ tests/topotests/isis_lfa_topo1/rt7/isisd.conf | 1 -
+ tests/topotests/isis_lsp_bits_topo1/rt1/isisd.conf | 1 -
+ tests/topotests/isis_lsp_bits_topo1/rt2/isisd.conf | 1 -
+ tests/topotests/isis_lsp_bits_topo1/rt3/isisd.conf | 1 -
+ tests/topotests/isis_lsp_bits_topo1/rt4/isisd.conf | 1 -
+ tests/topotests/isis_lsp_bits_topo1/rt5/isisd.conf | 1 -
+ tests/topotests/isis_lsp_bits_topo1/rt6/isisd.conf | 1 -
+ tests/topotests/isis_rlfa_topo1/rt1/isisd.conf | 1 -
+ tests/topotests/isis_rlfa_topo1/rt2/isisd.conf | 1 -
+ tests/topotests/isis_rlfa_topo1/rt3/isisd.conf | 1 -
+ tests/topotests/isis_rlfa_topo1/rt4/isisd.conf | 1 -
+ tests/topotests/isis_rlfa_topo1/rt5/isisd.conf | 1 -
+ tests/topotests/isis_rlfa_topo1/rt6/isisd.conf | 1 -
+ tests/topotests/isis_rlfa_topo1/rt7/isisd.conf | 1 -
+ tests/topotests/isis_rlfa_topo1/rt8/isisd.conf | 1 -
+ tests/topotests/isis_snmp/r1/isisd.conf | 1 -
+ tests/topotests/isis_snmp/r2/isisd.conf | 1 -
+ tests/topotests/isis_snmp/r3/isisd.conf | 1 -
+ tests/topotests/isis_snmp/r4/isisd.conf | 1 -
+ tests/topotests/isis_snmp/r5/isisd.conf | 1 -
+ tests/topotests/isis_sr_flex_algo_topo1/rt1/isisd.conf | 1 -
+ tests/topotests/isis_sr_flex_algo_topo1/rt2/isisd.conf | 1 -
+ tests/topotests/isis_sr_flex_algo_topo1/rt3/isisd.conf | 1 -
+ tests/topotests/isis_sr_flex_algo_topo2/rt0/isisd.conf | 1 -
+ tests/topotests/isis_sr_flex_algo_topo2/rt1/isisd.conf | 1 -
+ tests/topotests/isis_sr_flex_algo_topo2/rt2/isisd.conf | 1 -
+ tests/topotests/isis_sr_flex_algo_topo2/rt3/isisd.conf | 1 -
+ tests/topotests/isis_sr_flex_algo_topo2/rt4/isisd.conf | 1 -
+ tests/topotests/isis_sr_flex_algo_topo2/rt5/isisd.conf | 1 -
+ tests/topotests/isis_sr_flex_algo_topo2/rt6/isisd.conf | 1 -
+ tests/topotests/isis_sr_flex_algo_topo2/rt7/isisd.conf | 1 -
+ tests/topotests/isis_sr_flex_algo_topo2/rt8/isisd.conf | 1 -
+ tests/topotests/isis_sr_flex_algo_topo2/rt9/isisd.conf | 1 -
+ tests/topotests/isis_sr_te_topo1/rt1/isisd.conf | 1 -
+ tests/topotests/isis_sr_te_topo1/rt2/isisd.conf | 1 -
+ tests/topotests/isis_sr_te_topo1/rt3/isisd.conf | 1 -
+ tests/topotests/isis_sr_te_topo1/rt4/isisd.conf | 1 -
+ tests/topotests/isis_sr_te_topo1/rt5/isisd.conf | 1 -
+ tests/topotests/isis_sr_te_topo1/rt6/isisd.conf | 1 -
+ tests/topotests/isis_sr_topo1/rt1/isisd.conf | 1 -
+ tests/topotests/isis_sr_topo1/rt2/isisd.conf | 1 -
+ tests/topotests/isis_sr_topo1/rt3/isisd.conf | 1 -
+ tests/topotests/isis_sr_topo1/rt4/isisd.conf | 1 -
+ tests/topotests/isis_sr_topo1/rt5/isisd.conf | 1 -
+ tests/topotests/isis_sr_topo1/rt6/isisd.conf | 1 -
+ tests/topotests/isis_srv6_topo1/rt1/isisd.conf | 1 -
+ tests/topotests/isis_srv6_topo1/rt2/isisd.conf | 1 -
+ tests/topotests/isis_srv6_topo1/rt3/isisd.conf | 1 -
+ tests/topotests/isis_srv6_topo1/rt4/isisd.conf | 1 -
+ tests/topotests/isis_srv6_topo1/rt5/isisd.conf | 1 -
+ tests/topotests/isis_srv6_topo1/rt6/isisd.conf | 1 -
+ tests/topotests/isis_tilfa_topo1/rt1/isisd.conf | 1 -
+ tests/topotests/isis_tilfa_topo1/rt2/isisd.conf | 1 -
+ tests/topotests/isis_tilfa_topo1/rt3/isisd.conf | 1 -
+ tests/topotests/isis_tilfa_topo1/rt4/isisd.conf | 1 -
+ tests/topotests/isis_tilfa_topo1/rt5/isisd.conf | 1 -
+ tests/topotests/isis_tilfa_topo1/rt6/isisd.conf | 1 -
+ tests/topotests/ldp_snmp/r1/isisd.conf | 1 -
+ tests/topotests/ldp_snmp/r2/isisd.conf | 1 -
+ tests/topotests/ldp_snmp/r3/isisd.conf | 1 -
+ tests/topotests/ldp_sync_isis_topo1/r1/isisd.conf | 1 -
+ tests/topotests/ldp_sync_isis_topo1/r2/isisd.conf | 1 -
+ tests/topotests/ldp_sync_isis_topo1/r3/isisd.conf | 1 -
+ tests/topotests/srv6_sid_manager/rt1/isisd.conf | 1 -
+ tests/topotests/srv6_sid_manager/rt2/isisd.conf | 1 -
+ tests/topotests/srv6_sid_manager/rt3/isisd.conf | 1 -
+ tests/topotests/srv6_sid_manager/rt4/isisd.conf | 1 -
+ tests/topotests/srv6_sid_manager/rt5/isisd.conf | 1 -
+ tests/topotests/srv6_sid_manager/rt6/isisd.conf | 1 -
+ 76 files changed, 76 deletions(-)
+
+diff --git a/tests/topotests/all_protocol_startup/r1/isisd.conf b/tests/topotests/all_protocol_startup/r1/isisd.conf
+index 8ceded894fc7..b94b6fac8d0a 100644
+--- a/tests/topotests/all_protocol_startup/r1/isisd.conf
++++ b/tests/topotests/all_protocol_startup/r1/isisd.conf
+@@ -1,4 +1,3 @@
+-log file isisd.log
+ !
+ ! debug isis events
+ !
+diff --git a/tests/topotests/isis_lfa_topo1/rt1/isisd.conf b/tests/topotests/isis_lfa_topo1/rt1/isisd.conf
+index fc81df02cb8c..db580017386d 100644
+--- a/tests/topotests/isis_lfa_topo1/rt1/isisd.conf
++++ b/tests/topotests/isis_lfa_topo1/rt1/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt1
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_lfa_topo1/rt2/isisd.conf b/tests/topotests/isis_lfa_topo1/rt2/isisd.conf
+index 6981692add18..6a75d11bc5cb 100644
+--- a/tests/topotests/isis_lfa_topo1/rt2/isisd.conf
++++ b/tests/topotests/isis_lfa_topo1/rt2/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt2
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_lfa_topo1/rt3/isisd.conf b/tests/topotests/isis_lfa_topo1/rt3/isisd.conf
+index e3ddb0984b5f..175646390f29 100644
+--- a/tests/topotests/isis_lfa_topo1/rt3/isisd.conf
++++ b/tests/topotests/isis_lfa_topo1/rt3/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt3
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_lfa_topo1/rt4/isisd.conf b/tests/topotests/isis_lfa_topo1/rt4/isisd.conf
+index 4db5c8ed057d..cd1311340ed4 100644
+--- a/tests/topotests/isis_lfa_topo1/rt4/isisd.conf
++++ b/tests/topotests/isis_lfa_topo1/rt4/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt4
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_lfa_topo1/rt5/isisd.conf b/tests/topotests/isis_lfa_topo1/rt5/isisd.conf
+index 1206a4e51f82..c028cc0280e5 100644
+--- a/tests/topotests/isis_lfa_topo1/rt5/isisd.conf
++++ b/tests/topotests/isis_lfa_topo1/rt5/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt5
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_lfa_topo1/rt6/isisd.conf b/tests/topotests/isis_lfa_topo1/rt6/isisd.conf
+index 2ba9e4991960..6a40f52d6f4e 100644
+--- a/tests/topotests/isis_lfa_topo1/rt6/isisd.conf
++++ b/tests/topotests/isis_lfa_topo1/rt6/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt6
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_lfa_topo1/rt7/isisd.conf b/tests/topotests/isis_lfa_topo1/rt7/isisd.conf
+index 060be2bf6d08..421ed25b5154 100644
+--- a/tests/topotests/isis_lfa_topo1/rt7/isisd.conf
++++ b/tests/topotests/isis_lfa_topo1/rt7/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt6
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_lsp_bits_topo1/rt1/isisd.conf b/tests/topotests/isis_lsp_bits_topo1/rt1/isisd.conf
+index 51bf7e60a5d5..777899812e32 100644
+--- a/tests/topotests/isis_lsp_bits_topo1/rt1/isisd.conf
++++ b/tests/topotests/isis_lsp_bits_topo1/rt1/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt1
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_lsp_bits_topo1/rt2/isisd.conf b/tests/topotests/isis_lsp_bits_topo1/rt2/isisd.conf
+index 96c9f33dae4e..6bdb7612ca0b 100644
+--- a/tests/topotests/isis_lsp_bits_topo1/rt2/isisd.conf
++++ b/tests/topotests/isis_lsp_bits_topo1/rt2/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt2
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_lsp_bits_topo1/rt3/isisd.conf b/tests/topotests/isis_lsp_bits_topo1/rt3/isisd.conf
+index c3354f2e68c3..14cb6eaabc1f 100644
+--- a/tests/topotests/isis_lsp_bits_topo1/rt3/isisd.conf
++++ b/tests/topotests/isis_lsp_bits_topo1/rt3/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt3
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_lsp_bits_topo1/rt4/isisd.conf b/tests/topotests/isis_lsp_bits_topo1/rt4/isisd.conf
+index f1627e75473b..c1f5cdca820b 100644
+--- a/tests/topotests/isis_lsp_bits_topo1/rt4/isisd.conf
++++ b/tests/topotests/isis_lsp_bits_topo1/rt4/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt4
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_lsp_bits_topo1/rt5/isisd.conf b/tests/topotests/isis_lsp_bits_topo1/rt5/isisd.conf
+index 41241590d14c..0c4b6b04ac80 100644
+--- a/tests/topotests/isis_lsp_bits_topo1/rt5/isisd.conf
++++ b/tests/topotests/isis_lsp_bits_topo1/rt5/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt5
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_lsp_bits_topo1/rt6/isisd.conf b/tests/topotests/isis_lsp_bits_topo1/rt6/isisd.conf
+index b66f40e9ee64..553e94974351 100644
+--- a/tests/topotests/isis_lsp_bits_topo1/rt6/isisd.conf
++++ b/tests/topotests/isis_lsp_bits_topo1/rt6/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt6
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_rlfa_topo1/rt1/isisd.conf b/tests/topotests/isis_rlfa_topo1/rt1/isisd.conf
+index c96d0b137475..a7ec2c450005 100644
+--- a/tests/topotests/isis_rlfa_topo1/rt1/isisd.conf
++++ b/tests/topotests/isis_rlfa_topo1/rt1/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt1
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_rlfa_topo1/rt2/isisd.conf b/tests/topotests/isis_rlfa_topo1/rt2/isisd.conf
+index 27203375c150..baf2d46a3775 100644
+--- a/tests/topotests/isis_rlfa_topo1/rt2/isisd.conf
++++ b/tests/topotests/isis_rlfa_topo1/rt2/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt2
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_rlfa_topo1/rt3/isisd.conf b/tests/topotests/isis_rlfa_topo1/rt3/isisd.conf
+index 1139d9df41ad..4ee5fffa8696 100644
+--- a/tests/topotests/isis_rlfa_topo1/rt3/isisd.conf
++++ b/tests/topotests/isis_rlfa_topo1/rt3/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt3
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_rlfa_topo1/rt4/isisd.conf b/tests/topotests/isis_rlfa_topo1/rt4/isisd.conf
+index 980bd5d9f01a..af29a62b479c 100644
+--- a/tests/topotests/isis_rlfa_topo1/rt4/isisd.conf
++++ b/tests/topotests/isis_rlfa_topo1/rt4/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt4
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_rlfa_topo1/rt5/isisd.conf b/tests/topotests/isis_rlfa_topo1/rt5/isisd.conf
+index 82ba9cb56e51..5b7ce0c99a01 100644
+--- a/tests/topotests/isis_rlfa_topo1/rt5/isisd.conf
++++ b/tests/topotests/isis_rlfa_topo1/rt5/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt5
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_rlfa_topo1/rt6/isisd.conf b/tests/topotests/isis_rlfa_topo1/rt6/isisd.conf
+index ea859ffa3be8..c3c66374bcf2 100644
+--- a/tests/topotests/isis_rlfa_topo1/rt6/isisd.conf
++++ b/tests/topotests/isis_rlfa_topo1/rt6/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt6
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_rlfa_topo1/rt7/isisd.conf b/tests/topotests/isis_rlfa_topo1/rt7/isisd.conf
+index 5acfa95a1315..4f8ad87708fc 100644
+--- a/tests/topotests/isis_rlfa_topo1/rt7/isisd.conf
++++ b/tests/topotests/isis_rlfa_topo1/rt7/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt7
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_rlfa_topo1/rt8/isisd.conf b/tests/topotests/isis_rlfa_topo1/rt8/isisd.conf
+index 237784280a97..0e870a927dc0 100644
+--- a/tests/topotests/isis_rlfa_topo1/rt8/isisd.conf
++++ b/tests/topotests/isis_rlfa_topo1/rt8/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt8
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_snmp/r1/isisd.conf b/tests/topotests/isis_snmp/r1/isisd.conf
+index 492834122585..559273e15602 100644
+--- a/tests/topotests/isis_snmp/r1/isisd.conf
++++ b/tests/topotests/isis_snmp/r1/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname r1
+-log file isisd.log
+ ! debug isis adj-packets
+ ! debug isis events
+ ! debug isis update-packets
+diff --git a/tests/topotests/isis_snmp/r2/isisd.conf b/tests/topotests/isis_snmp/r2/isisd.conf
+index 9bb8a8d5f917..d735e5b85527 100644
+--- a/tests/topotests/isis_snmp/r2/isisd.conf
++++ b/tests/topotests/isis_snmp/r2/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname r2
+-log file isisd.log
+ ! debug isis adj-packets
+ ! debug isis events
+ ! debug isis update-packets
+diff --git a/tests/topotests/isis_snmp/r3/isisd.conf b/tests/topotests/isis_snmp/r3/isisd.conf
+index 4daec791b3d6..4002a56abf9e 100644
+--- a/tests/topotests/isis_snmp/r3/isisd.conf
++++ b/tests/topotests/isis_snmp/r3/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname r3
+-log file isisd.log
+ ! debug isis adj-packets
+ ! debug isis events
+ ! debug isis update-packets
+diff --git a/tests/topotests/isis_snmp/r4/isisd.conf b/tests/topotests/isis_snmp/r4/isisd.conf
+index 32b07b3cb4eb..004389a1d851 100644
+--- a/tests/topotests/isis_snmp/r4/isisd.conf
++++ b/tests/topotests/isis_snmp/r4/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname r4
+-log file isisd.log
+ ! debug isis adj-packets
+ ! debug isis events
+ ! debug isis update-packets
+diff --git a/tests/topotests/isis_snmp/r5/isisd.conf b/tests/topotests/isis_snmp/r5/isisd.conf
+index fe3ca0f3aa20..abd4bb27819b 100644
+--- a/tests/topotests/isis_snmp/r5/isisd.conf
++++ b/tests/topotests/isis_snmp/r5/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname r5
+-log file isisd.log
+ ! debug isis adj-packets
+ ! debug isis events
+ ! debug isis update-packets
+diff --git a/tests/topotests/isis_sr_flex_algo_topo1/rt1/isisd.conf b/tests/topotests/isis_sr_flex_algo_topo1/rt1/isisd.conf
+index 090e89628f8e..9ea4e481ec90 100644
+--- a/tests/topotests/isis_sr_flex_algo_topo1/rt1/isisd.conf
++++ b/tests/topotests/isis_sr_flex_algo_topo1/rt1/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt1
+-log file isisd.log
+ !
+ !debug northbound
+ !debug isis events
+diff --git a/tests/topotests/isis_sr_flex_algo_topo1/rt2/isisd.conf b/tests/topotests/isis_sr_flex_algo_topo1/rt2/isisd.conf
+index 3901ccaefe7e..9ee25c20043b 100644
+--- a/tests/topotests/isis_sr_flex_algo_topo1/rt2/isisd.conf
++++ b/tests/topotests/isis_sr_flex_algo_topo1/rt2/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt2
+-log file isisd.log
+ !
+ !debug northbound
+ !debug isis events
+diff --git a/tests/topotests/isis_sr_flex_algo_topo1/rt3/isisd.conf b/tests/topotests/isis_sr_flex_algo_topo1/rt3/isisd.conf
+index f7a52bc79d1d..21ef5519a17e 100644
+--- a/tests/topotests/isis_sr_flex_algo_topo1/rt3/isisd.conf
++++ b/tests/topotests/isis_sr_flex_algo_topo1/rt3/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt3
+-log file isisd.log
+ !
+ !debug northbound
+ !debug isis events
+diff --git a/tests/topotests/isis_sr_flex_algo_topo2/rt0/isisd.conf b/tests/topotests/isis_sr_flex_algo_topo2/rt0/isisd.conf
+index c102b1b22b79..e5391fd475b2 100644
+--- a/tests/topotests/isis_sr_flex_algo_topo2/rt0/isisd.conf
++++ b/tests/topotests/isis_sr_flex_algo_topo2/rt0/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt0
+-log file isisd.log
+ !
+ !debug isis events
+ !debug isis spf-events
+diff --git a/tests/topotests/isis_sr_flex_algo_topo2/rt1/isisd.conf b/tests/topotests/isis_sr_flex_algo_topo2/rt1/isisd.conf
+index a7933888cc71..b638d4bed17d 100644
+--- a/tests/topotests/isis_sr_flex_algo_topo2/rt1/isisd.conf
++++ b/tests/topotests/isis_sr_flex_algo_topo2/rt1/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt1
+-log file isisd.log
+ !
+ !debug isis events
+ !debug isis spf-events
+diff --git a/tests/topotests/isis_sr_flex_algo_topo2/rt2/isisd.conf b/tests/topotests/isis_sr_flex_algo_topo2/rt2/isisd.conf
+index 312a6df2284a..0618bf135884 100644
+--- a/tests/topotests/isis_sr_flex_algo_topo2/rt2/isisd.conf
++++ b/tests/topotests/isis_sr_flex_algo_topo2/rt2/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt2
+-log file isisd.log
+ !
+ !debug isis events
+ !debug isis route-events
+diff --git a/tests/topotests/isis_sr_flex_algo_topo2/rt3/isisd.conf b/tests/topotests/isis_sr_flex_algo_topo2/rt3/isisd.conf
+index c287e8a5da6c..3918a577efac 100644
+--- a/tests/topotests/isis_sr_flex_algo_topo2/rt3/isisd.conf
++++ b/tests/topotests/isis_sr_flex_algo_topo2/rt3/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt3
+-log file isisd.log
+ !
+ !debug isis events
+ !debug isis route-events
+diff --git a/tests/topotests/isis_sr_flex_algo_topo2/rt4/isisd.conf b/tests/topotests/isis_sr_flex_algo_topo2/rt4/isisd.conf
+index c040ce200b21..0a3ee536652e 100644
+--- a/tests/topotests/isis_sr_flex_algo_topo2/rt4/isisd.conf
++++ b/tests/topotests/isis_sr_flex_algo_topo2/rt4/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt4
+-log file isisd.log
+ !
+ !debug isis events
+ !debug isis spf-events
+diff --git a/tests/topotests/isis_sr_flex_algo_topo2/rt5/isisd.conf b/tests/topotests/isis_sr_flex_algo_topo2/rt5/isisd.conf
+index 6cf87d44fb5f..377369514201 100644
+--- a/tests/topotests/isis_sr_flex_algo_topo2/rt5/isisd.conf
++++ b/tests/topotests/isis_sr_flex_algo_topo2/rt5/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt5
+-log file isisd.log
+ !
+ !debug isis events
+ !debug isis spf-events
+diff --git a/tests/topotests/isis_sr_flex_algo_topo2/rt6/isisd.conf b/tests/topotests/isis_sr_flex_algo_topo2/rt6/isisd.conf
+index 87a259696d9a..23121ec62001 100644
+--- a/tests/topotests/isis_sr_flex_algo_topo2/rt6/isisd.conf
++++ b/tests/topotests/isis_sr_flex_algo_topo2/rt6/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt6
+-log file isisd.log
+ !
+ !debug isis events
+ !debug isis spf-events
+diff --git a/tests/topotests/isis_sr_flex_algo_topo2/rt7/isisd.conf b/tests/topotests/isis_sr_flex_algo_topo2/rt7/isisd.conf
+index 6645542db9b3..e10354debc24 100644
+--- a/tests/topotests/isis_sr_flex_algo_topo2/rt7/isisd.conf
++++ b/tests/topotests/isis_sr_flex_algo_topo2/rt7/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt7
+-log file isisd.log
+ !
+ !debug isis events
+ !debug isis spf-events
+diff --git a/tests/topotests/isis_sr_flex_algo_topo2/rt8/isisd.conf b/tests/topotests/isis_sr_flex_algo_topo2/rt8/isisd.conf
+index 04e925e4820e..a6b7796a12c5 100644
+--- a/tests/topotests/isis_sr_flex_algo_topo2/rt8/isisd.conf
++++ b/tests/topotests/isis_sr_flex_algo_topo2/rt8/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt8
+-log file isisd.log
+ !
+ !debug isis events
+ !debug isis spf-events
+diff --git a/tests/topotests/isis_sr_flex_algo_topo2/rt9/isisd.conf b/tests/topotests/isis_sr_flex_algo_topo2/rt9/isisd.conf
+index dabb9986dffe..ce38b6ce52a8 100644
+--- a/tests/topotests/isis_sr_flex_algo_topo2/rt9/isisd.conf
++++ b/tests/topotests/isis_sr_flex_algo_topo2/rt9/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt9
+-log file isisd.log
+ !
+ !debug isis events
+ !debug isis spf-events
+diff --git a/tests/topotests/isis_sr_te_topo1/rt1/isisd.conf b/tests/topotests/isis_sr_te_topo1/rt1/isisd.conf
+index 3a94af7e0d78..93b7e7a6afe4 100644
+--- a/tests/topotests/isis_sr_te_topo1/rt1/isisd.conf
++++ b/tests/topotests/isis_sr_te_topo1/rt1/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt1
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_sr_te_topo1/rt2/isisd.conf b/tests/topotests/isis_sr_te_topo1/rt2/isisd.conf
+index 553e72cb2df2..b1539a8ee018 100644
+--- a/tests/topotests/isis_sr_te_topo1/rt2/isisd.conf
++++ b/tests/topotests/isis_sr_te_topo1/rt2/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt2
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_sr_te_topo1/rt3/isisd.conf b/tests/topotests/isis_sr_te_topo1/rt3/isisd.conf
+index 8d89612b5cb4..f6295b76cdca 100644
+--- a/tests/topotests/isis_sr_te_topo1/rt3/isisd.conf
++++ b/tests/topotests/isis_sr_te_topo1/rt3/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt3
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_sr_te_topo1/rt4/isisd.conf b/tests/topotests/isis_sr_te_topo1/rt4/isisd.conf
+index e5f72a77133e..002e838a64e7 100644
+--- a/tests/topotests/isis_sr_te_topo1/rt4/isisd.conf
++++ b/tests/topotests/isis_sr_te_topo1/rt4/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt4
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_sr_te_topo1/rt5/isisd.conf b/tests/topotests/isis_sr_te_topo1/rt5/isisd.conf
+index 1a66d18ee1f6..58a451ca60ab 100644
+--- a/tests/topotests/isis_sr_te_topo1/rt5/isisd.conf
++++ b/tests/topotests/isis_sr_te_topo1/rt5/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt5
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_sr_te_topo1/rt6/isisd.conf b/tests/topotests/isis_sr_te_topo1/rt6/isisd.conf
+index bfa988305be5..a8083667dad3 100644
+--- a/tests/topotests/isis_sr_te_topo1/rt6/isisd.conf
++++ b/tests/topotests/isis_sr_te_topo1/rt6/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt6
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_sr_topo1/rt1/isisd.conf b/tests/topotests/isis_sr_topo1/rt1/isisd.conf
+index ef8d4275c2a3..49262809c02f 100644
+--- a/tests/topotests/isis_sr_topo1/rt1/isisd.conf
++++ b/tests/topotests/isis_sr_topo1/rt1/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt1
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_sr_topo1/rt2/isisd.conf b/tests/topotests/isis_sr_topo1/rt2/isisd.conf
+index e65ec81a3c52..d67edd6e32f7 100644
+--- a/tests/topotests/isis_sr_topo1/rt2/isisd.conf
++++ b/tests/topotests/isis_sr_topo1/rt2/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt2
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_sr_topo1/rt3/isisd.conf b/tests/topotests/isis_sr_topo1/rt3/isisd.conf
+index e7b8d942ccca..36fbbd3a1352 100644
+--- a/tests/topotests/isis_sr_topo1/rt3/isisd.conf
++++ b/tests/topotests/isis_sr_topo1/rt3/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt3
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_sr_topo1/rt4/isisd.conf b/tests/topotests/isis_sr_topo1/rt4/isisd.conf
+index 92ea1ea3d9d3..6451c4a29b52 100644
+--- a/tests/topotests/isis_sr_topo1/rt4/isisd.conf
++++ b/tests/topotests/isis_sr_topo1/rt4/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt4
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_sr_topo1/rt5/isisd.conf b/tests/topotests/isis_sr_topo1/rt5/isisd.conf
+index de604d71f4c9..0db2bcef6eb8 100644
+--- a/tests/topotests/isis_sr_topo1/rt5/isisd.conf
++++ b/tests/topotests/isis_sr_topo1/rt5/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt5
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_sr_topo1/rt6/isisd.conf b/tests/topotests/isis_sr_topo1/rt6/isisd.conf
+index b96a2c6e1e1c..af1d8ec4f333 100644
+--- a/tests/topotests/isis_sr_topo1/rt6/isisd.conf
++++ b/tests/topotests/isis_sr_topo1/rt6/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt6
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_srv6_topo1/rt1/isisd.conf b/tests/topotests/isis_srv6_topo1/rt1/isisd.conf
+index 29e1a3117165..0f7af9633f2c 100644
+--- a/tests/topotests/isis_srv6_topo1/rt1/isisd.conf
++++ b/tests/topotests/isis_srv6_topo1/rt1/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt1
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_srv6_topo1/rt2/isisd.conf b/tests/topotests/isis_srv6_topo1/rt2/isisd.conf
+index b095f049101f..a8fd364bf769 100644
+--- a/tests/topotests/isis_srv6_topo1/rt2/isisd.conf
++++ b/tests/topotests/isis_srv6_topo1/rt2/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt2
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_srv6_topo1/rt3/isisd.conf b/tests/topotests/isis_srv6_topo1/rt3/isisd.conf
+index e237db2f4940..31c904fba7b9 100644
+--- a/tests/topotests/isis_srv6_topo1/rt3/isisd.conf
++++ b/tests/topotests/isis_srv6_topo1/rt3/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt3
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_srv6_topo1/rt4/isisd.conf b/tests/topotests/isis_srv6_topo1/rt4/isisd.conf
+index b4c92146a1f6..0df3fe1b99b8 100644
+--- a/tests/topotests/isis_srv6_topo1/rt4/isisd.conf
++++ b/tests/topotests/isis_srv6_topo1/rt4/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt4
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_srv6_topo1/rt5/isisd.conf b/tests/topotests/isis_srv6_topo1/rt5/isisd.conf
+index 26f895dd82ea..ffb4993cd523 100644
+--- a/tests/topotests/isis_srv6_topo1/rt5/isisd.conf
++++ b/tests/topotests/isis_srv6_topo1/rt5/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt5
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_srv6_topo1/rt6/isisd.conf b/tests/topotests/isis_srv6_topo1/rt6/isisd.conf
+index f8816db43aac..99cec5bca0cf 100644
+--- a/tests/topotests/isis_srv6_topo1/rt6/isisd.conf
++++ b/tests/topotests/isis_srv6_topo1/rt6/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt6
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_tilfa_topo1/rt1/isisd.conf b/tests/topotests/isis_tilfa_topo1/rt1/isisd.conf
+index 1218ed350f8e..c573a6a47699 100644
+--- a/tests/topotests/isis_tilfa_topo1/rt1/isisd.conf
++++ b/tests/topotests/isis_tilfa_topo1/rt1/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt1
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_tilfa_topo1/rt2/isisd.conf b/tests/topotests/isis_tilfa_topo1/rt2/isisd.conf
+index aed69713e183..d14135dc24df 100644
+--- a/tests/topotests/isis_tilfa_topo1/rt2/isisd.conf
++++ b/tests/topotests/isis_tilfa_topo1/rt2/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt2
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_tilfa_topo1/rt3/isisd.conf b/tests/topotests/isis_tilfa_topo1/rt3/isisd.conf
+index d2f01e459514..8b4e1c035d1a 100644
+--- a/tests/topotests/isis_tilfa_topo1/rt3/isisd.conf
++++ b/tests/topotests/isis_tilfa_topo1/rt3/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt3
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_tilfa_topo1/rt4/isisd.conf b/tests/topotests/isis_tilfa_topo1/rt4/isisd.conf
+index c1117b5d1bd8..8bf7c842f902 100644
+--- a/tests/topotests/isis_tilfa_topo1/rt4/isisd.conf
++++ b/tests/topotests/isis_tilfa_topo1/rt4/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt4
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_tilfa_topo1/rt5/isisd.conf b/tests/topotests/isis_tilfa_topo1/rt5/isisd.conf
+index 3678ff9074df..9366d56f440e 100644
+--- a/tests/topotests/isis_tilfa_topo1/rt5/isisd.conf
++++ b/tests/topotests/isis_tilfa_topo1/rt5/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt5
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/isis_tilfa_topo1/rt6/isisd.conf b/tests/topotests/isis_tilfa_topo1/rt6/isisd.conf
+index 9d3b464726d4..b139393fa2b0 100644
+--- a/tests/topotests/isis_tilfa_topo1/rt6/isisd.conf
++++ b/tests/topotests/isis_tilfa_topo1/rt6/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt6
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/ldp_snmp/r1/isisd.conf b/tests/topotests/ldp_snmp/r1/isisd.conf
+index d1abb497a6ce..ee23d9a308d9 100644
+--- a/tests/topotests/ldp_snmp/r1/isisd.conf
++++ b/tests/topotests/ldp_snmp/r1/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname r1
+-log file isisd.log
+ ! debug isis adj-packets
+ ! debug isis events
+ ! debug isis update-packets
+diff --git a/tests/topotests/ldp_snmp/r2/isisd.conf b/tests/topotests/ldp_snmp/r2/isisd.conf
+index 213b65ee4cc7..ec79aaa71d20 100644
+--- a/tests/topotests/ldp_snmp/r2/isisd.conf
++++ b/tests/topotests/ldp_snmp/r2/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname r2
+-log file isisd.log
+ ! debug isis adj-packets
+ ! debug isis events
+ ! debug isis update-packets
+diff --git a/tests/topotests/ldp_snmp/r3/isisd.conf b/tests/topotests/ldp_snmp/r3/isisd.conf
+index 956d58239bf1..48ca62aab15c 100644
+--- a/tests/topotests/ldp_snmp/r3/isisd.conf
++++ b/tests/topotests/ldp_snmp/r3/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname r3
+-log file isisd.log
+ ! debug isis adj-packets
+ ! debug isis events
+ ! debug isis update-packets
+diff --git a/tests/topotests/ldp_sync_isis_topo1/r1/isisd.conf b/tests/topotests/ldp_sync_isis_topo1/r1/isisd.conf
+index d1abb497a6ce..ee23d9a308d9 100644
+--- a/tests/topotests/ldp_sync_isis_topo1/r1/isisd.conf
++++ b/tests/topotests/ldp_sync_isis_topo1/r1/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname r1
+-log file isisd.log
+ ! debug isis adj-packets
+ ! debug isis events
+ ! debug isis update-packets
+diff --git a/tests/topotests/ldp_sync_isis_topo1/r2/isisd.conf b/tests/topotests/ldp_sync_isis_topo1/r2/isisd.conf
+index 213b65ee4cc7..ec79aaa71d20 100644
+--- a/tests/topotests/ldp_sync_isis_topo1/r2/isisd.conf
++++ b/tests/topotests/ldp_sync_isis_topo1/r2/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname r2
+-log file isisd.log
+ ! debug isis adj-packets
+ ! debug isis events
+ ! debug isis update-packets
+diff --git a/tests/topotests/ldp_sync_isis_topo1/r3/isisd.conf b/tests/topotests/ldp_sync_isis_topo1/r3/isisd.conf
+index 956d58239bf1..48ca62aab15c 100644
+--- a/tests/topotests/ldp_sync_isis_topo1/r3/isisd.conf
++++ b/tests/topotests/ldp_sync_isis_topo1/r3/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname r3
+-log file isisd.log
+ ! debug isis adj-packets
+ ! debug isis events
+ ! debug isis update-packets
+diff --git a/tests/topotests/srv6_sid_manager/rt1/isisd.conf b/tests/topotests/srv6_sid_manager/rt1/isisd.conf
+index 29e1a3117165..0f7af9633f2c 100644
+--- a/tests/topotests/srv6_sid_manager/rt1/isisd.conf
++++ b/tests/topotests/srv6_sid_manager/rt1/isisd.conf
+@@ -1,6 +1,5 @@
+ password 1
+ hostname rt1
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/srv6_sid_manager/rt2/isisd.conf b/tests/topotests/srv6_sid_manager/rt2/isisd.conf
+index b095f049101f..a8fd364bf769 100644
+--- a/tests/topotests/srv6_sid_manager/rt2/isisd.conf
++++ b/tests/topotests/srv6_sid_manager/rt2/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt2
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/srv6_sid_manager/rt3/isisd.conf b/tests/topotests/srv6_sid_manager/rt3/isisd.conf
+index e237db2f4940..31c904fba7b9 100644
+--- a/tests/topotests/srv6_sid_manager/rt3/isisd.conf
++++ b/tests/topotests/srv6_sid_manager/rt3/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt3
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/srv6_sid_manager/rt4/isisd.conf b/tests/topotests/srv6_sid_manager/rt4/isisd.conf
+index b4c92146a1f6..0df3fe1b99b8 100644
+--- a/tests/topotests/srv6_sid_manager/rt4/isisd.conf
++++ b/tests/topotests/srv6_sid_manager/rt4/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt4
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/srv6_sid_manager/rt5/isisd.conf b/tests/topotests/srv6_sid_manager/rt5/isisd.conf
+index 26f895dd82ea..ffb4993cd523 100644
+--- a/tests/topotests/srv6_sid_manager/rt5/isisd.conf
++++ b/tests/topotests/srv6_sid_manager/rt5/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt5
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+diff --git a/tests/topotests/srv6_sid_manager/rt6/isisd.conf b/tests/topotests/srv6_sid_manager/rt6/isisd.conf
+index f8816db43aac..99cec5bca0cf 100644
+--- a/tests/topotests/srv6_sid_manager/rt6/isisd.conf
++++ b/tests/topotests/srv6_sid_manager/rt6/isisd.conf
+@@ -1,5 +1,4 @@
+ hostname rt6
+-log file isisd.log
+ !
+ ! debug isis events
+ ! debug isis route-events
+--
+2.47.3
+
diff --git a/debian/patches/upstream/0011-tests-Tell-fpm_listener-to-shutdown.patch b/debian/patches/upstream/0011-tests-Tell-fpm_listener-to-shutdown.patch
new file mode 100644
index 000000000000..d0a0b9acddca
--- /dev/null
+++ b/debian/patches/upstream/0011-tests-Tell-fpm_listener-to-shutdown.patch
@@ -0,0 +1,52 @@
+From c6c1ceea720527b68350eefb854aebfbeb49f695 Mon Sep 17 00:00:00 2001
+From: Donald Sharp <sharpd@nvidia.com>
+Date: Sun, 3 May 2026 12:23:50 -0400
+Subject: [PATCH 07/21] tests: Tell fpm_listener to shutdown
+
+Allow gcoverage to work with fpm_listener
+
+Currently there is no way to tell fpm_listener to shutdown,
+so let's allow it to listen to signals and cleanly shutdown.
+
+Signed-off-by: Donald Sharp <sharpd@nvidia.com>
+---
+ tests/topotests/lib/topotest.py | 23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
+index 52a85eef8536..1989b7c94b35 100644
+--- a/tests/topotests/lib/topotest.py
++++ b/tests/topotests/lib/topotest.py
+@@ -1623,6 +1623,29 @@ class Router(Node):
+ return ret
+
+ def stopRouter(self, assertOnError=True):
++ # fpm_listener writes its PID file to the gear log directory (next to
++ # its data dump), not to /var/run/frr/, so listDaemons() can't see it.
++ # Send it SIGTERM first and give it a brief moment to run its atexit
++ # handlers (in particular gcov flush under --enable-gcov) before the
++ # namespace teardown SIGKILLs it. This must happen before listDaemons()
++ # below sends SIGTERM to the FRR daemons because once zebra exits the
++ # FPM client side closes the socket and we want fpm_listener's last
++ # accept loop iteration to be reflected in coverage.
++ fpm_pidfile = "{}/{}/fpm_listener.pid".format(self.logdir, self.name)
++ try:
++ with open(fpm_pidfile) as f:
++ fpm_pid = int(f.read().strip())
++ try:
++ os.kill(fpm_pid, signal.SIGTERM)
++ logger.debug(
++ "%s: sent SIGTERM to fpm_listener pid %d", self.name, fpm_pid
++ )
++ except OSError:
++ pass
++ time.sleep(0.1)
++ except (FileNotFoundError, ValueError):
++ pass
++
+ # Stop Running FRR Daemons
+ running = self.listDaemons()
+ if not running:
+--
+2.47.3
+
diff --git a/debian/patches/upstream/0012-isisd-Clean-up-and-memory-leaks-in-isis.patch b/debian/patches/upstream/0012-isisd-Clean-up-and-memory-leaks-in-isis.patch
new file mode 100644
index 000000000000..fcdf28a2f08b
--- /dev/null
+++ b/debian/patches/upstream/0012-isisd-Clean-up-and-memory-leaks-in-isis.patch
@@ -0,0 +1,324 @@
+From 27141f85fbd8d6e9bec4e74e86eac241ce7b4a4b Mon Sep 17 00:00:00 2001
+From: Donald Sharp <sharpd@nvidia.com>
+Date: Fri, 1 May 2026 12:26:01 -0400
+Subject: [PATCH 08/21] isisd: Clean up and memory leaks in isis
+
+a) isisd is using a MTYPE_TMP in a bunch of different places,
+add better descriptors and break it up a bit.
+
+b) Cleanup of sbuf usage such that memory is not leaked on shutdown.
+
+Signed-off-by: Donald Sharp <sharpd@nvidia.com>
+---
+ isisd/isis_circuit.c | 2 +-
+ isisd/isis_main.c | 2 ++
+ isisd/isis_misc.c | 13 +++++++----
+ isisd/isis_nb_config.c | 13 +++++++----
+ isisd/isis_tlvs.c | 50 +++++++++++++++++++++++++++++-----------
+ isisd/isis_tlvs.h | 1 +
+ isisd/isis_vty_fabricd.c | 6 +++--
+ isisd/isisd.c | 1 +
+ isisd/isisd.h | 1 +
+ 9 files changed, 62 insertions(+), 27 deletions(-)
+
+diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
+index 6bcb7190c764..cc6a699981c0 100644
+--- a/isisd/isis_circuit.c
++++ b/isisd/isis_circuit.c
+@@ -211,7 +211,7 @@ void isis_circuit_del(struct isis_circuit *circuit)
+ circuit->ext = NULL;
+ }
+
+- XFREE(MTYPE_TMP, circuit->bfd_config.profile);
++ XFREE(MTYPE_ISIS_BFD_PROFILE, circuit->bfd_config.profile);
+ XFREE(MTYPE_ISIS_CIRCUIT, circuit->tag);
+
+ /* and lastly the circuit itself */
+diff --git a/isisd/isis_main.c b/isisd/isis_main.c
+index 24b40de912e8..7acfb3b2327d 100644
+--- a/isisd/isis_main.c
++++ b/isisd/isis_main.c
+@@ -46,6 +46,7 @@
+ #include "isisd/isis_bfd.h"
+ #include "isisd/isis_lsp.h"
+ #include "isisd/isis_mt.h"
++#include "isisd/isis_tlvs.h"
+ #include "isisd/fabricd.h"
+ #include "isisd/isis_nb.h"
+ #include "isisd/isis_ldp_sync.h"
+@@ -122,6 +123,7 @@ static FRR_NORETURN void terminate(int i)
+ isis_affinity_map_terminate();
+ #endif
+ isis_master_terminate();
++ isis_tlvs_terminate();
+
+ frr_fini();
+ exit(i);
+diff --git a/isisd/isis_misc.c b/isisd/isis_misc.c
+index 088b8016cc45..66b0b5cf91e5 100644
+--- a/isisd/isis_misc.c
++++ b/isisd/isis_misc.c
+@@ -31,7 +31,10 @@
+ #include "isisd/isis_adjacency.h"
+ #include "isisd/isis_dynhn.h"
+
+-/* staticly assigned vars for printing purposes */
++DEFINE_MTYPE_STATIC(ISISD, ISIS_TMP_LOG_MULTILINE, "ISIS log multiline temporary");
++DEFINE_MTYPE_STATIC(ISISD, ISIS_TMP_VTY_MULTILINE, "ISIS vty multiline temporary");
++
++/* statically assigned vars for printing purposes */
+ static char sys_hostname[ISO_SYSID_STRLEN];
+ struct in_addr new_prefix;
+ /* len of xxYxxMxWxdxxhxxmxxs + place for #0 termination */
+@@ -408,7 +411,7 @@ void log_multiline(int priority, const char *prefix, const char *format, ...)
+ char *p;
+
+ va_start(ap, format);
+- p = vasnprintfrr(MTYPE_TMP, shortbuf, sizeof(shortbuf), format, ap);
++ p = vasnprintfrr(MTYPE_ISIS_TMP_LOG_MULTILINE, shortbuf, sizeof(shortbuf), format, ap);
+ va_end(ap);
+
+ if (!p)
+@@ -421,7 +424,7 @@ void log_multiline(int priority, const char *prefix, const char *format, ...)
+ }
+
+ if (p != shortbuf)
+- XFREE(MTYPE_TMP, p);
++ XFREE(MTYPE_ISIS_TMP_LOG_MULTILINE, p);
+ }
+
+ void vty_multiline(struct vty *vty, const char *prefix, const char *format, ...)
+@@ -431,7 +434,7 @@ void vty_multiline(struct vty *vty, const char *prefix, const char *format, ...)
+ char *p;
+
+ va_start(ap, format);
+- p = vasnprintfrr(MTYPE_TMP, shortbuf, sizeof(shortbuf), format, ap);
++ p = vasnprintfrr(MTYPE_ISIS_TMP_VTY_MULTILINE, shortbuf, sizeof(shortbuf), format, ap);
+ va_end(ap);
+
+ if (!p)
+@@ -444,7 +447,7 @@ void vty_multiline(struct vty *vty, const char *prefix, const char *format, ...)
+ }
+
+ if (p != shortbuf)
+- XFREE(MTYPE_TMP, p);
++ XFREE(MTYPE_ISIS_TMP_VTY_MULTILINE, p);
+ }
+
+ void vty_out_timestr(struct vty *vty, time_t uptime)
+diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c
+index a6ce9f674278..8b11ba56e1ab 100644
+--- a/isisd/isis_nb_config.c
++++ b/isisd/isis_nb_config.c
+@@ -45,6 +45,8 @@
+ #include "isisd/isis_flex_algo.h"
+ #include "isisd/isis_zebra.h"
+
++DEFINE_MTYPE_STATIC(ISISD, ISIS_TMP_SPF_BACKOFF_BUF_NB, "ISIS NB SPF backoff temporary buffer");
++
+ #define AFFINITY_INCLUDE_ANY 0
+ #define AFFINITY_INCLUDE_ALL 1
+ #define AFFINITY_EXCLUDE_ANY 2
+@@ -632,7 +634,7 @@ void ietf_backoff_delay_apply_finish(struct nb_cb_apply_finish_args *args)
+ long timetolearn = yang_dnode_get_uint16(args->dnode, "time-to-learn");
+ struct isis_area *area = nb_running_get_entry(args->dnode, NULL, true);
+ size_t bufsiz = strlen(area->area_tag) + sizeof("IS-IS Lx");
+- char *buf = XCALLOC(MTYPE_TMP, bufsiz);
++ char *buf = XCALLOC(MTYPE_ISIS_TMP_SPF_BACKOFF_BUF_NB, bufsiz);
+
+ snprintf(buf, bufsiz, "IS-IS %s L1", area->area_tag);
+ spf_backoff_free(area->spf_delay_ietf[0]);
+@@ -644,7 +646,7 @@ void ietf_backoff_delay_apply_finish(struct nb_cb_apply_finish_args *args)
+ area->spf_delay_ietf[1] = spf_backoff_new(master, buf, init_delay, short_delay, long_delay,
+ holddown, timetolearn);
+
+- XFREE(MTYPE_TMP, buf);
++ XFREE(MTYPE_ISIS_TMP_SPF_BACKOFF_BUF_NB, buf);
+ }
+
+ int isis_instance_spf_ietf_backoff_delay_create(struct nb_cb_create_args *args)
+@@ -3633,8 +3635,9 @@ int lib_interface_isis_bfd_monitoring_profile_modify(struct nb_cb_modify_args *a
+ return NB_OK;
+
+ circuit = nb_running_get_entry(args->dnode, NULL, true);
+- XFREE(MTYPE_TMP, circuit->bfd_config.profile);
+- circuit->bfd_config.profile = XSTRDUP(MTYPE_TMP, yang_dnode_get_string(args->dnode, NULL));
++ XFREE(MTYPE_ISIS_BFD_PROFILE, circuit->bfd_config.profile);
++ circuit->bfd_config.profile = XSTRDUP(MTYPE_ISIS_BFD_PROFILE,
++ yang_dnode_get_string(args->dnode, NULL));
+
+ return NB_OK;
+ }
+@@ -3647,7 +3650,7 @@ int lib_interface_isis_bfd_monitoring_profile_destroy(struct nb_cb_destroy_args
+ return NB_OK;
+
+ circuit = nb_running_get_entry(args->dnode, NULL, true);
+- XFREE(MTYPE_TMP, circuit->bfd_config.profile);
++ XFREE(MTYPE_ISIS_BFD_PROFILE, circuit->bfd_config.profile);
+
+ return NB_OK;
+ }
+diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c
+index b0b51ea9e75f..303b9ae6106e 100644
+--- a/isisd/isis_tlvs.c
++++ b/isisd/isis_tlvs.c
+@@ -58,6 +58,11 @@ typedef void (*format_item_func)(uint16_t mtid, struct isis_item *i, struct sbuf
+ struct json_object *json, int indent);
+ typedef struct isis_item *(*copy_item_func)(struct isis_item *i);
+
++static struct sbuf format_tlvs_buf;
++static bool format_tlvs_buf_inited;
++static struct sbuf unpack_tlvs_logbuf;
++static bool unpack_tlvs_logbuf_inited;
++
+ struct tlv_ops {
+ const char *name;
+ unpack_tlv_func unpack;
+@@ -6303,14 +6308,14 @@ const char *isis_format_tlvs(struct isis_tlvs *tlvs, struct json_object *json)
+ format_tlvs(tlvs, NULL, json, 0);
+ return NULL;
+ } else {
+- static struct sbuf buf;
+-
+- if (!sbuf_buf(&buf))
+- sbuf_init(&buf, NULL, 0);
++ if (!format_tlvs_buf_inited) {
++ sbuf_init(&format_tlvs_buf, NULL, 0);
++ format_tlvs_buf_inited = true;
++ }
+
+- sbuf_reset(&buf);
+- format_tlvs(tlvs, &buf, NULL, 0);
+- return sbuf_buf(&buf);
++ sbuf_reset(&format_tlvs_buf);
++ format_tlvs(tlvs, &format_tlvs_buf, NULL, 0);
++ return sbuf_buf(&format_tlvs_buf);
+ }
+ }
+
+@@ -6664,31 +6669,48 @@ static int unpack_tlvs(enum isis_tlv_context context, size_t avail_len, struct s
+ int isis_unpack_tlvs(size_t avail_len, struct stream *stream, struct isis_tlvs **dest,
+ const char **log)
+ {
+- static struct sbuf logbuf;
+ int indent = 0;
+ int rv;
+ struct isis_tlvs *result;
+
+- if (!sbuf_buf(&logbuf))
+- sbuf_init(&logbuf, NULL, 0);
++ if (!unpack_tlvs_logbuf_inited) {
++ sbuf_init(&unpack_tlvs_logbuf, NULL, 0);
++ unpack_tlvs_logbuf_inited = true;
++ }
+
+- sbuf_reset(&logbuf);
++ sbuf_reset(&unpack_tlvs_logbuf);
+ if (avail_len > STREAM_READABLE(stream)) {
+- sbuf_push(&logbuf, indent,
++ sbuf_push(&unpack_tlvs_logbuf, indent,
+ "Stream doesn't contain sufficient data. Claimed %zu, available %zu\n",
+ avail_len, STREAM_READABLE(stream));
+ return 1;
+ }
+
+ result = isis_alloc_tlvs();
+- rv = unpack_tlvs(ISIS_CONTEXT_LSP, avail_len, stream, &logbuf, result, indent, NULL);
++ rv = unpack_tlvs(ISIS_CONTEXT_LSP, avail_len, stream, &unpack_tlvs_logbuf, result, indent,
++ NULL);
+
+- *log = sbuf_buf(&logbuf);
++ *log = sbuf_buf(&unpack_tlvs_logbuf);
+ *dest = result;
+
+ return rv;
+ }
+
++void isis_tlvs_terminate(void)
++{
++ if (format_tlvs_buf_inited) {
++ sbuf_free(&format_tlvs_buf);
++ memset(&format_tlvs_buf, 0, sizeof(format_tlvs_buf));
++ format_tlvs_buf_inited = false;
++ }
++
++ if (unpack_tlvs_logbuf_inited) {
++ sbuf_free(&unpack_tlvs_logbuf);
++ memset(&unpack_tlvs_logbuf, 0, sizeof(unpack_tlvs_logbuf));
++ unpack_tlvs_logbuf_inited = false;
++ }
++}
++
+ #define TLV_OPS(_name_, _desc_) \
+ static const struct tlv_ops tlv_##_name_##_ops = { \
+ .name = _desc_, \
+diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h
+index 889d7369b2e6..b952e4f28890 100644
+--- a/isisd/isis_tlvs.h
++++ b/isisd/isis_tlvs.h
+@@ -757,6 +757,7 @@ struct isis_subsubtlvs *isis_alloc_subsubtlvs(enum isis_tlv_context context);
+ int isis_unpack_tlvs(size_t avail_len, struct stream *stream, struct isis_tlvs **dest,
+ const char **error_log);
+ const char *isis_format_tlvs(struct isis_tlvs *tlvs, struct json_object *json);
++void isis_tlvs_terminate(void);
+ struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs);
+ struct list *isis_fragment_tlvs(struct isis_tlvs *tlvs, size_t size);
+
+diff --git a/isisd/isis_vty_fabricd.c b/isisd/isis_vty_fabricd.c
+index 8560e898cba4..b99b677df79b 100644
+--- a/isisd/isis_vty_fabricd.c
++++ b/isisd/isis_vty_fabricd.c
+@@ -22,6 +22,8 @@
+ #include "lib/spf_backoff.h"
+ #include "isisd/isis_mt.h"
+
++DEFINE_MTYPE_STATIC(ISISD, ISIS_TMP_SPF_BACKOFF_BUF_VTY, "ISIS VTY SPF backoff temporary buffer");
++
+ static struct isis_circuit *isis_circuit_lookup(struct vty *vty)
+ {
+ struct interface *ifp = VTY_GET_CONTEXT(interface);
+@@ -696,7 +698,7 @@ DEFUN (spf_delay_ietf,
+ long timetolearn = atol(argv[10]->arg);
+
+ size_t bufsiz = strlen(area->area_tag) + sizeof("IS-IS Lx");
+- char *buf = XCALLOC(MTYPE_TMP, bufsiz);
++ char *buf = XCALLOC(MTYPE_ISIS_TMP_SPF_BACKOFF_BUF_VTY, bufsiz);
+
+ snprintf(buf, bufsiz, "IS-IS %s L1", area->area_tag);
+ spf_backoff_free(area->spf_delay_ietf[0]);
+@@ -710,7 +712,7 @@ DEFUN (spf_delay_ietf,
+ spf_backoff_new(master, buf, init_delay, short_delay,
+ long_delay, holddown, timetolearn);
+
+- XFREE(MTYPE_TMP, buf);
++ XFREE(MTYPE_ISIS_TMP_SPF_BACKOFF_BUF_VTY, buf);
+ return CMD_SUCCESS;
+ }
+
+diff --git a/isisd/isisd.c b/isisd/isisd.c
+index e4986bc56f86..6aae50ba5985 100644
+--- a/isisd/isisd.c
++++ b/isisd/isisd.c
+@@ -80,6 +80,7 @@ DEFINE_MTYPE_STATIC(ISISD, ISIS_AREA, "ISIS area");
+ DEFINE_MTYPE(ISISD, ISIS_AREA_ADDR, "ISIS area address");
+ DEFINE_MTYPE(ISISD, ISIS_ACL_NAME, "ISIS access-list name");
+ DEFINE_MTYPE(ISISD, ISIS_PLIST_NAME, "ISIS prefix-list name");
++DEFINE_MTYPE(ISISD, ISIS_BFD_PROFILE, "ISIS BFD profile");
+
+ DEFINE_QOBJ_TYPE(isis_area);
+
+diff --git a/isisd/isisd.h b/isisd/isisd.h
+index 62363151585c..2721e50fbed7 100644
+--- a/isisd/isisd.h
++++ b/isisd/isisd.h
+@@ -286,6 +286,7 @@ DECLARE_DLIST(isis_area_list, struct isis_area, area_list_item);
+ DECLARE_MTYPE(ISIS_ACL_NAME); /* isis_area->spf_prefix_prioritites */
+ DECLARE_MTYPE(ISIS_AREA_ADDR); /* isis_area->area_addrs */
+ DECLARE_MTYPE(ISIS_PLIST_NAME);
++DECLARE_MTYPE(ISIS_BFD_PROFILE); /* isis_circuit->bfd_config.profile */
+
+ DECLARE_HOOK(isis_area_overload_bit_update, (struct isis_area * area), (area));
+
+--
+2.47.3
+
diff --git a/debian/patches/upstream/0013-bgpd-Cleanup-memory-leaks-on-shutdown.patch b/debian/patches/upstream/0013-bgpd-Cleanup-memory-leaks-on-shutdown.patch
new file mode 100644
index 000000000000..9fbb4dfc29a3
--- /dev/null
+++ b/debian/patches/upstream/0013-bgpd-Cleanup-memory-leaks-on-shutdown.patch
@@ -0,0 +1,608 @@
+From 1bf2f572adb0908e6a002d99e74ba20e4d3e1248 Mon Sep 17 00:00:00 2001
+From: Donald Sharp <sharpd@nvidia.com>
+Date: Fri, 1 May 2026 12:17:06 -0400
+Subject: [PATCH 09/21] bgpd: Cleanup memory leaks on shutdown
+
+a) tx addpath id's not being cleaned up properly, fix.
+b) evpn memory leaks on shutdown, fix.
+c) route_nodes not being properly released on shutdown, fix.
+d) rpki memory leaks on shutdown, fix.
+e) srv6 memory leaks on shutdown, fix.
+f) hidden bgp instances memory leaks on recreate, fix.
+
+Signed-off-by: Donald Sharp <sharpd@nvidia.com>
+---
+ bgpd/bgp_addpath.c | 32 ++++++++++++++++
+ bgpd/bgp_addpath.h | 2 +
+ bgpd/bgp_evpn.c | 44 +++++++++++++++++++++
+ bgpd/bgp_evpn.h | 1 +
+ bgpd/bgp_labelpool.c | 91 ++++++++++++++++++++++++++++++++++++++++++--
+ bgpd/bgp_labelpool.h | 1 +
+ bgpd/bgp_main.c | 19 +++++++++
+ bgpd/bgp_route.c | 30 ++++++++++++++-
+ bgpd/bgp_route.h | 1 +
+ bgpd/bgp_rpki.c | 2 +
+ bgpd/bgp_srv6.c | 10 +++++
+ bgpd/bgp_table.c | 24 ++++++++++++
+ bgpd/bgp_updgrp.c | 13 ++++++-
+ bgpd/bgpd.c | 57 ++++++++++++++++++++++-----
+ 14 files changed, 312 insertions(+), 15 deletions(-)
+
+diff --git a/bgpd/bgp_addpath.c b/bgpd/bgp_addpath.c
+index cb3a33180cbf..1b361e651dd8 100644
+--- a/bgpd/bgp_addpath.c
++++ b/bgpd/bgp_addpath.c
+@@ -84,6 +84,38 @@ void bgp_addpath_init_bgp_data(struct bgp_addpath_bgp_data *d)
+ }
+ }
+
++/*
++ * Destroy any tx addpath id_allocators still attached to the BGP instance.
++ *
++ * Allocators are normally created by bgp_addpath_populate_type() when the
++ * peer count for an (afi, safi, type) combination transitions from zero to
++ * non-zero, and destroyed by the matching bgp_addpath_flush_type() when the
++ * count drops back to zero. Some configurations keep that count >= 1 even
++ * after every peer has been deleted (e.g. an L3VNI VRF advertising
++ * "ipv4/ipv6 unicast gateway-ip" keeps the BGP_ADDPATH_ALL count at 1 via
++ * advertise_type5_routes_multipath()), so bgp_addpath_flush_type() never
++ * fires. Call this from bgp_free() to release those leftover allocators.
++ *
++ * It is safe to skip the per-path id drain here because every bgp_path_info
++ * has already been freed by bgp_path_info_free_with_caller() ->
++ * bgp_addpath_free_info_data() by the time bgp_free() runs.
++ */
++void bgp_addpath_finish_bgp_data(struct bgp_addpath_bgp_data *d)
++{
++ safi_t safi;
++ afi_t afi;
++ int i;
++
++ FOREACH_AFI_SAFI (afi, safi) {
++ for (i = 0; i < BGP_ADDPATH_MAX; i++) {
++ if (d->id_allocators[afi][safi][i]) {
++ idalloc_destroy(d->id_allocators[afi][safi][i]);
++ d->id_allocators[afi][safi][i] = NULL;
++ }
++ }
++ }
++}
++
+ /*
+ * Free up resources associated with BGP route info structures.
+ */
+diff --git a/bgpd/bgp_addpath.h b/bgpd/bgp_addpath.h
+index c136671ea455..c7b1bff23800 100644
+--- a/bgpd/bgp_addpath.h
++++ b/bgpd/bgp_addpath.h
+@@ -25,6 +25,8 @@ struct bgp_paths_limit_capability {
+
+ void bgp_addpath_init_bgp_data(struct bgp_addpath_bgp_data *d);
+
++void bgp_addpath_finish_bgp_data(struct bgp_addpath_bgp_data *d);
++
+ bool bgp_addpath_is_addpath_used(struct bgp_addpath_bgp_data *d, afi_t afi,
+ safi_t safi);
+
+diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
+index 5d1122e34554..4f8ee466bb74 100644
+--- a/bgpd/bgp_evpn.c
++++ b/bgpd/bgp_evpn.c
+@@ -5420,6 +5420,40 @@ static void free_vni_entry(struct hash_bucket *bucket, struct bgp *bgp)
+ bgp_evpn_free(bgp, vpn);
+ }
+
++/*
++ * Iterator helper: drain per-VNI route tables (mac_table/ip_table) without
++ * freeing the bgpevpn struct itself. Used during early cleanup so that the
++ * imported per-VNI bgp_path_info entries (which reference parent path_info
++ * and dest objects in the global EVPN RIB) are reaped before the global
++ * EVPN RIB is finalized by bgp_cleanup_routes().
++ */
++static void drain_vni_routes(struct hash_bucket *bucket, struct bgp *bgp)
++{
++ struct bgpevpn *vpn = (struct bgpevpn *)bucket->data;
++
++ delete_all_vni_routes(bgp, vpn);
++}
++
++/*
++ * Drain the per-VNI route tables for every VNI owned by this bgp instance.
++ *
++ * Per-VNI imported paths (in vpn->mac_table and vpn->ip_table) hold
++ * extra->vrfleak->parent references back to BPI/dest objects in the global
++ * EVPN RIB. bgp_cleanup_routes() later finalizes those tables via
++ * bgp_table_finish() which forcibly zeroes the dest lock counts and frees the
++ * dest nodes, leaving dangling pointers behind. Reap the per-VNI paths now
++ * so that their bgp_path_info_extra_free() can safely unlock parent dests
++ * while those parents are still alive; the subsequent bgp_evpn_cleanup() then
++ * walks empty per-VNI tables and is a no-op for routes.
++ */
++void bgp_evpn_cleanup_per_vni_routes(struct bgp *bgp)
++{
++ if (!bgp->vnihash)
++ return;
++
++ hash_iterate(bgp->vnihash, (void (*)(struct hash_bucket *, void *))drain_vni_routes, bgp);
++}
++
+ /*
+ * Derive AUTO import RT for BGP VRF - L3VNI
+ */
+@@ -6104,6 +6138,16 @@ void bgp_evpn_handle_deferred_bestpath_for_vnis(struct bgp *bgp, uint16_t cnt)
+ {
+ struct vni_gr_walk ctx;
+
++ /*
++ * GR deferred path selection for SAFI_EVPN runs for any bgp instance
++ * with peers participating in graceful restart, but vnihash is only
++ * allocated by bgp_evpn_init() on instances that actually configure
++ * "address-family l2vpn evpn". Skip non-EVPN instances cleanly
++ * instead of crashing in hash_iterate().
++ */
++ if (!bgp->vnihash)
++ return;
++
+ ctx.bgp = bgp;
+ ctx.cnt = cnt;
+
+diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h
+index 38ec840b7ffd..f5d5b26137cb 100644
+--- a/bgpd/bgp_evpn.h
++++ b/bgpd/bgp_evpn.h
+@@ -179,6 +179,7 @@ extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
+ ifindex_t svi_ifindex);
+ extern void bgp_evpn_flood_control_change(struct bgp *bgp);
+ extern void bgp_evpn_cleanup_on_disable(struct bgp *bgp);
++extern void bgp_evpn_cleanup_per_vni_routes(struct bgp *bgp);
+ extern void bgp_evpn_cleanup(struct bgp *bgp);
+ extern void bgp_evpn_init(struct bgp *bgp);
+ extern int bgp_evpn_get_type5_prefixlen(const struct prefix *pfx);
+diff --git a/bgpd/bgp_labelpool.c b/bgpd/bgp_labelpool.c
+index 52cd676f4876..0fee625d8c5c 100644
+--- a/bgpd/bgp_labelpool.c
++++ b/bgpd/bgp_labelpool.c
+@@ -124,6 +124,14 @@ static wq_item_status lp_cbq_docallback(struct work_queue *wq, void *data)
+ return WQ_SUCCESS;
+ }
+
++ /*
++ * Drained item: bgp_lp_release_pending_lu_locks() has already
++ * dropped the dest reference and zeroed labelid as a marker.
++ * Don't run the callback - it would deref a stale or NULL labelid.
++ */
++ if (!lcbq->labelid)
++ return WQ_SUCCESS;
++
+ if (!bgp) {
+ /*
+ * If we can't find the BGP instance, we should still release
+@@ -201,7 +209,13 @@ void bgp_lp_init(struct event_loop *master, struct labelpool *pool)
+ /* check if a label callback was for a BGP LU node, and if so, unlock it */
+ static void check_bgp_lu_cb_unlock(struct lp_lcb *lcb)
+ {
+- if (lcb->type == LP_TYPE_BGP_LU)
++ /*
++ * NULL labelid is the marker left by bgp_lp_release_pending_lu_locks()
++ * for entries whose dest reference has already been dropped early
++ * (before bgp_delete() force-frees the underlying dests at shutdown).
++ * Skip those so we don't double-unlock or read freed memory.
++ */
++ if (lcb->type == LP_TYPE_BGP_LU && lcb->labelid)
+ bgp_dest_unlock_node(lcb->labelid);
+ }
+
+@@ -212,10 +226,68 @@ static void check_bgp_lu_cb_lock(struct lp_lcb *lcb)
+ bgp_dest_lock_node(lcb->labelid);
+ }
+
++/*
++ * Release any bgp_dest locks held by pending BGP-LU label requests.
++ *
++ * Pending LU requests live in the labelpool's slow-path FIFO
++ * (lp->requests) and on its callback workqueue (lp->callback_q); each one
++ * bumps the underlying bgp_dest's lock count via check_bgp_lu_cb_lock()
++ * so the dest stays alive until the request is satisfied or cancelled.
++ *
++ * At daemon shutdown bgp_exit() runs bgp_delete() for every bgp instance
++ * before bgp_lp_finish(). bgp_delete() / bgp_free() calls
++ * bgp_table_finish() which calls route_table_finish() which calls
++ * bgp_node_destroy() for every node, force-freeing the dest regardless
++ * of its lock count. Anything still held by the labelpool then becomes
++ * a dangling pointer; the unlock attempts in bgp_lp_finish() are a
++ * use-after-free, observable as an occasional
++ * assert(node->lock > 0) in route_unlock_node().
++ *
++ * This function must be called BEFORE bgp_delete() so the labelpool
++ * drops its dest references while the dests are still valid. Each
++ * neutralized entry is marked by zeroing its labelid; both the
++ * subsequent bgp_lp_finish() walk and lp_cbq_docallback() (in case the
++ * workqueue ever does run after this) treat NULL labelid as a no-op.
++ *
++ * The labelpool itself is left fully functional so bgp_delete() and its
++ * callees (e.g. bgp_label_per_nexthop_free() -> bgp_lp_release()) keep
++ * working. The earlier "just move bgp_lp_finish() up" patch
++ * (PR #15583) failed precisely because it made bgp_delete()-time
++ * label releases dereference an already-freed labelpool.
++ */
++void bgp_lp_release_pending_lu_locks(void)
++{
++ struct lp_fifo *lf;
++ struct work_queue_item *item;
++ struct lp_cbq_item *q;
++
++ if (!lp)
++ return;
++
++ frr_each (lp_fifo, &lp->requests, lf) {
++ if (lf->lcb.type == LP_TYPE_BGP_LU && lf->lcb.labelid) {
++ bgp_dest_unlock_node(lf->lcb.labelid);
++ lf->lcb.labelid = NULL;
++ }
++ }
++
++ if (!lp->callback_q)
++ return;
++
++ STAILQ_FOREACH (item, &lp->callback_q->items, wq) {
++ q = item->data;
++ if (q && q->type == LP_TYPE_BGP_LU && q->labelid) {
++ bgp_dest_unlock_node(q->labelid);
++ q->labelid = NULL;
++ }
++ }
++}
++
+ void bgp_lp_finish(void)
+ {
+ struct lp_fifo *lf;
+ struct work_queue_item *item, *titem;
++ struct lp_cbq_item *q;
+ struct listnode *node;
+ struct lp_chunk *chunk;
+
+@@ -247,11 +319,22 @@ void bgp_lp_finish(void)
+ * to remove an element from the queue after it has been run, resulting
+ * in a double unlock. Hence we need to iterate over our queues and
+ * lists and manually perform the unlocking (ugh)
++ *
++ * NB: callback workqueue items are struct lp_cbq_item, NOT struct
++ * lp_lcb - the two have different layouts so a cast is wrong.
++ * Read the type/labelid fields directly off lp_cbq_item. Entries
++ * already drained by bgp_lp_release_pending_lu_locks() carry a NULL
++ * labelid and are skipped.
+ */
+- STAILQ_FOREACH_SAFE (item, &lp->callback_q->items, wq, titem)
+- check_bgp_lu_cb_unlock(item->data);
++ if (lp->callback_q) {
++ STAILQ_FOREACH_SAFE (item, &lp->callback_q->items, wq, titem) {
++ q = item->data;
++ if (q && q->type == LP_TYPE_BGP_LU && q->labelid)
++ bgp_dest_unlock_node(q->labelid);
++ }
+
+- work_queue_free_and_null(&lp->callback_q);
++ work_queue_free_and_null(&lp->callback_q);
++ }
+
+ lp = NULL;
+ }
+diff --git a/bgpd/bgp_labelpool.h b/bgpd/bgp_labelpool.h
+index 809d5c305cca..9a2d86b23e8e 100644
+--- a/bgpd/bgp_labelpool.h
++++ b/bgpd/bgp_labelpool.h
+@@ -34,6 +34,7 @@ struct labelpool {
+ };
+
+ extern void bgp_lp_init(struct event_loop *master, struct labelpool *pool);
++extern void bgp_lp_release_pending_lu_locks(void);
+ extern void bgp_lp_finish(void);
+ extern void bgp_lp_get(int type, void *labelid, vrf_id_t vrf_id,
+ int (*cbfunc)(mpls_label_t label, void *labelid, bool allocated));
+diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
+index ff8493e776a6..3f3ea0150800 100644
+--- a/bgpd/bgp_main.c
++++ b/bgpd/bgp_main.c
+@@ -179,6 +179,25 @@ static FRR_NORETURN void bgp_exit(int status)
+ bgp_default = bgp_get_default();
+ bgp_evpn = bgp_get_evpn();
+
++ /*
++ * Drop any bgp_dest references the labelpool is still holding for
++ * pending BGP-LU label requests BEFORE bgp_delete() runs.
++ *
++ * bgp_delete() -> bgp_free() -> bgp_table_finish() force-frees every
++ * dest in the instance's tables regardless of lock count; if the
++ * labelpool's slow-path FIFO or callback workqueue still pin any of
++ * those dests, the unlock attempts later in bgp_lp_finish() become
++ * a use-after-free (occasional assert(node->lock > 0) crash in
++ * route_unlock_node()).
++ *
++ * This only releases the dest locks - the labelpool itself stays
++ * functional so bgp_delete()-time callers (e.g.
++ * bgp_label_per_nexthop_free() -> bgp_lp_release()) keep working.
++ * The remainder of the labelpool is torn down by bgp_lp_finish()
++ * below.
++ */
++ bgp_lp_release_pending_lu_locks();
++
+ /* reverse bgp_master_init */
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+ if (bgp_default == bgp || bgp_evpn == bgp)
+diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
+index 778b1ce214c8..ddbd24d9aafb 100644
+--- a/bgpd/bgp_route.c
++++ b/bgpd/bgp_route.c
+@@ -7087,11 +7087,39 @@ static void bgp_clear_node_queue_init(struct peer *peer)
+ peer->clear_node_queue->spec.data = peer;
+ }
+
++bool bgp_clear_node_queue_drain(struct peer *peer)
++{
++ struct work_queue *wq;
++ struct work_queue_item *item;
++ bool need_peer_unlock = false;
++
++ if (!peer || !peer->clear_node_queue)
++ return false;
++
++ wq = peer->clear_node_queue;
++ need_peer_unlock = work_queue_is_scheduled(wq) || !work_queue_empty(wq);
++
++ /*
++ * During daemon termination we need the clear-route work to run
++ * synchronously before queue teardown, otherwise we only drop refs.
++ *
++ * This is intentionally done this way because we are trying to cleanup
++ * memory on shutdown and these items need to be handled no matter what.
++ */
++ if (bm->terminating && wq->spec.workfunc) {
++ STAILQ_FOREACH (item, &wq->items, wq)
++ wq->spec.workfunc(wq, item->data);
++ }
++
++ work_queue_free_and_null(&peer->clear_node_queue);
++ return need_peer_unlock;
++}
++
+ static void bgp_clear_route_table(struct peer *peer, afi_t afi, safi_t safi,
+ struct bgp_table *table)
+ {
+ struct bgp_dest *dest;
+- int force = peer->bgp->process_queue ? 0 : 1;
++ int force = (!peer->bgp->process_queue || bm->terminating) ? 1 : 0;
+
+ if (!table)
+ table = peer->bgp->rib[afi][safi];
+diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
+index 8c26de1b45b7..d93e89e98584 100644
+--- a/bgpd/bgp_route.h
++++ b/bgpd/bgp_route.h
+@@ -786,6 +786,7 @@ extern void bgp_soft_reconfig_table_task_cancel(const struct bgp *bgp,
+ extern bool bgp_soft_reconfig_in(struct peer *peer, afi_t afi, safi_t safi);
+ extern void bgp_clear_route(struct peer *peer, afi_t afi, safi_t safi);
+ extern void bgp_clear_route_all(struct peer *peer);
++extern bool bgp_clear_node_queue_drain(struct peer *peer);
+ /* Clear routes for a batch of peers */
+ void bgp_clear_route_batch(struct bgp_clearing_info *cinfo);
+
+diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c
+index 1f4541088334..2a884a071a5d 100644
+--- a/bgpd/bgp_rpki.c
++++ b/bgpd/bgp_rpki.c
+@@ -878,6 +878,8 @@ static int bgp_rpki_fini(void)
+ XFREE(MTYPE_BGP_RPKI_CACHE, rpki_vrf);
+ }
+
++ list_delete(&rpki_vrf_list);
++
+ return 0;
+ }
+
+diff --git a/bgpd/bgp_srv6.c b/bgpd/bgp_srv6.c
+index 5b3b2e4d90bb..c16c3d57fd9b 100644
+--- a/bgpd/bgp_srv6.c
++++ b/bgpd/bgp_srv6.c
+@@ -262,6 +262,16 @@ void bgp_srv6_unicast_register_route(struct bgp *bgp, afi_t afi, struct bgp_dest
+ if (dest->srv6_unicast && sid_same(bgp->srv6_unicast[afi].sid, &dest->srv6_unicast->sid))
+ return;
+
++ /*
++ * If a previous SID was installed on this dest (e.g. the operator
++ * reconfigured the unicast SID without first walking/withdrawing the
++ * RIB), free the old descriptor before allocating a new one. Without
++ * this the previous XCALLOC is leaked across "no sid export ..." +
++ * re-add sequences that change the SID value.
++ */
++ if (dest->srv6_unicast)
++ bgp_srv6_unicast_unregister_route(dest);
++
+ locator = bgp->srv6_unicast[afi].sid_locator;
+ dest->srv6_unicast = XCALLOC(MTYPE_BGP_SRV6_L3SERVICE,
+ sizeof(struct bgp_attr_srv6_l3service));
+diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c
+index 17b417895f17..34847609df7b 100644
+--- a/bgpd/bgp_table.c
++++ b/bgpd/bgp_table.c
+@@ -18,6 +18,7 @@
+ #include "bgp_addpath.h"
+ #include "bgp_trace.h"
+ #include "bgp_mpath.h"
++#include "bgp_srv6.h"
+
+ void bgp_table_lock(struct bgp_table *rt)
+ {
+@@ -99,6 +100,17 @@ inline struct bgp_dest *bgp_dest_unlock_node(struct bgp_dest *dest)
+ if (dest->mpath)
+ bgp_path_info_mpath_free(&dest->mpath);
+
++ /*
++ * Release any SRv6 unicast prefix-sid descriptor still
++ * attached to this dest before the dest itself is freed.
++ * Normally bgp_cleanup_table() reaps these at instance
++ * teardown, but a dest can also be freed mid-run when its
++ * last path is reaped (e.g. peer flap, route withdrawal),
++ * which bypasses the cleanup walk and leaks the descriptor.
++ */
++ if (dest->srv6_unicast)
++ bgp_srv6_unicast_unregister_route(dest);
++
+ XFREE(MTYPE_BGP_NODE, dest);
+ dest = NULL;
+ rn->info = NULL;
+@@ -129,6 +141,18 @@ static void bgp_node_destroy(route_table_delegate_t *delegate,
+ if (dest->mpath)
+ bgp_path_info_mpath_free(&dest->mpath);
+
++ /*
++ * As in bgp_dest_unlock_node_debug(), make sure any
++ * lingering SRv6 unicast descriptor is released before
++ * the dest itself goes away. This path is hit when a
++ * route_table is force-finished (e.g. via
++ * bgp_table_finish() during instance teardown) while
++ * one or more dests still carry their dest->srv6_unicast
++ * pointer.
++ */
++ if (dest->srv6_unicast)
++ bgp_srv6_unicast_unregister_route(dest);
++
+ XFREE(MTYPE_BGP_NODE, dest);
+ node->info = NULL;
+ }
+diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c
+index f92e19ad69da..e523528c86c4 100644
+--- a/bgpd/bgp_updgrp.c
++++ b/bgpd/bgp_updgrp.c
+@@ -1940,10 +1940,21 @@ void update_bgp_group_init(struct bgp *bgp)
+ {
+ int afid;
+
+- AF_FOREACH (afid)
++ /*
++ * Be idempotent: when a hidden bgp instance is revived (see
++ * bgp_lookup_by_as_name_type() -> bgp_create() with hidden=true),
++ * bgp_create() runs again on the same struct bgp. The connectionhash
++ * and per-afi import_vrf list are already guarded with explicit NULL
++ * checks; without the same check here we would re-allocate the per-afi
++ * update_groups hash tables and leak the previously allocated set.
++ */
++ AF_FOREACH (afid) {
++ if (bgp->update_groups[afid])
++ continue;
+ bgp->update_groups[afid] =
+ hash_create(updgrp_hash_key_make, updgrp_hash_cmp,
+ "BGP Update Group Hash");
++ }
+ }
+
+ void update_bgp_group_free(struct bgp *bgp)
+diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
+index ef8ebea216d6..e92fe29af871 100644
+--- a/bgpd/bgpd.c
++++ b/bgpd/bgpd.c
+@@ -2796,6 +2796,7 @@ int peer_delete(struct peer *peer)
+ struct bgp_filter *filter;
+ struct listnode *pn;
+ int accept_peer;
++ bool clear_queue_lock_held = false;
+
+ assert(peer->connection->status != Deleted);
+
+@@ -2873,6 +2874,13 @@ int peer_delete(struct peer *peer)
+ bgp_stop(peer->connection);
+ UNSET_FLAG(peer->flags, PEER_FLAG_DELETE);
+
++ /*
++ * If shutdown interrupts clear-node workers, drain the queue now and
++ * account for the deferred bgp_clear_route() peer lock explicitly.
++ */
++ if (bm->terminating)
++ clear_queue_lock_held = bgp_clear_node_queue_drain(peer);
++
+ if (peer->doppelganger) {
+ peer->doppelganger->doppelganger = NULL;
+ peer->doppelganger = NULL;
+@@ -2946,7 +2954,9 @@ int peer_delete(struct peer *peer)
+ XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
+ XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version);
+
+- peer_unlock(peer); /* initial reference */
++ if (clear_queue_lock_held)
++ peer_unlock(peer); /* bgp_clear_route, completion callback equivalent */
++ peer_unlock(peer); /* initial reference */
+
+ return 0;
+ }
+@@ -3636,11 +3646,13 @@ static struct bgp *bgp_create(as_t *as, const char *name,
+
+ peer_init:
+ bgp->peer->cmp = (int (*)(void *, void *))peer_cmp;
+- bgp->connectionhash = hash_create(connection_hash_key_make, connection_hash_same,
+- "BGP Peer Hash");
+- bgp->connectionhash->max_size = BGP_PEER_MAX_HASH_SIZE;
++ if (!bgp->connectionhash) {
++ bgp->connectionhash = hash_create(connection_hash_key_make, connection_hash_same,
++ "BGP Peer Hash");
++ bgp->connectionhash->max_size = BGP_PEER_MAX_HASH_SIZE;
++ }
+
+- if (!hidden)
++ if (!bgp->group)
+ bgp->group = list_new();
+ bgp->group->cmp = (int (*)(void *, void *))peer_group_cmp;
+
+@@ -4416,13 +4428,39 @@ int bgp_delete(struct bgp *bgp)
+ }
+ }
+
++ if (bm->bgp_evpn == bgp) {
++ /*
++ * Reap all paths from per-VNI route tables BEFORE the global
++ * EVPN RIB is finalized by bgp_cleanup_routes() below.
++ *
++ * Per-VNI imported BPIs hold extra->vrfleak->parent references
++ * back into the global EVPN RIB. bgp_cleanup_routes() calls
++ * bgp_table_finish() on the per-RD inner tables which forcibly
++ * zeroes node->lock and frees the dest objects. If the per-VNI
++ * paths are reaped after that, bgp_path_info_extra_free()
++ * tries to bgp_dest_unlock_node() those already-freed dests,
++ * tripping the "node->lock > 0" assert.
++ */
++ bgp_evpn_cleanup_per_vni_routes(bgp);
++ }
++
+ bgp_cleanup_routes(bgp);
+
+- if (bm->terminating)
++ if (bm->bgp_evpn == bgp) {
+ /*
+- * Release EVPN VNI bgp_lock references so the
+- * subsequent bgp_unlock() can drive refcount to
+- * zero and trigger bgp_free().
++ * Release EVPN VNI bgp_lock references so the subsequent
++ * bgp_unlock() can drive refcount to zero and trigger
++ * bgp_free().
++ *
++ * This must run on every teardown of the EVPN-owner instance
++ * (not only during daemon termination). Each L2VNI holds a
++ * bgp_lock on the owner via bgpevpn_link_to_l3vni(); without
++ * releasing those locks here, "no router bgp" of the EVPN
++ * owner leaks the instance, its peer_self, and any local
++ * EVPN paths still held in the per-VNI tables. The per-VNI
++ * route tables were already drained above; free_vni_entry()
++ * here re-runs delete_all_vni_routes() which is a no-op (the
++ * tables are empty) and then frees the bgpevpn structs.
+ */
+ bgp_evpn_cleanup(bgp);
+ }
+@@ -4565,6 +4603,7 @@ void bgp_free(struct bgp *bgp)
+
+ bgp_evpn_cleanup(bgp);
+ bgp_pbr_cleanup(bgp);
++ bgp_addpath_finish_bgp_data(&bgp->tx_addpath);
+
+ for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+ enum vpn_policy_direction dir;
+--
+2.47.3
+
diff --git a/debian/patches/upstream/0014-ripd-Cleanup-memory-leaks-on-shutdown.patch b/debian/patches/upstream/0014-ripd-Cleanup-memory-leaks-on-shutdown.patch
new file mode 100644
index 000000000000..67807a0a6a41
--- /dev/null
+++ b/debian/patches/upstream/0014-ripd-Cleanup-memory-leaks-on-shutdown.patch
@@ -0,0 +1,58 @@
+From b235bb1ae2a4ad049d93560ce1e1f72e65313b49 Mon Sep 17 00:00:00 2001
+From: Donald Sharp <sharpd@nvidia.com>
+Date: Fri, 1 May 2026 13:54:28 -0400
+Subject: [PATCH 10/21] ripd: Cleanup memory leaks on shutdown
+
+a) access_list memory leaks
+b) snmp memory leaks
+
+Signed-off-by: Donald Sharp <sharpd@nvidia.com>
+---
+ ripd/rip_main.c | 1 +
+ ripd/rip_snmp.c | 12 ++++++++++++
+ 2 files changed, 13 insertions(+)
+
+diff --git a/ripd/rip_main.c b/ripd/rip_main.c
+index f7b011b747e3..a179919c9779 100644
+--- a/ripd/rip_main.c
++++ b/ripd/rip_main.c
+@@ -94,6 +94,7 @@ static FRR_NORETURN void sigint(void)
+ rip_zclient_stop();
+
+ route_map_finish();
++ access_list_reset();
+ prefix_list_reset();
+
+ keychain_terminate();
+diff --git a/ripd/rip_snmp.c b/ripd/rip_snmp.c
+index 118b08e527e9..8f8edd0247eb 100644
+--- a/ripd/rip_snmp.c
++++ b/ripd/rip_snmp.c
+@@ -562,12 +562,24 @@ static int rip_snmp_init(struct event_loop *mstr)
+ return 0;
+ }
+
++static int rip_snmp_terminate(void)
++{
++ if (rip_ifaddr_table) {
++ route_table_finish(rip_ifaddr_table);
++ rip_ifaddr_table = NULL;
++ }
++
++ smux_terminate();
++ return 0;
++}
++
+ static int rip_snmp_module_init(void)
+ {
+ hook_register(rip_ifaddr_add, rip_snmp_ifaddr_add);
+ hook_register(rip_ifaddr_del, rip_snmp_ifaddr_del);
+
+ hook_register(frr_late_init, rip_snmp_init);
++ hook_register(frr_fini, rip_snmp_terminate);
+ return 0;
+ }
+
+--
+2.47.3
+
diff --git a/debian/patches/upstream/0015-pbrd-termination-cleanup-of-memory-leaks.patch b/debian/patches/upstream/0015-pbrd-termination-cleanup-of-memory-leaks.patch
new file mode 100644
index 000000000000..0862da9df6a7
--- /dev/null
+++ b/debian/patches/upstream/0015-pbrd-termination-cleanup-of-memory-leaks.patch
@@ -0,0 +1,126 @@
+From c2e0c6c9b8d5d4e8c127f9a5cf0930eed93c607c Mon Sep 17 00:00:00 2001
+From: Donald Sharp <sharpd@nvidia.com>
+Date: Fri, 1 May 2026 14:11:37 -0400
+Subject: [PATCH 11/21] pbrd: termination cleanup of memory leaks
+
+a) pbr maps were being leaked, stop
+b) nexthop-groups were being leaked, stop
+c) access list's were being leaked, stop
+
+Signed-off-by: Donald Sharp <sharpd@nvidia.com>
+---
+ pbrd/pbr_main.c | 4 ++++
+ pbrd/pbr_map.c | 14 ++++++++++++++
+ pbrd/pbr_map.h | 1 +
+ pbrd/pbr_nht.c | 28 ++++++++++++++++++++++++++++
+ pbrd/pbr_nht.h | 1 +
+ 5 files changed, 48 insertions(+)
+
+diff --git a/pbrd/pbr_main.c b/pbrd/pbr_main.c
+index 7724a795d7f0..0a4aa34d501f 100644
+--- a/pbrd/pbr_main.c
++++ b/pbrd/pbr_main.c
+@@ -69,7 +69,11 @@ static FRR_NORETURN void sigint(void)
+ {
+ zlog_notice("Terminating on signal");
+
++ pbr_map_terminate();
+ pbr_vrf_terminate();
++ nexthop_group_terminate();
++ pbr_nht_terminate();
++ access_list_reset();
+
+ pbr_zebra_destroy();
+
+diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c
+index 713345a13016..0bd1fb3ba3a1 100644
+--- a/pbrd/pbr_map.c
++++ b/pbrd/pbr_map.c
+@@ -957,3 +957,17 @@ void pbr_map_init(void)
+
+ pbr_map_sequence_unique = 1;
+ }
++
++void pbr_map_terminate(void)
++{
++ struct pbr_map *pbrm;
++
++ while ((pbrm = RB_ROOT(pbr_map_entry_head, &pbr_maps))) {
++ struct pbr_map_sequence *pbrms;
++
++ pbrms = listnode_head(pbrm->seqnumbers);
++ assert(pbrms);
++
++ pbr_map_delete(pbrms);
++ }
++}
+diff --git a/pbrd/pbr_map.h b/pbrd/pbr_map.h
+index 9fb674bd6eb8..976e0e65ffff 100644
+--- a/pbrd/pbr_map.h
++++ b/pbrd/pbr_map.h
+@@ -246,6 +246,7 @@ extern void pbr_map_schedule_policy_from_nhg(const char *nh_group,
+ bool installed);
+
+ extern void pbr_map_install(struct pbr_map *pbrm);
++extern void pbr_map_terminate(void);
+
+ extern void pbr_map_policy_install(const char *name);
+ extern void pbr_map_policy_delete(struct pbr_map *pbrm,
+diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c
+index 5f87c0c1fa61..76fecc3f8866 100644
+--- a/pbrd/pbr_nht.c
++++ b/pbrd/pbr_nht.c
+@@ -173,6 +173,13 @@ static void pbr_nhgc_delete(struct pbr_nexthop_group_cache *p)
+ XFREE(MTYPE_PBR_NHG, p);
+ }
+
++static void pbr_nhrc_delete(void *arg)
++{
++ struct nhrc *nhrc = arg;
++
++ XFREE(MTYPE_PBR_NHG, nhrc);
++}
++
+ static void *pbr_nhgc_alloc(void *p)
+ {
+ struct pbr_nexthop_group_cache *new;
+@@ -1486,3 +1493,24 @@ void pbr_nht_init(void)
+ /* First unallocated table is lowest in range on init */
+ pbr_next_unallocated_table_id = PBR_NHT_DEFAULT_LOW_TABLEID;
+ }
++
++void pbr_nht_terminate(void)
++{
++ if (pbr_nhg_hash) {
++ hash_clean(pbr_nhg_hash, (void (*)(void *))pbr_nhgc_delete);
++ hash_free(pbr_nhg_hash);
++ pbr_nhg_hash = NULL;
++ }
++
++ if (pbr_nhrc_hash) {
++ hash_clean(pbr_nhrc_hash, pbr_nhrc_delete);
++ hash_free(pbr_nhrc_hash);
++ pbr_nhrc_hash = NULL;
++ }
++
++ if (pbr_nhg_allocated_id_hash) {
++ hash_clean(pbr_nhg_allocated_id_hash, NULL);
++ hash_free(pbr_nhg_allocated_id_hash);
++ pbr_nhg_allocated_id_hash = NULL;
++ }
++}
+diff --git a/pbrd/pbr_nht.h b/pbrd/pbr_nht.h
+index a8c26413798b..92dc4060bbc7 100644
+--- a/pbrd/pbr_nht.h
++++ b/pbrd/pbr_nht.h
+@@ -139,6 +139,7 @@ extern void pbr_nht_nexthop_update(struct zapi_route *nhr);
+ extern void pbr_nht_nexthop_interface_update(struct interface *ifp);
+
+ extern void pbr_nht_init(void);
++extern void pbr_nht_terminate(void);
+
+ extern void pbr_nht_vrf_update(struct pbr_vrf *pbr_vrf);
+ extern void pbr_nht_interface_update(struct interface *ifp);
+--
+2.47.3
+
diff --git a/debian/patches/upstream/0016-nhrpd-Cleanup-nhrpd-termination-memory-leaks.patch b/debian/patches/upstream/0016-nhrpd-Cleanup-nhrpd-termination-memory-leaks.patch
new file mode 100644
index 000000000000..b91050d58ac6
--- /dev/null
+++ b/debian/patches/upstream/0016-nhrpd-Cleanup-nhrpd-termination-memory-leaks.patch
@@ -0,0 +1,105 @@
+From 5bec9de50fe664bcbc857e16f6e656c328968c03 Mon Sep 17 00:00:00 2001
+From: Donald Sharp <sharpd@nvidia.com>
+Date: Fri, 1 May 2026 14:18:31 -0400
+Subject: [PATCH 12/21] nhrpd: Cleanup nhrpd termination memory leaks
+
+a) interface gre memory leaks, stop
+b) packet request id memory leaks, stop
+c) event request id memory leaks, stop
+
+Signed-off-by: Donald Sharp <sharpd@nvidia.com>
+---
+ nhrpd/nhrp_interface.c | 10 ++++++++++
+ nhrpd/nhrp_main.c | 3 +++
+ nhrpd/nhrpd.h | 2 ++
+ nhrpd/reqid.c | 9 +++++++++
+ 4 files changed, 24 insertions(+)
+
+diff --git a/nhrpd/nhrp_interface.c b/nhrpd/nhrp_interface.c
+index 947ef77b9410..a70ce536fbea 100644
+--- a/nhrpd/nhrp_interface.c
++++ b/nhrpd/nhrp_interface.c
+@@ -52,6 +52,11 @@ static void *nhrp_interface_gre_alloc(void *data)
+ return a;
+ }
+
++static void nhrp_interface_gre_free(void *data)
++{
++ XFREE(MTYPE_NHRP_IF_GRE, data);
++}
++
+ struct nhrp_gre_info *nhrp_gre_info_alloc(struct nhrp_gre_info *p)
+ {
+ struct nhrp_gre_info *a;
+@@ -115,6 +120,11 @@ void nhrp_interface_init(void)
+ "NHRP GRE list Hash");
+ }
+
++void nhrp_interface_terminate(void)
++{
++ hash_clean_and_free(&nhrp_gre_list, nhrp_interface_gre_free);
++}
++
+ void nhrp_interface_update_mtu(struct interface *ifp, afi_t afi)
+ {
+ struct nhrp_interface *nifp = ifp->info;
+diff --git a/nhrpd/nhrp_main.c b/nhrpd/nhrp_main.c
+index 3c33db316701..480ab6b9f0ac 100644
+--- a/nhrpd/nhrp_main.c
++++ b/nhrpd/nhrp_main.c
+@@ -88,12 +88,15 @@ static FRR_NORETURN void nhrp_request_stop(void)
+ nhrp_zebra_terminate();
+ vici_terminate();
+ evmgr_terminate();
++ nhrp_interface_terminate();
+ vrf_terminate();
+ nhrp_vc_terminate();
+
+ debugf(NHRP_DEBUG_COMMON, "Done.");
+
+ resolver_terminate();
++ nhrp_reqid_terminate(&nhrp_packet_reqid);
++ nhrp_reqid_terminate(&nhrp_event_reqid);
+ frr_fini();
+
+ exit(0);
+diff --git a/nhrpd/nhrpd.h b/nhrpd/nhrpd.h
+index 5d59a60e766e..97be65cd087b 100644
+--- a/nhrpd/nhrpd.h
++++ b/nhrpd/nhrpd.h
+@@ -364,6 +364,7 @@ extern struct zebra_privs_t nhrpd_privs;
+ int sock_open_unix(const char *path);
+
+ void nhrp_interface_init(void);
++void nhrp_interface_terminate(void);
+ void nhrp_interface_update(struct interface *ifp);
+ void nhrp_interface_update_arp(struct interface *ifp, bool arp_enable);
+ void nhrp_interface_update_mtu(struct interface *ifp, afi_t afi);
+@@ -516,6 +517,7 @@ uint32_t nhrp_reqid_alloc(struct nhrp_reqid_pool *p, struct nhrp_reqid *r,
+ void (*cb)(struct nhrp_reqid *, void *));
+ void nhrp_reqid_free(struct nhrp_reqid_pool *p, struct nhrp_reqid *r);
+ struct nhrp_reqid *nhrp_reqid_lookup(struct nhrp_reqid_pool *, uint32_t reqid);
++void nhrp_reqid_terminate(struct nhrp_reqid_pool *p);
+
+ int nhrp_packet_init(void);
+
+diff --git a/nhrpd/reqid.c b/nhrpd/reqid.c
+index c2f5d24b69b8..d6d094919cad 100644
+--- a/nhrpd/reqid.c
++++ b/nhrpd/reqid.c
+@@ -52,3 +52,12 @@ struct nhrp_reqid *nhrp_reqid_lookup(struct nhrp_reqid_pool *p, uint32_t reqid)
+ key.request_id = reqid;
+ return hash_lookup(p->reqid_hash, &key);
+ }
++
++void nhrp_reqid_terminate(struct nhrp_reqid_pool *p)
++{
++ if (!p)
++ return;
++
++ hash_clean_and_free(&p->reqid_hash, NULL);
++ p->next_request_id = 0;
++}
+--
+2.47.3
+
diff --git a/debian/patches/upstream/0017-sharpd-memory-leaks-on-shutdown-cleanup.patch b/debian/patches/upstream/0017-sharpd-memory-leaks-on-shutdown-cleanup.patch
new file mode 100644
index 000000000000..580793fda534
--- /dev/null
+++ b/debian/patches/upstream/0017-sharpd-memory-leaks-on-shutdown-cleanup.patch
@@ -0,0 +1,80 @@
+From 506287772549bbd5ff59a4e74cbb32ed98a5b36a Mon Sep 17 00:00:00 2001
+From: Donald Sharp <sharpd@nvidia.com>
+Date: Fri, 1 May 2026 14:30:58 -0400
+Subject: [PATCH 13/21] sharpd: memory leaks on shutdown cleanup
+
+a) srv6 memory leaks on shutdown, stop
+b) nexthop-group memory leaks on shutdown, stop
+
+Signed-off-by: Donald Sharp <sharpd@nvidia.com>
+---
+ sharpd/sharp_main.c | 14 ++++++++++++++
+ sharpd/sharp_nht.c | 5 +++++
+ sharpd/sharp_nht.h | 1 +
+ 3 files changed, 20 insertions(+)
+
+diff --git a/sharpd/sharp_main.c b/sharpd/sharp_main.c
+index 76aa923e09c8..7f39f4a8ab64 100644
+--- a/sharpd/sharp_main.c
++++ b/sharpd/sharp_main.c
+@@ -27,6 +27,7 @@
+ #include "distribute.h"
+ #include "libfrr.h"
+ #include "routemap.h"
++#include "nexthop.h"
+ #include "nexthop_group.h"
+ #include "link_state.h"
+
+@@ -74,6 +75,18 @@ static void sharp_srv6_locators_list_delete(void *item)
+
+ static void sharp_global_destroy(void)
+ {
++ /*
++ * Route templates can keep SRv6 encap/seg6local payloads attached to
++ * sg.r.nhop across command invocations. Ensure they are released at exit.
++ */
++ nexthop_del_srv6_seg6local(&sg.r.nhop);
++ nexthop_del_srv6_seg6(&sg.r.nhop);
++ nexthop_del_srv6_seg6local(&sg.r.backup_nhop);
++ nexthop_del_srv6_seg6(&sg.r.backup_nhop);
++
++ /* Free imported Traffic Engineering LSDB (nodes/edges/subnets + attrs). */
++ ls_ted_del_all(&sg.ted);
++
+ list_delete(&sg.nhs);
+
+ sg.srv6_locators->del = sharp_srv6_locators_list_delete;
+@@ -94,6 +107,7 @@ static FRR_NORETURN void sigint(void)
+ {
+ zlog_notice("Terminating on signal");
+
++ sharp_nhgroup_terminate();
+ vrf_terminate();
+ sharp_zebra_terminate();
+
+diff --git a/sharpd/sharp_nht.c b/sharpd/sharp_nht.c
+index 6d64fcfb259b..b42a1fba7f19 100644
+--- a/sharpd/sharp_nht.c
++++ b/sharpd/sharp_nht.c
+@@ -229,3 +229,8 @@ void sharp_nhgroup_init(void)
+ sharp_nhgroup_del_nexthop_cb,
+ sharp_nhgroup_delete_cb);
+ }
++
++void sharp_nhgroup_terminate(void)
++{
++ nexthop_group_terminate();
++}
+diff --git a/sharpd/sharp_nht.h b/sharpd/sharp_nht.h
+index b27952ac511c..233b0c5f77fa 100644
+--- a/sharpd/sharp_nht.h
++++ b/sharpd/sharp_nht.h
+@@ -27,4 +27,5 @@ extern void sharp_nhgroup_id_set_installed(uint32_t id, bool installed);
+ extern bool sharp_nhgroup_id_is_installed(uint32_t id);
+
+ extern void sharp_nhgroup_init(void);
++extern void sharp_nhgroup_terminate(void);
+ #endif
+--
+2.47.3
+
diff --git a/debian/patches/upstream/0018-ospfd-memory-leaks-on-shutdown.patch b/debian/patches/upstream/0018-ospfd-memory-leaks-on-shutdown.patch
new file mode 100644
index 000000000000..1cee15a00517
--- /dev/null
+++ b/debian/patches/upstream/0018-ospfd-memory-leaks-on-shutdown.patch
@@ -0,0 +1,38 @@
+From c45c8876301933ede0948775bc34a2cb911c33d5 Mon Sep 17 00:00:00 2001
+From: Donald Sharp <sharpd@nvidia.com>
+Date: Fri, 1 May 2026 14:33:23 -0400
+Subject: [PATCH 14/21] ospfd: memory leaks on shutdown
+
+Cleanup ted memory leaks on shutdown.
+
+Signed-off-by: Donald Sharp <sharpd@nvidia.com>
+---
+ ospfd/ospf_te.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c
+index 22abb58b02e5..a5c40f5d547d 100644
+--- a/ospfd/ospf_te.c
++++ b/ospfd/ospf_te.c
+@@ -159,6 +159,9 @@ int ospf_mpls_te_init(void)
+
+ void ospf_mpls_te_term(void)
+ {
++ /* Release imported/exported TE link-state database on daemon exit. */
++ ls_ted_del_all(&OspfMplsTE.ted);
++
+ list_delete(&OspfMplsTE.iflist);
+
+ ospf_delete_opaque_functab(OSPF_OPAQUE_AREA_LSA,
+@@ -177,6 +180,8 @@ void ospf_mpls_te_term(void)
+
+ void ospf_mpls_te_finish(void)
+ {
++ ls_ted_del_all(&OspfMplsTE.ted);
++
+ OspfMplsTE.enabled = false;
+ OspfMplsTE.inter_as = Off;
+ OspfMplsTE.export = false;
+--
+2.47.3
+
diff --git a/debian/patches/upstream/0019-lib-Cleanup-memory-leaks-in-shutdown-in-affinitymaps.patch b/debian/patches/upstream/0019-lib-Cleanup-memory-leaks-in-shutdown-in-affinitymaps.patch
new file mode 100644
index 000000000000..b82688c63a5c
--- /dev/null
+++ b/debian/patches/upstream/0019-lib-Cleanup-memory-leaks-in-shutdown-in-affinitymaps.patch
@@ -0,0 +1,32 @@
+From 4372bf1cca88569b95c1cab1fc8627dc2f4d2ff6 Mon Sep 17 00:00:00 2001
+From: Donald Sharp <sharpd@nvidia.com>
+Date: Fri, 1 May 2026 15:09:11 -0400
+Subject: [PATCH 15/21] lib: Cleanup memory leaks in shutdown in affinitymaps
+
+Signed-off-by: Donald Sharp <sharpd@nvidia.com>
+---
+ lib/affinitymap.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/lib/affinitymap.c b/lib/affinitymap.c
+index e8659ccabb3b..cd7029e36c87 100644
+--- a/lib/affinitymap.c
++++ b/lib/affinitymap.c
+@@ -115,9 +115,10 @@ void affinity_map_set_update_hook(void (*func)(const char *affmap_name,
+
+ void affinity_map_terminate(void)
+ {
+- struct affinity_map *map;
+- struct listnode *node, *nnode;
++ if (!affinity_map_master.maps)
++ return;
+
+- for (ALL_LIST_ELEMENTS(affinity_map_master.maps, node, nnode, map))
+- affinity_map_free(map);
++ affinity_map_master.maps->del = (void (*)(void *))affinity_map_free;
++ list_delete(&affinity_map_master.maps);
++ affinity_map_master.update_hook = NULL;
+ }
+--
+2.47.3
+
diff --git a/debian/patches/upstream/0020-zebra-cleanup-memory-leaks-on-shutdown.patch b/debian/patches/upstream/0020-zebra-cleanup-memory-leaks-on-shutdown.patch
new file mode 100644
index 000000000000..5b45d20e35c0
--- /dev/null
+++ b/debian/patches/upstream/0020-zebra-cleanup-memory-leaks-on-shutdown.patch
@@ -0,0 +1,175 @@
+From ce85fb6a6ba5f81a2782d87d1ac6c60ee29d575d Mon Sep 17 00:00:00 2001
+From: Donald Sharp <sharpd@nvidia.com>
+Date: Fri, 1 May 2026 15:09:52 -0400
+Subject: [PATCH 16/21] zebra: cleanup memory leaks on shutdown
+
+a) vxlan memory leaks on shutdown, fix.
+b) evpn-mh memory leaks on shutdown, fix.
+c) mpls-fec memory leaks on shutdown, fix.
+d) route-map memory leaks on shutdown, fix.
+
+Signed-off-by: Donald Sharp <sharpd@nvidia.com>
+---
+ zebra/interface.c | 16 ++++++++++++++++
+ zebra/zebra_evpn_mh.c | 23 +++++++++++++++++------
+ zebra/zebra_mpls.c | 15 +++++++++++++++
+ zebra/zebra_routemap.c | 22 ++++++++++++++++++++++
+ 4 files changed, 70 insertions(+), 6 deletions(-)
+
+diff --git a/zebra/interface.c b/zebra/interface.c
+index 23324a677314..de71b0c31a81 100644
+--- a/zebra/interface.c
++++ b/zebra/interface.c
+@@ -32,6 +32,7 @@
+ #include "zebra/rt_netlink.h"
+ #include "zebra/if_netlink.h"
+ #include "zebra/zebra_vxlan.h"
++#include "zebra/zebra_vxlan_if.h"
+ #include "zebra/zebra_errors.h"
+ #include "zebra/zebra_evpn_mh.h"
+ #include "zebra/zebra_trace.h"
+@@ -228,6 +229,21 @@ static int if_zebra_delete_hook(struct interface *ifp)
+ list_delete(&bond->mbr_zifs);
+
+ zebra_l2_bridge_if_cleanup(ifp);
++ /*
++ * Destroy any per-VXLAN-IF SVD VNI table that is still hanging
++ * around. In the runtime delete path this is already done via
++ * zebra_l2_vxlanif_del() before if_delete_update() fires the
++ * if_del hook, so this is a no-op there. At zebra shutdown,
++ * however, dplane delete events do not arrive, so we need to
++ * release the VNI table here or the L2 VNI entries leak.
++ *
++ * Must guard on IS_ZEBRA_VXLAN_IF_SVD: for per-VNI VXLAN
++ * interfaces vni_info->vni_table aliases the embedded
++ * zebra_vxlan_vni struct via a union, so reading it as a hash
++ * pointer would dereference garbage.
++ */
++ if (IS_ZEBRA_IF_VXLAN(ifp) && IS_ZEBRA_VXLAN_IF_SVD(zebra_if))
++ zebra_vxlan_if_vni_table_destroy(zebra_if);
+ zebra_evpn_if_cleanup(zebra_if);
+ zebra_evpn_mac_ifp_del(ifp);
+
+diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c
+index 2c95342ac587..de602f529024 100644
+--- a/zebra/zebra_evpn_mh.c
++++ b/zebra/zebra_evpn_mh.c
+@@ -826,7 +826,7 @@ void zebra_evpn_vl_vxl_ref(uint16_t vid, vni_t vni_id,
+ void zebra_evpn_vl_vxl_deref(uint16_t vid, vni_t vni_id,
+ struct zebra_if *vxlan_zif)
+ {
+- struct interface *br_if;
++ ifindex_t bridge_ifindex;
+ struct zebra_evpn_access_bd *acc_bd;
+ uint8_t tmp_cnt;
+
+@@ -836,11 +836,22 @@ void zebra_evpn_vl_vxl_deref(uint16_t vid, vni_t vni_id,
+ if (!vni_id)
+ return;
+
+- br_if = vxlan_zif->brslave_info.br_if;
+- if (!br_if)
++ /*
++ * Use the stored bridge_ifindex rather than dereferencing
++ * brslave_info.br_if. At zebra shutdown, vrf_terminate_single() ->
++ * if_terminate() walks the per-VRF interface tree by name and frees
++ * interfaces one by one; if the bridge is freed before the VxLAN
++ * interface, the back pointer becomes a dangling reference. The
++ * bridge_ifindex field is never invalidated this way, and
++ * zebra_evpn_acc_vl_find_index() looks up the access-bd directly by
++ * (vid, ifindex), avoiding the heap-use-after-free in
++ * zebra_evpn_acc_vl_find()'s br_if->ifindex deref.
++ */
++ bridge_ifindex = vxlan_zif->brslave_info.bridge_ifindex;
++ if (bridge_ifindex == IFINDEX_INTERNAL)
+ return;
+
+- acc_bd = zebra_evpn_acc_vl_find(vid, br_if);
++ acc_bd = zebra_evpn_acc_vl_find_index(vid, bridge_ifindex);
+ if (!acc_bd)
+ return;
+ if (acc_bd->vni_refcnt > 1) {
+@@ -857,8 +868,8 @@ void zebra_evpn_vl_vxl_deref(uint16_t vid, vni_t vni_id,
+ return;
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+- zlog_debug("access vlan %d bridge %s vni %u deref", acc_bd->vid,
+- br_if->name, vni_id);
++ zlog_debug("access vlan %d bridge ifindex %u vni %u deref", acc_bd->vid,
++ bridge_ifindex, vni_id);
+
+ if (acc_bd->zevpn)
+ zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, acc_bd->zevpn);
+diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c
+index 3325532ca920..c6bb8e619d10 100644
+--- a/zebra/zebra_mpls.c
++++ b/zebra/zebra_mpls.c
+@@ -4055,6 +4055,19 @@ static void lsp_table_free(void *p)
+ XFREE(MTYPE_LSP, lsp);
+ }
+
++static void zebra_mpls_fec_node_cleanup(struct route_table *table, struct route_node *node)
++{
++ struct zebra_fec *fec;
++
++ if (!node->info)
++ return;
++
++ fec = node->info;
++ list_delete(&fec->client_list);
++ XFREE(MTYPE_FEC, fec);
++ node->info = NULL;
++}
++
+ /*
+ * Called upon process exiting, need to delete LSP forwarding
+ * entries from the kernel.
+@@ -4089,6 +4102,8 @@ void zebra_mpls_init_tables(struct zebra_vrf *zvrf)
+ zvrf->lsp_table = hash_create_size(8, label_hash, label_cmp, buffer);
+ zvrf->fec_table[AFI_IP] = route_table_init();
+ zvrf->fec_table[AFI_IP6] = route_table_init();
++ zvrf->fec_table[AFI_IP]->cleanup = zebra_mpls_fec_node_cleanup;
++ zvrf->fec_table[AFI_IP6]->cleanup = zebra_mpls_fec_node_cleanup;
+ zvrf->mpls_flags = 0;
+ zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
+ zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
+diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c
+index cdc05fe2ab1f..93e067f8308f 100644
+--- a/zebra/zebra_routemap.c
++++ b/zebra/zebra_routemap.c
+@@ -1196,10 +1196,32 @@ void zebra_route_map_set_delay_timer(uint32_t value)
+
+ void zebra_routemap_finish(void)
+ {
++ afi_t afi;
++ safi_t safi;
++ uint32_t table;
++
+ /* Set zebra_rmap_update_timer to 0 so that it wont schedule again */
+ zebra_rmap_update_timer = 0;
+ /* Thread off if any scheduled already */
+ event_cancel(&zebra_t_rmap_update);
++
++ /*
++ * Release any per-import-table route-map name strings that were
++ * never explicitly removed via "no ip import-table ...". The import
++ * table machinery only frees the string when the import is torn down
++ * at runtime, so on a clean SIGTERM shutdown the configured names
++ * leak.
++ */
++ for (afi = AFI_IP; afi < AFI_MAX; afi++) {
++ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
++ for (table = 0; table < ZEBRA_KERNEL_TABLE_MAX; table++) {
++ if (zebra_import_table_routemap[afi][safi][table])
++ XFREE(MTYPE_ROUTE_MAP_NAME,
++ zebra_import_table_routemap[afi][safi][table]);
++ }
++ }
++ }
++
+ route_map_finish();
+ }
+
+--
+2.47.3
+
diff --git a/debian/patches/upstream/0021-ldpd-Fixup-memory-leaks-on-shutdown.patch b/debian/patches/upstream/0021-ldpd-Fixup-memory-leaks-on-shutdown.patch
new file mode 100644
index 000000000000..000a9129cd3f
--- /dev/null
+++ b/debian/patches/upstream/0021-ldpd-Fixup-memory-leaks-on-shutdown.patch
@@ -0,0 +1,207 @@
+From 364545ba9db021b924c047006b584eff47bc3290 Mon Sep 17 00:00:00 2001
+From: Donald Sharp <sharpd@nvidia.com>
+Date: Fri, 1 May 2026 16:03:37 -0400
+Subject: [PATCH 17/21] ldpd: Fixup memory leaks on shutdown
+
+a) zclient memory not cleaned up on shutdown, fix.
+b) libfrr memory not cleaned up on shutdown, fix.
+c) lde label list not cleaned up on shutdown, fix.
+d) snmp memory not cleaned up on shutdown, fix.
+e) accept memory not cleaned up on shutdown, fix.
+
+Signed-off-by: Donald Sharp <sharpd@nvidia.com>
+---
+ ldpd/lde.c | 40 ++++++++++++++++++++++++++++++++++++----
+ ldpd/ldp_snmp.c | 8 ++++++++
+ ldpd/ldpd.c | 17 +++++++++++++++++
+ ldpd/ldpe.c | 15 ++++++++++++---
+ 4 files changed, 73 insertions(+), 7 deletions(-)
+
+diff --git a/ldpd/lde.c b/ldpd/lde.c
+index 83bc806e49a2..6dc48b17a239 100644
+--- a/ldpd/lde.c
++++ b/ldpd/lde.c
+@@ -48,7 +48,9 @@ static int lde_address_add(struct lde_nbr *, struct lde_addr *);
+ static int lde_address_del(struct lde_nbr *, struct lde_addr *);
+ static void lde_address_list_free(struct lde_nbr *);
+ static void zclient_sync_init(void);
++static void zclient_sync_cleanup(void);
+ static void lde_label_list_init(void);
++static void lde_label_list_cleanup(void);
+ static int lde_get_label_chunk(void);
+ static void on_get_label_chunk_response(uint32_t start, uint32_t end);
+ static uint32_t lde_get_next_label(void);
+@@ -194,6 +196,8 @@ static FRR_NORETURN void lde_shutdown(void)
+ lde_gc_stop_timer();
+ lde_nbr_clear();
+ fec_tree_clear();
++ lde_label_list_cleanup();
++ zclient_sync_cleanup();
+
+ config_clear(ldeconf);
+
+@@ -203,7 +207,8 @@ static FRR_NORETURN void lde_shutdown(void)
+
+ log_info("label decision engine exiting");
+
+- zlog_fini();
++ frr_early_fini();
++ frr_fini();
+ exit(0);
+ }
+
+@@ -2219,14 +2224,22 @@ static void zclient_sync_init(void)
+ retry:
+
+ /* Discard failed zclient object */
+- zclient_stop(zclient_sync);
+- zclient_free(zclient_sync);
+- zclient_sync = NULL;
++ zclient_sync_cleanup();
+
+ /* Retry using a timer */
+ event_add_timer(master, zclient_sync_retry, NULL, 1, NULL);
+ }
+
++static void zclient_sync_cleanup(void)
++{
++ if (!zclient_sync)
++ return;
++
++ zclient_stop(zclient_sync);
++ zclient_free(zclient_sync);
++ zclient_sync = NULL;
++}
++
+ static void
+ lde_del_label_chunk(void *val)
+ {
+@@ -2278,6 +2291,25 @@ lde_label_list_init(void)
+ }
+ }
+
++static void
++lde_label_list_cleanup(void)
++{
++ struct listnode *node, *nnode;
++ struct label_chunk *label_chunk;
++
++ if (!label_chunk_list)
++ return;
++
++ for (ALL_LIST_ELEMENTS(label_chunk_list, node, nnode, label_chunk)) {
++ if (zclient_sync &&
++ lde_release_label_chunk(label_chunk->start, label_chunk->end) != 0)
++ log_warnx("%s: Error releasing label chunk!", __func__);
++ }
++
++ current_label_chunk = NULL;
++ list_delete(&label_chunk_list);
++}
++
+ static void
+ on_get_label_chunk_response(uint32_t start, uint32_t end)
+ {
+diff --git a/ldpd/ldp_snmp.c b/ldpd/ldp_snmp.c
+index 2e7933f95c94..c289080195cc 100644
+--- a/ldpd/ldp_snmp.c
++++ b/ldpd/ldp_snmp.c
+@@ -1173,6 +1173,12 @@ static int ldp_snmp_nbr_state_change(struct nbr * nbr, int old_state)
+ return 0;
+ }
+
++static int ldp_snmp_terminate(void)
++{
++ smux_terminate();
++ return 0;
++}
++
+ static int ldp_snmp_init(struct event_loop *tm)
+ {
+ hook_register(agentx_enabled, ldp_snmp_agentx_enabled);
+@@ -1208,6 +1214,8 @@ static int ldp_snmp_register_mib(struct event_loop *tm)
+
+ static int ldp_snmp_module_init(void)
+ {
++ hook_register(frr_fini, ldp_snmp_terminate);
++
+ if (ldpd_process == PROC_MAIN)
+ hook_register(frr_late_init, ldp_snmp_init);
+ else
+diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c
+index 8675edf1ddf8..0d1698cdd288 100644
+--- a/ldpd/ldpd.c
++++ b/ldpd/ldpd.c
+@@ -2026,6 +2026,7 @@ void
+ config_clear(struct ldpd_conf *conf)
+ {
+ struct ldpd_conf *xconf;
++ struct tnbr *tnbr;
+
+ /*
+ * Merge current config with an empty config, this will deactivate
+@@ -2041,5 +2042,21 @@ config_clear(struct ldpd_conf *conf)
+ xconf->flags = conf->flags;
+ merge_config(conf, xconf);
+ free(xconf);
++
++ /*
++ * merge_tnbrs() only walks tnbrs that have F_TNBR_CONFIGURED set;
++ * dynamic targeted neighbours learned from received hello packets
++ * (F_TNBR_DYNAMIC, recv_hello() in hello.c) and rlfa tnbrs created
++ * by ldpe_rlfa_init() in rlfa.c are skipped, so they remain in the
++ * tree and would leak when conf is freed below. Drain the tree
++ * explicitly before letting the container go.
++ */
++ while (!RB_EMPTY(tnbr_head, &conf->tnbr_tree)) {
++ tnbr = RB_ROOT(tnbr_head, &conf->tnbr_tree);
++ event_cancel(&tnbr->hello_timer);
++ RB_REMOVE(tnbr_head, &conf->tnbr_tree, tnbr);
++ free(tnbr);
++ }
++
+ free(conf);
+ }
+diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c
+index f88d566b4188..b5e0f2dea946 100644
+--- a/ldpd/ldpe.c
++++ b/ldpd/ldpe.c
+@@ -152,6 +152,16 @@ ldpe_init(struct ldpd_init *init)
+ zprivs_preinit(&ldpe_privs);
+ zprivs_init(&ldpe_privs);
+
++ /*
++ * Initialise the accept_queue before any caller of accept_add() so we
++ * don't LIST_INIT-clobber entries that have already been registered
++ * (the control socket registers one in control_listen() below). When
++ * the orphaned entry is later left on a dangling list head, accept_del()
++ * at shutdown can't find the fd and the struct accept_ev allocation
++ * leaks.
++ */
++ accept_init();
++
+ /* listen on ldpd control socket */
+ strlcpy(ctl_sock_path, init->ctl_sock_path, sizeof(ctl_sock_path));
+ if (control_init(ctl_sock_path) == -1)
+@@ -177,8 +187,6 @@ ldpe_init(struct ldpd_init *init)
+
+ if ((pkt_ptr = calloc(1, IBUF_READ_SIZE)) == NULL)
+ fatal(__func__);
+-
+- accept_init();
+ }
+
+ static FRR_NORETURN void ldpe_shutdown(void)
+@@ -231,7 +239,8 @@ static FRR_NORETURN void ldpe_shutdown(void)
+
+ log_info("ldp engine exiting");
+
+- zlog_fini();
++ frr_early_fini();
++ frr_fini();
+
+ exit(0);
+ }
+--
+2.47.3
+
diff --git a/debian/patches/upstream/0022-Cleanup-snmp-memory-leaks.patch b/debian/patches/upstream/0022-Cleanup-snmp-memory-leaks.patch
new file mode 100644
index 000000000000..d11209c96cc7
--- /dev/null
+++ b/debian/patches/upstream/0022-Cleanup-snmp-memory-leaks.patch
@@ -0,0 +1,121 @@
+From f34c158e097ca662b8aab6f074c31fa419d9a15e Mon Sep 17 00:00:00 2001
+From: Donald Sharp <sharpd@nvidia.com>
+Date: Fri, 1 May 2026 16:40:34 -0400
+Subject: [PATCH 18/21] *: Cleanup snmp memory leaks
+
+bgpd, ospf6d, ospfd and zebra were not cleaning up snmp smux
+data structures no shutdown. Do so.
+
+Signed-off-by: Donald Sharp <sharpd@nvidia.com>
+---
+ bgpd/bgp_snmp.c | 7 +++++++
+ ospf6d/ospf6_snmp.c | 7 +++++++
+ ospfd/ospf_snmp.c | 17 +++++++++++++++++
+ zebra/zebra_snmp.c | 7 +++++++
+ 4 files changed, 38 insertions(+)
+
+diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c
+index eff7c5e0f653..03b5798770e6 100644
+--- a/bgpd/bgp_snmp.c
++++ b/bgpd/bgp_snmp.c
+@@ -144,11 +144,18 @@ static int bgp_snmp_init(struct event_loop *tm)
+ return 0;
+ }
+
++static int bgp_snmp_terminate(void)
++{
++ smux_terminate();
++ return 0;
++}
++
+ static int bgp_snmp_module_init(void)
+ {
+ hook_register(peer_status_changed, bgpTrapEstablished);
+ hook_register(peer_backward_transition, bgpTrapBackwardTransition);
+ hook_register(frr_late_init, bgp_snmp_init);
++ hook_register(frr_fini, bgp_snmp_terminate);
+ hook_register(bgp_snmp_traps_config_write,
+ bgp_cli_snmp_traps_config_write);
+ return 0;
+diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c
+index f00d1dc125ca..7ac701973a98 100644
+--- a/ospf6d/ospf6_snmp.c
++++ b/ospf6d/ospf6_snmp.c
+@@ -1429,11 +1429,18 @@ static int ospf6_snmp_init(struct event_loop *mstr)
+ return 0;
+ }
+
++static int ospf6_snmp_terminate(void)
++{
++ smux_terminate();
++ return 0;
++}
++
+ static int ospf6_snmp_module_init(void)
+ {
+ hook_register(ospf6_interface_change, ospf6TrapIfStateChange);
+ hook_register(ospf6_neighbor_change, ospf6TrapNbrStateChange);
+ hook_register(frr_late_init, ospf6_snmp_init);
++ hook_register(frr_fini, ospf6_snmp_terminate);
+ return 0;
+ }
+
+diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c
+index 83cd45788da1..084b02ff4f48 100644
+--- a/ospfd/ospf_snmp.c
++++ b/ospfd/ospf_snmp.c
+@@ -2533,6 +2533,22 @@ static int ospf_snmp_init(struct event_loop *tm)
+ return 0;
+ }
+
++static int ospf_snmp_terminate(void)
++{
++ if (ospf_snmp_iflist) {
++ ospf_snmp_iflist->del = (void (*)(void *))ospf_snmp_if_free;
++ list_delete(&ospf_snmp_iflist);
++ }
++
++ if (ospf_snmp_vl_table) {
++ route_table_finish(ospf_snmp_vl_table);
++ ospf_snmp_vl_table = NULL;
++ }
++
++ smux_terminate();
++ return 0;
++}
++
+ static int ospf_snmp_module_init(void)
+ {
+ hook_register(ospf_if_update, ospf_snmp_if_update);
+@@ -2543,6 +2559,7 @@ static int ospf_snmp_module_init(void)
+ hook_register(ospf_nsm_change, ospf_snmp_nsm_change);
+
+ hook_register(frr_late_init, ospf_snmp_init);
++ hook_register(frr_fini, ospf_snmp_terminate);
+ return 0;
+ }
+
+diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c
+index 06a9c0debec1..1fd1f3820823 100644
+--- a/zebra/zebra_snmp.c
++++ b/zebra/zebra_snmp.c
+@@ -546,9 +546,16 @@ static int zebra_snmp_init(struct event_loop *tm)
+ return 0;
+ }
+
++static int zebra_snmp_terminate(void)
++{
++ smux_terminate();
++ return 0;
++}
++
+ static int zebra_snmp_module_init(void)
+ {
+ hook_register(frr_late_init, zebra_snmp_init);
++ hook_register(frr_fini, zebra_snmp_terminate);
+ return 0;
+ }
+
+--
+2.47.3
+
diff --git a/debian/patches/upstream/0023-pimd-cleanup-of-leaked-memory-on-shutdown.patch b/debian/patches/upstream/0023-pimd-cleanup-of-leaked-memory-on-shutdown.patch
new file mode 100644
index 000000000000..f20acc964ca9
--- /dev/null
+++ b/debian/patches/upstream/0023-pimd-cleanup-of-leaked-memory-on-shutdown.patch
@@ -0,0 +1,41 @@
+From 7fb6badbe9170bddee2ba03058eb50181fed505b Mon Sep 17 00:00:00 2001
+From: Donald Sharp <sharpd@nvidia.com>
+Date: Sat, 2 May 2026 14:50:20 -0400
+Subject: [PATCH 19/21] pimd: cleanup of leaked memory on shutdown
+
+a) route-map memory was not being cleaned up
+b) Some mld memory was not being cleaned up
+
+Signed-off-by: Donald Sharp <sharpd@nvidia.com>
+---
+ pimd/pim6_main.c | 1 +
+ pimd/pim6_mld.c | 1 +
+ 2 files changed, 2 insertions(+)
+
+diff --git a/pimd/pim6_main.c b/pimd/pim6_main.c
+index 1d94f9d27eb6..2cf095f5c439 100644
+--- a/pimd/pim6_main.c
++++ b/pimd/pim6_main.c
+@@ -197,6 +197,7 @@ static void pim6_terminate(void)
+
+ prefix_list_reset();
+ access_list_reset();
++ pim_route_map_terminate();
+
+ zclient = pim_zebra_zclient_get();
+ if (zclient) {
+diff --git a/pimd/pim6_mld.c b/pimd/pim6_mld.c
+index 5e4f18af8aac..ce8fc1cd3ad4 100644
+--- a/pimd/pim6_mld.c
++++ b/pimd/pim6_mld.c
+@@ -2381,6 +2381,7 @@ void gm_ifp_teardown(struct interface *ifp)
+
+ gm_group_delete(gm_ifp);
+
++ gm_gsq_pends_fini(gm_ifp->gsq_pends);
+ gm_grp_pends_fini(gm_ifp->grp_pends);
+ gm_packet_expires_fini(gm_ifp->expires);
+ gm_subscribers_fini(gm_ifp->subscribers);
+--
+2.47.3
+
diff --git a/debian/patches/upstream/0024-tests-make-the-topotest-fail-if-a-memory-leak-is-det.patch b/debian/patches/upstream/0024-tests-make-the-topotest-fail-if-a-memory-leak-is-det.patch
new file mode 100644
index 000000000000..92b3f8a2caa8
--- /dev/null
+++ b/debian/patches/upstream/0024-tests-make-the-topotest-fail-if-a-memory-leak-is-det.patch
@@ -0,0 +1,126 @@
+From d2f1cd9158eb960b4e1d120e2992aa41199066f7 Mon Sep 17 00:00:00 2001
+From: Donald Sharp <sharpd@nvidia.com>
+Date: Sat, 2 May 2026 15:16:55 -0400
+Subject: [PATCH 20/21] tests: make the topotest fail if a memory leak is
+ detected
+
+Currently the topotests output a bunch of memory leaks detected
+on shutdown, modify the code such that the memory leaks are detected
+and cause the test to fail.
+
+Signed-off-by: Donald Sharp <sharpd@nvidia.com>
+---
+ tests/topotests/lib/topogen.py | 21 ++++++++++++++++-----
+ tests/topotests/lib/topotest.py | 22 +++++++++++++++-------
+ 2 files changed, 31 insertions(+), 12 deletions(-)
+
+diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py
+index fff9d492072c..33be0d292dc2 100644
+--- a/tests/topotests/lib/topogen.py
++++ b/tests/topotests/lib/topogen.py
+@@ -487,14 +487,17 @@ class Topogen(object):
+ errors = ""
+ for gear in self.gears.values():
+ errors += gear.stop()
+- if len(errors) > 0:
+- logger.error(
+- "Errors found post shutdown - details follow: {}".format(errors)
+- )
+
++ # Always tear down the underlying munet topology before reporting any
++ # gear-level errors back to pytest. gear.stop() only kills the FRR
++ # daemons inside each router; self.net.stop() (Mininet.delete()) is
++ # what actually reaps the per-gear mutini.py namespace processes,
++ # removes the bridge(s), and unmounts the per-router tmpfs/cgroup
++ # binds. If we assert before this runs (e.g. on a memory-leak
++ # report from gear.stop()), those mutini.py PID-1 processes - and
++ # the namespaces / mounts they anchor - are leaked across runs.
+ try:
+ self.net.stop()
+-
+ except OSError as error:
+ # OSError exception is raised when mininet tries to stop switch
+ # though switch is stopped once but mininet tries to stop same
+@@ -503,6 +506,14 @@ class Topogen(object):
+ logger.info(error)
+ logger.info("Exception ignored: switch is already stopped")
+
++ if len(errors) > 0:
++ logger.error(
++ "Errors found post shutdown - details follow: {}".format(errors)
++ )
++ assert False, "Errors found post shutdown - details follow:\n{}".format(
++ errors
++ )
++
+ def get_exabgp_cmd(self):
+ if not self.exabgp_cmd:
+ self.exabgp_cmd = get_exabgp_cmd(self.net)
+diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
+index 1989b7c94b35..e619771ca41a 100644
+--- a/tests/topotests/lib/topotest.py
++++ b/tests/topotests/lib/topotest.py
+@@ -1914,7 +1914,6 @@ class Router(Node):
+ self.run_in_window("vtysh", title="vt-%s" % self.name)
+
+ if self.unified_config:
+-
+ # Check that none of the datastores are locked before proceeding
+ def check_datastores_unlocked():
+ """Check that all datastores are unlocked"""
+@@ -1993,7 +1992,8 @@ class Router(Node):
+ # Get global bundle data
+ if not self.path_exists("/etc/frr/support_bundle_commands.conf"):
+ logger.info(
+- "No support bundle commands.conf found in %s namespace, copying them over", self.name
++ "No support bundle commands.conf found in %s namespace, copying them over",
++ self.name,
+ )
+ # Copy global value if was covered by namespace mount
+ bundle_data = ""
+@@ -2001,7 +2001,9 @@ class Router(Node):
+ with open("/etc/frr/support_bundle_commands.conf", "r") as rf:
+ bundle_data = rf.read()
+ else:
+- logger.warning("No support bundle commands.conf found, please install them on this system")
++ logger.warning(
++ "No support bundle commands.conf found, please install them on this system"
++ )
+ self.cmd_raises(
+ "cat > /etc/frr/support_bundle_commands.conf",
+ stdin=bundle_data,
+@@ -2677,11 +2679,11 @@ class Router(Node):
+ dname,
+ )
+ reportMade = True
+- return reportMade
++ return reportMade, traces
+
+ def checkRouterCores(self, reportLeaks=True, reportOnce=False):
+ if reportOnce and not self.reportCores:
+- return
++ return ""
+ reportMade = False
+ traces = ""
+ for daemon in self.daemons:
+@@ -2691,9 +2693,15 @@ class Router(Node):
+ and len(self.daemon_instances[daemon]) > 0
+ ):
+ for inst in self.daemon_instances[daemon]:
+- self.check_daemon(daemon, reportLeaks, traces, inst)
++ daemon_reported, traces = self.check_daemon(
++ daemon, reportLeaks, traces, inst
++ )
++ reportMade = reportMade or daemon_reported
+ else:
+- self.check_daemon(daemon, reportLeaks, traces)
++ daemon_reported, traces = self.check_daemon(
++ daemon, reportLeaks, traces
++ )
++ reportMade = reportMade or daemon_reported
+
+ if reportMade:
+ self.reportCores = False
+--
+2.47.3
+
diff --git a/debian/patches/upstream/0025-Use-hash_clean_and_free-remove-hash_free.patch b/debian/patches/upstream/0025-Use-hash_clean_and_free-remove-hash_free.patch
new file mode 100644
index 000000000000..a5b62e0a1fd7
--- /dev/null
+++ b/debian/patches/upstream/0025-Use-hash_clean_and_free-remove-hash_free.patch
@@ -0,0 +1,480 @@
+From 0716102a0a7f755b33f2bab064fa4167570eb9a6 Mon Sep 17 00:00:00 2001
+From: Donald Sharp <sharpd@nvidia.com>
+Date: Wed, 6 May 2026 10:54:28 -0400
+Subject: [PATCH 21/21] *: Use hash_clean_and_free, remove hash_free
+
+Ran across a single case of a hash bucket not being freed,
+on shutdown. Let's convert everything to use hash_clean_and_free
+and remove usage of hash_free outside of the .c file.
+
+Signed-off-by: Donald Sharp <sharpd@nvidia.com>
+---
+ bfdd/bfd.c | 6 +++---
+ bgpd/bgp_clist.c | 6 +++---
+ bgpd/bgp_evpn.c | 3 +--
+ bgpd/bgp_updgrp.c | 8 ++------
+ bgpd/bgpd.c | 5 +----
+ isisd/fabricd.c | 2 +-
+ isisd/isis_spf_private.h | 3 +--
+ lib/hash.c | 34 +++++++++++++++++-----------------
+ lib/hash.h | 11 -----------
+ lib/routemap.c | 13 +++++--------
+ mgmtd/mgmt_fe_adapter.c | 2 +-
+ mgmtd/mgmt_txn.c | 3 +--
+ nhrpd/nhrp_cache.c | 4 ++--
+ nhrpd/nhrp_vc.c | 2 +-
+ pbrd/pbr_nht.c | 11 ++++-------
+ pimd/pim_igmp.c | 2 +-
+ pimd/pim_nht.c | 2 +-
+ zebra/kernel_netlink.c | 3 +--
+ zebra/zebra_evpn.c | 6 ++----
+ zebra/zebra_evpn_mh.c | 6 +++---
+ zebra/zebra_vxlan.c | 13 +++++--------
+ 21 files changed, 56 insertions(+), 89 deletions(-)
+
+diff --git a/bfdd/bfd.c b/bfdd/bfd.c
+index 003052d843f1..36b2f70c1364 100644
+--- a/bfdd/bfd.c
++++ b/bfdd/bfd.c
+@@ -2214,9 +2214,9 @@ void bfd_shutdown(void)
+ assert(sbfd_rflt_hash->count == 0);
+
+ /* Now free the hashes themselves. */
+- hash_free(bfd_id_hash);
+- hash_free(bfd_key_hash);
+- hash_free(sbfd_rflt_hash);
++ hash_clean_and_free(&bfd_id_hash, NULL);
++ hash_clean_and_free(&bfd_key_hash, NULL);
++ hash_clean_and_free(&sbfd_rflt_hash, NULL);
+
+ destroy_bfd_perm_vrfs_data();
+
+diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
+index 9de32e85db5f..62244935f71c 100644
+--- a/bgpd/bgp_clist.c
++++ b/bgpd/bgp_clist.c
+@@ -1456,21 +1456,21 @@ void community_list_terminate(struct community_list_handler *ch)
+ community_list_delete(cm, list);
+ while ((list = cm->str.head) != NULL)
+ community_list_delete(cm, list);
+- hash_free(cm->hash);
++ hash_clean_and_free(&cm->hash, NULL);
+
+ cm = &ch->lcommunity_list;
+ while ((list = cm->num.head) != NULL)
+ community_list_delete(cm, list);
+ while ((list = cm->str.head) != NULL)
+ community_list_delete(cm, list);
+- hash_free(cm->hash);
++ hash_clean_and_free(&cm->hash, NULL);
+
+ cm = &ch->extcommunity_list;
+ while ((list = cm->num.head) != NULL)
+ community_list_delete(cm, list);
+ while ((list = cm->str.head) != NULL)
+ community_list_delete(cm, list);
+- hash_free(cm->hash);
++ hash_clean_and_free(&cm->hash, NULL);
+
+ XFREE(MTYPE_COMMUNITY_LIST_HANDLER, ch);
+ }
+diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
+index 4f8ee466bb74..f04242455527 100644
+--- a/bgpd/bgp_evpn.c
++++ b/bgpd/bgp_evpn.c
+@@ -7999,8 +7999,7 @@ static void bgp_evpn_remote_ip_hash_destroy(struct bgpevpn *vpn)
+ (void (*)(struct hash_bucket *, void *))bgp_evpn_remote_ip_hash_free,
+ vpn);
+
+- hash_free(vpn->remote_ip_hash);
+- vpn->remote_ip_hash = NULL;
++ hash_clean_and_free(&vpn->remote_ip_hash, NULL);
+ }
+
+ /* Add a remote MAC/IP route to hash table */
+diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c
+index e523528c86c4..03d4b6fe3148 100644
+--- a/bgpd/bgp_updgrp.c
++++ b/bgpd/bgp_updgrp.c
+@@ -1961,12 +1961,8 @@ void update_bgp_group_free(struct bgp *bgp)
+ {
+ int afid;
+
+- AF_FOREACH (afid) {
+- if (bgp->update_groups[afid]) {
+- hash_free(bgp->update_groups[afid]);
+- bgp->update_groups[afid] = NULL;
+- }
+- }
++ AF_FOREACH (afid)
++ hash_clean_and_free(&bgp->update_groups[afid], NULL);
+ }
+
+ void update_group_show(struct bgp *bgp, afi_t afi, safi_t safi, struct vty *vty,
+diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
+index e92fe29af871..dfbd8d00dca6 100644
+--- a/bgpd/bgpd.c
++++ b/bgpd/bgpd.c
+@@ -4563,10 +4563,7 @@ void bgp_free(struct bgp *bgp)
+ list_delete(&bgp->group);
+ list_delete(&bgp->peer);
+
+- if (bgp->connectionhash) {
+- hash_free(bgp->connectionhash);
+- bgp->connectionhash = NULL;
+- }
++ hash_clean_and_free(&bgp->connectionhash, NULL);
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ /* Special handling for 2-level routing tables. */
+diff --git a/isisd/fabricd.c b/isisd/fabricd.c
+index 059ec0d278eb..62624e5789fb 100644
+--- a/isisd/fabricd.c
++++ b/isisd/fabricd.c
+@@ -233,7 +233,7 @@ void fabricd_finish(struct fabricd *f)
+ isis_spftree_del(f->spftree);
+ neighbor_lists_clear(f);
+ skiplist_free(f->neighbors);
+- hash_free(f->neighbors_neighbors);
++ hash_clean_and_free(&f->neighbors_neighbors, NULL);
+ }
+
+ static void fabricd_initial_sync_timeout(struct event *event)
+diff --git a/isisd/isis_spf_private.h b/isisd/isis_spf_private.h
+index fd09346c9d59..1d5ac953842a 100644
+--- a/isisd/isis_spf_private.h
++++ b/isisd/isis_spf_private.h
+@@ -191,8 +191,7 @@ __attribute__((__unused__)) static void isis_vertex_queue_free(struct isis_verte
+ {
+ isis_vertex_queue_clear(queue);
+
+- hash_free(queue->hash);
+- queue->hash = NULL;
++ hash_clean_and_free(&queue->hash, NULL);
+
+ if (queue->insert_counter) {
+ skiplist_free(queue->l.slist);
+diff --git a/lib/hash.c b/lib/hash.c
+index edbfeec4645e..6ecbf03ab3f0 100644
+--- a/lib/hash.c
++++ b/lib/hash.c
+@@ -297,6 +297,23 @@ void hash_clean(struct hash *hash, void (*free_func)(void *))
+ hash->stats.empty = hash->size;
+ }
+
++static void hash_free(struct hash *hash)
++{
++ frr_with_mutex (&_hashes_mtx) {
++ if (_hashes) {
++ listnode_delete(_hashes, hash);
++ if (_hashes->count == 0) {
++ list_delete(&_hashes);
++ }
++ }
++ }
++
++ XFREE(MTYPE_HASH, hash->name);
++
++ XFREE(MTYPE_HASH_INDEX, hash->index);
++ XFREE(MTYPE_HASH, hash);
++}
++
+ void hash_clean_and_free(struct hash **hash, void (*free_func)(void *))
+ {
+ if (!*hash)
+@@ -322,23 +339,6 @@ struct list *hash_to_list(struct hash *hash)
+ return list;
+ }
+
+-void hash_free(struct hash *hash)
+-{
+- frr_with_mutex (&_hashes_mtx) {
+- if (_hashes) {
+- listnode_delete(_hashes, hash);
+- if (_hashes->count == 0) {
+- list_delete(&_hashes);
+- }
+- }
+- }
+-
+- XFREE(MTYPE_HASH, hash->name);
+-
+- XFREE(MTYPE_HASH_INDEX, hash->index);
+- XFREE(MTYPE_HASH, hash);
+-}
+-
+
+ /* CLI commands ------------------------------------------------------------ */
+
+diff --git a/lib/hash.h b/lib/hash.h
+index f9584ae109fa..bee91bcc7f27 100644
+--- a/lib/hash.h
++++ b/lib/hash.h
+@@ -302,17 +302,6 @@ extern void hash_clean(struct hash *hash, void (*free_func)(void *data));
+ */
+ extern void hash_clean_and_free(struct hash **hash, void (*free_func)(void *data));
+
+-/*
+- * Delete a hash table.
+- *
+- * This function assumes the table is empty. Call hash_clean to delete the
+- * hashtable contents if necessary.
+- *
+- * hash
+- * hash table to delete
+- */
+-extern void hash_free(struct hash *hash);
+-
+ /*
+ * Converts a hash table to an unsorted linked list.
+ * Does not modify the hash table in any way.
+diff --git a/lib/routemap.c b/lib/routemap.c
+index 67600b1f89d8..d7eefd2317c2 100644
+--- a/lib/routemap.c
++++ b/lib/routemap.c
+@@ -2850,7 +2850,7 @@ static void route_map_clear_reference(struct hash_bucket *bucket, void *arg)
+ }
+ if (!dep->dep_rmap_hash->count) {
+ dep = hash_release(dep->this_hash, (void *)dep->dep_name);
+- hash_free(dep->dep_rmap_hash);
++ hash_clean_and_free(&dep->dep_rmap_hash, NULL);
+ XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
+ XFREE(MTYPE_ROUTE_MAP_DEP, dep);
+ }
+@@ -3002,7 +3002,7 @@ static int route_map_dep_update(struct hash *dephash, const char *dep_name,
+
+ if (!dep->dep_rmap_hash->count) {
+ dep = hash_release(dephash, dname);
+- hash_free(dep->dep_rmap_hash);
++ hash_clean_and_free(&dep->dep_rmap_hash, NULL);
+ XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
+ XFREE(MTYPE_ROUTE_MAP_DEP, dep);
+ }
+@@ -3338,13 +3338,10 @@ void route_map_finish(void)
+ route_map_delete(map);
+ }
+
+- for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
+- hash_free(route_map_dep_hash[i]);
+- route_map_dep_hash[i] = NULL;
+- }
++ for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
++ hash_clean_and_free(&route_map_dep_hash[i], NULL);
+
+- hash_free(route_map_master_hash);
+- route_map_master_hash = NULL;
++ hash_clean_and_free(&route_map_master_hash, NULL);
+ }
+
+ /* Increment the use_count counter while attaching the route map */
+diff --git a/mgmtd/mgmt_fe_adapter.c b/mgmtd/mgmt_fe_adapter.c
+index 891c28b5aa1b..6c43f01cd1c6 100644
+--- a/mgmtd/mgmt_fe_adapter.c
++++ b/mgmtd/mgmt_fe_adapter.c
+@@ -2065,5 +2065,5 @@ void mgmt_fe_adapter_destroy(void)
+
+ mgmt_fe_free_ns_strings(&mgmt_fe_ns_strings);
+
+- hash_free(mgmt_fe_sessions);
++ hash_clean_and_free(&mgmt_fe_sessions, NULL);
+ }
+diff --git a/mgmtd/mgmt_txn.c b/mgmtd/mgmt_txn.c
+index 1d0756d4a782..554fd38cfc8b 100644
+--- a/mgmtd/mgmt_txn.c
++++ b/mgmtd/mgmt_txn.c
+@@ -863,6 +863,5 @@ void mgmt_txn_destroy(void)
+ TXN_DECREF(txn);
+ }
+
+- if (txn_id_tab)
+- hash_free(txn_id_tab);
++ hash_clean_and_free(&txn_id_tab, NULL);
+ }
+diff --git a/nhrpd/nhrp_cache.c b/nhrpd/nhrp_cache.c
+index 13b05da5db58..dd71d3361ac1 100644
+--- a/nhrpd/nhrp_cache.c
++++ b/nhrpd/nhrp_cache.c
+@@ -164,13 +164,13 @@ void nhrp_cache_interface_del(struct interface *ifp)
+
+ if (nifp->cache_hash) {
+ hash_iterate(nifp->cache_hash, do_nhrp_cache_free, NULL);
+- hash_free(nifp->cache_hash);
++ hash_clean_and_free(&nifp->cache_hash, NULL);
+ }
+
+ if (nifp->cache_config_hash) {
+ hash_iterate(nifp->cache_config_hash, do_nhrp_cache_config_free,
+ NULL);
+- hash_free(nifp->cache_config_hash);
++ hash_clean_and_free(&nifp->cache_config_hash, NULL);
+ }
+ }
+
+diff --git a/nhrpd/nhrp_vc.c b/nhrpd/nhrp_vc.c
+index 6f3346c95c74..ac6d1398f84e 100644
+--- a/nhrpd/nhrp_vc.c
++++ b/nhrpd/nhrp_vc.c
+@@ -214,5 +214,5 @@ void nhrp_vc_terminate(void)
+ {
+ nhrp_vc_reset();
+ hash_clean(nhrp_vc_hash, nhrp_vc_free);
+- hash_free(nhrp_vc_hash);
++ hash_clean_and_free(&nhrp_vc_hash, NULL);
+ }
+diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c
+index 76fecc3f8866..da452f6040b3 100644
+--- a/pbrd/pbr_nht.c
++++ b/pbrd/pbr_nht.c
+@@ -169,7 +169,7 @@ static bool pbr_nh_hash_equal(const void *arg1, const void *arg2)
+ static void pbr_nhgc_delete(struct pbr_nexthop_group_cache *p)
+ {
+ hash_iterate(p->nhh, pbr_nh_delete_iterate, NULL);
+- hash_free(p->nhh);
++ hash_clean_and_free(&p->nhh, NULL);
+ XFREE(MTYPE_PBR_NHG, p);
+ }
+
+@@ -1498,19 +1498,16 @@ void pbr_nht_terminate(void)
+ {
+ if (pbr_nhg_hash) {
+ hash_clean(pbr_nhg_hash, (void (*)(void *))pbr_nhgc_delete);
+- hash_free(pbr_nhg_hash);
+- pbr_nhg_hash = NULL;
++ hash_clean_and_free(&pbr_nhg_hash, NULL);
+ }
+
+ if (pbr_nhrc_hash) {
+ hash_clean(pbr_nhrc_hash, pbr_nhrc_delete);
+- hash_free(pbr_nhrc_hash);
+- pbr_nhrc_hash = NULL;
++ hash_clean_and_free(&pbr_nhrc_hash, NULL);
+ }
+
+ if (pbr_nhg_allocated_id_hash) {
+ hash_clean(pbr_nhg_allocated_id_hash, NULL);
+- hash_free(pbr_nhg_allocated_id_hash);
+- pbr_nhg_allocated_id_hash = NULL;
++ hash_clean_and_free(&pbr_nhg_allocated_id_hash, NULL);
+ }
+ }
+diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c
+index a9565e692e30..ba128a7daf47 100644
+--- a/pimd/pim_igmp.c
++++ b/pimd/pim_igmp.c
+@@ -1200,7 +1200,7 @@ void pim_igmp_if_fini(struct pim_interface *pim_ifp)
+ assert(!listcount(pim_ifp->gm_group_list));
+
+ list_delete(&pim_ifp->gm_group_list);
+- hash_free(pim_ifp->gm_group_hash);
++ hash_clean_and_free(&pim_ifp->gm_group_hash, NULL);
+
+ list_delete(&pim_ifp->gm_socket_list);
+ }
+diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c
+index 3a1527185f1e..2671fe43288d 100644
+--- a/pimd/pim_nht.c
++++ b/pimd/pim_nht.c
+@@ -652,7 +652,7 @@ static void pim_nht_drop_maybe(struct pim_instance *pim, struct pim_nexthop_cach
+
+ list_delete(&pnc->rp_list);
+
+- hash_free(pnc->upstream_hash);
++ hash_clean_and_free(&pnc->upstream_hash, NULL);
+ hash_release(pim->nht_hash, pnc);
+
+ if (pnc->urib.nexthop)
+diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
+index ea1337d3c143..fec0b017880b 100644
+--- a/zebra/kernel_netlink.c
++++ b/zebra/kernel_netlink.c
+@@ -1863,8 +1863,7 @@ void kernel_router_terminate(void)
+
+ pthread_mutex_destroy(&nlsock_mutex);
+
+- hash_free(nlsock_hash);
+- nlsock_hash = NULL;
++ hash_clean_and_free(&nlsock_hash, NULL);
+ }
+
+ #endif /* HAVE_NETLINK */
+diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c
+index 258e818ec5d2..963fde4d262e 100644
+--- a/zebra/zebra_evpn.c
++++ b/zebra/zebra_evpn.c
+@@ -1075,12 +1075,10 @@ int zebra_evpn_del(struct zebra_evpn *zevpn)
+ zevpn->svi_if = NULL;
+
+ /* Free the neighbor hash table. */
+- hash_free(zevpn->neigh_table);
+- zevpn->neigh_table = NULL;
++ hash_clean_and_free(&zevpn->neigh_table, NULL);
+
+ /* Free the MAC hash table. */
+- hash_free(zevpn->mac_table);
+- zevpn->mac_table = NULL;
++ hash_clean_and_free(&zevpn->mac_table, NULL);
+
+ /* Remove references to the zevpn in the MH databases */
+ if (zevpn->vxlan_if)
+diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c
+index de602f529024..0b174d803f34 100644
+--- a/zebra/zebra_evpn_mh.c
++++ b/zebra/zebra_evpn_mh.c
+@@ -3972,9 +3972,9 @@ void zebra_evpn_mh_terminate(void)
+
+ hash_iterate(zmh_info->evpn_vlan_table,
+ zebra_evpn_acc_vl_cleanup_all, NULL);
+- hash_free(zmh_info->evpn_vlan_table);
+- hash_free(zmh_info->nhg_table);
+- hash_free(zmh_info->nh_ip_table);
++ hash_clean_and_free(&zmh_info->evpn_vlan_table, NULL);
++ hash_clean_and_free(&zmh_info->nhg_table, NULL);
++ hash_clean_and_free(&zmh_info->nh_ip_table, NULL);
+ bf_free(zmh_info->nh_id_bitmap);
+
+ XFREE(MTYPE_ZMH_INFO, zrouter.mh_info);
+diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
+index 26769979e874..ecf1eea0db56 100644
+--- a/zebra/zebra_vxlan.c
++++ b/zebra/zebra_vxlan.c
+@@ -2075,12 +2075,10 @@ static int zl3vni_del(struct zebra_l3vni *zl3vni)
+ zl3vni->l2vnis = NULL;
+
+ /* Free the rmac table */
+- hash_free(zl3vni->rmac_table);
+- zl3vni->rmac_table = NULL;
++ hash_clean_and_free(&zl3vni->rmac_table, NULL);
+
+ /* Free the nh table */
+- hash_free(zl3vni->nh_table);
+- zl3vni->nh_table = NULL;
++ hash_clean_and_free(&zl3vni->nh_table, NULL);
+
+ /* Free the VNI hash entry and allocated memory. */
+ tmp_zl3vni = hash_release(zrouter.l3vni_table, zl3vni);
+@@ -6031,11 +6029,10 @@ void zebra_vxlan_close_tables(struct zebra_vrf *zvrf)
+ if (!zvrf)
+ return;
+ hash_iterate(zvrf->evpn_table, zebra_evpn_vxlan_cleanup_all, zvrf);
+- hash_free(zvrf->evpn_table);
++ hash_clean_and_free(&zvrf->evpn_table, NULL);
+ if (zvrf->vxlan_sg_table) {
+ zebra_vxlan_cleanup_sg_table(zvrf);
+- hash_free(zvrf->vxlan_sg_table);
+- zvrf->vxlan_sg_table = NULL;
++ hash_clean_and_free(&zvrf->vxlan_sg_table, NULL);
+ }
+ }
+
+@@ -6059,7 +6056,7 @@ void zebra_vxlan_terminate(void)
+ /* free l3vni table */
+ void zebra_vxlan_disable(void)
+ {
+- hash_free(zrouter.l3vni_table);
++ hash_clean_and_free(&zrouter.l3vni_table, NULL);
+ zebra_evpn_mh_terminate();
+ }
+
+--
+2.47.3
+
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH frr v2 3/3] bump to version 10.6.1-1+pve2
2026-05-15 12:03 [PATCH frr v2 0/3] Backport FRR EVPN local RT2 leaking fixes Gabriel Goller
2026-05-15 12:03 ` [PATCH frr v2 1/3] frr: backport "bgpd: fix valgrind memory leaks on daemon shutdown" (#21511) Gabriel Goller
2026-05-15 12:03 ` [PATCH frr v2 2/3] frr: backport the "Memory leak problems." (#21844) upstream PR Gabriel Goller
@ 2026-05-15 12:03 ` Gabriel Goller
2026-05-16 23:59 ` [PATCH frr v2 0/3] Backport FRR EVPN local RT2 leaking fixes Thomas Lamprecht
3 siblings, 0 replies; 5+ messages in thread
From: Gabriel Goller @ 2026-05-15 12:03 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Gabriel Goller <g.goller@proxmox.com>
---
debian/changelog | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/debian/changelog b/debian/changelog
index b246abfbe50e..8a18529d59fe 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+frr (10.6.1-1+pve2) trixie; urgency=medium
+
+ * fix race-conditions with the EVPN local RT2 leaking patch
+
+ -- Proxmox Support Team <support@proxmox.com> Fri, 15 May 2026 11:04:53 +0200
+
frr (10.6.1-1+pve1) trixie; urgency=medium
* update upstream source to 10.6.1
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH frr v2 0/3] Backport FRR EVPN local RT2 leaking fixes
2026-05-15 12:03 [PATCH frr v2 0/3] Backport FRR EVPN local RT2 leaking fixes Gabriel Goller
` (2 preceding siblings ...)
2026-05-15 12:03 ` [PATCH frr v2 3/3] bump to version 10.6.1-1+pve2 Gabriel Goller
@ 2026-05-16 23:59 ` Thomas Lamprecht
3 siblings, 0 replies; 5+ messages in thread
From: Thomas Lamprecht @ 2026-05-16 23:59 UTC (permalink / raw)
To: pve-devel, Gabriel Goller
On Fri, 15 May 2026 14:03:44 +0200, Gabriel Goller wrote:
> Since packaging 10.6.1, we also pull in the EVPN local RT2 leaking patches
> (which are applied on upstream master).
>
> The RT2 route leaking PR seems to have some race-condition-related problems,
> namely a crash at bgp router shutdown and one case in which the rt2 route is not
> leaked (see the last comment at #20005 [1]).
>
> [...]
Tested thise one with 500 VXLAN+bridge churn cycles on a host with the EVPN
address-family active (no leaks, no asserts, +12 KB bgpd RSS) and a `no router
bgp` with an active VNI to exercise the new cleanup path (runs clean). The 21
commits across both upstream PRs (#21511 and #21844) were also checked against
upstream and are logically equivalent; deviations are limited to a few hunks
that account for backport-target context that doesn't exist in 10.6.1 yet, so:
Applied, thanks!
btw. I resolved the merge conflict with the other series, but it isn't perfect
git history wise - but we probably won't have to bisect these two commits on
the packaging level, or rather, one can relatively easy work around doing so.
[1/3] frr: backport "bgpd: fix valgrind memory leaks on daemon shutdown" (#21511)
commit: 6ddac172c96f3bad0f90f5d61876e98344c33c0c
[2/3] frr: backport the "Memory leak problems." (#21844) upstream PR
commit: 4e14853e8f9d59d47b5f35792ce6efe601601d5f
[3/3] bump to version 10.6.1-1+pve2
commit: 9f188e1b4459edfd6174aa1ad48ee4ab6bde7749
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-05-17 0:02 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-15 12:03 [PATCH frr v2 0/3] Backport FRR EVPN local RT2 leaking fixes Gabriel Goller
2026-05-15 12:03 ` [PATCH frr v2 1/3] frr: backport "bgpd: fix valgrind memory leaks on daemon shutdown" (#21511) Gabriel Goller
2026-05-15 12:03 ` [PATCH frr v2 2/3] frr: backport the "Memory leak problems." (#21844) upstream PR Gabriel Goller
2026-05-15 12:03 ` [PATCH frr v2 3/3] bump to version 10.6.1-1+pve2 Gabriel Goller
2026-05-16 23:59 ` [PATCH frr v2 0/3] Backport FRR EVPN local RT2 leaking fixes Thomas Lamprecht
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.