summaryrefslogtreecommitdiffstats
path: root/pimd
diff options
context:
space:
mode:
authorDavid Lamparter <equinox@opensourcerouting.org>2022-02-28 11:42:48 +0100
committerDavid Lamparter <equinox@opensourcerouting.org>2022-03-12 22:47:08 +0100
commitcd6d285855954039624f115a9fad7d4abbb4574d (patch)
treeee7c2288a648ae032b552577759040daa8c7b1d3 /pimd
parentpimd: add safety check to OIL add/del (diff)
downloadfrr-cd6d285855954039624f115a9fad7d4abbb4574d.tar.xz
frr-cd6d285855954039624f115a9fad7d4abbb4574d.zip
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>
Diffstat (limited to 'pimd')
-rw-r--r--pimd/pim_igmp.c171
-rw-r--r--pimd/pim_igmp.h11
-rw-r--r--pimd/pim_ssm.c2
-rw-r--r--pimd/pim_tib.c178
-rw-r--r--pimd/pim_tib.h33
-rw-r--r--pimd/pim_zebra.c329
-rw-r--r--pimd/pim_zebra.h10
-rw-r--r--pimd/subdir.am2
8 files changed, 395 insertions, 341 deletions
diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c
index 5cdefd282..289e8e457 100644
--- a/pimd/pim_igmp.c
+++ b/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()
*/
diff --git a/pimd/pim_igmp.h b/pimd/pim_igmp.h
index 5c3599663..d1490fddf 100644
--- a/pimd/pim_igmp.h
+++ b/pimd/pim_igmp.h
@@ -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,
diff --git a/pimd/pim_ssm.c b/pimd/pim_ssm.c
index 688d38c84..74310474d 100644
--- a/pimd/pim_ssm.c
+++ b/pimd/pim_ssm.c
@@ -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)
{
diff --git a/pimd/pim_tib.c b/pimd/pim_tib.c
new file mode 100644
index 000000000..838f11211
--- /dev/null
+++ b/pimd/pim_tib.c
@@ -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);
+}
diff --git a/pimd/pim_tib.h b/pimd/pim_tib.h
new file mode 100644
index 000000000..b320f4cde
--- /dev/null
+++ b/pimd/pim_tib.h
@@ -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 */
diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c
index 526fdcbc2..91d4a479c 100644
--- a/pimd/pim_zebra.c
+++ b/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;
diff --git a/pimd/pim_zebra.h b/pimd/pim_zebra.h
index 8656d7563..5879cdefb 100644
--- a/pimd/pim_zebra.h
+++ b/pimd/pim_zebra.h
@@ -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);
diff --git a/pimd/subdir.am b/pimd/subdir.am
index d617be3cb..cda5acb00 100644
--- a/pimd/subdir.am
+++ b/pimd/subdir.am
@@ -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 \