mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-05-02 21:06:01 +00:00
Merge pull request #10772 from opensourcerouting/pim6-mld-prep
pim6d: address management & MLD preparation
This commit is contained in:
commit
a0cd0ce4a8
124
pimd/pim_iface.c
124
pimd/pim_iface.c
@ -127,7 +127,6 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim,
|
||||
pim_ifp->pim = ifp->vrf->info;
|
||||
pim_ifp->mroute_vif_index = -1;
|
||||
|
||||
#if PIM_IPV == 4
|
||||
pim_ifp->igmp_version = IGMP_DEFAULT_VERSION;
|
||||
pim_ifp->gm_default_robustness_variable =
|
||||
IGMP_DEFAULT_ROBUSTNESS_VARIABLE;
|
||||
@ -153,10 +152,12 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim,
|
||||
|
||||
if (pim)
|
||||
PIM_IF_DO_PIM(pim_ifp->options);
|
||||
#if PIM_IPV == 4
|
||||
if (igmp)
|
||||
PIM_IF_DO_IGMP(pim_ifp->options);
|
||||
|
||||
PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp->options);
|
||||
#endif
|
||||
|
||||
pim_ifp->gm_join_list = NULL;
|
||||
pim_ifp->pim_neighbor_list = NULL;
|
||||
@ -186,10 +187,11 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim,
|
||||
|
||||
ifp->info = pim_ifp;
|
||||
|
||||
#if PIM_IPV == 4
|
||||
pim_sock_reset(ifp);
|
||||
#endif
|
||||
|
||||
pim_if_add_vif(ifp, ispimreg, is_vxlan_term);
|
||||
#endif
|
||||
pim_ifp->pim->mcast_if_count++;
|
||||
|
||||
return pim_ifp;
|
||||
@ -208,9 +210,12 @@ void pim_if_delete(struct interface *ifp)
|
||||
if (pim_ifp->gm_join_list) {
|
||||
pim_if_igmp_join_del_all(ifp);
|
||||
}
|
||||
#endif
|
||||
|
||||
pim_ifchannel_delete_all(ifp);
|
||||
#if PIM_IPV == 4
|
||||
igmp_sock_delete_all(ifp);
|
||||
#endif
|
||||
|
||||
pim_neighbor_delete_all(ifp, "Interface removed from configuration");
|
||||
|
||||
@ -224,7 +229,6 @@ void pim_if_delete(struct interface *ifp)
|
||||
|
||||
XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist);
|
||||
XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
|
||||
#endif
|
||||
|
||||
ifp->info = NULL;
|
||||
}
|
||||
@ -512,6 +516,26 @@ void pim_if_addr_add(struct connected *ifc)
|
||||
CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)
|
||||
? "secondary"
|
||||
: "primary");
|
||||
#if PIM_IPV != 4
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6) ||
|
||||
IN6_IS_ADDR_LOOPBACK(&ifc->address->u.prefix6)) {
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&pim_ifp->ll_lowest))
|
||||
pim_ifp->ll_lowest = ifc->address->u.prefix6;
|
||||
else if (IPV6_ADDR_CMP(&ifc->address->u.prefix6,
|
||||
&pim_ifp->ll_lowest) < 0)
|
||||
pim_ifp->ll_lowest = ifc->address->u.prefix6;
|
||||
|
||||
if (IPV6_ADDR_CMP(&ifc->address->u.prefix6,
|
||||
&pim_ifp->ll_highest) > 0)
|
||||
pim_ifp->ll_highest = ifc->address->u.prefix6;
|
||||
|
||||
if (PIM_DEBUG_ZEBRA)
|
||||
zlog_debug(
|
||||
"%s: new link-local %pI6, lowest now %pI6, highest %pI6",
|
||||
ifc->ifp->name, &ifc->address->u.prefix6,
|
||||
&pim_ifp->ll_lowest, &pim_ifp->ll_highest);
|
||||
}
|
||||
#endif
|
||||
|
||||
detect_address_change(ifp, 0, __func__);
|
||||
|
||||
@ -711,6 +735,43 @@ void pim_if_addr_del(struct connected *ifc, int force_prim_as_any)
|
||||
? "secondary"
|
||||
: "primary");
|
||||
|
||||
#if PIM_IPV == 6
|
||||
struct pim_interface *pim_ifp = ifc->ifp->info;
|
||||
|
||||
if (pim_ifp &&
|
||||
(!IPV6_ADDR_CMP(&ifc->address->u.prefix6, &pim_ifp->ll_lowest) ||
|
||||
!IPV6_ADDR_CMP(&ifc->address->u.prefix6, &pim_ifp->ll_highest))) {
|
||||
struct listnode *cnode;
|
||||
struct connected *cc;
|
||||
|
||||
memset(&pim_ifp->ll_lowest, 0xff, sizeof(pim_ifp->ll_lowest));
|
||||
memset(&pim_ifp->ll_highest, 0, sizeof(pim_ifp->ll_highest));
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(ifc->ifp->connected, cnode, cc)) {
|
||||
if (!IN6_IS_ADDR_LINKLOCAL(&cc->address->u.prefix6) &&
|
||||
!IN6_IS_ADDR_LOOPBACK(&cc->address->u.prefix6))
|
||||
continue;
|
||||
|
||||
if (IPV6_ADDR_CMP(&cc->address->u.prefix6,
|
||||
&pim_ifp->ll_lowest) < 0)
|
||||
pim_ifp->ll_lowest = cc->address->u.prefix6;
|
||||
if (IPV6_ADDR_CMP(&cc->address->u.prefix6,
|
||||
&pim_ifp->ll_highest) > 0)
|
||||
pim_ifp->ll_highest = cc->address->u.prefix6;
|
||||
}
|
||||
|
||||
if (pim_ifp->ll_lowest.s6_addr[0] == 0xff)
|
||||
memset(&pim_ifp->ll_lowest, 0,
|
||||
sizeof(pim_ifp->ll_lowest));
|
||||
|
||||
if (PIM_DEBUG_ZEBRA)
|
||||
zlog_debug(
|
||||
"%s: removed link-local %pI6, lowest now %pI6, highest %pI6",
|
||||
ifc->ifp->name, &ifc->address->u.prefix6,
|
||||
&pim_ifp->ll_lowest, &pim_ifp->ll_highest);
|
||||
}
|
||||
#endif
|
||||
|
||||
detect_address_change(ifp, force_prim_as_any, __func__);
|
||||
|
||||
pim_if_addr_del_igmp(ifc);
|
||||
@ -825,17 +886,36 @@ pim_addr pim_find_primary_addr(struct interface *ifp)
|
||||
{
|
||||
struct connected *ifc;
|
||||
struct listnode *node;
|
||||
int v4_addrs = 0;
|
||||
int v6_addrs = 0;
|
||||
struct pim_interface *pim_ifp = ifp->info;
|
||||
|
||||
if (pim_ifp && !pim_addr_is_any(pim_ifp->update_source)) {
|
||||
if (pim_ifp && !pim_addr_is_any(pim_ifp->update_source))
|
||||
return pim_ifp->update_source;
|
||||
}
|
||||
|
||||
#if PIM_IPV == 6
|
||||
if (pim_ifp)
|
||||
return pim_ifp->ll_highest;
|
||||
|
||||
pim_addr best_addr = PIMADDR_ANY;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
|
||||
pim_addr addr;
|
||||
|
||||
if (ifc->address->family != AF_INET6)
|
||||
continue;
|
||||
|
||||
addr = pim_addr_from_prefix(ifc->address);
|
||||
if (!IN6_IS_ADDR_LINKLOCAL(&addr))
|
||||
continue;
|
||||
if (pim_addr_cmp(addr, best_addr) > 0)
|
||||
best_addr = addr;
|
||||
}
|
||||
|
||||
return best_addr;
|
||||
#else
|
||||
int v4_addrs = 0;
|
||||
int v6_addrs = 0;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
|
||||
switch (ifc->address->family) {
|
||||
case AF_INET:
|
||||
v4_addrs++;
|
||||
@ -853,16 +933,9 @@ pim_addr pim_find_primary_addr(struct interface *ifp)
|
||||
if (ifc->address->family != PIM_AF)
|
||||
continue;
|
||||
|
||||
addr = pim_addr_from_prefix(ifc->address);
|
||||
|
||||
#if PIM_IPV == 6
|
||||
if (!IN6_IS_ADDR_LINKLOCAL(&addr))
|
||||
continue;
|
||||
#endif
|
||||
return addr;
|
||||
return pim_addr_from_prefix(ifc->address);
|
||||
}
|
||||
|
||||
#if PIM_IPV == 4
|
||||
/*
|
||||
* If we have no v4_addrs and v6 is configured
|
||||
* We probably are using unnumbered
|
||||
@ -882,8 +955,8 @@ pim_addr pim_find_primary_addr(struct interface *ifp)
|
||||
if (lo_ifp && (lo_ifp != ifp))
|
||||
return pim_find_primary_addr(lo_ifp);
|
||||
}
|
||||
#endif
|
||||
return PIMADDR_ANY;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int pim_iface_next_vif_index(struct interface *ifp)
|
||||
@ -1549,7 +1622,6 @@ static int pim_ifp_create(struct interface *ifp)
|
||||
*/
|
||||
if (pim_ifp)
|
||||
pim_ifp->pim = pim;
|
||||
#if PIM_IPV == 4
|
||||
pim_if_addr_add_all(ifp);
|
||||
|
||||
/*
|
||||
@ -1561,7 +1633,6 @@ static int pim_ifp_create(struct interface *ifp)
|
||||
* this is a no-op if it's already been done.
|
||||
*/
|
||||
pim_if_create_pimreg(pim);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if PIM_IPV == 4
|
||||
@ -1599,6 +1670,7 @@ static int pim_ifp_create(struct interface *ifp)
|
||||
|
||||
static int pim_ifp_up(struct interface *ifp)
|
||||
{
|
||||
uint32_t table_id;
|
||||
struct pim_interface *pim_ifp;
|
||||
struct pim_instance *pim;
|
||||
|
||||
@ -1621,9 +1693,6 @@ static int pim_ifp_up(struct interface *ifp)
|
||||
if (pim_ifp)
|
||||
pim_ifp->pim = pim;
|
||||
|
||||
#if PIM_IPV == 4
|
||||
uint32_t table_id;
|
||||
|
||||
/*
|
||||
pim_if_addr_add_all() suffices for bringing up both IGMP and
|
||||
PIM
|
||||
@ -1652,7 +1721,6 @@ static int pim_ifp_up(struct interface *ifp)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1666,7 +1734,6 @@ static int pim_ifp_down(struct interface *ifp)
|
||||
ifp->mtu, if_is_operative(ifp));
|
||||
}
|
||||
|
||||
#if PIM_IPV == 4
|
||||
if (!if_is_operative(ifp)) {
|
||||
pim_ifchannel_delete_all(ifp);
|
||||
/*
|
||||
@ -1675,6 +1742,7 @@ static int pim_ifp_down(struct interface *ifp)
|
||||
*/
|
||||
pim_if_addr_del_all(ifp);
|
||||
|
||||
#if PIM_IPV == 4
|
||||
/*
|
||||
pim_sock_delete() closes the socket, stops read and timer
|
||||
threads,
|
||||
@ -1683,13 +1751,15 @@ static int pim_ifp_down(struct interface *ifp)
|
||||
if (ifp->info) {
|
||||
pim_sock_delete(ifp, "link down");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ifp->info) {
|
||||
pim_if_del_vif(ifp);
|
||||
#if PIM_IPV == 4
|
||||
pim_ifstat_reset(ifp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1704,12 +1774,12 @@ static int pim_ifp_destroy(struct interface *ifp)
|
||||
ifp->mtu, if_is_operative(ifp));
|
||||
}
|
||||
|
||||
#if PIM_IPV == 4
|
||||
struct pim_instance *pim;
|
||||
|
||||
if (!if_is_operative(ifp))
|
||||
pim_if_addr_del_all(ifp);
|
||||
|
||||
#if PIM_IPV == 4
|
||||
struct pim_instance *pim;
|
||||
|
||||
pim = ifp->vrf->info;
|
||||
if (pim && pim->vxlan.term_if == ifp)
|
||||
pim_vxlan_del_term_dev(pim);
|
||||
|
@ -96,6 +96,13 @@ struct pim_interface {
|
||||
uint32_t options; /* bit vector */
|
||||
ifindex_t mroute_vif_index;
|
||||
struct pim_instance *pim;
|
||||
|
||||
#if PIM_IPV == 6
|
||||
/* link-locals: MLD uses lowest addr, PIM uses highest... */
|
||||
pim_addr ll_lowest;
|
||||
pim_addr ll_highest;
|
||||
#endif
|
||||
|
||||
pim_addr primary_address; /* remember addr to detect change */
|
||||
struct list *sec_addr_list; /* list of struct pim_secondary_addr */
|
||||
pim_addr update_source; /* user can statically set the primary
|
||||
|
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()
|
||||
*/
|
||||
|
@ -128,6 +128,15 @@ void pim_igmp_other_querier_timer_off(struct gm_sock *igmp);
|
||||
int igmp_validate_checksum(char *igmp_msg, int igmp_msg_len);
|
||||
|
||||
#else /* PIM_IPV != 4 */
|
||||
static inline void pim_igmp_if_init(struct pim_interface *pim_ifp,
|
||||
struct interface *ifp)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void pim_igmp_if_fini(struct pim_interface *pim_ifp)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void pim_igmp_general_query_on(struct gm_sock *igmp)
|
||||
{
|
||||
}
|
||||
@ -204,6 +213,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,
|
||||
|
@ -216,6 +216,10 @@ int pim_channel_del_oif(struct channel_oil *channel_oil, struct interface *oif,
|
||||
|
||||
pim_ifp = oif->info;
|
||||
|
||||
assertf(pim_ifp->mroute_vif_index >= 0,
|
||||
"trying to del OIF %s with VIF (%d)", oif->name,
|
||||
pim_ifp->mroute_vif_index);
|
||||
|
||||
/*
|
||||
* Don't do anything if we've been asked to remove a source
|
||||
* that is not actually on it.
|
||||
@ -418,6 +422,10 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif,
|
||||
|
||||
pim_ifp = oif->info;
|
||||
|
||||
assertf(pim_ifp->mroute_vif_index >= 0,
|
||||
"trying to add OIF %s with VIF (%d)", oif->name,
|
||||
pim_ifp->mroute_vif_index);
|
||||
|
||||
/* Prevent single protocol from subscribing same interface to
|
||||
channel (S,G) multiple times */
|
||||
if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
|
||||
|
@ -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 */
|
345
pimd/pim_zebra.c
345
pimd/pim_zebra.c
@ -55,7 +55,6 @@ struct zclient *zclient;
|
||||
|
||||
|
||||
/* Router-id update message from zebra. */
|
||||
__attribute__((unused))
|
||||
static int pim_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
|
||||
{
|
||||
struct prefix router_id;
|
||||
@ -65,7 +64,6 @@ static int pim_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
|
||||
return 0;
|
||||
}
|
||||
|
||||
__attribute__((unused))
|
||||
static int pim_zebra_interface_vrf_update(ZAPI_CALLBACK_ARGS)
|
||||
{
|
||||
struct interface *ifp;
|
||||
@ -158,6 +156,10 @@ static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS)
|
||||
SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
|
||||
}
|
||||
}
|
||||
#else /* PIM_IPV != 4 */
|
||||
if (p->family != PIM_AF)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
pim_if_addr_add(c);
|
||||
if (pim_ifp) {
|
||||
@ -178,10 +180,6 @@ static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS)
|
||||
pim_if_addr_add_all(ifp);
|
||||
}
|
||||
}
|
||||
#else /* PIM_IPV != 4 */
|
||||
/* unused - for now */
|
||||
(void)pim_ifp;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -220,8 +218,7 @@ static int pim_zebra_if_address_del(ZAPI_CALLBACK_ARGS)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if PIM_IPV == 4
|
||||
if (p->family == AF_INET) {
|
||||
if (p->family == PIM_AF) {
|
||||
struct pim_instance *pim;
|
||||
|
||||
pim = vrf->info;
|
||||
@ -229,7 +226,6 @@ static int pim_zebra_if_address_del(ZAPI_CALLBACK_ARGS)
|
||||
pim_rp_setup(pim);
|
||||
pim_i_am_rp_re_evaluate(pim);
|
||||
}
|
||||
#endif
|
||||
|
||||
connected_free(&c);
|
||||
return 0;
|
||||
@ -456,10 +452,10 @@ static zclient_handler *const pim_handlers[] = {
|
||||
[ZEBRA_INTERFACE_ADDRESS_DELETE] = pim_zebra_if_address_del,
|
||||
|
||||
[ZEBRA_NEXTHOP_UPDATE] = pim_parse_nexthop_update,
|
||||
#if PIM_IPV == 4
|
||||
[ZEBRA_ROUTER_ID_UPDATE] = pim_router_id_update_zebra,
|
||||
[ZEBRA_INTERFACE_VRF_UPDATE] = pim_zebra_interface_vrf_update,
|
||||
|
||||
#if PIM_IPV == 4
|
||||
[ZEBRA_VXLAN_SG_ADD] = pim_zebra_vxlan_sg_proc,
|
||||
[ZEBRA_VXLAN_SG_DEL] = pim_zebra_vxlan_sg_proc,
|
||||
|
||||
@ -486,335 +482,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