From 9871c05034df0e56370aaace06d40ab43142d89e Mon Sep 17 00:00:00 2001 From: Nathan Bahr Date: Wed, 28 May 2025 19:35:33 +0000 Subject: [PATCH] pimd: Fix DM graft/prune from IGMP join/leave events Fix grafting of dense mode flows triggered by IGMP joins. Move the processing to tib, rather than during IGMP group object creation. Fix prune of dense flow triggered by IGMP leaves. Move the processing to tib, rather than during IGMP delete. Signed-off-by: Nathan Bahr --- pimd/pim_igmp.c | 28 ------------------------ pimd/pim_tib.c | 53 +++++++++++++++++++++++++++++++++++++++++++++ pimd/pim_upstream.c | 4 ++-- 3 files changed, 55 insertions(+), 30 deletions(-) diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index d4ec6b7074..69c771b0f2 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -1072,7 +1072,6 @@ void igmp_group_delete(struct gm_group *group) struct gm_source *src; struct interface *ifp = group->interface; struct pim_interface *pim_ifp = ifp->info; - struct channel_oil *c_oil; if (PIM_DEBUG_GM_TRACE) { @@ -1096,18 +1095,6 @@ void igmp_group_delete(struct gm_group *group) hash_release(pim_ifp->gm_group_hash, group); igmp_group_free(group); - /* dm: check if we need to send a prune message */ - if (pim_ifp->pim_neighbor_list->count == 0 && !pim_dm_check_gm_group_list(ifp)) { - frr_each (rb_pim_oil, &pim_ifp->pim->channel_oil_head, c_oil) { - if (pim_iface_grp_dm(pim_ifp, *oil_mcastgrp(c_oil)) && c_oil->installed && - !pim_upstream_up_connected(c_oil->up)) { - event_cancel(&c_oil->up->t_graft_timer); - PIM_UPSTREAM_DM_SET_PRUNE(c_oil->up->flags); - pim_dm_prune_send(c_oil->up->rpf, c_oil->up, 0); - prune_timer_start(c_oil->up); - } - } - } } void igmp_group_delete_empty_include(struct gm_group *group) @@ -1450,7 +1437,6 @@ struct gm_group *igmp_add_group_by_addr(struct gm_sock *igmp, { struct gm_group *group; struct pim_interface *pim_ifp = igmp->interface->info; - struct channel_oil *c_oil; group = find_group_by_addr(igmp, group_addr); if (group) { @@ -1536,20 +1522,6 @@ struct gm_group *igmp_add_group_by_addr(struct gm_sock *igmp, /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */ igmp_anysource_forward_stop(group); - /* dm: check is we need to send a graft message */ - if (pim_ifp->pim_neighbor_list->count > 0 || pim_iface_grp_dm(pim_ifp, group->group_addr)) { - frr_each (rb_pim_oil, &pim_ifp->pim->channel_oil_head, c_oil) { - if (pim_iface_grp_dm(pim_ifp, *oil_mcastgrp(c_oil)) && c_oil->installed && - pim_upstream_up_connected(c_oil->up) && - PIM_UPSTREAM_DM_TEST_PRUNE(c_oil->up->flags)) { - PIM_UPSTREAM_DM_UNSET_PRUNE(c_oil->up->flags); - event_cancel(&c_oil->up->t_prune_timer); - pim_dm_graft_send(c_oil->up->rpf, c_oil->up); - graft_timer_start(c_oil->up); - } - } - } - return group; } diff --git a/pimd/pim_tib.c b/pimd/pim_tib.c index d067abf45a..a60bbe4d4f 100644 --- a/pimd/pim_tib.c +++ b/pimd/pim_tib.c @@ -14,6 +14,7 @@ #include "pim_upstream.h" #include "pim_oil.h" #include "pim_nht.h" +#include "pim_dm.h" static struct channel_oil * tib_sg_oil_setup(struct pim_instance *pim, pim_sgaddr sg, struct interface *oif) @@ -108,6 +109,7 @@ bool tib_sg_gm_join(struct pim_instance *pim, pim_sgaddr sg, struct interface *oif, struct channel_oil **oilp) { struct pim_interface *pim_oif = oif->info; + struct channel_oil *c_oil; if (!pim_oif) { if (PIM_DEBUG_GM_TRACE) @@ -123,6 +125,36 @@ bool tib_sg_gm_join(struct pim_instance *pim, pim_sgaddr sg, tib_sg_proxy_join_prune_check(pim, sg, oif, true); + /* For dense mode, we know we have a new IGMP that we may need to forward + * We need to look for any existing pruned coil for this group and graft as needed + * Go over every interface, look for a pruned coil, and graft if found + */ + /* Only do dense on dense interfaces (and/or groups if SM-DM or have a prefix list)*/ + if (pim_iface_grp_dm(pim_oif, sg.grp)) { + frr_each (rb_pim_oil, &(pim->channel_oil_head), c_oil) { + /* TODO debug log of oil */ + if (PIM_DEBUG_GRAFT) + zlog_debug("%s: Evaluating c_oil for DM graft", __func__); + + if (!pim_addr_cmp(sg.grp, *oil_mcastgrp(c_oil))) { + if (c_oil->up && PIM_UPSTREAM_DM_TEST_PRUNE(c_oil->up->flags)) { + struct interface *ifp = + c_oil->up->rpf.source_nexthop.interface; + if (ifp && ifp->info) { + struct pim_interface *pim_ifp = ifp->info; + if (HAVE_DENSE_MODE(pim_ifp->pim_mode)) { + PIM_UPSTREAM_DM_UNSET_PRUNE( + c_oil->up->flags); + event_cancel(&c_oil->up->t_prune_timer); + pim_dm_graft_send(c_oil->up->rpf, c_oil->up); + graft_timer_start(c_oil->up); + } + } + } + } + } + } + if (PIM_I_am_DR(pim_oif) || PIM_I_am_DualActive(pim_oif)) { int result; @@ -164,6 +196,7 @@ void tib_sg_gm_prune(struct pim_instance *pim, pim_sgaddr sg, struct interface *oif, struct channel_oil **oilp) { int result; + struct pim_interface *pim_oif = oif->info; tib_sg_proxy_join_prune_check(pim, sg, oif, false); @@ -195,6 +228,26 @@ void tib_sg_gm_prune(struct pim_instance *pim, pim_sgaddr sg, return; } + /* dm: check if we need to send a prune message */ + if ((*oilp)->oil_size == 0) { + /* Not forwarding to any other interfaces, prune it */ + /* Only if the upstream is dense and group is dense */ + if (pim_iface_grp_dm(pim_oif, sg.grp) && HAVE_DENSE_MODE(pim_oif->pim_mode)) { + if ((*oilp)->up) { + struct interface *ifp = (*oilp)->up->rpf.source_nexthop.interface; + if (ifp && ifp->info) { + struct pim_interface *pim_ifp = ifp->info; + if (HAVE_DENSE_MODE(pim_ifp->pim_mode)) { + event_cancel(&(*oilp)->up->t_graft_timer); + PIM_UPSTREAM_DM_SET_PRUNE((*oilp)->up->flags); + pim_dm_prune_send((*oilp)->up->rpf, (*oilp)->up, 0); + prune_timer_start((*oilp)->up); + } + } + } + } + } + /* Feed IGMPv3-gathered local membership information into PIM per-interface (S,G) state. diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 87e0a2b66b..6bf5ed6c3f 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -1015,8 +1015,8 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, /* Set up->upstream_addr as INADDR_ANY, if RP is not * configured and retain the upstream data structure */ - if (!pim_rp_set_upstream_addr(pim, &up->upstream_addr, sg->src, - sg->grp)) { + if (!pim_rp_set_upstream_addr(pim, &up->upstream_addr, sg->src, sg->grp) && + pim_is_grp_dm(pim, sg->grp)) { if (PIM_DEBUG_PIM_TRACE) zlog_debug("%s: Received a (*,G) with no RP configured", __func__);