pimd: MLAG: skip pim_register_join on non-DR - #21920
Conversation
Greptile SummaryThis PR fixes a multicast software-forwarding regression in MLAG+PIM deployments where non-DR nodes get stuck in
Confidence Score: 5/5Safe to merge β a minimal two-line change in each affected path, with no modification to data structures, timers, or state-machine transitions. The change guards exactly the two pim_register_join call sites that lacked a DR check in the MLAG context. All other call sites in the file and in pim_upstream.c are already gated by pim_upstream_could_register or an equivalent early-exit, so the fix is complete. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Multicast packet arrives] --> B{WRVIFWHOLE or WHOLEPKT?}
B -->|WRVIFWHOLE| C[pim_mroute_msg_wrvifwhole]
B -->|WHOLEPKT on pimreg| D[pim_mroute_msg_wholepkt]
C --> E{pim_if_connected_to_source?}
E -->|Yes| F[pim_upstream_add with FHR flag]
F --> G{pim_is_group_filtered AND pim_upstream_could_register?}
G -->|DR node: both pass| H[pim_register_join]
G -->|non-DR node: could_register=0| I[Skip pim_register_join]
D --> K{Exact S,G upstream found?}
K -->|No, but *,G with CAN_BE_LHR| L{src locally connected?}
L -->|Yes| M[pim_upstream_add with FHR flag]
M --> N{pim_is_group_filtered AND pim_upstream_could_register?}
N -->|DR node| O[pim_register_join]
N -->|non-DR node| P[Skip pim_register_join]
Reviews (4): Last reviewed commit: "pimd: MLAG: skip pim_register_join on no..." | Re-trigger Greptile |
|
ci:rerun |
|
@greptile review |
|
@Mergifyio backport stable/10.6 stable/10.5 |
β Backports have been createdDetails
|
There was a problem hiding this comment.
Do we need to do the same here?
|
ci:rerun |
Rootcause and fix: In mlag+pim, packets are software forwarded because the mroute is stuck in pimreg state in non-DR node. Align with RFC:avoid REG_JOIN on the mlag node that lost DR election. Gate pim_register_join() with pim_upstream_could_register() on the WRVIFWHOLE connected-source path. Signed-off-by: harini <hnattamaisub@nvidia.com>
|
@greptile review |
|
@Mergifyio backport stable/10.4 |
β Backports have been createdDetails
|
pimd: MLAG: skip pim_register_join on non-DR (backport #21920)
pimd: MLAG: skip pim_register_join on non-DR (backport #21920)
pimd: MLAG: skip pim_register_join on non-DR (backport #21920)
Issue: On an MLAG active-active pair where both PIM peers sit on the same source SVI, every data packet on the SVI is CPU-punted on the non-DR peer, forever. Root cause: In pim_mroute_msg_wrvifwhole() we set PIM_UPSTREAM_FLAG_MASK_FHR without a DR check, so the non-DR peer ends up with an FHR-flagged upstream. Later, on a state re-evaluation, pim_upstream_switch() sees this FHR flag with reg_state == PIM_REG_NOINFO and silently adds pimreg to the channel_oil OIF via pim_channel_add_oif(). From then on, the kernel copies every packet of that (S,G) to pimreg, which upcalls pimd (WHOLEPKT) forever -- CPU-punt loop. Per RFC 7761, only the DR is the FHR for a directly-connected source; the non-DR must not send Register and must not have pimreg in the channel OIF. Fix: Setting PIM_UPSTREAM_FLAG_MASK_FHR for DR only, non-DR will use PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE and so in pim_upstream_switch() it never adds pimreg to channel_oil. Handled in pim_mroute_msg_wholepkt() and pim_mroute_msg_wrvifwhole() APIs. Note: FRR PR FRRouting#21920 already blocked the Register-send side by gating pim_register_join() with a pim_upstream_could_register() check. But the FHR flag itself is still set unconditionally on the non-DR, so the OIF-side leak (pim_upstream_switch() -> pim_channel_add_oif(pimreg)) is still triggered. This patch closes the remaining gap. Signed-off-by: Harini Nattamai Subramanian <hnattamaisub@nvidia.com>
Issue: On an MLAG active-active pair where both PIM peers sit on the same source SVI, every data packet on the SVI is CPU-punted on the non-DR peer, forever. Root cause: In pim_mroute_msg_wrvifwhole() we set PIM_UPSTREAM_FLAG_MASK_FHR without a DR check, so the non-DR peer ends up with an FHR-flagged upstream. Later, on a state re-evaluation, pim_upstream_switch() sees this FHR flag with reg_state == PIM_REG_NOINFO and silently adds pimreg to the channel_oil OIF via pim_channel_add_oif(). From then on, the kernel copies every packet of that (S,G) to pimreg, which upcalls pimd (WHOLEPKT) forever -- CPU-punt loop. Per RFC 7761, only the DR is the FHR for a directly-connected source; the non-DR must not send Register and must not have pimreg in the channel OIF. Fix: Setting PIM_UPSTREAM_FLAG_MASK_FHR for DR only, non-DR will use PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE and so in pim_upstream_switch() it never adds pimreg to channel_oil. Handled in pim_mroute_msg_wholepkt() and pim_mroute_msg_wrvifwhole() APIs. Note: FRR PR FRRouting#21920 already blocked the Register-send side by gating pim_register_join() with a pim_upstream_could_register() check. But the FHR flag itself is still set unconditionally on the non-DR, so the OIF-side leak (pim_upstream_switch() -> pim_channel_add_oif(pimreg)) is still triggered. This patch closes the remaining gap. Signed-off-by: Harini Nattamai Subramanian <hnattamaisub@nvidia.com>
Issue: On an MLAG active-active pair where both PIM peers sit on the same source SVI, every data packet on the SVI is CPU-punted on the non-DR peer, forever. Root cause: In pim_mroute_msg_wrvifwhole() we set PIM_UPSTREAM_FLAG_MASK_FHR without a DR check, so the non-DR peer ends up with an FHR-flagged upstream. Later, on a state re-evaluation, pim_upstream_switch() sees this FHR flag with reg_state == PIM_REG_NOINFO and silently adds pimreg to the channel_oil OIF via pim_channel_add_oif(). From then on, the kernel copies every packet of that (S,G) to pimreg, which upcalls pimd (WHOLEPKT) forever -- CPU-punt loop. Per RFC 7761, only the DR is the FHR for a directly-connected source; the non-DR must not send Register and must not have pimreg in the channel OIF. Fix: Setting PIM_UPSTREAM_FLAG_MASK_FHR for DR only, non-DR will use PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE and so in pim_upstream_switch() it never adds pimreg to channel_oil. Handled in pim_mroute_msg_wholepkt() and pim_mroute_msg_wrvifwhole() APIs. Note: FRR PR FRRouting#21920 already blocked the Register-send side by gating pim_register_join() with a pim_upstream_could_register() check. But the FHR flag itself is still set unconditionally on the non-DR, so the OIF-side leak (pim_upstream_switch() -> pim_channel_add_oif(pimreg)) is still triggered. This patch closes the remaining gap. Signed-off-by: Harini Nattamai Subramanian <hnattamaisub@nvidia.com>
Issue: On an MLAG active-active pair where both PIM peers sit on the same source SVI, every data packet on the SVI is CPU-punted on the non-DR peer, forever. Root cause: In pim_mroute_msg_wrvifwhole() we set PIM_UPSTREAM_FLAG_MASK_FHR without a DR check, so the non-DR peer ends up with an FHR-flagged upstream. Later, on a state re-evaluation, pim_upstream_switch() sees this FHR flag with reg_state == PIM_REG_NOINFO and silently adds pimreg to the channel_oil OIF via pim_channel_add_oif(). From then on, the kernel copies every packet of that (S,G) to pimreg, which upcalls pimd (WHOLEPKT) forever -- CPU-punt loop. Per RFC 7761, only the DR is the FHR for a directly-connected source; the non-DR must not send Register and must not have pimreg in the channel OIF. Fix: Setting PIM_UPSTREAM_FLAG_MASK_FHR for DR only, non-DR will use PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE and so in pim_upstream_switch() it never adds pimreg to channel_oil. Handled in pim_mroute_msg_wholepkt() and pim_mroute_msg_wrvifwhole() APIs. Note: FRR PR FRRouting#21920 already blocked the Register-send side by gating pim_register_join() with a pim_upstream_could_register() check. But the FHR flag itself is still set unconditionally on the non-DR, so the OIF-side leak (pim_upstream_switch() -> pim_channel_add_oif(pimreg)) is still triggered. This patch closes the remaining gap. Signed-off-by: Harini Nattamai Subramanian <hnattamaisub@nvidia.com> (cherry picked from commit c8ac634)
Issue: On an MLAG active-active pair where both PIM peers sit on the same source SVI, every data packet on the SVI is CPU-punted on the non-DR peer, forever. Root cause: In pim_mroute_msg_wrvifwhole() we set PIM_UPSTREAM_FLAG_MASK_FHR without a DR check, so the non-DR peer ends up with an FHR-flagged upstream. Later, on a state re-evaluation, pim_upstream_switch() sees this FHR flag with reg_state == PIM_REG_NOINFO and silently adds pimreg to the channel_oil OIF via pim_channel_add_oif(). From then on, the kernel copies every packet of that (S,G) to pimreg, which upcalls pimd (WHOLEPKT) forever -- CPU-punt loop. Per RFC 7761, only the DR is the FHR for a directly-connected source; the non-DR must not send Register and must not have pimreg in the channel OIF. Fix: Setting PIM_UPSTREAM_FLAG_MASK_FHR for DR only, non-DR will use PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE and so in pim_upstream_switch() it never adds pimreg to channel_oil. Handled in pim_mroute_msg_wholepkt() and pim_mroute_msg_wrvifwhole() APIs. Note: FRR PR FRRouting#21920 already blocked the Register-send side by gating pim_register_join() with a pim_upstream_could_register() check. But the FHR flag itself is still set unconditionally on the non-DR, so the OIF-side leak (pim_upstream_switch() -> pim_channel_add_oif(pimreg)) is still triggered. This patch closes the remaining gap. Signed-off-by: Harini Nattamai Subramanian <hnattamaisub@nvidia.com> (cherry picked from commit c8ac634)
Rootcause and fix:
In mlag+pim, packets are software forwarded because the mroute is stuck in pimreg state in non-DR node.
Align with RFC:avoid REG_JOIN on the mlag node that lost DR election. Gate pim_register_join() with pim_upstream_could_register() on the WRVIFWHOLE connected-source path.