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 <nbahr@atcorp.com>
This commit is contained in:
Nathan Bahr 2025-05-28 19:35:33 +00:00
parent 5b44e6ecbc
commit 9871c05034
3 changed files with 55 additions and 30 deletions

View file

@ -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;
}

View file

@ -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.

View file

@ -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__);