mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-03 08:56:13 +00:00
pimd: refactor/split IGMP integration
Try to untangle some spaghetti... This is an 1:1 change that should not result in any functional difference. Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
This commit is contained in:
parent
d6890c49b2
commit
cd6d285855
171
pimd/pim_igmp.c
171
pimd/pim_igmp.c
@ -37,11 +37,180 @@
|
||||
#include "pim_str.h"
|
||||
#include "pim_util.h"
|
||||
#include "pim_time.h"
|
||||
#include "pim_zebra.h"
|
||||
#include "pim_ssm.h"
|
||||
#include "pim_tib.h"
|
||||
|
||||
static void group_timer_off(struct gm_group *group);
|
||||
static void pim_igmp_general_query(struct thread *t);
|
||||
|
||||
void igmp_anysource_forward_start(struct pim_instance *pim,
|
||||
struct gm_group *group)
|
||||
{
|
||||
struct gm_source *source;
|
||||
struct in_addr src_addr = {.s_addr = 0};
|
||||
/* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
|
||||
assert(group->group_filtermode_isexcl);
|
||||
assert(listcount(group->group_source_list) < 1);
|
||||
|
||||
source = igmp_get_source_by_addr(group, src_addr, NULL);
|
||||
if (!source) {
|
||||
zlog_warn("%s: Failure to create * source", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
igmp_source_forward_start(pim, source);
|
||||
}
|
||||
|
||||
void igmp_anysource_forward_stop(struct gm_group *group)
|
||||
{
|
||||
struct gm_source *source;
|
||||
struct in_addr star = {.s_addr = 0};
|
||||
|
||||
source = igmp_find_source_by_addr(group, star);
|
||||
if (source)
|
||||
igmp_source_forward_stop(source);
|
||||
}
|
||||
|
||||
static void igmp_source_forward_reevaluate_one(struct pim_instance *pim,
|
||||
struct gm_source *source)
|
||||
{
|
||||
pim_sgaddr sg;
|
||||
struct gm_group *group = source->source_group;
|
||||
struct pim_ifchannel *ch;
|
||||
|
||||
if ((source->source_addr.s_addr != INADDR_ANY) ||
|
||||
!IGMP_SOURCE_TEST_FORWARDING(source->source_flags))
|
||||
return;
|
||||
|
||||
memset(&sg, 0, sizeof(sg));
|
||||
sg.src = source->source_addr;
|
||||
sg.grp = group->group_addr;
|
||||
|
||||
ch = pim_ifchannel_find(group->interface, &sg);
|
||||
if (pim_is_grp_ssm(pim, group->group_addr)) {
|
||||
/* If SSM group withdraw local membership */
|
||||
if (ch &&
|
||||
(ch->local_ifmembership == PIM_IFMEMBERSHIP_INCLUDE)) {
|
||||
if (PIM_DEBUG_PIM_EVENTS)
|
||||
zlog_debug(
|
||||
"local membership del for %pSG as G is now SSM",
|
||||
&sg);
|
||||
pim_ifchannel_local_membership_del(group->interface,
|
||||
&sg);
|
||||
}
|
||||
} else {
|
||||
/* If ASM group add local membership */
|
||||
if (!ch ||
|
||||
(ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO)) {
|
||||
if (PIM_DEBUG_PIM_EVENTS)
|
||||
zlog_debug(
|
||||
"local membership add for %pSG as G is now ASM",
|
||||
&sg);
|
||||
pim_ifchannel_local_membership_add(
|
||||
group->interface, &sg, false /*is_vxlan*/);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void igmp_source_forward_reevaluate_all(struct pim_instance *pim)
|
||||
{
|
||||
struct interface *ifp;
|
||||
|
||||
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
||||
struct pim_interface *pim_ifp = ifp->info;
|
||||
struct listnode *grpnode;
|
||||
struct gm_group *grp;
|
||||
struct pim_ifchannel *ch, *ch_temp;
|
||||
|
||||
if (!pim_ifp)
|
||||
continue;
|
||||
|
||||
/* scan igmp groups */
|
||||
for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, grpnode,
|
||||
grp)) {
|
||||
struct listnode *srcnode;
|
||||
struct gm_source *src;
|
||||
|
||||
/* scan group sources */
|
||||
for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
|
||||
srcnode, src)) {
|
||||
igmp_source_forward_reevaluate_one(pim, src);
|
||||
} /* scan group sources */
|
||||
} /* scan igmp groups */
|
||||
|
||||
RB_FOREACH_SAFE (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb,
|
||||
ch_temp) {
|
||||
if (pim_is_grp_ssm(pim, ch->sg.grp)) {
|
||||
if (pim_addr_is_any(ch->sg.src))
|
||||
pim_ifchannel_delete(ch);
|
||||
}
|
||||
}
|
||||
} /* scan interfaces */
|
||||
}
|
||||
|
||||
void igmp_source_forward_start(struct pim_instance *pim,
|
||||
struct gm_source *source)
|
||||
{
|
||||
struct gm_group *group;
|
||||
pim_sgaddr sg;
|
||||
|
||||
memset(&sg, 0, sizeof(sg));
|
||||
sg.src = source->source_addr;
|
||||
sg.grp = source->source_group->group_addr;
|
||||
|
||||
if (PIM_DEBUG_IGMP_TRACE) {
|
||||
zlog_debug("%s: (S,G)=%pSG oif=%s fwd=%d", __func__, &sg,
|
||||
source->source_group->interface->name,
|
||||
IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
|
||||
}
|
||||
|
||||
/* Prevent IGMP interface from installing multicast route multiple
|
||||
times */
|
||||
if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
|
||||
return;
|
||||
}
|
||||
|
||||
group = source->source_group;
|
||||
|
||||
if (tib_sg_gm_join(pim, sg, group->interface,
|
||||
&source->source_channel_oil))
|
||||
IGMP_SOURCE_DO_FORWARDING(source->source_flags);
|
||||
}
|
||||
|
||||
/*
|
||||
igmp_source_forward_stop: stop fowarding, but keep the source
|
||||
igmp_source_delete: stop fowarding, and delete the source
|
||||
*/
|
||||
void igmp_source_forward_stop(struct gm_source *source)
|
||||
{
|
||||
struct pim_interface *pim_oif;
|
||||
struct gm_group *group;
|
||||
pim_sgaddr sg;
|
||||
|
||||
memset(&sg, 0, sizeof(sg));
|
||||
sg.src = source->source_addr;
|
||||
sg.grp = source->source_group->group_addr;
|
||||
|
||||
if (PIM_DEBUG_IGMP_TRACE) {
|
||||
zlog_debug("%s: (S,G)=%pSG oif=%s fwd=%d", __func__, &sg,
|
||||
source->source_group->interface->name,
|
||||
IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
|
||||
}
|
||||
|
||||
/* Prevent IGMP interface from removing multicast route multiple
|
||||
times */
|
||||
if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
|
||||
return;
|
||||
}
|
||||
|
||||
group = source->source_group;
|
||||
pim_oif = group->interface->info;
|
||||
|
||||
tib_sg_gm_prune(pim_oif->pim, sg, group->interface,
|
||||
&source->source_channel_oil);
|
||||
IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
|
||||
}
|
||||
|
||||
/* This socket is used for TXing IGMP packets only, IGMP RX happens
|
||||
* in pim_mroute_msg()
|
||||
*/
|
||||
|
@ -204,6 +204,17 @@ struct gm_group {
|
||||
};
|
||||
|
||||
#if PIM_IPV == 4
|
||||
struct pim_instance;
|
||||
|
||||
void igmp_anysource_forward_start(struct pim_instance *pim,
|
||||
struct gm_group *group);
|
||||
void igmp_anysource_forward_stop(struct gm_group *group);
|
||||
|
||||
void igmp_source_forward_start(struct pim_instance *pim,
|
||||
struct gm_source *source);
|
||||
void igmp_source_forward_stop(struct gm_source *source);
|
||||
void igmp_source_forward_reevaluate_all(struct pim_instance *pim);
|
||||
|
||||
struct gm_group *find_group_by_addr(struct gm_sock *igmp,
|
||||
struct in_addr group_addr);
|
||||
struct gm_group *igmp_add_group_by_addr(struct gm_sock *igmp,
|
||||
|
@ -28,7 +28,7 @@
|
||||
|
||||
#include "pimd.h"
|
||||
#include "pim_ssm.h"
|
||||
#include "pim_zebra.h"
|
||||
#include "pim_igmp.h"
|
||||
|
||||
static void pim_ssm_range_reevaluate(struct pim_instance *pim)
|
||||
{
|
||||
|
178
pimd/pim_tib.c
Normal file
178
pimd/pim_tib.c
Normal file
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* TIB (Tree Information Base) - just PIM <> IGMP/MLD glue for now
|
||||
* Copyright (C) 2022 David Lamparter for NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include "pim_tib.h"
|
||||
|
||||
#include "pimd.h"
|
||||
#include "pim_iface.h"
|
||||
#include "pim_upstream.h"
|
||||
#include "pim_oil.h"
|
||||
#include "pim_nht.h"
|
||||
|
||||
static struct channel_oil *
|
||||
tib_sg_oil_setup(struct pim_instance *pim, pim_sgaddr sg, struct interface *oif)
|
||||
{
|
||||
struct pim_interface *pim_oif = oif->info;
|
||||
int input_iface_vif_index = 0;
|
||||
pim_addr vif_source;
|
||||
struct prefix src, grp;
|
||||
struct pim_nexthop nexthop;
|
||||
struct pim_upstream *up = NULL;
|
||||
|
||||
if (!pim_rp_set_upstream_addr(pim, &vif_source, sg.src, sg.grp)) {
|
||||
/* no PIM RP - create a dummy channel oil */
|
||||
return pim_channel_oil_add(pim, &sg, __func__);
|
||||
}
|
||||
|
||||
pim_addr_to_prefix(&src, vif_source); // RP or Src addr
|
||||
pim_addr_to_prefix(&grp, sg.grp);
|
||||
|
||||
up = pim_upstream_find(pim, &sg);
|
||||
if (up) {
|
||||
memcpy(&nexthop, &up->rpf.source_nexthop,
|
||||
sizeof(struct pim_nexthop));
|
||||
pim_ecmp_nexthop_lookup(pim, &nexthop, &src, &grp, 0);
|
||||
if (nexthop.interface)
|
||||
input_iface_vif_index = pim_if_find_vifindex_by_ifindex(
|
||||
pim, nexthop.interface->ifindex);
|
||||
} else
|
||||
input_iface_vif_index =
|
||||
pim_ecmp_fib_lookup_if_vif_index(pim, &src, &grp);
|
||||
|
||||
if (PIM_DEBUG_ZEBRA)
|
||||
zlog_debug("%s: NHT %pSG vif_source %pPAs vif_index:%d",
|
||||
__func__, &sg, &vif_source, input_iface_vif_index);
|
||||
|
||||
if (input_iface_vif_index < 1) {
|
||||
if (PIM_DEBUG_IGMP_TRACE)
|
||||
zlog_debug(
|
||||
"%s %s: could not find input interface for %pSG",
|
||||
__FILE__, __func__, &sg);
|
||||
|
||||
return pim_channel_oil_add(pim, &sg, __func__);
|
||||
}
|
||||
|
||||
/*
|
||||
* Protect IGMP against adding looped MFC entries created by both
|
||||
* source and receiver attached to the same interface. See TODO T22.
|
||||
* Block only when the intf is non DR DR must create upstream.
|
||||
*/
|
||||
if ((input_iface_vif_index == pim_oif->mroute_vif_index) &&
|
||||
!(PIM_I_am_DR(pim_oif))) {
|
||||
/* ignore request for looped MFC entry */
|
||||
if (PIM_DEBUG_IGMP_TRACE)
|
||||
zlog_debug(
|
||||
"%s: ignoring request for looped MFC entry (S,G)=%pSG: oif=%s vif_index=%d",
|
||||
__func__, &sg, oif->name,
|
||||
input_iface_vif_index);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pim_channel_oil_add(pim, &sg, __func__);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (!pim_oif) {
|
||||
if (PIM_DEBUG_IGMP_TRACE)
|
||||
zlog_debug("%s: multicast not enabled on oif=%s?",
|
||||
__func__, oif->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!*oilp)
|
||||
*oilp = tib_sg_oil_setup(pim, sg, oif);
|
||||
if (!*oilp)
|
||||
return false;
|
||||
|
||||
if (PIM_I_am_DR(pim_oif) || PIM_I_am_DualActive(pim_oif)) {
|
||||
int result;
|
||||
|
||||
result = pim_channel_add_oif(*oilp, oif,
|
||||
PIM_OIF_FLAG_PROTO_IGMP, __func__);
|
||||
if (result) {
|
||||
if (PIM_DEBUG_MROUTE)
|
||||
zlog_warn("%s: add_oif() failed with return=%d",
|
||||
__func__, result);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (PIM_DEBUG_IGMP_TRACE)
|
||||
zlog_debug(
|
||||
"%s: %pSG was received on %s interface but we are not DR for that interface",
|
||||
__func__, &sg, oif->name);
|
||||
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
Feed IGMPv3-gathered local membership information into PIM
|
||||
per-interface (S,G) state.
|
||||
*/
|
||||
if (!pim_ifchannel_local_membership_add(oif, &sg, false /*is_vxlan*/)) {
|
||||
if (PIM_DEBUG_MROUTE)
|
||||
zlog_warn(
|
||||
"%s: Failure to add local membership for %pSG",
|
||||
__func__, &sg);
|
||||
|
||||
pim_channel_del_oif(*oilp, oif, PIM_OIF_FLAG_PROTO_IGMP,
|
||||
__func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void tib_sg_gm_prune(struct pim_instance *pim, pim_sgaddr sg,
|
||||
struct interface *oif, struct channel_oil **oilp)
|
||||
{
|
||||
int result;
|
||||
|
||||
/*
|
||||
It appears that in certain circumstances that
|
||||
igmp_source_forward_stop is called when IGMP forwarding
|
||||
was not enabled in oif_flags for this outgoing interface.
|
||||
Possibly because of multiple calls. When that happens, we
|
||||
enter the below if statement and this function returns early
|
||||
which in turn triggers the calling function to assert.
|
||||
Making the call to pim_channel_del_oif and ignoring the return code
|
||||
fixes the issue without ill effect, similar to
|
||||
pim_forward_stop below.
|
||||
*/
|
||||
result = pim_channel_del_oif(*oilp, oif, PIM_OIF_FLAG_PROTO_IGMP,
|
||||
__func__);
|
||||
if (result) {
|
||||
if (PIM_DEBUG_IGMP_TRACE)
|
||||
zlog_debug(
|
||||
"%s: pim_channel_del_oif() failed with return=%d",
|
||||
__func__, result);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Feed IGMPv3-gathered local membership information into PIM
|
||||
per-interface (S,G) state.
|
||||
*/
|
||||
pim_ifchannel_local_membership_del(oif, &sg);
|
||||
}
|
33
pimd/pim_tib.h
Normal file
33
pimd/pim_tib.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* TIB (Tree Information Base) - just PIM <> IGMP/MLD glue for now
|
||||
* Copyright (C) 2022 David Lamparter for NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _FRR_PIM_GLUE_H
|
||||
#define _FRR_PIM_GLUE_H
|
||||
|
||||
#include "pim_addr.h"
|
||||
|
||||
struct pim_instance;
|
||||
struct channel_oil;
|
||||
|
||||
extern bool tib_sg_gm_join(struct pim_instance *pim, pim_sgaddr sg,
|
||||
struct interface *oif, struct channel_oil **oilp);
|
||||
extern void tib_sg_gm_prune(struct pim_instance *pim, pim_sgaddr sg,
|
||||
struct interface *oif, struct channel_oil **oilp);
|
||||
|
||||
#endif /* _FRR_PIM_GLUE_H */
|
329
pimd/pim_zebra.c
329
pimd/pim_zebra.c
@ -486,335 +486,6 @@ void pim_zebra_init(void)
|
||||
zclient_lookup_new();
|
||||
}
|
||||
|
||||
#if PIM_IPV == 4
|
||||
void igmp_anysource_forward_start(struct pim_instance *pim,
|
||||
struct gm_group *group)
|
||||
{
|
||||
struct gm_source *source;
|
||||
struct in_addr src_addr = {.s_addr = 0};
|
||||
/* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
|
||||
assert(group->group_filtermode_isexcl);
|
||||
assert(listcount(group->group_source_list) < 1);
|
||||
|
||||
source = igmp_get_source_by_addr(group, src_addr, NULL);
|
||||
if (!source) {
|
||||
zlog_warn("%s: Failure to create * source", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
igmp_source_forward_start(pim, source);
|
||||
}
|
||||
|
||||
void igmp_anysource_forward_stop(struct gm_group *group)
|
||||
{
|
||||
struct gm_source *source;
|
||||
struct in_addr star = {.s_addr = 0};
|
||||
|
||||
source = igmp_find_source_by_addr(group, star);
|
||||
if (source)
|
||||
igmp_source_forward_stop(source);
|
||||
}
|
||||
|
||||
static void igmp_source_forward_reevaluate_one(struct pim_instance *pim,
|
||||
struct gm_source *source)
|
||||
{
|
||||
pim_sgaddr sg;
|
||||
struct gm_group *group = source->source_group;
|
||||
struct pim_ifchannel *ch;
|
||||
|
||||
if ((source->source_addr.s_addr != INADDR_ANY)
|
||||
|| !IGMP_SOURCE_TEST_FORWARDING(source->source_flags))
|
||||
return;
|
||||
|
||||
memset(&sg, 0, sizeof(sg));
|
||||
sg.src = source->source_addr;
|
||||
sg.grp = group->group_addr;
|
||||
|
||||
ch = pim_ifchannel_find(group->interface, &sg);
|
||||
if (pim_is_grp_ssm(pim, group->group_addr)) {
|
||||
/* If SSM group withdraw local membership */
|
||||
if (ch
|
||||
&& (ch->local_ifmembership == PIM_IFMEMBERSHIP_INCLUDE)) {
|
||||
if (PIM_DEBUG_PIM_EVENTS)
|
||||
zlog_debug("local membership del for %pSG as G is now SSM",
|
||||
&sg);
|
||||
pim_ifchannel_local_membership_del(group->interface,
|
||||
&sg);
|
||||
}
|
||||
} else {
|
||||
/* If ASM group add local membership */
|
||||
if (!ch
|
||||
|| (ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO)) {
|
||||
if (PIM_DEBUG_PIM_EVENTS)
|
||||
zlog_debug("local membership add for %pSG as G is now ASM",
|
||||
&sg);
|
||||
pim_ifchannel_local_membership_add(
|
||||
group->interface, &sg, false /*is_vxlan*/);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void igmp_source_forward_reevaluate_all(struct pim_instance *pim)
|
||||
{
|
||||
struct interface *ifp;
|
||||
|
||||
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
||||
struct pim_interface *pim_ifp = ifp->info;
|
||||
struct listnode *grpnode;
|
||||
struct gm_group *grp;
|
||||
struct pim_ifchannel *ch, *ch_temp;
|
||||
|
||||
if (!pim_ifp)
|
||||
continue;
|
||||
|
||||
/* scan igmp groups */
|
||||
for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, grpnode,
|
||||
grp)) {
|
||||
struct listnode *srcnode;
|
||||
struct gm_source *src;
|
||||
|
||||
/* scan group sources */
|
||||
for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
|
||||
srcnode, src)) {
|
||||
igmp_source_forward_reevaluate_one(pim, src);
|
||||
} /* scan group sources */
|
||||
} /* scan igmp groups */
|
||||
|
||||
RB_FOREACH_SAFE (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb,
|
||||
ch_temp) {
|
||||
if (pim_is_grp_ssm(pim, ch->sg.grp)) {
|
||||
if (pim_addr_is_any(ch->sg.src))
|
||||
pim_ifchannel_delete(ch);
|
||||
}
|
||||
}
|
||||
} /* scan interfaces */
|
||||
}
|
||||
|
||||
void igmp_source_forward_start(struct pim_instance *pim,
|
||||
struct gm_source *source)
|
||||
{
|
||||
struct pim_interface *pim_oif;
|
||||
struct gm_group *group;
|
||||
pim_sgaddr sg;
|
||||
int result;
|
||||
int input_iface_vif_index = 0;
|
||||
|
||||
memset(&sg, 0, sizeof(sg));
|
||||
sg.src = source->source_addr;
|
||||
sg.grp = source->source_group->group_addr;
|
||||
|
||||
if (PIM_DEBUG_IGMP_TRACE) {
|
||||
zlog_debug("%s: (S,G)=%pSG oif=%s fwd=%d", __func__, &sg,
|
||||
source->source_group->interface->name,
|
||||
IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
|
||||
}
|
||||
|
||||
/* Prevent IGMP interface from installing multicast route multiple
|
||||
times */
|
||||
if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
|
||||
return;
|
||||
}
|
||||
|
||||
group = source->source_group;
|
||||
pim_oif = group->interface->info;
|
||||
if (!pim_oif) {
|
||||
if (PIM_DEBUG_IGMP_TRACE) {
|
||||
zlog_debug("%s: multicast not enabled on oif=%s ?",
|
||||
__func__,
|
||||
source->source_group->interface->name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!source->source_channel_oil) {
|
||||
pim_addr vif_source;
|
||||
struct prefix src, grp;
|
||||
struct pim_nexthop nexthop;
|
||||
struct pim_upstream *up = NULL;
|
||||
|
||||
if (!pim_rp_set_upstream_addr(pim, &vif_source,
|
||||
source->source_addr, sg.grp)) {
|
||||
/*Create a dummy channel oil */
|
||||
source->source_channel_oil =
|
||||
pim_channel_oil_add(pim, &sg, __func__);
|
||||
}
|
||||
|
||||
else {
|
||||
pim_addr_to_prefix(&src, vif_source); // RP or Src addr
|
||||
pim_addr_to_prefix(&grp, sg.grp);
|
||||
|
||||
up = pim_upstream_find(pim, &sg);
|
||||
if (up) {
|
||||
memcpy(&nexthop, &up->rpf.source_nexthop,
|
||||
sizeof(struct pim_nexthop));
|
||||
pim_ecmp_nexthop_lookup(pim, &nexthop, &src,
|
||||
&grp, 0);
|
||||
if (nexthop.interface)
|
||||
input_iface_vif_index =
|
||||
pim_if_find_vifindex_by_ifindex(
|
||||
pim,
|
||||
nexthop.interface->ifindex);
|
||||
} else
|
||||
input_iface_vif_index =
|
||||
pim_ecmp_fib_lookup_if_vif_index(
|
||||
pim, &src, &grp);
|
||||
|
||||
if (PIM_DEBUG_ZEBRA)
|
||||
zlog_debug(
|
||||
"%s: NHT %pSG vif_source %pPAs vif_index:%d ",
|
||||
__func__, &sg, &vif_source,
|
||||
input_iface_vif_index);
|
||||
|
||||
if (input_iface_vif_index < 1) {
|
||||
if (PIM_DEBUG_IGMP_TRACE) {
|
||||
char source_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<source?>",
|
||||
source->source_addr,
|
||||
source_str, sizeof(source_str));
|
||||
zlog_debug(
|
||||
"%s %s: could not find input interface for source %s",
|
||||
__FILE__, __func__, source_str);
|
||||
}
|
||||
source->source_channel_oil =
|
||||
pim_channel_oil_add(pim, &sg, __func__);
|
||||
}
|
||||
|
||||
else {
|
||||
/*
|
||||
* Protect IGMP against adding looped MFC
|
||||
* entries created by both source and receiver
|
||||
* attached to the same interface. See TODO
|
||||
* T22. Block only when the intf is non DR
|
||||
* DR must create upstream.
|
||||
*/
|
||||
if ((input_iface_vif_index ==
|
||||
pim_oif->mroute_vif_index) &&
|
||||
!(PIM_I_am_DR(pim_oif))) {
|
||||
/* ignore request for looped MFC entry
|
||||
*/
|
||||
if (PIM_DEBUG_IGMP_TRACE) {
|
||||
zlog_debug("%s: ignoring request for looped MFC entry (S,G)=%pSG: oif=%s vif_index=%d",
|
||||
__func__,
|
||||
&sg,
|
||||
source->source_group
|
||||
->interface->name,
|
||||
input_iface_vif_index);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
source->source_channel_oil =
|
||||
pim_channel_oil_add(pim, &sg, __func__);
|
||||
if (!source->source_channel_oil) {
|
||||
if (PIM_DEBUG_IGMP_TRACE) {
|
||||
zlog_debug("%s %s: could not create OIL for channel (S,G)=%pSG",
|
||||
__FILE__, __func__,
|
||||
&sg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (PIM_I_am_DR(pim_oif) || PIM_I_am_DualActive(pim_oif)) {
|
||||
result = pim_channel_add_oif(source->source_channel_oil,
|
||||
group->interface,
|
||||
PIM_OIF_FLAG_PROTO_IGMP, __func__);
|
||||
if (result) {
|
||||
if (PIM_DEBUG_MROUTE) {
|
||||
zlog_warn("%s: add_oif() failed with return=%d",
|
||||
__func__, result);
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (PIM_DEBUG_IGMP_TRACE)
|
||||
zlog_debug("%s: %pSG was received on %s interface but we are not DR for that interface",
|
||||
__func__, &sg,
|
||||
group->interface->name);
|
||||
|
||||
return;
|
||||
}
|
||||
/*
|
||||
Feed IGMPv3-gathered local membership information into PIM
|
||||
per-interface (S,G) state.
|
||||
*/
|
||||
if (!pim_ifchannel_local_membership_add(group->interface, &sg,
|
||||
false /*is_vxlan*/)) {
|
||||
if (PIM_DEBUG_MROUTE)
|
||||
zlog_warn("%s: Failure to add local membership for %pSG",
|
||||
__func__, &sg);
|
||||
|
||||
pim_channel_del_oif(source->source_channel_oil,
|
||||
group->interface, PIM_OIF_FLAG_PROTO_IGMP,
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
IGMP_SOURCE_DO_FORWARDING(source->source_flags);
|
||||
}
|
||||
|
||||
/*
|
||||
igmp_source_forward_stop: stop fowarding, but keep the source
|
||||
igmp_source_delete: stop fowarding, and delete the source
|
||||
*/
|
||||
void igmp_source_forward_stop(struct gm_source *source)
|
||||
{
|
||||
struct gm_group *group;
|
||||
pim_sgaddr sg;
|
||||
int result;
|
||||
|
||||
memset(&sg, 0, sizeof(sg));
|
||||
sg.src = source->source_addr;
|
||||
sg.grp = source->source_group->group_addr;
|
||||
|
||||
if (PIM_DEBUG_IGMP_TRACE) {
|
||||
zlog_debug("%s: (S,G)=%pSG oif=%s fwd=%d", __func__, &sg,
|
||||
source->source_group->interface->name,
|
||||
IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
|
||||
}
|
||||
|
||||
/* Prevent IGMP interface from removing multicast route multiple
|
||||
times */
|
||||
if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
|
||||
return;
|
||||
}
|
||||
|
||||
group = source->source_group;
|
||||
|
||||
/*
|
||||
It appears that in certain circumstances that
|
||||
igmp_source_forward_stop is called when IGMP forwarding
|
||||
was not enabled in oif_flags for this outgoing interface.
|
||||
Possibly because of multiple calls. When that happens, we
|
||||
enter the below if statement and this function returns early
|
||||
which in turn triggers the calling function to assert.
|
||||
Making the call to pim_channel_del_oif and ignoring the return code
|
||||
fixes the issue without ill effect, similar to
|
||||
pim_forward_stop below.
|
||||
*/
|
||||
result = pim_channel_del_oif(source->source_channel_oil,
|
||||
group->interface, PIM_OIF_FLAG_PROTO_IGMP,
|
||||
__func__);
|
||||
if (result) {
|
||||
if (PIM_DEBUG_IGMP_TRACE)
|
||||
zlog_debug(
|
||||
"%s: pim_channel_del_oif() failed with return=%d",
|
||||
__func__, result);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Feed IGMPv3-gathered local membership information into PIM
|
||||
per-interface (S,G) state.
|
||||
*/
|
||||
pim_ifchannel_local_membership_del(group->interface, &sg);
|
||||
|
||||
IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
|
||||
}
|
||||
#endif /* PIM_IPV == 4 */
|
||||
|
||||
void pim_forward_start(struct pim_ifchannel *ch)
|
||||
{
|
||||
struct pim_upstream *up = ch->upstream;
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include <zebra.h>
|
||||
#include "zclient.h"
|
||||
|
||||
#include "pim_igmp.h"
|
||||
#include "pim_ifchannel.h"
|
||||
|
||||
void pim_zebra_init(void);
|
||||
@ -32,15 +31,6 @@ void pim_zebra_zclient_update(struct vty *vty);
|
||||
void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index);
|
||||
void pim_scan_oil(struct pim_instance *pim_matcher);
|
||||
|
||||
void igmp_anysource_forward_start(struct pim_instance *pim,
|
||||
struct gm_group *group);
|
||||
void igmp_anysource_forward_stop(struct gm_group *group);
|
||||
|
||||
void igmp_source_forward_start(struct pim_instance *pim,
|
||||
struct gm_source *source);
|
||||
void igmp_source_forward_stop(struct gm_source *source);
|
||||
void igmp_source_forward_reevaluate_all(struct pim_instance *pim);
|
||||
|
||||
void pim_forward_start(struct pim_ifchannel *ch);
|
||||
void pim_forward_stop(struct pim_ifchannel *ch);
|
||||
|
||||
|
@ -47,6 +47,7 @@ pim_common = \
|
||||
pimd/pim_ssmpingd.c \
|
||||
pimd/pim_static.c \
|
||||
pimd/pim_str.c \
|
||||
pimd/pim_tib.c \
|
||||
pimd/pim_time.c \
|
||||
pimd/pim_tlv.c \
|
||||
pimd/pim_upstream.c \
|
||||
@ -141,6 +142,7 @@ noinst_HEADERS += \
|
||||
pimd/pim_ssmpingd.h \
|
||||
pimd/pim_static.h \
|
||||
pimd/pim_str.h \
|
||||
pimd/pim_tib.h \
|
||||
pimd/pim_time.h \
|
||||
pimd/pim_tlv.h \
|
||||
pimd/pim_upstream.h \
|
||||
|
Loading…
Reference in New Issue
Block a user