Commit 33016631dc for frr
commit 33016631dc885d7041822bb448d900dc3aa2a520
Author: Vic Lan <vic.lan@pica8.com>
Date: Sat Sep 12 08:46:46 2026 +0800
zebra: avoid duplicate dependency refs on NHG keep-around reuse
An installed or queued NHG whose refcount reaches zero is retained with
a KEEP_AROUND reference until its timer expires. Its dependencies remain
referenced while the parent is retained.
When the same NHG is reused before timer expiry, `zebra_nhg_increment_ref()`
cancels the timer and reuses the retained parent reference. However, it
wrongly incremented every dependency, even though no additional parent
reference was acquired.
Just avoid propagating dependency references when cancelling a KEEP_AROUND
timer.
Signed-off-by: Vic Lan <vic.lan@pica8.com>
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 52b43bbe5b..da62d5947c 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -2005,15 +2005,16 @@ void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe)
{
- if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: nhe %p (%pNG) %d => %d", __func__, nhe, nhe,
- nhe->refcnt, nhe->refcnt + 1);
-
- nhe->refcnt++;
-
+ /*
+ * A KEEP_AROUND reference already retains the NHE and its dependencies.
+ * Reusing that reference must not increment the dependencies again.
+ */
if (event_is_scheduled(nhe->timer)) {
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nhe %p (%pNG) %d => %d (cancel keep-around)", __func__,
+ nhe, nhe, nhe->refcnt, nhe->refcnt);
+
event_cancel(&nhe->timer);
- nhe->refcnt--;
UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_KEEP_AROUND);
/*
* This group is being resurrected from KEEP_AROUND.
@@ -2028,6 +2029,12 @@ void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe)
return;
}
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nhe %p (%pNG) %d => %d", __func__, nhe, nhe, nhe->refcnt,
+ nhe->refcnt + 1);
+
+ nhe->refcnt++;
+
if (!zebra_nhg_depends_is_empty(nhe))
nhg_connected_tree_increment_ref(&nhe->nhg_depends);
}