Commit 47cd801b9a for frr
commit 47cd801b9a0f14ef9e8df6744ad66a8160dfdcb5
Author: Rajesh Varatharaj <rvaratharaj@nvidia.com>
Date: Wed Nov 4 13:29:16 2026 -0800
pimd: don't send (*,G) join for a NotJoined parent
When an (S,G) goes NotJoined, pim_upstream_switch() prunes it and can
also send a (*,G) join on the parent's RPF, which is how the (S,G,rpt)
change reaches the RP right away (added in c692bd2ad4). It does this
without looking at the parent. If the parent (*,G) has already gone
NotJoined and sent its own (*,G) prune, this join cancels that prune
upstream, and the upstream router keeps forwarding the group toward us
until the join's holdtime runs out, since the parent will neither
refresh it nor prune it again.
On an EVPN VTEP using a PIM-SM underlay group for BUM, this happens
when the VTEP's interfaces are bounced. Tearing down VXLAN termination
takes the BUM group's (*,G) NotJoined, then the (S,G) for a remote
VTEP's source, and the join above undoes the (*,G) prune. The stale
(*,G) left on the upstream router showed up as duplicated BUM traffic.
Only send the (*,G) join while the parent is still Joined. A parent
that has gone NotJoined has nothing to re-join, and its prune must
stand. When it joins again, it sends its own (*,G) join and starts its
join timer.
Fixes: #24196
Signed-off-by: Rajesh Varatharaj <rvaratharaj@nvidia.com>
diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c
index 5079453c52..a4fa43f0e6 100644
--- a/pimd/pim_upstream.c
+++ b/pimd/pim_upstream.c
@@ -1206,7 +1206,10 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up,
pim_jp_agg_single_upstream_send(&up->rpf, up, 0 /* prune */);
- if (send_xg_jp) {
+ /* A parent that went NotJoined has already sent its (*,G)
+ * prune, a (W,G) join here would undo it upstream.
+ */
+ if (send_xg_jp && up->parent->join_state == PIM_UPSTREAM_JOINED) {
if (PIM_DEBUG_PIM_TRACE_DETAIL)
zlog_debug(
"re-join RPT; *,G IIF %s S,G IIF %s ",