public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Gabriel Goller <g.goller@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH frr v2 2/3] frr: backport the "Memory leak problems." (#21844) upstream PR
Date: Fri, 15 May 2026 14:03:46 +0200	[thread overview]
Message-ID: <20260515120351.395649-3-g.goller@proxmox.com> (raw)
In-Reply-To: <20260515120351.395649-1-g.goller@proxmox.com>

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





  parent reply	other threads:[~2026-05-15 19:24 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260515120351.395649-3-g.goller@proxmox.com \
    --to=g.goller@proxmox.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal