2015-02-04 07:01:14 +01:00
|
|
|
/*
|
2017-05-13 10:25:29 +02:00
|
|
|
* PIM for Quagga
|
|
|
|
* Copyright (C) 2008 Everton da Silva Marques
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
2015-02-04 07:01:14 +01:00
|
|
|
|
|
|
|
#include <zebra.h>
|
|
|
|
|
|
|
|
#include "linklist.h"
|
|
|
|
#include "thread.h"
|
|
|
|
#include "memory.h"
|
2016-06-18 02:43:21 +02:00
|
|
|
#include "if.h"
|
2016-08-24 16:25:11 +02:00
|
|
|
#include "vrf.h"
|
2017-02-13 02:16:08 +01:00
|
|
|
#include "hash.h"
|
|
|
|
#include "jhash.h"
|
2017-04-07 16:16:23 +02:00
|
|
|
#include "prefix.h"
|
2015-02-04 07:01:14 +01:00
|
|
|
|
|
|
|
#include "pimd.h"
|
|
|
|
#include "pim_str.h"
|
|
|
|
#include "pim_iface.h"
|
|
|
|
#include "pim_ifchannel.h"
|
|
|
|
#include "pim_zebra.h"
|
|
|
|
#include "pim_time.h"
|
|
|
|
#include "pim_msg.h"
|
|
|
|
#include "pim_pim.h"
|
|
|
|
#include "pim_join.h"
|
|
|
|
#include "pim_rpf.h"
|
|
|
|
#include "pim_macro.h"
|
2016-08-15 13:28:36 +02:00
|
|
|
#include "pim_oil.h"
|
2016-09-15 22:50:08 +02:00
|
|
|
#include "pim_upstream.h"
|
2017-03-17 19:51:13 +01:00
|
|
|
#include "pim_ssm.h"
|
2017-08-24 15:55:19 +02:00
|
|
|
#include "pim_rp.h"
|
2019-08-19 11:06:00 +02:00
|
|
|
#include "pim_mlag.h"
|
2015-02-04 07:01:14 +01:00
|
|
|
|
2017-07-31 18:44:20 +02:00
|
|
|
RB_GENERATE(pim_ifchannel_rb, pim_ifchannel, pim_ifp_rb, pim_ifchannel_compare);
|
|
|
|
|
|
|
|
int pim_ifchannel_compare(const struct pim_ifchannel *ch1,
|
|
|
|
const struct pim_ifchannel *ch2)
|
2016-11-07 20:33:54 +01:00
|
|
|
{
|
|
|
|
struct pim_interface *pim_ifp1;
|
|
|
|
struct pim_interface *pim_ifp2;
|
|
|
|
|
2017-04-20 18:21:02 +02:00
|
|
|
pim_ifp1 = ch1->interface->info;
|
|
|
|
pim_ifp2 = ch2->interface->info;
|
2016-11-07 20:33:54 +01:00
|
|
|
|
2017-04-20 18:21:02 +02:00
|
|
|
if (pim_ifp1->mroute_vif_index < pim_ifp2->mroute_vif_index)
|
2016-11-07 20:33:54 +01:00
|
|
|
return -1;
|
|
|
|
|
2017-04-20 18:21:02 +02:00
|
|
|
if (pim_ifp1->mroute_vif_index > pim_ifp2->mroute_vif_index)
|
2016-11-07 20:33:54 +01:00
|
|
|
return 1;
|
|
|
|
|
2017-04-20 18:21:02 +02:00
|
|
|
if (ntohl(ch1->sg.grp.s_addr) < ntohl(ch2->sg.grp.s_addr))
|
2016-11-07 20:33:54 +01:00
|
|
|
return -1;
|
|
|
|
|
2017-04-20 18:21:02 +02:00
|
|
|
if (ntohl(ch1->sg.grp.s_addr) > ntohl(ch2->sg.grp.s_addr))
|
2016-11-07 20:33:54 +01:00
|
|
|
return 1;
|
|
|
|
|
2017-04-20 18:21:02 +02:00
|
|
|
if (ntohl(ch1->sg.src.s_addr) < ntohl(ch2->sg.src.s_addr))
|
2016-11-07 20:33:54 +01:00
|
|
|
return -1;
|
|
|
|
|
2017-04-20 18:21:02 +02:00
|
|
|
if (ntohl(ch1->sg.src.s_addr) > ntohl(ch2->sg.src.s_addr))
|
2016-11-07 20:33:54 +01:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-07-28 18:21:31 +02:00
|
|
|
/*
|
|
|
|
* A (*,G) or a (*,*) is going away
|
|
|
|
* remove the parent pointer from
|
|
|
|
* those pointing at us
|
|
|
|
*/
|
|
|
|
static void pim_ifchannel_remove_children(struct pim_ifchannel *ch)
|
|
|
|
{
|
|
|
|
struct pim_ifchannel *child;
|
|
|
|
|
2016-11-07 20:33:54 +01:00
|
|
|
if (!ch->sources)
|
2016-07-28 18:21:31 +02:00
|
|
|
return;
|
|
|
|
|
2016-11-07 20:33:54 +01:00
|
|
|
while (!list_isempty(ch->sources)) {
|
|
|
|
child = listnode_head(ch->sources);
|
|
|
|
child->parent = NULL;
|
|
|
|
listnode_delete(ch->sources, child);
|
2016-07-28 18:21:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A (*,G) or a (*,*) is being created
|
|
|
|
* find all the children that would point
|
|
|
|
* at us.
|
|
|
|
*/
|
|
|
|
static void pim_ifchannel_find_new_children(struct pim_ifchannel *ch)
|
|
|
|
{
|
|
|
|
struct pim_interface *pim_ifp = ch->interface->info;
|
|
|
|
struct pim_ifchannel *child;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-07-28 18:21:31 +02:00
|
|
|
// Basic Sanity that we are not being silly
|
2016-08-02 10:38:11 +02:00
|
|
|
if ((ch->sg.src.s_addr != INADDR_ANY)
|
|
|
|
&& (ch->sg.grp.s_addr != INADDR_ANY))
|
2016-07-28 18:21:31 +02:00
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-08-02 10:38:11 +02:00
|
|
|
if ((ch->sg.src.s_addr == INADDR_ANY)
|
|
|
|
&& (ch->sg.grp.s_addr == INADDR_ANY))
|
2016-07-28 18:21:31 +02:00
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-09-15 17:47:35 +02:00
|
|
|
RB_FOREACH (child, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
|
2016-08-02 10:38:11 +02:00
|
|
|
if ((ch->sg.grp.s_addr != INADDR_ANY)
|
|
|
|
&& (child->sg.grp.s_addr == ch->sg.grp.s_addr)
|
2016-07-28 18:21:31 +02:00
|
|
|
&& (child != ch)) {
|
2016-11-07 20:33:54 +01:00
|
|
|
child->parent = ch;
|
|
|
|
listnode_add_sort(ch->sources, child);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2016-11-07 20:33:54 +01:00
|
|
|
}
|
2016-07-28 18:21:31 +02:00
|
|
|
}
|
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
void pim_ifchannel_delete(struct pim_ifchannel *ch)
|
|
|
|
{
|
|
|
|
struct pim_interface *pim_ifp;
|
pimd: fix problem with oif being re-added during ifchannel del
Series of events leading to the problem -
1. (S,G) has been pruned on the rp on downlink-1
2. a (*,G) join is rxed on downlink-1 without the source S. This
results in the (S,G,rpt) prune state being cleared on downlink-1.
As a part of the clear the ifchannel associated with downlink-1
is deleted.
3. The ifchannel_delete handling is expected to add downlink-1
as an inherited OIF to the channel OIL (which it does). However
it is also added in as an immediate OIF (accidentally) as the
ifchannel is still present (in the process of being deleted).
To avoid the problem defer pim_upstream_update_join_desired
evaluation until after the channel is deleted.
Relevant debug logs -
PIM: pim_ifchannel_delete: ifchannel entry (27.0.0.15,239.1.1.106)(downlink-1) del start
PIM: pim_channel_add_oif(pim_ifchannel_delete): (S,G)=(27.0.0.15,239.1.1.106): proto_mask=4 OIF=downlink-1 vif_index=7: DONE
PIM: pimd/pim_oil.c pim_channel_del_oif: no existing protocol mask 2(4) for requested OIF downlink-1 (vif_index=7, min_ttl=1) for channel (S,G)=(27.0.0.15,239.1.1.106)
PIM: pim_upstream_switch: PIM_UPSTREAM_(27.0.0.15,239.1.1.106): (S,G) old: NotJoined new: Joined
PIM: pim_channel_add_oif(pim_upstream_inherited_olist_decide): (S,G)=(27.0.0.15,239.1.1.106): proto_mask=2 OIF=downlink-1 vif_index=7 added to 0x6 >>>>>>>>>>>>>>>>>>
PIM: pim_upstream_del(pim_ifchannel_delete): Delete (27.0.0.15,239.1.1.106)[default] ref count: 2 , flags: 81 c_oil ref count 1 (Pre decrement)
PIM: pim_ifchannel_delete: ifchannel entry (27.0.0.15,239.1.1.106)(downlink-1) del end
Ticket: CM-26732
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2019-10-15 01:02:36 +02:00
|
|
|
struct pim_upstream *up;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
pim_ifp = ch->interface->info;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-10-14 21:41:33 +02:00
|
|
|
if (PIM_DEBUG_PIM_TRACE)
|
|
|
|
zlog_debug("%s: ifchannel entry %s(%s) del start", __func__,
|
|
|
|
ch->sg_str, ch->interface->name);
|
|
|
|
|
2019-08-19 11:06:00 +02:00
|
|
|
if (PIM_I_am_DualActive(pim_ifp)) {
|
|
|
|
if (PIM_DEBUG_MLAG)
|
|
|
|
zlog_debug(
|
2020-03-27 12:35:23 +01:00
|
|
|
"%s: if-chnanel-%s is deleted from a Dual active Interface",
|
2019-08-19 11:06:00 +02:00
|
|
|
__func__, ch->sg_str);
|
|
|
|
/* Post Delete only if it is the last Dual-active Interface */
|
|
|
|
if (ch->upstream->dualactive_ifchannel_count == 1) {
|
|
|
|
pim_mlag_up_local_del(pim_ifp->pim, ch->upstream);
|
|
|
|
PIM_UPSTREAM_FLAG_UNSET_MLAG_INTERFACE(
|
|
|
|
ch->upstream->flags);
|
|
|
|
}
|
|
|
|
ch->upstream->dualactive_ifchannel_count--;
|
|
|
|
}
|
|
|
|
|
2016-12-08 18:40:05 +01:00
|
|
|
if (ch->upstream->channel_oil) {
|
2017-01-25 20:47:04 +01:00
|
|
|
uint32_t mask = PIM_OIF_FLAG_PROTO_PIM;
|
|
|
|
if (ch->upstream->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
|
2019-06-07 19:17:39 +02:00
|
|
|
mask |= PIM_OIF_FLAG_PROTO_IGMP;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-04-24 10:33:37 +02:00
|
|
|
/*
|
|
|
|
* A S,G RPT channel can have an empty oil, we also
|
|
|
|
* need to take into account the fact that a ifchannel
|
|
|
|
* might have been suppressing a *,G ifchannel from
|
|
|
|
* being inherited. So let's figure out what
|
|
|
|
* needs to be done here
|
|
|
|
*/
|
2019-06-07 19:17:39 +02:00
|
|
|
if ((ch->sg.src.s_addr != INADDR_ANY) &&
|
|
|
|
pim_upstream_evaluate_join_desired_interface(
|
|
|
|
ch->upstream, ch, ch->parent))
|
2019-04-24 10:33:37 +02:00
|
|
|
pim_channel_add_oif(ch->upstream->channel_oil,
|
2019-06-07 19:17:39 +02:00
|
|
|
ch->interface,
|
2019-11-15 17:47:33 +01:00
|
|
|
PIM_OIF_FLAG_PROTO_STAR,
|
|
|
|
__func__);
|
2019-06-07 19:17:39 +02:00
|
|
|
|
|
|
|
pim_channel_del_oif(ch->upstream->channel_oil,
|
2019-11-15 17:47:33 +01:00
|
|
|
ch->interface, mask, __func__);
|
2016-12-08 18:40:05 +01:00
|
|
|
/*
|
|
|
|
* Do we have any S,G's that are inheriting?
|
|
|
|
* Nuke from on high too.
|
|
|
|
*/
|
|
|
|
if (ch->upstream->sources) {
|
|
|
|
struct pim_upstream *child;
|
|
|
|
struct listnode *up_node;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-12-08 18:40:05 +01:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(ch->upstream->sources,
|
|
|
|
up_node, child))
|
2019-11-15 20:43:27 +01:00
|
|
|
pim_channel_del_inherited_oif(
|
|
|
|
child->channel_oil,
|
|
|
|
ch->interface,
|
|
|
|
__func__);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2016-07-28 18:21:31 +02:00
|
|
|
* When this channel is removed
|
|
|
|
* we need to find all our children
|
|
|
|
* and make sure our pointers are fixed
|
2017-07-17 14:03:14 +02:00
|
|
|
*/
|
2016-07-28 18:21:31 +02:00
|
|
|
pim_ifchannel_remove_children(ch);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-07 20:33:54 +01:00
|
|
|
if (ch->sources)
|
2018-10-02 11:39:51 +02:00
|
|
|
list_delete(&ch->sources);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-04-20 13:48:27 +02:00
|
|
|
listnode_delete(ch->upstream->ifchannels, ch);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
pimd: fix problem with oif being re-added during ifchannel del
Series of events leading to the problem -
1. (S,G) has been pruned on the rp on downlink-1
2. a (*,G) join is rxed on downlink-1 without the source S. This
results in the (S,G,rpt) prune state being cleared on downlink-1.
As a part of the clear the ifchannel associated with downlink-1
is deleted.
3. The ifchannel_delete handling is expected to add downlink-1
as an inherited OIF to the channel OIL (which it does). However
it is also added in as an immediate OIF (accidentally) as the
ifchannel is still present (in the process of being deleted).
To avoid the problem defer pim_upstream_update_join_desired
evaluation until after the channel is deleted.
Relevant debug logs -
PIM: pim_ifchannel_delete: ifchannel entry (27.0.0.15,239.1.1.106)(downlink-1) del start
PIM: pim_channel_add_oif(pim_ifchannel_delete): (S,G)=(27.0.0.15,239.1.1.106): proto_mask=4 OIF=downlink-1 vif_index=7: DONE
PIM: pimd/pim_oil.c pim_channel_del_oif: no existing protocol mask 2(4) for requested OIF downlink-1 (vif_index=7, min_ttl=1) for channel (S,G)=(27.0.0.15,239.1.1.106)
PIM: pim_upstream_switch: PIM_UPSTREAM_(27.0.0.15,239.1.1.106): (S,G) old: NotJoined new: Joined
PIM: pim_channel_add_oif(pim_upstream_inherited_olist_decide): (S,G)=(27.0.0.15,239.1.1.106): proto_mask=2 OIF=downlink-1 vif_index=7 added to 0x6 >>>>>>>>>>>>>>>>>>
PIM: pim_upstream_del(pim_ifchannel_delete): Delete (27.0.0.15,239.1.1.106)[default] ref count: 2 , flags: 81 c_oil ref count 1 (Pre decrement)
PIM: pim_ifchannel_delete: ifchannel entry (27.0.0.15,239.1.1.106)(downlink-1) del end
Ticket: CM-26732
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2019-10-15 01:02:36 +02:00
|
|
|
up = ch->upstream;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-07-28 18:21:31 +02:00
|
|
|
/* upstream is common across ifchannels, check if upstream's
|
2017-04-20 13:48:27 +02:00
|
|
|
ifchannel list is empty before deleting upstream_del
|
2015-02-04 07:01:14 +01:00
|
|
|
ref count will take care of it.
|
2017-07-17 14:03:14 +02:00
|
|
|
*/
|
2018-08-22 09:00:32 +02:00
|
|
|
if (ch->upstream->ref_count > 0)
|
pimd: fix problem with oif being re-added during ifchannel del
Series of events leading to the problem -
1. (S,G) has been pruned on the rp on downlink-1
2. a (*,G) join is rxed on downlink-1 without the source S. This
results in the (S,G,rpt) prune state being cleared on downlink-1.
As a part of the clear the ifchannel associated with downlink-1
is deleted.
3. The ifchannel_delete handling is expected to add downlink-1
as an inherited OIF to the channel OIL (which it does). However
it is also added in as an immediate OIF (accidentally) as the
ifchannel is still present (in the process of being deleted).
To avoid the problem defer pim_upstream_update_join_desired
evaluation until after the channel is deleted.
Relevant debug logs -
PIM: pim_ifchannel_delete: ifchannel entry (27.0.0.15,239.1.1.106)(downlink-1) del start
PIM: pim_channel_add_oif(pim_ifchannel_delete): (S,G)=(27.0.0.15,239.1.1.106): proto_mask=4 OIF=downlink-1 vif_index=7: DONE
PIM: pimd/pim_oil.c pim_channel_del_oif: no existing protocol mask 2(4) for requested OIF downlink-1 (vif_index=7, min_ttl=1) for channel (S,G)=(27.0.0.15,239.1.1.106)
PIM: pim_upstream_switch: PIM_UPSTREAM_(27.0.0.15,239.1.1.106): (S,G) old: NotJoined new: Joined
PIM: pim_channel_add_oif(pim_upstream_inherited_olist_decide): (S,G)=(27.0.0.15,239.1.1.106): proto_mask=2 OIF=downlink-1 vif_index=7 added to 0x6 >>>>>>>>>>>>>>>>>>
PIM: pim_upstream_del(pim_ifchannel_delete): Delete (27.0.0.15,239.1.1.106)[default] ref count: 2 , flags: 81 c_oil ref count 1 (Pre decrement)
PIM: pim_ifchannel_delete: ifchannel entry (27.0.0.15,239.1.1.106)(downlink-1) del end
Ticket: CM-26732
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2019-10-15 01:02:36 +02:00
|
|
|
up = pim_upstream_del(pim_ifp->pim, ch->upstream, __func__);
|
2018-08-22 09:00:32 +02:00
|
|
|
|
2019-11-01 15:10:10 +01:00
|
|
|
else {
|
|
|
|
if (PIM_DEBUG_PIM_TRACE)
|
2020-03-06 15:23:22 +01:00
|
|
|
zlog_debug(
|
2020-03-27 12:35:23 +01:00
|
|
|
"%s: Avoiding deletion of upstream with ref_count %d from ifchannel(%s): %s",
|
2020-03-06 15:23:22 +01:00
|
|
|
__func__, ch->upstream->ref_count,
|
|
|
|
ch->interface->name, ch->sg_str);
|
2019-11-01 15:10:10 +01:00
|
|
|
}
|
2018-08-22 09:00:32 +02:00
|
|
|
|
2017-05-09 20:30:43 +02:00
|
|
|
ch->upstream = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-09 20:30:43 +02:00
|
|
|
THREAD_OFF(ch->t_ifjoin_expiry_timer);
|
2016-10-27 14:05:57 +02:00
|
|
|
THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
|
2015-02-04 07:01:14 +01:00
|
|
|
THREAD_OFF(ch->t_ifassert_timer);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-07 20:33:54 +01:00
|
|
|
if (ch->parent) {
|
|
|
|
listnode_delete(ch->parent->sources, ch);
|
|
|
|
ch->parent = NULL;
|
|
|
|
}
|
2017-07-31 18:44:20 +02:00
|
|
|
|
|
|
|
RB_REMOVE(pim_ifchannel_rb, &pim_ifp->ifchannel_rb, ch);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-09 20:30:43 +02:00
|
|
|
if (PIM_DEBUG_PIM_TRACE)
|
2019-06-11 14:34:23 +02:00
|
|
|
zlog_debug("%s: ifchannel entry %s(%s) is deleted ", __func__,
|
|
|
|
ch->sg_str, ch->interface->name);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-05-11 20:07:53 +02:00
|
|
|
XFREE(MTYPE_PIM_IFCHANNEL, ch);
|
pimd: fix problem with oif being re-added during ifchannel del
Series of events leading to the problem -
1. (S,G) has been pruned on the rp on downlink-1
2. a (*,G) join is rxed on downlink-1 without the source S. This
results in the (S,G,rpt) prune state being cleared on downlink-1.
As a part of the clear the ifchannel associated with downlink-1
is deleted.
3. The ifchannel_delete handling is expected to add downlink-1
as an inherited OIF to the channel OIL (which it does). However
it is also added in as an immediate OIF (accidentally) as the
ifchannel is still present (in the process of being deleted).
To avoid the problem defer pim_upstream_update_join_desired
evaluation until after the channel is deleted.
Relevant debug logs -
PIM: pim_ifchannel_delete: ifchannel entry (27.0.0.15,239.1.1.106)(downlink-1) del start
PIM: pim_channel_add_oif(pim_ifchannel_delete): (S,G)=(27.0.0.15,239.1.1.106): proto_mask=4 OIF=downlink-1 vif_index=7: DONE
PIM: pimd/pim_oil.c pim_channel_del_oif: no existing protocol mask 2(4) for requested OIF downlink-1 (vif_index=7, min_ttl=1) for channel (S,G)=(27.0.0.15,239.1.1.106)
PIM: pim_upstream_switch: PIM_UPSTREAM_(27.0.0.15,239.1.1.106): (S,G) old: NotJoined new: Joined
PIM: pim_channel_add_oif(pim_upstream_inherited_olist_decide): (S,G)=(27.0.0.15,239.1.1.106): proto_mask=2 OIF=downlink-1 vif_index=7 added to 0x6 >>>>>>>>>>>>>>>>>>
PIM: pim_upstream_del(pim_ifchannel_delete): Delete (27.0.0.15,239.1.1.106)[default] ref count: 2 , flags: 81 c_oil ref count 1 (Pre decrement)
PIM: pim_ifchannel_delete: ifchannel entry (27.0.0.15,239.1.1.106)(downlink-1) del end
Ticket: CM-26732
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2019-10-15 01:02:36 +02:00
|
|
|
|
|
|
|
if (up)
|
|
|
|
pim_upstream_update_join_desired(pim_ifp->pim, up);
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
2016-10-28 02:35:22 +02:00
|
|
|
|
|
|
|
void pim_ifchannel_delete_all(struct interface *ifp)
|
|
|
|
{
|
|
|
|
struct pim_interface *pim_ifp;
|
2017-07-31 18:44:20 +02:00
|
|
|
struct pim_ifchannel *ch;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-10-28 02:35:22 +02:00
|
|
|
pim_ifp = ifp->info;
|
2016-12-08 18:40:05 +01:00
|
|
|
if (!pim_ifp)
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-02-18 01:02:55 +01:00
|
|
|
while (!RB_EMPTY(pim_ifchannel_rb, &pim_ifp->ifchannel_rb)) {
|
|
|
|
ch = RB_ROOT(pim_ifchannel_rb, &pim_ifp->ifchannel_rb);
|
|
|
|
|
2020-03-05 19:17:54 +01:00
|
|
|
pim_ifchannel_ifjoin_switch(__func__, ch, PIM_IFJOIN_NOINFO);
|
2017-07-31 18:44:20 +02:00
|
|
|
pim_ifchannel_delete(ch);
|
2016-10-28 02:35:22 +02:00
|
|
|
}
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-10-28 15:32:00 +01:00
|
|
|
void delete_on_noinfo(struct pim_ifchannel *ch)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
2016-10-14 17:22:12 +02:00
|
|
|
if (ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO
|
2016-11-08 01:43:13 +01:00
|
|
|
&& ch->ifjoin_state == PIM_IFJOIN_NOINFO
|
|
|
|
&& ch->t_ifjoin_expiry_timer == NULL)
|
2015-02-04 07:01:14 +01:00
|
|
|
pim_ifchannel_delete(ch);
|
|
|
|
}
|
|
|
|
|
|
|
|
void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch,
|
|
|
|
enum pim_ifjoin_state new_state)
|
|
|
|
{
|
|
|
|
enum pim_ifjoin_state old_state = ch->ifjoin_state;
|
2017-05-20 01:36:53 +02:00
|
|
|
struct pim_interface *pim_ifp = ch->interface->info;
|
2019-11-15 20:21:11 +01:00
|
|
|
struct pim_ifchannel *child_ch;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-09-30 16:22:46 +02:00
|
|
|
if (PIM_DEBUG_PIM_EVENTS)
|
|
|
|
zlog_debug(
|
|
|
|
"PIM_IFCHANNEL(%s): %s is switching from %s to %s",
|
|
|
|
ch->interface->name, ch->sg_str,
|
2017-03-17 18:46:47 +01:00
|
|
|
pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags),
|
2016-12-05 22:26:59 +01:00
|
|
|
pim_ifchannel_ifjoin_name(new_state, 0));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
|
2016-12-05 22:26:59 +01:00
|
|
|
if (old_state == new_state) {
|
|
|
|
if (PIM_DEBUG_PIM_EVENTS) {
|
|
|
|
zlog_debug(
|
|
|
|
"%s calledby %s: non-transition on state %d (%s)",
|
2020-03-06 15:23:22 +01:00
|
|
|
__func__, caller, new_state,
|
2017-01-19 18:09:26 +01:00
|
|
|
pim_ifchannel_ifjoin_name(new_state, 0));
|
2016-12-05 22:26:59 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2016-12-05 22:26:59 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-12-05 22:26:59 +01:00
|
|
|
ch->ifjoin_state = new_state;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-12-05 22:26:59 +01:00
|
|
|
if (ch->sg.src.s_addr == INADDR_ANY) {
|
|
|
|
struct pim_upstream *up = ch->upstream;
|
|
|
|
struct pim_upstream *child;
|
|
|
|
struct listnode *up_node;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
if (up) {
|
2016-12-05 22:26:59 +01:00
|
|
|
if (ch->ifjoin_state == PIM_IFJOIN_NOINFO) {
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(up->sources, up_node,
|
|
|
|
child)) {
|
|
|
|
struct channel_oil *c_oil =
|
|
|
|
child->channel_oil;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-12-05 22:26:59 +01:00
|
|
|
if (PIM_DEBUG_PIM_TRACE)
|
|
|
|
zlog_debug(
|
|
|
|
"%s %s: Prune(S,G)=%s from %s",
|
2020-03-06 15:23:22 +01:00
|
|
|
__FILE__, __func__,
|
2016-12-05 22:26:59 +01:00
|
|
|
child->sg_str,
|
|
|
|
up->sg_str);
|
|
|
|
if (!c_oil)
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
/*
|
2016-12-05 22:26:59 +01:00
|
|
|
* If the S,G has no if channel and the
|
|
|
|
* c_oil still
|
|
|
|
* has output here then the *,G was
|
|
|
|
* supplying the implied
|
|
|
|
* if channel. So remove it.
|
2017-07-17 14:03:14 +02:00
|
|
|
*/
|
2017-05-11 02:06:17 +02:00
|
|
|
if (c_oil->oil.mfcc_ttls
|
|
|
|
[pim_ifp->mroute_vif_index])
|
2019-11-15 20:43:27 +01:00
|
|
|
pim_channel_del_inherited_oif(
|
pimd: Fix WG/SGRpt & WG J/P processing
During processing of Join/Prune,
for a S,G entry, current state is SGRpt, when only *,G is
received, need to clear SGRpt and add/inherit the *,G OIF to S,G so
it can forward traffic to downstream where *,G is received.
Upon receiving SGRpt prune remove the inherited *,G OIF.
Testing Done:
Trigger SPT switchover, *,G path received SGRpt later data
traffic stopped S,G ages out from LHR, sends only
*,G join to upstream, verified S,G entry inherit the OIF.
Upon receiving SGRpt deletes inherited oif and retains in SGRpt state.
Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2017-04-22 00:08:03 +02:00
|
|
|
c_oil, ch->interface,
|
2019-11-15 17:47:33 +01:00
|
|
|
__func__);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
2016-08-24 16:25:11 +02:00
|
|
|
if (ch->ifjoin_state == PIM_IFJOIN_JOIN) {
|
2016-12-05 22:26:59 +01:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(up->sources, up_node,
|
2017-07-17 14:03:14 +02:00
|
|
|
child)) {
|
2017-05-09 20:30:43 +02:00
|
|
|
if (PIM_DEBUG_PIM_TRACE)
|
2016-07-23 05:28:13 +02:00
|
|
|
zlog_debug(
|
2016-12-05 22:26:59 +01:00
|
|
|
"%s %s: Join(S,G)=%s from %s",
|
2020-03-06 15:23:22 +01:00
|
|
|
__FILE__, __func__,
|
2016-12-05 22:26:59 +01:00
|
|
|
child->sg_str,
|
|
|
|
up->sg_str);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-11-15 20:21:11 +01:00
|
|
|
/* check if the channel can be
|
|
|
|
* inherited into the SG's OIL
|
|
|
|
*/
|
|
|
|
child_ch = pim_ifchannel_find(
|
|
|
|
ch->interface,
|
|
|
|
&child->sg);
|
|
|
|
if (pim_upstream_eval_inherit_if(
|
|
|
|
child, child_ch, ch)) {
|
2017-01-19 18:09:26 +01:00
|
|
|
pim_channel_add_oif(
|
|
|
|
child->channel_oil,
|
|
|
|
ch->interface,
|
2019-11-15 17:47:33 +01:00
|
|
|
PIM_OIF_FLAG_PROTO_STAR,
|
|
|
|
__func__);
|
2017-01-24 22:11:40 +01:00
|
|
|
pim_upstream_update_join_desired(
|
2017-05-20 01:36:53 +02:00
|
|
|
pim_ifp->pim, child);
|
2016-12-05 22:26:59 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
2016-12-05 22:26:59 +01:00
|
|
|
}
|
|
|
|
}
|
2015-02-04 07:01:14 +01:00
|
|
|
/* Transition to/from NOINFO ? */
|
2016-10-14 17:22:12 +02:00
|
|
|
if ((old_state == PIM_IFJOIN_NOINFO)
|
|
|
|
|| (new_state == PIM_IFJOIN_NOINFO)) {
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
if (PIM_DEBUG_PIM_EVENTS) {
|
2016-07-23 05:28:13 +02:00
|
|
|
zlog_debug("PIM_IFCHANNEL_%s: (S,G)=%s on interface %s",
|
2015-02-04 07:01:14 +01:00
|
|
|
((new_state == PIM_IFJOIN_NOINFO) ? "DOWN"
|
|
|
|
: "UP"),
|
2016-11-17 14:17:25 +01:00
|
|
|
ch->sg_str, ch->interface->name);
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
/*
|
|
|
|
Record uptime of state transition to/from NOINFO
|
|
|
|
*/
|
|
|
|
ch->ifjoin_creation = pim_time_monotonic_sec();
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-20 01:36:53 +02:00
|
|
|
pim_upstream_update_join_desired(pim_ifp->pim, ch->upstream);
|
2015-02-04 07:01:14 +01:00
|
|
|
pim_ifchannel_update_could_assert(ch);
|
|
|
|
pim_ifchannel_update_assert_tracking_desired(ch);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-17 18:46:47 +01:00
|
|
|
const char *pim_ifchannel_ifjoin_name(enum pim_ifjoin_state ifjoin_state,
|
|
|
|
int flags)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
|
|
|
switch (ifjoin_state) {
|
2017-03-17 18:46:47 +01:00
|
|
|
case PIM_IFJOIN_NOINFO:
|
|
|
|
if (PIM_IF_FLAG_TEST_S_G_RPT(flags))
|
2017-08-24 15:55:19 +02:00
|
|
|
return "SGRpt(NI)";
|
2017-03-17 18:46:47 +01:00
|
|
|
else
|
|
|
|
return "NOINFO";
|
|
|
|
case PIM_IFJOIN_JOIN:
|
|
|
|
return "JOIN";
|
|
|
|
case PIM_IFJOIN_PRUNE:
|
2017-08-24 15:55:19 +02:00
|
|
|
if (PIM_IF_FLAG_TEST_S_G_RPT(flags))
|
|
|
|
return "SGRpt(P)";
|
|
|
|
else
|
|
|
|
return "PRUNE";
|
2017-03-17 18:46:47 +01:00
|
|
|
case PIM_IFJOIN_PRUNE_PENDING:
|
2017-08-24 15:55:19 +02:00
|
|
|
if (PIM_IF_FLAG_TEST_S_G_RPT(flags))
|
|
|
|
return "SGRpt(PP)";
|
|
|
|
else
|
|
|
|
return "PRUNEP";
|
2017-03-17 18:46:47 +01:00
|
|
|
case PIM_IFJOIN_PRUNE_TMP:
|
2017-08-24 15:55:19 +02:00
|
|
|
if (PIM_IF_FLAG_TEST_S_G_RPT(flags))
|
|
|
|
return "SGRpt(P')";
|
|
|
|
else
|
|
|
|
return "PRUNET";
|
2017-03-17 18:46:47 +01:00
|
|
|
case PIM_IFJOIN_PRUNE_PENDING_TMP:
|
2017-08-24 15:55:19 +02:00
|
|
|
if (PIM_IF_FLAG_TEST_S_G_RPT(flags))
|
|
|
|
return "SGRpt(PP')";
|
|
|
|
else
|
|
|
|
return "PRUNEPT";
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
return "ifjoin_bad_state";
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *pim_ifchannel_ifassert_name(enum pim_ifassert_state ifassert_state)
|
|
|
|
{
|
|
|
|
switch (ifassert_state) {
|
|
|
|
case PIM_IFASSERT_NOINFO:
|
|
|
|
return "NOINFO";
|
|
|
|
case PIM_IFASSERT_I_AM_WINNER:
|
|
|
|
return "WINNER";
|
|
|
|
case PIM_IFASSERT_I_AM_LOSER:
|
|
|
|
return "LOSER";
|
|
|
|
}
|
|
|
|
|
|
|
|
return "ifassert_bad_state";
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
RFC 4601: 4.6.5. Assert State Macros
|
|
|
|
|
|
|
|
AssertWinner(S,G,I) defaults to NULL and AssertWinnerMetric(S,G,I)
|
|
|
|
defaults to Infinity when in the NoInfo state.
|
|
|
|
*/
|
|
|
|
void reset_ifassert_state(struct pim_ifchannel *ch)
|
|
|
|
{
|
2017-05-04 16:44:51 +02:00
|
|
|
struct in_addr any = {.s_addr = INADDR_ANY};
|
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
THREAD_OFF(ch->t_ifassert_timer);
|
|
|
|
|
|
|
|
pim_ifassert_winner_set(ch, PIM_IFASSERT_NOINFO, any,
|
2018-12-20 17:18:14 +01:00
|
|
|
router->infinite_assert_metric);
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp,
|
2016-08-02 10:38:11 +02:00
|
|
|
struct prefix_sg *sg)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
|
|
|
struct pim_interface *pim_ifp;
|
|
|
|
struct pim_ifchannel *ch;
|
2017-02-13 02:16:08 +01:00
|
|
|
struct pim_ifchannel lookup;
|
2015-02-04 07:01:14 +01:00
|
|
|
|
|
|
|
pim_ifp = ifp->info;
|
|
|
|
|
|
|
|
if (!pim_ifp) {
|
2016-07-23 05:12:06 +02:00
|
|
|
zlog_warn("%s: (S,G)=%s: multicast not enabled on interface %s",
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__, pim_str_sg_dump(sg), ifp->name);
|
2017-02-13 02:16:08 +01:00
|
|
|
return NULL;
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
|
2017-02-13 02:16:08 +01:00
|
|
|
lookup.sg = *sg;
|
2017-07-31 18:44:20 +02:00
|
|
|
lookup.interface = ifp;
|
|
|
|
ch = RB_FIND(pim_ifchannel_rb, &pim_ifp->ifchannel_rb, &lookup);
|
2015-02-04 07:01:14 +01:00
|
|
|
|
2017-02-13 02:16:08 +01:00
|
|
|
return ch;
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ifmembership_set(struct pim_ifchannel *ch,
|
|
|
|
enum pim_ifmembership membership)
|
|
|
|
{
|
2017-05-20 01:36:53 +02:00
|
|
|
struct pim_interface *pim_ifp = ch->interface->info;
|
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
if (ch->local_ifmembership == membership)
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-09-30 16:22:46 +02:00
|
|
|
if (PIM_DEBUG_PIM_EVENTS) {
|
2016-07-23 05:28:13 +02:00
|
|
|
zlog_debug("%s: (S,G)=%s membership now is %s on interface %s",
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__, ch->sg_str,
|
2015-02-04 07:01:14 +01:00
|
|
|
membership == PIM_IFMEMBERSHIP_INCLUDE ? "INCLUDE"
|
|
|
|
: "NOINFO",
|
|
|
|
ch->interface->name);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
ch->local_ifmembership = membership;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-20 01:36:53 +02:00
|
|
|
pim_upstream_update_join_desired(pim_ifp->pim, ch->upstream);
|
2015-02-04 07:01:14 +01:00
|
|
|
pim_ifchannel_update_could_assert(ch);
|
|
|
|
pim_ifchannel_update_assert_tracking_desired(ch);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void pim_ifchannel_membership_clear(struct interface *ifp)
|
|
|
|
{
|
|
|
|
struct pim_interface *pim_ifp;
|
|
|
|
struct pim_ifchannel *ch;
|
|
|
|
|
|
|
|
pim_ifp = ifp->info;
|
|
|
|
zassert(pim_ifp);
|
|
|
|
|
2017-09-15 17:47:35 +02:00
|
|
|
RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb)
|
2015-02-04 07:01:14 +01:00
|
|
|
ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO);
|
|
|
|
}
|
|
|
|
|
|
|
|
void pim_ifchannel_delete_on_noinfo(struct interface *ifp)
|
|
|
|
{
|
|
|
|
struct pim_interface *pim_ifp;
|
2017-07-31 18:44:20 +02:00
|
|
|
struct pim_ifchannel *ch, *ch_tmp;
|
2015-02-04 07:01:14 +01:00
|
|
|
|
|
|
|
pim_ifp = ifp->info;
|
|
|
|
zassert(pim_ifp);
|
|
|
|
|
2017-09-15 17:47:35 +02:00
|
|
|
RB_FOREACH_SAFE (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb, ch_tmp)
|
2015-02-04 07:01:14 +01:00
|
|
|
delete_on_noinfo(ch);
|
|
|
|
}
|
|
|
|
|
2016-07-28 18:21:31 +02:00
|
|
|
/*
|
|
|
|
* For a given Interface, if we are given a S,G
|
|
|
|
* Find the *,G (If we have it).
|
|
|
|
* If we are passed a *,G, find the *,* ifchannel
|
|
|
|
* if we have it.
|
|
|
|
*/
|
2016-11-07 20:33:54 +01:00
|
|
|
static struct pim_ifchannel *pim_ifchannel_find_parent(struct pim_ifchannel *ch)
|
2016-07-28 18:21:31 +02:00
|
|
|
{
|
2016-11-07 20:33:54 +01:00
|
|
|
struct prefix_sg parent_sg = ch->sg;
|
|
|
|
struct pim_ifchannel *parent = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-07-28 18:21:31 +02:00
|
|
|
// (S,G)
|
2016-11-07 20:33:54 +01:00
|
|
|
if ((parent_sg.src.s_addr != INADDR_ANY)
|
|
|
|
&& (parent_sg.grp.s_addr != INADDR_ANY)) {
|
2016-08-02 10:38:11 +02:00
|
|
|
parent_sg.src.s_addr = INADDR_ANY;
|
2016-11-07 20:33:54 +01:00
|
|
|
parent = pim_ifchannel_find(ch->interface, &parent_sg);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-07 20:33:54 +01:00
|
|
|
if (parent)
|
|
|
|
listnode_add(parent->sources, ch);
|
|
|
|
return parent;
|
2016-07-28 18:21:31 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-07 20:33:54 +01:00
|
|
|
return NULL;
|
2016-07-28 18:21:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp,
|
2017-06-22 17:05:03 +02:00
|
|
|
struct prefix_sg *sg,
|
|
|
|
uint8_t source_flags, int up_flags)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
2016-07-15 17:03:15 +02:00
|
|
|
struct pim_interface *pim_ifp;
|
2015-02-04 07:01:14 +01:00
|
|
|
struct pim_ifchannel *ch;
|
2016-07-15 17:03:15 +02:00
|
|
|
struct pim_upstream *up;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-07-23 05:12:06 +02:00
|
|
|
ch = pim_ifchannel_find(ifp, sg);
|
2020-12-17 11:37:25 +01:00
|
|
|
if (ch) {
|
|
|
|
if (up_flags == PIM_UPSTREAM_FLAG_MASK_SRC_PIM)
|
|
|
|
PIM_IF_FLAG_SET_PROTO_PIM(ch->flags);
|
|
|
|
|
|
|
|
if (up_flags == PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
|
|
|
|
PIM_IF_FLAG_SET_PROTO_IGMP(ch->flags);
|
|
|
|
|
|
|
|
if (ch->upstream)
|
|
|
|
ch->upstream->flags |= up_flags;
|
|
|
|
else if (PIM_DEBUG_EVENTS)
|
|
|
|
zlog_debug("%s:%s No Upstream found", __func__,
|
|
|
|
pim_str_sg_dump(sg));
|
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
return ch;
|
2020-12-17 11:37:25 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-07-15 17:03:15 +02:00
|
|
|
pim_ifp = ifp->info;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-12-12 01:28:08 +01:00
|
|
|
ch = XCALLOC(MTYPE_PIM_IFCHANNEL, sizeof(*ch));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-07-15 17:03:15 +02:00
|
|
|
ch->flags = 0;
|
2017-06-22 17:05:03 +02:00
|
|
|
if ((source_flags & PIM_ENCODE_RPT_BIT)
|
|
|
|
&& !(source_flags & PIM_ENCODE_WC_BIT))
|
|
|
|
PIM_IF_FLAG_SET_S_G_RPT(ch->flags);
|
|
|
|
|
2016-07-15 17:03:15 +02:00
|
|
|
ch->interface = ifp;
|
2016-07-23 05:12:06 +02:00
|
|
|
ch->sg = *sg;
|
2016-11-17 14:17:25 +01:00
|
|
|
pim_str_sg_set(sg, ch->sg_str);
|
2016-11-07 20:33:54 +01:00
|
|
|
ch->parent = pim_ifchannel_find_parent(ch);
|
|
|
|
if (ch->sg.src.s_addr == INADDR_ANY) {
|
|
|
|
ch->sources = list_new();
|
|
|
|
ch->sources->cmp =
|
|
|
|
(int (*)(void *, void *))pim_ifchannel_compare;
|
|
|
|
} else
|
|
|
|
ch->sources = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-07-28 18:21:31 +02:00
|
|
|
pim_ifchannel_find_new_children(ch);
|
2016-07-15 17:03:15 +02:00
|
|
|
ch->local_ifmembership = PIM_IFMEMBERSHIP_NOINFO;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-07-15 17:03:15 +02:00
|
|
|
ch->ifjoin_state = PIM_IFJOIN_NOINFO;
|
|
|
|
ch->t_ifjoin_expiry_timer = NULL;
|
|
|
|
ch->t_ifjoin_prune_pending_timer = NULL;
|
|
|
|
ch->ifjoin_creation = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-31 18:44:20 +02:00
|
|
|
RB_INSERT(pim_ifchannel_rb, &pim_ifp->ifchannel_rb, ch);
|
2017-06-22 17:05:03 +02:00
|
|
|
|
2020-03-05 19:17:54 +01:00
|
|
|
up = pim_upstream_add(pim_ifp->pim, sg, NULL, up_flags, __func__, ch);
|
2017-06-22 17:05:03 +02:00
|
|
|
|
2017-06-26 19:14:47 +02:00
|
|
|
ch->upstream = up;
|
2017-06-22 17:05:03 +02:00
|
|
|
|
|
|
|
listnode_add_sort(up->ifchannels, ch);
|
|
|
|
|
2016-07-15 17:03:15 +02:00
|
|
|
ch->ifassert_my_metric = pim_macro_ch_my_assert_metric_eval(ch);
|
|
|
|
ch->ifassert_winner_metric = pim_macro_ch_my_assert_metric_eval(ch);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-02-06 07:49:02 +01:00
|
|
|
ch->ifassert_winner.s_addr = INADDR_ANY;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-07-15 17:03:15 +02:00
|
|
|
/* Assert state */
|
|
|
|
ch->t_ifassert_timer = NULL;
|
2016-12-12 01:28:08 +01:00
|
|
|
ch->ifassert_state = PIM_IFASSERT_NOINFO;
|
2016-07-15 17:03:15 +02:00
|
|
|
reset_ifassert_state(ch);
|
|
|
|
if (pim_macro_ch_could_assert_eval(ch))
|
|
|
|
PIM_IF_FLAG_SET_COULD_ASSERT(ch->flags);
|
|
|
|
else
|
|
|
|
PIM_IF_FLAG_UNSET_COULD_ASSERT(ch->flags);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-07-15 17:03:15 +02:00
|
|
|
if (pim_macro_assert_tracking_desired_eval(ch))
|
|
|
|
PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch->flags);
|
|
|
|
else
|
|
|
|
PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-08-19 11:06:00 +02:00
|
|
|
/*
|
|
|
|
* advertise MLAG Data to MLAG peer
|
|
|
|
*/
|
|
|
|
if (PIM_I_am_DualActive(pim_ifp)) {
|
|
|
|
up->dualactive_ifchannel_count++;
|
|
|
|
/* Sync once for upstream */
|
|
|
|
if (up->dualactive_ifchannel_count == 1) {
|
|
|
|
PIM_UPSTREAM_FLAG_SET_MLAG_INTERFACE(up->flags);
|
|
|
|
pim_mlag_up_local_add(pim_ifp->pim, up);
|
|
|
|
}
|
|
|
|
if (PIM_DEBUG_MLAG)
|
|
|
|
zlog_debug(
|
2020-03-27 12:35:23 +01:00
|
|
|
"%s: New Dual active if-chnanel is added to upstream:%s count:%d, flags:0x%x",
|
2019-08-19 11:06:00 +02:00
|
|
|
__func__, up->sg_str,
|
|
|
|
up->dualactive_ifchannel_count, up->flags);
|
|
|
|
}
|
|
|
|
|
pimd: fix OIL not removed after IGMP prune
Issue: Client1------LHR-----(int-1)RP(int-2)------client2
Client2 send IGMP join for group G.
Client1 send IGMP join for group G.
verify show ip mroute in RP, will have 2 OIL.
Client2 send IGMP leave.
Verify show ip mroute in RP, will still have 2.
Root cause: When RP receives IGMP join from client2, it creates
a (s,g) channel oil and add the interface int-2 into oil list and
set the flag PIM_OIF_FLAG_PROTO_IGMP to int-2
Client1 send IGMP join, LHR will send a (*,G) join to RP. RP will
add the interface int-1 into the oil list of (s,g) channel_oil and
will set the flag PIM_OIF_FLAG_PROTO_IGMP and PIM_OIF_FLAG_PROTO_PIM
to the int-1 and set PIM_OIF_FLAG_PROTO_PIM to int-2 as well. It is
happening because of the pim_upstream_inherited_olist_decide() and
forward_on() get all the oil and update the flag wrongly.
So now when client 2 sends IGMP prune, RP will not remove the int-2
from oil list since both PIM_OIF_FLAG_PROTO_PIM & PIM_OIF_FLAG_PROTO_IGMP
are set, it just unset the flag PIM_OIF_FLAG_PROTO_IGMP.
Fix: Introduced new flags in if_channel, PIM_IF_FLAG_MASK_PROTO_PIM
& PIM_IF_FLAG_MASK_PROTO_IGMP. If a if_channel is created because of
pim join or pim (s,g,rpt) prune received, then set the flag
PIM_IF_FLAG_MASK_PROTO_PIM. If a if_channel is created becuase of IGMP
join received, then set the flag PIM_IF_FLAG_MASK_PROTO_IGMP.
When an interface needs to be added into the oil list check if
PIM_IF_FLAG_MASK_PROTO_PIM or PIM_IF_FLAG_MASK_PROTO_IGMP is set, then
update oil flag accordingly.
Signed-off-by: Sarita Patra <saritap@vmware.com>
2020-03-02 09:55:22 +01:00
|
|
|
if (up_flags == PIM_UPSTREAM_FLAG_MASK_SRC_PIM)
|
|
|
|
PIM_IF_FLAG_SET_PROTO_PIM(ch->flags);
|
|
|
|
|
|
|
|
if (up_flags == PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
|
|
|
|
PIM_IF_FLAG_SET_PROTO_IGMP(ch->flags);
|
|
|
|
|
2017-05-09 20:30:43 +02:00
|
|
|
if (PIM_DEBUG_PIM_TRACE)
|
2019-10-14 21:41:33 +02:00
|
|
|
zlog_debug("%s: ifchannel %s(%s) is created ", __func__,
|
|
|
|
ch->sg_str, ch->interface->name);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-07-15 17:03:15 +02:00
|
|
|
return ch;
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
|
2017-05-17 06:57:25 +02:00
|
|
|
static void ifjoin_to_noinfo(struct pim_ifchannel *ch, bool ch_del)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
2017-07-10 15:45:04 +02:00
|
|
|
pim_forward_stop(ch, !ch_del);
|
2020-03-05 19:17:54 +01:00
|
|
|
pim_ifchannel_ifjoin_switch(__func__, ch, PIM_IFJOIN_NOINFO);
|
2020-12-17 11:37:25 +01:00
|
|
|
|
|
|
|
if (ch->upstream)
|
|
|
|
PIM_UPSTREAM_FLAG_UNSET_SRC_PIM(ch->upstream->flags);
|
|
|
|
|
|
|
|
PIM_IF_FLAG_UNSET_PROTO_PIM(ch->flags);
|
|
|
|
|
2017-05-09 20:30:43 +02:00
|
|
|
if (ch_del)
|
|
|
|
delete_on_noinfo(ch);
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int on_ifjoin_expiry_timer(struct thread *t)
|
|
|
|
{
|
|
|
|
struct pim_ifchannel *ch;
|
|
|
|
|
|
|
|
ch = THREAD_ARG(t);
|
|
|
|
|
2019-11-12 14:02:06 +01:00
|
|
|
if (PIM_DEBUG_PIM_TRACE)
|
2020-03-05 19:17:54 +01:00
|
|
|
zlog_debug("%s: ifchannel %s expiry timer", __func__,
|
2019-06-11 01:47:07 +02:00
|
|
|
ch->sg_str);
|
|
|
|
|
2017-05-17 06:57:25 +02:00
|
|
|
ifjoin_to_noinfo(ch, true);
|
2015-02-04 07:01:14 +01:00
|
|
|
/* ch may have been deleted */
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int on_ifjoin_prune_pending_timer(struct thread *t)
|
|
|
|
{
|
|
|
|
struct pim_ifchannel *ch;
|
|
|
|
int send_prune_echo; /* boolean */
|
|
|
|
struct interface *ifp;
|
|
|
|
struct pim_interface *pim_ifp;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
ch = THREAD_ARG(t);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-11-12 14:02:06 +01:00
|
|
|
if (PIM_DEBUG_PIM_TRACE)
|
2017-12-13 02:29:38 +01:00
|
|
|
zlog_debug(
|
|
|
|
"%s: IFCHANNEL%s %s Prune Pending Timer Popped",
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__, pim_str_sg_dump(&ch->sg),
|
2017-12-13 02:29:38 +01:00
|
|
|
pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags));
|
|
|
|
|
2016-12-02 02:32:03 +01:00
|
|
|
if (ch->ifjoin_state == PIM_IFJOIN_PRUNE_PENDING) {
|
|
|
|
ifp = ch->interface;
|
|
|
|
pim_ifp = ifp->info;
|
2017-08-24 15:55:19 +02:00
|
|
|
if (!PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)) {
|
|
|
|
/* Send PruneEcho(S,G) ? */
|
|
|
|
send_prune_echo =
|
|
|
|
(listcount(pim_ifp->pim_neighbor_list) > 1);
|
|
|
|
|
|
|
|
if (send_prune_echo) {
|
|
|
|
struct pim_rpf rpf;
|
|
|
|
|
|
|
|
rpf.source_nexthop.interface = ifp;
|
|
|
|
rpf.rpf_addr.u.prefix4 =
|
|
|
|
pim_ifp->primary_address;
|
|
|
|
pim_jp_agg_single_upstream_send(
|
|
|
|
&rpf, ch->upstream, 0);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-08-24 15:55:19 +02:00
|
|
|
ifjoin_to_noinfo(ch, true);
|
|
|
|
} else {
|
|
|
|
/* If SGRpt flag is set on ifchannel, Trigger SGRpt
|
|
|
|
* message on RP path upon prune timer expiry.
|
|
|
|
*/
|
|
|
|
ch->ifjoin_state = PIM_IFJOIN_PRUNE;
|
2017-12-13 02:29:38 +01:00
|
|
|
if (ch->upstream) {
|
|
|
|
struct pim_upstream *parent =
|
|
|
|
ch->upstream->parent;
|
|
|
|
|
2017-05-20 01:36:53 +02:00
|
|
|
pim_upstream_update_join_desired(pim_ifp->pim,
|
|
|
|
ch->upstream);
|
2017-12-13 02:29:38 +01:00
|
|
|
|
|
|
|
pim_jp_agg_single_upstream_send(&parent->rpf,
|
|
|
|
parent, true);
|
2020-03-19 11:33:41 +01:00
|
|
|
/*
|
|
|
|
* SGRpt prune pending expiry has to install
|
|
|
|
* SG entry with empty olist to drop the SG
|
|
|
|
* traffic incase no other intf exists.
|
|
|
|
* On that scenario, SG entry wouldn't have
|
|
|
|
* got installed until Prune pending timer
|
|
|
|
* expired. So install now.
|
|
|
|
*/
|
|
|
|
pim_channel_del_oif(
|
|
|
|
ch->upstream->channel_oil, ifp,
|
|
|
|
PIM_OIF_FLAG_PROTO_STAR, __func__);
|
|
|
|
if (!ch->upstream->channel_oil->installed)
|
|
|
|
pim_upstream_mroute_add(
|
|
|
|
ch->upstream->channel_oil,
|
|
|
|
__PRETTY_FUNCTION__);
|
2017-12-13 02:29:38 +01:00
|
|
|
}
|
2017-08-24 15:55:19 +02:00
|
|
|
}
|
2017-05-09 20:30:43 +02:00
|
|
|
/* from here ch may have been deleted */
|
2016-12-02 02:32:03 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void check_recv_upstream(int is_join, struct interface *recv_ifp,
|
|
|
|
struct in_addr upstream, struct prefix_sg *sg,
|
|
|
|
uint8_t source_flags, int holdtime)
|
|
|
|
{
|
|
|
|
struct pim_upstream *up;
|
2017-05-20 01:36:53 +02:00
|
|
|
struct pim_interface *pim_ifp = recv_ifp->info;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
/* Upstream (S,G) in Joined state ? */
|
2017-05-20 01:36:53 +02:00
|
|
|
up = pim_upstream_find(pim_ifp->pim, sg);
|
2015-02-04 07:01:14 +01:00
|
|
|
if (!up)
|
|
|
|
return;
|
|
|
|
if (up->join_state != PIM_UPSTREAM_JOINED)
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
/* Upstream (S,G) in Joined state */
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-09-02 18:17:10 +02:00
|
|
|
if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
|
2015-02-04 07:01:14 +01:00
|
|
|
/* RPF'(S,G) not found */
|
2020-03-05 19:17:54 +01:00
|
|
|
zlog_warn("%s %s: RPF'%s not found", __FILE__, __func__,
|
|
|
|
up->sg_str);
|
2015-02-04 07:01:14 +01:00
|
|
|
return;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
/* upstream directed to RPF'(S,G) ? */
|
2016-09-02 18:17:10 +02:00
|
|
|
if (upstream.s_addr != up->rpf.rpf_addr.u.prefix4.s_addr) {
|
2016-10-20 16:09:30 +02:00
|
|
|
char up_str[INET_ADDRSTRLEN];
|
|
|
|
char rpf_str[PREFIX_STRLEN];
|
2015-02-04 07:01:14 +01:00
|
|
|
pim_inet4_dump("<up?>", upstream, up_str, sizeof(up_str));
|
2016-09-02 18:17:10 +02:00
|
|
|
pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_str,
|
|
|
|
sizeof(rpf_str));
|
2016-07-23 05:58:55 +02:00
|
|
|
zlog_warn(
|
|
|
|
"%s %s: (S,G)=%s upstream=%s not directed to RPF'(S,G)=%s on interface %s",
|
2020-03-05 19:17:54 +01:00
|
|
|
__FILE__, __func__, up->sg_str, up_str, rpf_str,
|
|
|
|
recv_ifp->name);
|
2015-02-04 07:01:14 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* upstream directed to RPF'(S,G) */
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
if (is_join) {
|
|
|
|
/* Join(S,G) to RPF'(S,G) */
|
2016-09-02 18:17:10 +02:00
|
|
|
pim_upstream_join_suppress(up, up->rpf.rpf_addr.u.prefix4,
|
|
|
|
holdtime);
|
2015-02-04 07:01:14 +01:00
|
|
|
return;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
/* Prune to RPF'(S,G) */
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
if (source_flags & PIM_RPT_BIT_MASK) {
|
|
|
|
if (source_flags & PIM_WILDCARD_BIT_MASK) {
|
|
|
|
/* Prune(*,G) to RPF'(S,G) */
|
2017-02-10 21:04:17 +01:00
|
|
|
pim_upstream_join_timer_decrease_to_t_override(
|
|
|
|
"Prune(*,G)", up);
|
2015-02-04 07:01:14 +01:00
|
|
|
return;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
/* Prune(S,G,rpt) to RPF'(S,G) */
|
2017-02-10 21:04:17 +01:00
|
|
|
pim_upstream_join_timer_decrease_to_t_override("Prune(S,G,rpt)",
|
|
|
|
up);
|
2015-02-04 07:01:14 +01:00
|
|
|
return;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
/* Prune(S,G) to RPF'(S,G) */
|
2017-02-10 21:04:17 +01:00
|
|
|
pim_upstream_join_timer_decrease_to_t_override("Prune(S,G)", up);
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
|
2017-02-10 21:14:16 +01:00
|
|
|
static int nonlocal_upstream(int is_join, struct interface *recv_ifp,
|
|
|
|
struct in_addr upstream, struct prefix_sg *sg,
|
|
|
|
uint8_t source_flags, uint16_t holdtime)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
|
|
|
struct pim_interface *recv_pim_ifp;
|
|
|
|
int is_local; /* boolean */
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
recv_pim_ifp = recv_ifp->info;
|
|
|
|
zassert(recv_pim_ifp);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
is_local = (upstream.s_addr == recv_pim_ifp->primary_address.s_addr);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-02-10 21:14:16 +01:00
|
|
|
if (is_local)
|
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-28 18:18:43 +01:00
|
|
|
if (PIM_DEBUG_PIM_TRACE_DETAIL) {
|
2016-10-20 16:09:30 +02:00
|
|
|
char up_str[INET_ADDRSTRLEN];
|
2015-02-04 07:01:14 +01:00
|
|
|
pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
|
2017-02-10 21:14:16 +01:00
|
|
|
zlog_warn("%s: recv %s (S,G)=%s to non-local upstream=%s on %s",
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__, is_join ? "join" : "prune",
|
2017-02-10 21:14:16 +01:00
|
|
|
pim_str_sg_dump(sg), up_str, recv_ifp->name);
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
/*
|
2017-02-10 21:14:16 +01:00
|
|
|
* Since recv upstream addr was not directed to our primary
|
|
|
|
* address, check if we should react to it in any way.
|
|
|
|
*/
|
2016-07-23 05:58:55 +02:00
|
|
|
check_recv_upstream(is_join, recv_ifp, upstream, sg, source_flags,
|
2017-02-10 21:14:16 +01:00
|
|
|
holdtime);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
return 1; /* non-local */
|
|
|
|
}
|
|
|
|
|
pimd: OIF add with PROTO_PIM is not happening if join rxed in PP state
Dumps while in problem state -
============================
[from "show ip pim state"]
Active Source Group RPT IIF OIL
1 6.0.0.31 239.1.1.111 n swp1 swp4( J * )
[from "show ip pim join"]
Interface Address Source Group State Uptime Expire Prune
swp3 6.0.0.22 6.0.0.31 239.1.1.111 JOIN --:--:-- 03:11 --:--
You can see from the dumps that the pim downstream router has joined on
swp3 but that OIF has not been added to the OIL with flag
PIM_OIF_FLAG_PROTO_PIM. This is because the join was rxed while the
ifchannel was in a prune-pending state.
Relevant logs -
===============
[
PIM: recv_prune: prune (S,G)=(6.0.0.31,239.1.1.111) rpt=1 wc=0 upstream=6.0.0.22 holdtime=210 from 6.0.0.28 on swp3
PIM: pim_upstream_ref(pim_ifchannel_add): upstream (6.0.0.31,239.1.1.111) ref count 3 increment
PIM: pim_upstream_add(pim_ifchannel_add): (6.0.0.31,239.1.1.111), iif 6.0.0.26/0 (swp1) found: 1: ref_count: 3
PIM: pim_ifchannel_add: ifchannel (6.0.0.31,239.1.1.111) is created
PIM: pim_joinprune_recv: SGRpt flag is set, del inherit oif from up (6.0.0.31,239.1.1.111)
PIM: pim_mroute_add(pim_channel_del_oif), vrf default Added Route: (6.0.0.31,239.1.1.111) IIF: swp1, OIFS: swp4
PIM: pim_channel_del_oif(pim_joinprune_recv): (S,G)=(6.0.0.31,239.1.1.111): proto_mask=4 IIF:1 OIF=swp3 vif_index=3
PIM: recv_join: join (S,G)=(6.0.0.31,239.1.1.111) rpt=0 wc=0 upstream=6.0.0.22 holdtime=210 from 6.0.0.28 on swp3
PIM: PIM_IFCHANNEL(swp3): (6.0.0.31,239.1.1.111) is switching from SGRpt(PP) to JOIN
PIM: Sending Request for New Channel Oil Information(6.0.0.31,239.1.1.111) VIIF 1(default)
]
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2019-11-15 20:47:39 +01:00
|
|
|
static void pim_ifchannel_ifjoin_handler(struct pim_ifchannel *ch,
|
|
|
|
struct pim_interface *pim_ifp)
|
|
|
|
{
|
2020-03-05 19:17:54 +01:00
|
|
|
pim_ifchannel_ifjoin_switch(__func__, ch, PIM_IFJOIN_JOIN);
|
pimd: OIF add with PROTO_PIM is not happening if join rxed in PP state
Dumps while in problem state -
============================
[from "show ip pim state"]
Active Source Group RPT IIF OIL
1 6.0.0.31 239.1.1.111 n swp1 swp4( J * )
[from "show ip pim join"]
Interface Address Source Group State Uptime Expire Prune
swp3 6.0.0.22 6.0.0.31 239.1.1.111 JOIN --:--:-- 03:11 --:--
You can see from the dumps that the pim downstream router has joined on
swp3 but that OIF has not been added to the OIL with flag
PIM_OIF_FLAG_PROTO_PIM. This is because the join was rxed while the
ifchannel was in a prune-pending state.
Relevant logs -
===============
[
PIM: recv_prune: prune (S,G)=(6.0.0.31,239.1.1.111) rpt=1 wc=0 upstream=6.0.0.22 holdtime=210 from 6.0.0.28 on swp3
PIM: pim_upstream_ref(pim_ifchannel_add): upstream (6.0.0.31,239.1.1.111) ref count 3 increment
PIM: pim_upstream_add(pim_ifchannel_add): (6.0.0.31,239.1.1.111), iif 6.0.0.26/0 (swp1) found: 1: ref_count: 3
PIM: pim_ifchannel_add: ifchannel (6.0.0.31,239.1.1.111) is created
PIM: pim_joinprune_recv: SGRpt flag is set, del inherit oif from up (6.0.0.31,239.1.1.111)
PIM: pim_mroute_add(pim_channel_del_oif), vrf default Added Route: (6.0.0.31,239.1.1.111) IIF: swp1, OIFS: swp4
PIM: pim_channel_del_oif(pim_joinprune_recv): (S,G)=(6.0.0.31,239.1.1.111): proto_mask=4 IIF:1 OIF=swp3 vif_index=3
PIM: recv_join: join (S,G)=(6.0.0.31,239.1.1.111) rpt=0 wc=0 upstream=6.0.0.22 holdtime=210 from 6.0.0.28 on swp3
PIM: PIM_IFCHANNEL(swp3): (6.0.0.31,239.1.1.111) is switching from SGRpt(PP) to JOIN
PIM: Sending Request for New Channel Oil Information(6.0.0.31,239.1.1.111) VIIF 1(default)
]
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2019-11-15 20:47:39 +01:00
|
|
|
PIM_IF_FLAG_UNSET_S_G_RPT(ch->flags);
|
|
|
|
/* check if the interface qualifies as an immediate
|
|
|
|
* OIF
|
|
|
|
*/
|
|
|
|
if (pim_upstream_evaluate_join_desired_interface(
|
|
|
|
ch->upstream, ch,
|
|
|
|
NULL /*starch*/)) {
|
|
|
|
pim_channel_add_oif(ch->upstream->channel_oil,
|
|
|
|
ch->interface,
|
|
|
|
PIM_OIF_FLAG_PROTO_PIM,
|
|
|
|
__func__);
|
|
|
|
pim_upstream_update_join_desired(pim_ifp->pim,
|
|
|
|
ch->upstream);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr,
|
|
|
|
struct in_addr upstream, struct prefix_sg *sg,
|
|
|
|
uint8_t source_flags, uint16_t holdtime)
|
|
|
|
{
|
|
|
|
struct pim_interface *pim_ifp;
|
|
|
|
struct pim_ifchannel *ch;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
if (nonlocal_upstream(1 /* join */, ifp, upstream, sg, source_flags,
|
|
|
|
holdtime)) {
|
2016-07-23 05:12:06 +02:00
|
|
|
return;
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-06-22 17:05:03 +02:00
|
|
|
ch = pim_ifchannel_add(ifp, sg, source_flags,
|
|
|
|
PIM_UPSTREAM_FLAG_MASK_SRC_PIM);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
/*
|
|
|
|
RFC 4601: 4.6.1. (S,G) Assert Message State Machine
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
Transitions from "I am Assert Loser" State
|
|
|
|
|
|
|
|
Receive Join(S,G) on Interface I
|
|
|
|
|
|
|
|
We receive a Join(S,G) that has the Upstream Neighbor Address
|
|
|
|
field set to my primary IP address on interface I. The action is
|
|
|
|
to transition to NoInfo state, delete this (S,G) assert state
|
|
|
|
(Actions A5 below), and allow the normal PIM Join/Prune mechanisms
|
|
|
|
to operate.
|
|
|
|
|
|
|
|
Notice: The nonlocal_upstream() test above ensures the upstream
|
|
|
|
address of the join message is our primary address.
|
|
|
|
*/
|
|
|
|
if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
|
|
|
|
char neigh_str[INET_ADDRSTRLEN];
|
|
|
|
pim_inet4_dump("<neigh?>", neigh_addr, neigh_str,
|
|
|
|
sizeof(neigh_str));
|
2016-07-23 05:12:06 +02:00
|
|
|
zlog_warn("%s: Assert Loser recv Join%s from %s on %s",
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__, ch->sg_str, neigh_str, ifp->name);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
assert_action_a5(ch);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
pim_ifp = ifp->info;
|
|
|
|
zassert(pim_ifp);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
switch (ch->ifjoin_state) {
|
2016-10-28 19:23:17 +02:00
|
|
|
case PIM_IFJOIN_NOINFO:
|
2020-03-05 19:17:54 +01:00
|
|
|
pim_ifchannel_ifjoin_switch(__func__, ch, PIM_IFJOIN_JOIN);
|
2015-02-04 07:01:14 +01:00
|
|
|
if (pim_macro_chisin_oiflist(ch)) {
|
2017-05-20 01:36:53 +02:00
|
|
|
pim_upstream_inherited_olist(pim_ifp->pim,
|
|
|
|
ch->upstream);
|
2016-11-08 21:26:48 +01:00
|
|
|
pim_forward_start(ch);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
/*
|
2016-11-08 21:26:48 +01:00
|
|
|
* If we are going to be a LHR, we need to note it
|
2017-07-17 14:03:14 +02:00
|
|
|
*/
|
2020-02-06 18:30:51 +01:00
|
|
|
if (ch->upstream->parent &&
|
|
|
|
(PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(
|
|
|
|
ch->upstream->parent->flags))
|
2017-04-25 16:00:39 +02:00
|
|
|
&& !(ch->upstream->flags
|
|
|
|
& PIM_UPSTREAM_FLAG_MASK_SRC_LHR)) {
|
|
|
|
pim_upstream_ref(ch->upstream,
|
|
|
|
PIM_UPSTREAM_FLAG_MASK_SRC_LHR,
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__);
|
2017-04-25 16:00:39 +02:00
|
|
|
pim_upstream_keep_alive_timer_start(
|
2017-07-13 03:16:00 +02:00
|
|
|
ch->upstream, pim_ifp->pim->keep_alive_time);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2016-10-28 19:23:17 +02:00
|
|
|
break;
|
2015-02-04 07:01:14 +01:00
|
|
|
case PIM_IFJOIN_JOIN:
|
|
|
|
zassert(!ch->t_ifjoin_prune_pending_timer);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
/*
|
2015-02-04 07:01:14 +01:00
|
|
|
In the JOIN state ch->t_ifjoin_expiry_timer may be NULL due to
|
2017-07-17 14:03:14 +02:00
|
|
|
a
|
2015-02-04 07:01:14 +01:00
|
|
|
previously received join message with holdtime=0xFFFF.
|
2017-07-17 14:03:14 +02:00
|
|
|
*/
|
2015-02-04 07:01:14 +01:00
|
|
|
if (ch->t_ifjoin_expiry_timer) {
|
2016-12-02 02:32:03 +01:00
|
|
|
unsigned long remain = thread_timer_remain_second(
|
2015-02-04 07:01:14 +01:00
|
|
|
ch->t_ifjoin_expiry_timer);
|
|
|
|
if (remain > holdtime) {
|
2017-07-17 14:03:14 +02:00
|
|
|
/*
|
2016-12-02 02:32:03 +01:00
|
|
|
RFC 4601: 4.5.3. Receiving (S,G) Join/Prune
|
2017-07-17 14:03:14 +02:00
|
|
|
Messages
|
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
Transitions from Join State
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-08 21:26:48 +01:00
|
|
|
The (S,G) downstream state machine on
|
2015-02-04 07:01:14 +01:00
|
|
|
interface I remains in
|
|
|
|
Join state, and the Expiry Timer (ET) is
|
|
|
|
restarted, set to
|
2016-12-02 02:32:03 +01:00
|
|
|
maximum of its current value and the HoldTime
|
2017-07-17 14:03:14 +02:00
|
|
|
from the
|
2015-02-04 07:01:14 +01:00
|
|
|
triggering Join/Prune message.
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
Conclusion: Do not change the ET if the
|
|
|
|
current value is
|
|
|
|
higher than the received join holdtime.
|
2017-07-17 14:03:14 +02:00
|
|
|
*/
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2016-12-02 02:32:03 +01:00
|
|
|
THREAD_OFF(ch->t_ifjoin_expiry_timer);
|
2017-07-17 14:03:14 +02:00
|
|
|
break;
|
2016-10-28 19:23:17 +02:00
|
|
|
case PIM_IFJOIN_PRUNE:
|
2020-03-20 02:41:46 +01:00
|
|
|
if (source_flags & PIM_ENCODE_RPT_BIT) {
|
2020-03-05 19:17:54 +01:00
|
|
|
pim_ifchannel_ifjoin_switch(__func__, ch,
|
2016-11-10 16:25:36 +01:00
|
|
|
PIM_IFJOIN_NOINFO);
|
2020-03-20 02:41:46 +01:00
|
|
|
THREAD_OFF(ch->t_ifjoin_expiry_timer);
|
|
|
|
delete_on_noinfo(ch);
|
|
|
|
return;
|
|
|
|
} else
|
pimd: OIF add with PROTO_PIM is not happening if join rxed in PP state
Dumps while in problem state -
============================
[from "show ip pim state"]
Active Source Group RPT IIF OIL
1 6.0.0.31 239.1.1.111 n swp1 swp4( J * )
[from "show ip pim join"]
Interface Address Source Group State Uptime Expire Prune
swp3 6.0.0.22 6.0.0.31 239.1.1.111 JOIN --:--:-- 03:11 --:--
You can see from the dumps that the pim downstream router has joined on
swp3 but that OIF has not been added to the OIL with flag
PIM_OIF_FLAG_PROTO_PIM. This is because the join was rxed while the
ifchannel was in a prune-pending state.
Relevant logs -
===============
[
PIM: recv_prune: prune (S,G)=(6.0.0.31,239.1.1.111) rpt=1 wc=0 upstream=6.0.0.22 holdtime=210 from 6.0.0.28 on swp3
PIM: pim_upstream_ref(pim_ifchannel_add): upstream (6.0.0.31,239.1.1.111) ref count 3 increment
PIM: pim_upstream_add(pim_ifchannel_add): (6.0.0.31,239.1.1.111), iif 6.0.0.26/0 (swp1) found: 1: ref_count: 3
PIM: pim_ifchannel_add: ifchannel (6.0.0.31,239.1.1.111) is created
PIM: pim_joinprune_recv: SGRpt flag is set, del inherit oif from up (6.0.0.31,239.1.1.111)
PIM: pim_mroute_add(pim_channel_del_oif), vrf default Added Route: (6.0.0.31,239.1.1.111) IIF: swp1, OIFS: swp4
PIM: pim_channel_del_oif(pim_joinprune_recv): (S,G)=(6.0.0.31,239.1.1.111): proto_mask=4 IIF:1 OIF=swp3 vif_index=3
PIM: recv_join: join (S,G)=(6.0.0.31,239.1.1.111) rpt=0 wc=0 upstream=6.0.0.22 holdtime=210 from 6.0.0.28 on swp3
PIM: PIM_IFCHANNEL(swp3): (6.0.0.31,239.1.1.111) is switching from SGRpt(PP) to JOIN
PIM: Sending Request for New Channel Oil Information(6.0.0.31,239.1.1.111) VIIF 1(default)
]
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2019-11-15 20:47:39 +01:00
|
|
|
pim_ifchannel_ifjoin_handler(ch, pim_ifp);
|
2017-07-17 14:03:14 +02:00
|
|
|
break;
|
2015-02-04 07:01:14 +01:00
|
|
|
case PIM_IFJOIN_PRUNE_PENDING:
|
2020-03-17 07:48:05 +01:00
|
|
|
/*
|
|
|
|
* Transitions from Prune-Pending State (Receive Join)
|
|
|
|
* RFC 7761 Sec 4.5.2:
|
|
|
|
* The (S,G) downstream state machine on interface I
|
|
|
|
* transitions to the Join state. The Prune-Pending Timer is
|
|
|
|
* canceled (without triggering an expiry event). The
|
|
|
|
* Expiry Timer (ET) is restarted and is then set to the
|
|
|
|
* maximum of its current value and the HoldTime from the
|
|
|
|
* triggering Join/Prune message.
|
|
|
|
*/
|
2016-12-02 02:32:03 +01:00
|
|
|
THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
|
2020-03-19 10:31:42 +01:00
|
|
|
|
|
|
|
/* Check if SGRpt join Received */
|
|
|
|
if ((source_flags & PIM_ENCODE_RPT_BIT)
|
|
|
|
&& (sg->src.s_addr != INADDR_ANY)) {
|
2020-03-17 07:48:05 +01:00
|
|
|
/*
|
|
|
|
* Transitions from Prune-Pending State (Rcv SGRpt Join)
|
|
|
|
* RFC 7761 Sec 4.5.3:
|
|
|
|
* The (S,G,rpt) downstream state machine on interface
|
|
|
|
* I transitions to the NoInfo state.The ET and PPT are
|
|
|
|
* cancelled.
|
|
|
|
*/
|
2016-12-02 02:32:03 +01:00
|
|
|
THREAD_OFF(ch->t_ifjoin_expiry_timer);
|
2020-03-05 19:17:54 +01:00
|
|
|
pim_ifchannel_ifjoin_switch(__func__, ch,
|
2016-12-02 02:32:03 +01:00
|
|
|
PIM_IFJOIN_NOINFO);
|
2020-03-17 07:48:05 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pim_ifchannel_ifjoin_handler(ch, pim_ifp);
|
|
|
|
|
|
|
|
if (ch->t_ifjoin_expiry_timer) {
|
|
|
|
unsigned long remain = thread_timer_remain_second(
|
|
|
|
ch->t_ifjoin_expiry_timer);
|
|
|
|
|
|
|
|
if (remain > holdtime)
|
|
|
|
return;
|
pimd: OIF add with PROTO_PIM is not happening if join rxed in PP state
Dumps while in problem state -
============================
[from "show ip pim state"]
Active Source Group RPT IIF OIL
1 6.0.0.31 239.1.1.111 n swp1 swp4( J * )
[from "show ip pim join"]
Interface Address Source Group State Uptime Expire Prune
swp3 6.0.0.22 6.0.0.31 239.1.1.111 JOIN --:--:-- 03:11 --:--
You can see from the dumps that the pim downstream router has joined on
swp3 but that OIF has not been added to the OIL with flag
PIM_OIF_FLAG_PROTO_PIM. This is because the join was rxed while the
ifchannel was in a prune-pending state.
Relevant logs -
===============
[
PIM: recv_prune: prune (S,G)=(6.0.0.31,239.1.1.111) rpt=1 wc=0 upstream=6.0.0.22 holdtime=210 from 6.0.0.28 on swp3
PIM: pim_upstream_ref(pim_ifchannel_add): upstream (6.0.0.31,239.1.1.111) ref count 3 increment
PIM: pim_upstream_add(pim_ifchannel_add): (6.0.0.31,239.1.1.111), iif 6.0.0.26/0 (swp1) found: 1: ref_count: 3
PIM: pim_ifchannel_add: ifchannel (6.0.0.31,239.1.1.111) is created
PIM: pim_joinprune_recv: SGRpt flag is set, del inherit oif from up (6.0.0.31,239.1.1.111)
PIM: pim_mroute_add(pim_channel_del_oif), vrf default Added Route: (6.0.0.31,239.1.1.111) IIF: swp1, OIFS: swp4
PIM: pim_channel_del_oif(pim_joinprune_recv): (S,G)=(6.0.0.31,239.1.1.111): proto_mask=4 IIF:1 OIF=swp3 vif_index=3
PIM: recv_join: join (S,G)=(6.0.0.31,239.1.1.111) rpt=0 wc=0 upstream=6.0.0.22 holdtime=210 from 6.0.0.28 on swp3
PIM: PIM_IFCHANNEL(swp3): (6.0.0.31,239.1.1.111) is switching from SGRpt(PP) to JOIN
PIM: Sending Request for New Channel Oil Information(6.0.0.31,239.1.1.111) VIIF 1(default)
]
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2019-11-15 20:47:39 +01:00
|
|
|
}
|
2020-03-17 07:48:05 +01:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
break;
|
2016-10-28 19:23:17 +02:00
|
|
|
case PIM_IFJOIN_PRUNE_TMP:
|
|
|
|
break;
|
|
|
|
case PIM_IFJOIN_PRUNE_PENDING_TMP:
|
|
|
|
break;
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
if (holdtime != 0xFFFF) {
|
2018-12-20 16:34:04 +01:00
|
|
|
thread_add_timer(router->master, on_ifjoin_expiry_timer, ch,
|
|
|
|
holdtime, &ch->t_ifjoin_expiry_timer);
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream,
|
|
|
|
struct prefix_sg *sg, uint8_t source_flags,
|
|
|
|
uint16_t holdtime)
|
|
|
|
{
|
|
|
|
struct pim_ifchannel *ch;
|
2016-09-15 22:50:08 +02:00
|
|
|
struct pim_interface *pim_ifp;
|
2016-11-10 16:25:36 +01:00
|
|
|
int jp_override_interval_msec;
|
|
|
|
|
2017-03-22 15:11:04 +01:00
|
|
|
if (nonlocal_upstream(0 /* prune */, ifp, upstream, sg, source_flags,
|
|
|
|
holdtime)) {
|
|
|
|
return;
|
2016-11-10 16:25:36 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
ch = pim_ifchannel_find(ifp, sg);
|
|
|
|
if (!ch && !(source_flags & PIM_ENCODE_RPT_BIT)) {
|
2019-11-12 14:02:06 +01:00
|
|
|
if (PIM_DEBUG_PIM_TRACE)
|
2017-03-17 19:51:13 +01:00
|
|
|
zlog_debug(
|
2019-03-28 20:44:58 +01:00
|
|
|
"%s: Received prune with no relevant ifchannel %s%s state: %d",
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__, ifp->name, pim_str_sg_dump(sg),
|
|
|
|
source_flags);
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-06-22 17:05:03 +02:00
|
|
|
ch = pim_ifchannel_add(ifp, sg, source_flags,
|
|
|
|
PIM_UPSTREAM_FLAG_MASK_SRC_PIM);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-10 16:25:36 +01:00
|
|
|
pim_ifp = ifp->info;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-10 16:25:36 +01:00
|
|
|
switch (ch->ifjoin_state) {
|
2015-02-04 07:01:14 +01:00
|
|
|
case PIM_IFJOIN_NOINFO:
|
2016-11-10 16:25:36 +01:00
|
|
|
if (source_flags & PIM_ENCODE_RPT_BIT) {
|
2017-05-09 20:30:43 +02:00
|
|
|
if (!(source_flags & PIM_ENCODE_WC_BIT))
|
|
|
|
PIM_IF_FLAG_SET_S_G_RPT(ch->flags);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-10 16:25:36 +01:00
|
|
|
ch->ifjoin_state = PIM_IFJOIN_PRUNE_PENDING;
|
|
|
|
if (listcount(pim_ifp->pim_neighbor_list) > 1)
|
|
|
|
jp_override_interval_msec =
|
|
|
|
pim_if_jp_override_interval_msec(ifp);
|
|
|
|
else
|
|
|
|
jp_override_interval_msec =
|
|
|
|
0; /* schedule to expire immediately */
|
|
|
|
/* If we called ifjoin_prune() directly instead, care
|
|
|
|
should
|
|
|
|
be taken not to use "ch" afterwards since it would be
|
|
|
|
deleted. */
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-10 16:25:36 +01:00
|
|
|
THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
|
|
|
|
THREAD_OFF(ch->t_ifjoin_expiry_timer);
|
2017-04-25 00:33:25 +02:00
|
|
|
thread_add_timer_msec(
|
2018-12-20 16:34:04 +01:00
|
|
|
router->master, on_ifjoin_prune_pending_timer,
|
|
|
|
ch, jp_override_interval_msec,
|
2017-04-25 00:33:25 +02:00
|
|
|
&ch->t_ifjoin_prune_pending_timer);
|
2018-12-20 16:34:04 +01:00
|
|
|
thread_add_timer(router->master, on_ifjoin_expiry_timer,
|
|
|
|
ch, holdtime,
|
|
|
|
&ch->t_ifjoin_expiry_timer);
|
2017-05-20 01:36:53 +02:00
|
|
|
pim_upstream_update_join_desired(pim_ifp->pim,
|
|
|
|
ch->upstream);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
break;
|
2016-11-10 16:25:36 +01:00
|
|
|
case PIM_IFJOIN_PRUNE_PENDING:
|
2015-02-04 07:01:14 +01:00
|
|
|
/* nothing to do */
|
2017-07-17 14:03:14 +02:00
|
|
|
break;
|
2015-02-04 07:01:14 +01:00
|
|
|
case PIM_IFJOIN_JOIN:
|
2020-03-17 07:48:05 +01:00
|
|
|
/*
|
|
|
|
* The (S,G) downstream state machine on interface I
|
|
|
|
* transitions to the Prune-Pending state. The
|
|
|
|
* Prune-Pending Timer is started. It is set to the
|
|
|
|
* J/P_Override_Interval(I) if the router has more than one
|
|
|
|
* neighbor on that interface; otherwise, it is set to zero,
|
|
|
|
* causing it to expire immediately.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-03-05 19:17:54 +01:00
|
|
|
pim_ifchannel_ifjoin_switch(__func__, ch,
|
2017-05-09 20:30:43 +02:00
|
|
|
PIM_IFJOIN_PRUNE_PENDING);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-10 16:25:36 +01:00
|
|
|
if (listcount(pim_ifp->pim_neighbor_list) > 1)
|
2017-04-25 00:33:25 +02:00
|
|
|
jp_override_interval_msec =
|
|
|
|
pim_if_jp_override_interval_msec(ifp);
|
2017-07-17 14:03:14 +02:00
|
|
|
else
|
2017-04-25 00:33:25 +02:00
|
|
|
jp_override_interval_msec =
|
|
|
|
0; /* schedule to expire immediately */
|
2016-10-28 19:23:17 +02:00
|
|
|
/* If we called ifjoin_prune() directly instead, care should
|
2016-11-10 16:25:36 +01:00
|
|
|
be taken not to use "ch" afterwards since it would be
|
|
|
|
deleted. */
|
|
|
|
THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
|
2018-12-20 16:34:04 +01:00
|
|
|
thread_add_timer_msec(router->master,
|
|
|
|
on_ifjoin_prune_pending_timer, ch,
|
2017-04-25 00:33:25 +02:00
|
|
|
jp_override_interval_msec,
|
|
|
|
&ch->t_ifjoin_prune_pending_timer);
|
2017-07-17 14:03:14 +02:00
|
|
|
break;
|
2016-11-10 16:25:36 +01:00
|
|
|
case PIM_IFJOIN_PRUNE:
|
|
|
|
if (source_flags & PIM_ENCODE_RPT_BIT) {
|
|
|
|
THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
|
2020-03-19 11:33:41 +01:00
|
|
|
/*
|
|
|
|
* While in Prune State, Receive SGRpt Prune.
|
|
|
|
* RFC 7761 Sec 4.5.3:
|
|
|
|
* The (S,G,rpt) downstream state machine on interface I
|
|
|
|
* remains in Prune state. The Expiry Timer (ET) is
|
|
|
|
* restarted and is then set to the maximum of its
|
|
|
|
* current value and the HoldTime from the triggering
|
|
|
|
* Join/Prune message.
|
|
|
|
*/
|
|
|
|
if (ch->t_ifjoin_expiry_timer) {
|
|
|
|
unsigned long rem = thread_timer_remain_second(
|
|
|
|
ch->t_ifjoin_expiry_timer);
|
|
|
|
|
|
|
|
if (rem > holdtime)
|
|
|
|
return;
|
|
|
|
THREAD_OFF(ch->t_ifjoin_expiry_timer);
|
|
|
|
}
|
|
|
|
|
2018-12-20 16:34:04 +01:00
|
|
|
thread_add_timer(router->master, on_ifjoin_expiry_timer,
|
|
|
|
ch, holdtime,
|
|
|
|
&ch->t_ifjoin_expiry_timer);
|
2016-11-10 16:25:36 +01:00
|
|
|
}
|
|
|
|
break;
|
2016-10-28 19:23:17 +02:00
|
|
|
case PIM_IFJOIN_PRUNE_TMP:
|
2016-11-10 16:25:36 +01:00
|
|
|
if (source_flags & PIM_ENCODE_RPT_BIT) {
|
|
|
|
ch->ifjoin_state = PIM_IFJOIN_PRUNE;
|
|
|
|
THREAD_OFF(ch->t_ifjoin_expiry_timer);
|
2018-12-20 16:34:04 +01:00
|
|
|
thread_add_timer(router->master, on_ifjoin_expiry_timer,
|
|
|
|
ch, holdtime,
|
|
|
|
&ch->t_ifjoin_expiry_timer);
|
2016-11-10 16:25:36 +01:00
|
|
|
}
|
|
|
|
break;
|
2016-10-28 19:23:17 +02:00
|
|
|
case PIM_IFJOIN_PRUNE_PENDING_TMP:
|
2016-11-10 16:25:36 +01:00
|
|
|
if (source_flags & PIM_ENCODE_RPT_BIT) {
|
|
|
|
ch->ifjoin_state = PIM_IFJOIN_PRUNE_PENDING;
|
|
|
|
THREAD_OFF(ch->t_ifjoin_expiry_timer);
|
2018-12-20 16:34:04 +01:00
|
|
|
thread_add_timer(router->master, on_ifjoin_expiry_timer,
|
|
|
|
ch, holdtime,
|
|
|
|
&ch->t_ifjoin_expiry_timer);
|
2016-11-10 16:25:36 +01:00
|
|
|
}
|
2016-10-28 19:23:17 +02:00
|
|
|
break;
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-25 20:47:04 +01:00
|
|
|
int pim_ifchannel_local_membership_add(struct interface *ifp,
|
2020-02-06 18:30:51 +01:00
|
|
|
struct prefix_sg *sg, bool is_vxlan)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
2017-04-20 15:03:47 +02:00
|
|
|
struct pim_ifchannel *ch, *starch;
|
2015-02-04 07:01:14 +01:00
|
|
|
struct pim_interface *pim_ifp;
|
2017-05-17 22:21:33 +02:00
|
|
|
struct pim_instance *pim;
|
2020-02-06 18:30:51 +01:00
|
|
|
int up_flags;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
/* PIM enabled on interface? */
|
|
|
|
pim_ifp = ifp->info;
|
2018-11-16 01:17:17 +01:00
|
|
|
if (!pim_ifp) {
|
|
|
|
if (PIM_DEBUG_EVENTS)
|
|
|
|
zlog_debug("%s:%s Expected pim interface setup for %s",
|
2020-03-06 15:23:22 +01:00
|
|
|
__func__, pim_str_sg_dump(sg), ifp->name);
|
2017-01-25 20:47:04 +01:00
|
|
|
return 0;
|
2018-11-16 01:17:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
|
|
|
|
if (PIM_DEBUG_EVENTS)
|
2020-03-06 15:23:22 +01:00
|
|
|
zlog_debug(
|
|
|
|
"%s:%s PIM is not configured on this interface %s",
|
|
|
|
__func__, pim_str_sg_dump(sg), ifp->name);
|
2017-01-25 20:47:04 +01:00
|
|
|
return 0;
|
2018-11-16 01:17:17 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-17 22:21:33 +02:00
|
|
|
pim = pim_ifp->pim;
|
|
|
|
|
2017-03-17 19:51:13 +01:00
|
|
|
/* skip (*,G) ch creation if G is of type SSM */
|
|
|
|
if (sg->src.s_addr == INADDR_ANY) {
|
2017-05-21 15:30:02 +02:00
|
|
|
if (pim_is_grp_ssm(pim, sg->grp)) {
|
2017-03-17 19:51:13 +01:00
|
|
|
if (PIM_DEBUG_PIM_EVENTS)
|
|
|
|
zlog_debug(
|
|
|
|
"%s: local membership (S,G)=%s ignored as group is SSM",
|
2020-03-06 15:23:22 +01:00
|
|
|
__func__, pim_str_sg_dump(sg));
|
2017-03-17 19:51:13 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-02-19 15:52:17 +01:00
|
|
|
/* vxlan term mroutes use ipmr-lo as local member to
|
|
|
|
* pull down multicast vxlan tunnel traffic
|
|
|
|
*/
|
2020-02-06 18:30:51 +01:00
|
|
|
up_flags = is_vxlan ? PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM :
|
|
|
|
PIM_UPSTREAM_FLAG_MASK_SRC_IGMP;
|
|
|
|
ch = pim_ifchannel_add(ifp, sg, 0, up_flags);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
ifmembership_set(ch, PIM_IFMEMBERSHIP_INCLUDE);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-08-15 13:28:36 +02:00
|
|
|
if (sg->src.s_addr == INADDR_ANY) {
|
2017-05-20 01:36:53 +02:00
|
|
|
struct pim_upstream *up = pim_upstream_find(pim, sg);
|
2016-08-15 13:28:36 +02:00
|
|
|
struct pim_upstream *child;
|
|
|
|
struct listnode *up_node;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-04-20 15:03:47 +02:00
|
|
|
starch = ch;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-10-24 04:47:25 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(up->sources, up_node, child)) {
|
2017-04-20 15:03:47 +02:00
|
|
|
if (PIM_DEBUG_EVENTS)
|
|
|
|
zlog_debug("%s %s: IGMP (S,G)=%s(%s) from %s",
|
2020-03-06 15:23:22 +01:00
|
|
|
__FILE__, __func__, child->sg_str,
|
|
|
|
ifp->name, up->sg_str);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-04-20 15:03:47 +02:00
|
|
|
ch = pim_ifchannel_find(ifp, &child->sg);
|
|
|
|
if (pim_upstream_evaluate_join_desired_interface(
|
|
|
|
child, ch, starch)) {
|
|
|
|
pim_channel_add_oif(child->channel_oil, ifp,
|
2019-11-15 17:47:33 +01:00
|
|
|
PIM_OIF_FLAG_PROTO_STAR,
|
|
|
|
__func__);
|
2019-11-15 20:21:11 +01:00
|
|
|
pim_upstream_update_join_desired(pim, child);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-04-20 15:03:47 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-17 22:21:33 +02:00
|
|
|
if (pim->spt.switchover == PIM_SPT_INFINITY) {
|
2017-05-20 20:17:48 +02:00
|
|
|
if (pim->spt.plist) {
|
2017-04-07 16:16:23 +02:00
|
|
|
struct prefix_list *plist = prefix_list_lookup(
|
2017-05-17 22:21:33 +02:00
|
|
|
AFI_IP, pim->spt.plist);
|
2017-04-07 16:16:23 +02:00
|
|
|
struct prefix g;
|
|
|
|
g.family = AF_INET;
|
|
|
|
g.prefixlen = IPV4_MAX_PREFIXLEN;
|
|
|
|
g.u.prefix4 = up->sg.grp;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-04-07 16:16:23 +02:00
|
|
|
if (prefix_list_apply(plist, &g)
|
|
|
|
== PREFIX_DENY) {
|
|
|
|
pim_channel_add_oif(
|
2017-05-17 22:21:33 +02:00
|
|
|
up->channel_oil, pim->regiface,
|
2019-11-15 17:47:33 +01:00
|
|
|
PIM_OIF_FLAG_PROTO_IGMP,
|
|
|
|
__func__);
|
2017-04-07 16:16:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else
|
2017-05-17 22:21:33 +02:00
|
|
|
pim_channel_add_oif(up->channel_oil, pim->regiface,
|
2019-11-15 17:47:33 +01:00
|
|
|
PIM_OIF_FLAG_PROTO_IGMP,
|
|
|
|
__func__);
|
2016-08-15 13:28:36 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-01-25 20:47:04 +01:00
|
|
|
return 1;
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void pim_ifchannel_local_membership_del(struct interface *ifp,
|
2016-08-02 10:38:11 +02:00
|
|
|
struct prefix_sg *sg)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
2017-04-20 15:03:47 +02:00
|
|
|
struct pim_ifchannel *starch, *ch, *orig;
|
2015-02-04 07:01:14 +01:00
|
|
|
struct pim_interface *pim_ifp;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
/* PIM enabled on interface? */
|
|
|
|
pim_ifp = ifp->info;
|
|
|
|
if (!pim_ifp)
|
|
|
|
return;
|
|
|
|
if (!PIM_IF_TEST_PIM(pim_ifp->options))
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-04-20 15:03:47 +02:00
|
|
|
orig = ch = pim_ifchannel_find(ifp, sg);
|
2015-02-04 07:01:14 +01:00
|
|
|
if (!ch)
|
|
|
|
return;
|
|
|
|
ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-08-15 13:28:36 +02:00
|
|
|
if (sg->src.s_addr == INADDR_ANY) {
|
2017-05-20 01:36:53 +02:00
|
|
|
struct pim_upstream *up = pim_upstream_find(pim_ifp->pim, sg);
|
2016-08-15 13:28:36 +02:00
|
|
|
struct pim_upstream *child;
|
2017-04-18 15:01:00 +02:00
|
|
|
struct listnode *up_node, *up_nnode;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-04-20 15:03:47 +02:00
|
|
|
starch = ch;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-04-18 15:01:00 +02:00
|
|
|
for (ALL_LIST_ELEMENTS(up->sources, up_node, up_nnode, child)) {
|
2016-10-24 04:47:25 +02:00
|
|
|
struct channel_oil *c_oil = child->channel_oil;
|
|
|
|
struct pim_ifchannel *chchannel =
|
|
|
|
pim_ifchannel_find(ifp, &child->sg);
|
2018-09-12 12:55:31 +02:00
|
|
|
|
|
|
|
pim_ifp = ifp->info;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-10-24 04:47:25 +02:00
|
|
|
if (PIM_DEBUG_EVENTS)
|
2016-11-17 14:17:25 +01:00
|
|
|
zlog_debug("%s %s: Prune(S,G)=%s(%s) from %s",
|
2020-03-06 15:23:22 +01:00
|
|
|
__FILE__, __func__, up->sg_str,
|
|
|
|
ifp->name, child->sg_str);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-04-20 15:03:47 +02:00
|
|
|
ch = pim_ifchannel_find(ifp, &child->sg);
|
2016-10-24 04:47:25 +02:00
|
|
|
/*
|
|
|
|
* If the S,G has no if channel and the c_oil still
|
|
|
|
* has output here then the *,G was supplying the
|
|
|
|
* implied
|
|
|
|
* if channel. So remove it.
|
|
|
|
*/
|
2019-11-15 20:43:27 +01:00
|
|
|
if (!pim_upstream_evaluate_join_desired_interface(
|
|
|
|
child, ch, starch) ||
|
|
|
|
(!chchannel &&
|
|
|
|
c_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index])) {
|
|
|
|
pim_channel_del_inherited_oif(c_oil, ifp,
|
|
|
|
__func__);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
pimd: Fix WG/SGRpt & WG J/P processing
During processing of Join/Prune,
for a S,G entry, current state is SGRpt, when only *,G is
received, need to clear SGRpt and add/inherit the *,G OIF to S,G so
it can forward traffic to downstream where *,G is received.
Upon receiving SGRpt prune remove the inherited *,G OIF.
From, downstream router received *,G Prune along with SGRpt
prune. Avoid sending *,G and SGRpt Prune together.
Reset upstream_del reset ifchannel to NULL.
Testing Done:
Run failed smoke test of sending data packets, trigger SPT switchover,
*,G path received SGRpt later data traffic stopped S,G ages out from LHR, sends only
*,G join to upstream, verified S,G entry inherit the OIF.
Upon receiving SGRpt deletes inherited oif and retains in SGRpt state.
Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2017-04-22 00:08:03 +02:00
|
|
|
/* Child node removal/ref count-- will happen as part of
|
|
|
|
* parent' delete_no_info */
|
2016-08-15 13:28:36 +02:00
|
|
|
}
|
|
|
|
}
|
2020-12-17 11:37:25 +01:00
|
|
|
|
|
|
|
/* Resettng the IGMP flags here */
|
|
|
|
if (orig->upstream)
|
|
|
|
PIM_UPSTREAM_FLAG_UNSET_SRC_IGMP(orig->upstream->flags);
|
|
|
|
|
|
|
|
PIM_IF_FLAG_UNSET_PROTO_IGMP(orig->flags);
|
|
|
|
|
2017-04-20 15:03:47 +02:00
|
|
|
delete_on_noinfo(orig);
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void pim_ifchannel_update_could_assert(struct pim_ifchannel *ch)
|
|
|
|
{
|
|
|
|
int old_couldassert =
|
|
|
|
PIM_FORCE_BOOLEAN(PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags));
|
|
|
|
int new_couldassert =
|
|
|
|
PIM_FORCE_BOOLEAN(pim_macro_ch_could_assert_eval(ch));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
if (new_couldassert == old_couldassert)
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
if (PIM_DEBUG_PIM_EVENTS) {
|
2016-10-20 16:09:30 +02:00
|
|
|
char src_str[INET_ADDRSTRLEN];
|
|
|
|
char grp_str[INET_ADDRSTRLEN];
|
2016-08-02 10:38:11 +02:00
|
|
|
pim_inet4_dump("<src?>", ch->sg.src, src_str, sizeof(src_str));
|
|
|
|
pim_inet4_dump("<grp?>", ch->sg.grp, grp_str, sizeof(grp_str));
|
2015-02-04 07:01:14 +01:00
|
|
|
zlog_debug("%s: CouldAssert(%s,%s,%s) changed from %d to %d",
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__, src_str, grp_str, ch->interface->name,
|
|
|
|
old_couldassert, new_couldassert);
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
if (new_couldassert) {
|
2019-07-01 19:26:05 +02:00
|
|
|
/* CouldAssert(S,G,I) switched from false to true */
|
2015-02-04 07:01:14 +01:00
|
|
|
PIM_IF_FLAG_SET_COULD_ASSERT(ch->flags);
|
|
|
|
} else {
|
2019-07-01 19:26:05 +02:00
|
|
|
/* CouldAssert(S,G,I) switched from true to false */
|
2015-02-04 07:01:14 +01:00
|
|
|
PIM_IF_FLAG_UNSET_COULD_ASSERT(ch->flags);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
if (ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER) {
|
|
|
|
assert_action_a4(ch);
|
|
|
|
}
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
pim_ifchannel_update_my_assert_metric(ch);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
my_assert_metric may be affected by:
|
|
|
|
|
|
|
|
CouldAssert(S,G)
|
|
|
|
pim_ifp->primary_address
|
|
|
|
rpf->source_nexthop.mrib_metric_preference;
|
|
|
|
rpf->source_nexthop.mrib_route_metric;
|
|
|
|
*/
|
|
|
|
void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel *ch)
|
|
|
|
{
|
|
|
|
struct pim_assert_metric my_metric_new =
|
|
|
|
pim_macro_ch_my_assert_metric_eval(ch);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
if (pim_assert_metric_match(&my_metric_new, &ch->ifassert_my_metric))
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
if (PIM_DEBUG_PIM_EVENTS) {
|
2016-10-20 16:09:30 +02:00
|
|
|
char src_str[INET_ADDRSTRLEN];
|
|
|
|
char grp_str[INET_ADDRSTRLEN];
|
|
|
|
char old_addr_str[INET_ADDRSTRLEN];
|
|
|
|
char new_addr_str[INET_ADDRSTRLEN];
|
2016-08-02 10:38:11 +02:00
|
|
|
pim_inet4_dump("<src?>", ch->sg.src, src_str, sizeof(src_str));
|
|
|
|
pim_inet4_dump("<grp?>", ch->sg.grp, grp_str, sizeof(grp_str));
|
2015-02-04 07:01:14 +01:00
|
|
|
pim_inet4_dump("<old_addr?>", ch->ifassert_my_metric.ip_address,
|
|
|
|
old_addr_str, sizeof(old_addr_str));
|
|
|
|
pim_inet4_dump("<new_addr?>", my_metric_new.ip_address,
|
|
|
|
new_addr_str, sizeof(new_addr_str));
|
|
|
|
zlog_debug(
|
|
|
|
"%s: my_assert_metric(%s,%s,%s) changed from %u,%u,%u,%s to %u,%u,%u,%s",
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__, src_str, grp_str, ch->interface->name,
|
2015-02-04 07:01:14 +01:00
|
|
|
ch->ifassert_my_metric.rpt_bit_flag,
|
|
|
|
ch->ifassert_my_metric.metric_preference,
|
|
|
|
ch->ifassert_my_metric.route_metric, old_addr_str,
|
|
|
|
my_metric_new.rpt_bit_flag,
|
|
|
|
my_metric_new.metric_preference,
|
|
|
|
my_metric_new.route_metric, new_addr_str);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
ch->ifassert_my_metric = my_metric_new;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
if (pim_assert_metric_better(&ch->ifassert_my_metric,
|
|
|
|
&ch->ifassert_winner_metric)) {
|
|
|
|
assert_action_a5(ch);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch)
|
|
|
|
{
|
|
|
|
int old_atd = PIM_FORCE_BOOLEAN(
|
|
|
|
PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags));
|
|
|
|
int new_atd =
|
|
|
|
PIM_FORCE_BOOLEAN(pim_macro_assert_tracking_desired_eval(ch));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
if (new_atd == old_atd)
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
if (PIM_DEBUG_PIM_EVENTS) {
|
2016-10-20 16:09:30 +02:00
|
|
|
char src_str[INET_ADDRSTRLEN];
|
|
|
|
char grp_str[INET_ADDRSTRLEN];
|
2016-08-02 10:38:11 +02:00
|
|
|
pim_inet4_dump("<src?>", ch->sg.src, src_str, sizeof(src_str));
|
|
|
|
pim_inet4_dump("<grp?>", ch->sg.grp, grp_str, sizeof(grp_str));
|
2015-02-04 07:01:14 +01:00
|
|
|
zlog_debug(
|
|
|
|
"%s: AssertTrackingDesired(%s,%s,%s) changed from %d to %d",
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__, src_str, grp_str, ch->interface->name,
|
|
|
|
old_atd, new_atd);
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
if (new_atd) {
|
2019-07-01 19:26:05 +02:00
|
|
|
/* AssertTrackingDesired(S,G,I) switched from false to true */
|
2015-02-04 07:01:14 +01:00
|
|
|
PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch->flags);
|
|
|
|
} else {
|
2019-07-01 19:26:05 +02:00
|
|
|
/* AssertTrackingDesired(S,G,I) switched from true to false */
|
2015-02-04 07:01:14 +01:00
|
|
|
PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
|
|
|
|
assert_action_a5(ch);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-08-24 16:25:11 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we have a new pim interface, check to
|
|
|
|
* see if any of the pre-existing channels have
|
|
|
|
* their upstream out that way and turn on forwarding
|
|
|
|
* for that ifchannel then.
|
|
|
|
*/
|
|
|
|
void pim_ifchannel_scan_forward_start(struct interface *new_ifp)
|
|
|
|
{
|
|
|
|
struct pim_interface *new_pim_ifp = new_ifp->info;
|
2017-05-20 20:17:48 +02:00
|
|
|
struct pim_instance *pim = new_pim_ifp->pim;
|
2017-07-31 18:44:20 +02:00
|
|
|
struct interface *ifp;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-10-06 20:25:58 +02:00
|
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
2016-08-24 16:25:11 +02:00
|
|
|
struct pim_interface *loop_pim_ifp = ifp->info;
|
|
|
|
struct pim_ifchannel *ch;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-08-24 16:25:11 +02:00
|
|
|
if (!loop_pim_ifp)
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-08-24 16:25:11 +02:00
|
|
|
if (new_pim_ifp == loop_pim_ifp)
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-09-15 17:47:35 +02:00
|
|
|
RB_FOREACH (ch, pim_ifchannel_rb, &loop_pim_ifp->ifchannel_rb) {
|
2016-08-24 16:25:11 +02:00
|
|
|
if (ch->ifjoin_state == PIM_IFJOIN_JOIN) {
|
|
|
|
struct pim_upstream *up = ch->upstream;
|
|
|
|
if ((!up->channel_oil)
|
|
|
|
&& (up->rpf.source_nexthop
|
|
|
|
.interface == new_ifp))
|
|
|
|
pim_forward_start(ch);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-11-08 21:26:48 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Downstream per-interface (S,G,rpt) state machine
|
|
|
|
* states that we need to move (S,G,rpt) items
|
|
|
|
* into different states at the start of the
|
|
|
|
* reception of a *,G join as well, when
|
|
|
|
* we get End of Message
|
|
|
|
*/
|
pimd: Fix to Tx S,G Join when SGRpt->Join state
-Upon Rx (*,G) Join w/o SGRpt at RP, trigger (S,G) Join
towards FHR, unset SGRpt flag from channel,
add (*,G) oif to (S,G) entry.
-Add I am not RP check to triger SGRpt on *,G path otherwise,
send S,G Prune on SPT path from RP to FHR upon receving *,G Prune.
-Upon Rx SGRpt receive, remove OIF(downstream where Prune received) from specific S,G.
Testing Done:
pim-smoke
Ran 95 tests in 11790.552s
FAILED (SKIP=10, failures=4)
Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2017-05-12 21:05:46 +02:00
|
|
|
void pim_ifchannel_set_star_g_join_state(struct pim_ifchannel *ch, int eom,
|
2017-08-24 15:55:19 +02:00
|
|
|
uint8_t join)
|
2016-11-08 21:26:48 +01:00
|
|
|
{
|
pimd: Only send triggered response after all of *,G message is read
pim was sending a triggered response on every S,G RPT prune information
read. Suppose we had this in a *,G message:
*,G
S1, G RPT Prune
S2, G RPT Prune
We would send two triggered *,G messages upstream. This leads to over
processing and quickly changing state if S1 or S2 were in different
states.
Modify the code to send just one Triggered *,G upstream after looking
at all S,G state for a *,G.
Ticket: CM-24531
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
2019-04-09 00:02:45 +02:00
|
|
|
bool send_upstream_starg = false;
|
2016-11-08 21:26:48 +01:00
|
|
|
struct pim_ifchannel *child;
|
2017-09-14 01:43:39 +02:00
|
|
|
struct listnode *ch_node, *nch_node;
|
2017-08-24 15:55:19 +02:00
|
|
|
struct pim_instance *pim =
|
|
|
|
((struct pim_interface *)ch->interface->info)->pim;
|
pimd: Only send triggered response after all of *,G message is read
pim was sending a triggered response on every S,G RPT prune information
read. Suppose we had this in a *,G message:
*,G
S1, G RPT Prune
S2, G RPT Prune
We would send two triggered *,G messages upstream. This leads to over
processing and quickly changing state if S1 or S2 were in different
states.
Modify the code to send just one Triggered *,G upstream after looking
at all S,G state for a *,G.
Ticket: CM-24531
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
2019-04-09 00:02:45 +02:00
|
|
|
struct pim_upstream *starup = ch->upstream;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-08 21:26:48 +01:00
|
|
|
if (PIM_DEBUG_PIM_TRACE)
|
pimd: Fix WG/SGRpt & WG J/P processing
During processing of Join/Prune,
for a S,G entry, current state is SGRpt, when only *,G is
received, need to clear SGRpt and add/inherit the *,G OIF to S,G so
it can forward traffic to downstream where *,G is received.
Upon receiving SGRpt prune remove the inherited *,G OIF.
Testing Done:
Trigger SPT switchover, *,G path received SGRpt later data
traffic stopped S,G ages out from LHR, sends only
*,G join to upstream, verified S,G entry inherit the OIF.
Upon receiving SGRpt deletes inherited oif and retains in SGRpt state.
Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2017-04-22 00:08:03 +02:00
|
|
|
zlog_debug(
|
2020-03-06 15:23:22 +01:00
|
|
|
"%s: %s %s eom: %d join %u", __func__,
|
2017-03-17 18:46:47 +01:00
|
|
|
pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags),
|
pimd: Fix WG/SGRpt & WG J/P processing
During processing of Join/Prune,
for a S,G entry, current state is SGRpt, when only *,G is
received, need to clear SGRpt and add/inherit the *,G OIF to S,G so
it can forward traffic to downstream where *,G is received.
Upon receiving SGRpt prune remove the inherited *,G OIF.
Testing Done:
Trigger SPT switchover, *,G path received SGRpt later data
traffic stopped S,G ages out from LHR, sends only
*,G join to upstream, verified S,G entry inherit the OIF.
Upon receiving SGRpt deletes inherited oif and retains in SGRpt state.
Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2017-04-22 00:08:03 +02:00
|
|
|
ch->sg_str, eom, join);
|
2016-11-08 21:26:48 +01:00
|
|
|
if (!ch->sources)
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-09-14 01:43:39 +02:00
|
|
|
for (ALL_LIST_ELEMENTS(ch->sources, ch_node, nch_node, child)) {
|
2016-11-08 21:26:48 +01:00
|
|
|
if (!PIM_IF_FLAG_TEST_S_G_RPT(child->flags))
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-08 21:26:48 +01:00
|
|
|
switch (child->ifjoin_state) {
|
2016-11-10 16:25:36 +01:00
|
|
|
case PIM_IFJOIN_NOINFO:
|
|
|
|
case PIM_IFJOIN_JOIN:
|
|
|
|
break;
|
|
|
|
case PIM_IFJOIN_PRUNE:
|
|
|
|
if (!eom)
|
|
|
|
child->ifjoin_state = PIM_IFJOIN_PRUNE_TMP;
|
|
|
|
break;
|
|
|
|
case PIM_IFJOIN_PRUNE_PENDING:
|
|
|
|
if (!eom)
|
|
|
|
child->ifjoin_state =
|
|
|
|
PIM_IFJOIN_PRUNE_PENDING_TMP;
|
|
|
|
break;
|
|
|
|
case PIM_IFJOIN_PRUNE_TMP:
|
|
|
|
case PIM_IFJOIN_PRUNE_PENDING_TMP:
|
2017-09-14 01:43:39 +02:00
|
|
|
if (!eom)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (child->ifjoin_state == PIM_IFJOIN_PRUNE_PENDING_TMP)
|
|
|
|
THREAD_OFF(child->t_ifjoin_prune_pending_timer);
|
|
|
|
THREAD_OFF(child->t_ifjoin_expiry_timer);
|
|
|
|
|
|
|
|
PIM_IF_FLAG_UNSET_S_G_RPT(child->flags);
|
|
|
|
child->ifjoin_state = PIM_IFJOIN_NOINFO;
|
|
|
|
|
2019-05-16 18:55:34 +02:00
|
|
|
if ((I_am_RP(pim, child->sg.grp)) &&
|
|
|
|
(!pim_upstream_empty_inherited_olist(
|
|
|
|
child->upstream))) {
|
2017-09-14 01:43:39 +02:00
|
|
|
pim_channel_add_oif(
|
|
|
|
child->upstream->channel_oil,
|
2019-11-15 17:47:33 +01:00
|
|
|
ch->interface, PIM_OIF_FLAG_PROTO_STAR,
|
|
|
|
__func__);
|
2019-11-15 20:21:11 +01:00
|
|
|
pim_upstream_update_join_desired(pim,
|
|
|
|
child->upstream);
|
2017-08-24 15:55:19 +02:00
|
|
|
}
|
pimd: Only send triggered response after all of *,G message is read
pim was sending a triggered response on every S,G RPT prune information
read. Suppose we had this in a *,G message:
*,G
S1, G RPT Prune
S2, G RPT Prune
We would send two triggered *,G messages upstream. This leads to over
processing and quickly changing state if S1 or S2 were in different
states.
Modify the code to send just one Triggered *,G upstream after looking
at all S,G state for a *,G.
Ticket: CM-24531
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
2019-04-09 00:02:45 +02:00
|
|
|
send_upstream_starg = true;
|
2017-09-14 01:43:39 +02:00
|
|
|
|
|
|
|
delete_on_noinfo(child);
|
2016-11-10 16:25:36 +01:00
|
|
|
break;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2016-11-10 16:25:36 +01:00
|
|
|
}
|
pimd: Only send triggered response after all of *,G message is read
pim was sending a triggered response on every S,G RPT prune information
read. Suppose we had this in a *,G message:
*,G
S1, G RPT Prune
S2, G RPT Prune
We would send two triggered *,G messages upstream. This leads to over
processing and quickly changing state if S1 or S2 were in different
states.
Modify the code to send just one Triggered *,G upstream after looking
at all S,G state for a *,G.
Ticket: CM-24531
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
2019-04-09 00:02:45 +02:00
|
|
|
|
|
|
|
if (send_upstream_starg)
|
|
|
|
pim_jp_agg_single_upstream_send(&starup->rpf, starup, true);
|
2016-11-08 21:26:48 +01:00
|
|
|
}
|
2017-02-13 02:16:08 +01:00
|
|
|
|
2019-05-14 22:19:07 +02:00
|
|
|
unsigned int pim_ifchannel_hash_key(const void *arg)
|
2017-02-13 02:16:08 +01:00
|
|
|
{
|
2019-05-14 22:19:07 +02:00
|
|
|
const struct pim_ifchannel *ch = arg;
|
2017-02-13 02:16:08 +01:00
|
|
|
|
|
|
|
return jhash_2words(ch->sg.src.s_addr, ch->sg.grp.s_addr, 0);
|
|
|
|
}
|