pimd: fixup join desired handling to match the RFC defined macro

This commit includes the following changes -
1. kat needs to be included when evaluting join desired on a (S,G)
   entry.
2. there were cases where we were adding OIF based on joindesired
   being true for unrelated reasons (on other OIFs). cleaned up those
   cases.
3. make all calls to pim_upstream_switch conditional on the JoinDesired
   macro.

Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
This commit is contained in:
Anuradha Karuppiah 2019-11-15 11:21:11 -08:00
parent a749b90041
commit a53a9b3e6b
4 changed files with 126 additions and 64 deletions

View File

@ -252,6 +252,7 @@ void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch,
{ {
enum pim_ifjoin_state old_state = ch->ifjoin_state; enum pim_ifjoin_state old_state = ch->ifjoin_state;
struct pim_interface *pim_ifp = ch->interface->info; struct pim_interface *pim_ifp = ch->interface->info;
struct pim_ifchannel *child_ch;
if (PIM_DEBUG_PIM_EVENTS) if (PIM_DEBUG_PIM_EVENTS)
zlog_debug( zlog_debug(
@ -295,23 +296,12 @@ void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch,
if (!c_oil) if (!c_oil)
continue; continue;
if (!pim_upstream_evaluate_join_desired(
pim_ifp->pim, child)) {
pim_channel_del_oif(
c_oil, ch->interface,
PIM_OIF_FLAG_PROTO_STAR,
__func__);
pim_upstream_update_join_desired(
pim_ifp->pim, child);
}
/* /*
* If the S,G has no if channel and the * If the S,G has no if channel and the
* c_oil still * c_oil still
* has output here then the *,G was * has output here then the *,G was
* supplying the implied * supplying the implied
* if channel. So remove it. * if channel. So remove it.
* I think this is dead code now. is it?
*/ */
if (c_oil->oil.mfcc_ttls if (c_oil->oil.mfcc_ttls
[pim_ifp->mroute_vif_index]) [pim_ifp->mroute_vif_index])
@ -332,8 +322,14 @@ void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch,
child->sg_str, child->sg_str,
up->sg_str); up->sg_str);
if (pim_upstream_evaluate_join_desired( /* check if the channel can be
pim_ifp->pim, child)) { * 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)) {
pim_channel_add_oif( pim_channel_add_oif(
child->channel_oil, child->channel_oil,
ch->interface, ch->interface,
@ -905,14 +901,18 @@ void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr,
pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch,
PIM_IFJOIN_JOIN); PIM_IFJOIN_JOIN);
PIM_IF_FLAG_UNSET_S_G_RPT(ch->flags); PIM_IF_FLAG_UNSET_S_G_RPT(ch->flags);
if (pim_upstream_evaluate_join_desired(pim_ifp->pim, /* check if the interface qualifies as an immediate
ch->upstream)) { * OIF
*/
if (pim_upstream_evaluate_join_desired_interface(
ch->upstream, ch,
NULL /*starch*/)) {
pim_channel_add_oif(ch->upstream->channel_oil, pim_channel_add_oif(ch->upstream->channel_oil,
ch->interface, ch->interface,
PIM_OIF_FLAG_PROTO_PIM, PIM_OIF_FLAG_PROTO_PIM,
__func__); __func__);
pim_upstream_update_join_desired(pim_ifp->pim, pim_upstream_update_join_desired(pim_ifp->pim,
ch->upstream); ch->upstream);
} }
} }
break; break;
@ -1113,8 +1113,7 @@ int pim_ifchannel_local_membership_add(struct interface *ifp,
pim_channel_add_oif(child->channel_oil, ifp, pim_channel_add_oif(child->channel_oil, ifp,
PIM_OIF_FLAG_PROTO_STAR, PIM_OIF_FLAG_PROTO_STAR,
__func__); __func__);
pim_upstream_switch(pim, child, pim_upstream_update_join_desired(pim, child);
PIM_UPSTREAM_JOINED);
} }
} }
@ -1421,8 +1420,8 @@ void pim_ifchannel_set_star_g_join_state(struct pim_ifchannel *ch, int eom,
child->upstream->channel_oil, child->upstream->channel_oil,
ch->interface, PIM_OIF_FLAG_PROTO_STAR, ch->interface, PIM_OIF_FLAG_PROTO_STAR,
__func__); __func__);
pim_upstream_switch(pim, child->upstream, pim_upstream_update_join_desired(pim,
PIM_UPSTREAM_JOINED); child->upstream);
pim_jp_agg_single_upstream_send( pim_jp_agg_single_upstream_send(
&child->upstream->rpf, child->upstream, &child->upstream->rpf, child->upstream,
true); true);

View File

@ -277,8 +277,7 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp,
pim_upstream_keep_alive_timer_start( pim_upstream_keep_alive_timer_start(
up, pim_ifp->pim->keep_alive_time); up, pim_ifp->pim->keep_alive_time);
pim_upstream_inherited_olist(pim_ifp->pim, up); pim_upstream_inherited_olist(pim_ifp->pim, up);
pim_upstream_switch(pim_ifp->pim, up, pim_upstream_update_join_desired(pim_ifp->pim, up);
PIM_UPSTREAM_JOINED);
if (PIM_DEBUG_MROUTE) if (PIM_DEBUG_MROUTE)
zlog_debug("%s: Creating %s upstream on LHR", zlog_debug("%s: Creating %s upstream on LHR",

View File

@ -949,6 +949,36 @@ struct pim_upstream *pim_upstream_add(struct pim_instance *pim,
return up; return up;
} }
/*
* Passed in up must be the upstream for ch. starch is NULL if no
* information
* This function is copied over from
* pim_upstream_evaluate_join_desired_interface but limited to
* parent (*,G)'s includes/joins.
*/
int pim_upstream_eval_inherit_if(struct pim_upstream *up,
struct pim_ifchannel *ch,
struct pim_ifchannel *starch)
{
/* if there is an explicit prune for this interface we cannot
* add it to the OIL
*/
if (ch) {
if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
return 0;
}
/* Check if the OIF can be inherited fron the (*,G) entry
*/
if (starch) {
if (!pim_macro_ch_lost_assert(starch)
&& pim_macro_chisin_joins_or_include(starch))
return 1;
}
return 0;
}
/* /*
* Passed in up must be the upstream for ch. starch is NULL if no * Passed in up must be the upstream for ch. starch is NULL if no
* information * information
@ -970,8 +1000,14 @@ int pim_upstream_evaluate_join_desired_interface(struct pim_upstream *up,
* joins (*,G) * joins (*,G)
*/ */
if (starch) { if (starch) {
/* XXX: check on this with donald
* we are looking for PIM_IF_FLAG_MASK_S_G_RPT in
* upstream flags?
*/
#if 0
if (PIM_IF_FLAG_TEST_S_G_RPT(starch->upstream->flags)) if (PIM_IF_FLAG_TEST_S_G_RPT(starch->upstream->flags))
return 0; return 0;
#endif
if (!pim_macro_ch_lost_assert(starch) if (!pim_macro_ch_lost_assert(starch)
&& pim_macro_chisin_joins_or_include(starch)) && pim_macro_chisin_joins_or_include(starch))
@ -981,56 +1017,76 @@ int pim_upstream_evaluate_join_desired_interface(struct pim_upstream *up,
return 0; return 0;
} }
/* /* Returns true if immediate OIL is empty and is used to evaluate
Evaluate JoinDesired(S,G): * JoinDesired. See pim_upstream_evaluate_join_desired.
JoinDesired(S,G) is true if there is a downstream (S,G) interface I
in the set:
inherited_olist(S,G) =
joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
JoinDesired(S,G) may be affected by changes in the following:
pim_ifp->primary_address
pim_ifp->pim_dr_addr
ch->ifassert_winner_metric
ch->ifassert_winner
ch->local_ifmembership
ch->ifjoin_state
ch->upstream->rpf.source_nexthop.mrib_metric_preference
ch->upstream->rpf.source_nexthop.mrib_route_metric
ch->upstream->rpf.source_nexthop.interface
See also pim_upstream_update_join_desired() below.
*/ */
int pim_upstream_evaluate_join_desired(struct pim_instance *pim, static bool pim_upstream_empty_immediate_olist(struct pim_instance *pim,
struct pim_upstream *up) struct pim_upstream *up)
{ {
struct interface *ifp; struct interface *ifp;
struct pim_ifchannel *ch, *starch; struct pim_ifchannel *ch;
struct pim_upstream *starup = up->parent;
int ret = 0;
FOR_ALL_INTERFACES (pim->vrf, ifp) { FOR_ALL_INTERFACES (pim->vrf, ifp) {
if (!ifp->info) if (!ifp->info)
continue; continue;
ch = pim_ifchannel_find(ifp, &up->sg); ch = pim_ifchannel_find(ifp, &up->sg);
if (!ch)
if (starup)
starch = pim_ifchannel_find(ifp, &starup->sg);
else
starch = NULL;
if (!ch && !starch)
continue; continue;
ret += pim_upstream_evaluate_join_desired_interface(up, ch, /* If we have even one immediate OIF we can return with
starch); * not-empty
*/
if (pim_upstream_evaluate_join_desired_interface(up, ch,
NULL /* starch */))
return false;
} /* scan iface channel list */ } /* scan iface channel list */
return ret; /* false */ /* immediate_oil is empty */
return true;
}
static bool pim_upstream_is_kat_running(struct pim_upstream *up)
{
return (up->t_ka_timer != NULL);
}
/*
* bool JoinDesired(*,G) {
* if (immediate_olist(*,G) != NULL)
* return TRUE
* else
* return FALSE
* }
*
* bool JoinDesired(S,G) {
* return( immediate_olist(S,G) != NULL
* OR ( KeepaliveTimer(S,G) is running
* AND inherited_olist(S,G) != NULL ) )
* }
*/
int pim_upstream_evaluate_join_desired(struct pim_instance *pim,
struct pim_upstream *up)
{
bool empty_imm_oil;
bool empty_inh_oil;
empty_imm_oil = pim_upstream_empty_immediate_olist(pim, up);
/* (*,G) */
if (up->sg.src.s_addr == INADDR_ANY)
return !empty_imm_oil;
/* (S,G) */
if (!empty_imm_oil)
return true;
empty_inh_oil = pim_upstream_empty_inherited_olist(up);
if (!empty_inh_oil &&
(pim_upstream_is_kat_running(up) ||
I_am_RP(pim, up->sg.grp)))
return true;
return false;
} }
/* /*
@ -1257,6 +1313,9 @@ struct pim_upstream *pim_upstream_keep_alive_timer_proc(
/* source is no longer active - pull the SA from MSDP's cache */ /* source is no longer active - pull the SA from MSDP's cache */
pim_msdp_sa_local_del(pim, &up->sg); pim_msdp_sa_local_del(pim, &up->sg);
/* JoinDesired can change when KAT is started or stopped */
pim_upstream_update_join_desired(pim, up);
/* if entry was created because of activity we need to deref it */ /* if entry was created because of activity we need to deref it */
if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) { if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
pim_upstream_fhr_kat_expiry(pim, up); pim_upstream_fhr_kat_expiry(pim, up);
@ -1319,6 +1378,8 @@ void pim_upstream_keep_alive_timer_start(struct pim_upstream *up, uint32_t time)
/* any time keepalive is started against a SG we will have to /* any time keepalive is started against a SG we will have to
* re-evaluate our active source database */ * re-evaluate our active source database */
pim_msdp_sa_local_update(up); pim_msdp_sa_local_update(up);
/* JoinDesired can change when KAT is started or stopped */
pim_upstream_update_join_desired(up->pim, up);
} }
/* MSDP on RP needs to know if a source is registerable to this RP */ /* MSDP on RP needs to know if a source is registerable to this RP */
@ -1669,9 +1730,9 @@ int pim_upstream_inherited_olist(struct pim_instance *pim,
* switch on a stick so turn on forwarding to just accept the * switch on a stick so turn on forwarding to just accept the
* incoming packets so we don't bother the other stuff! * incoming packets so we don't bother the other stuff!
*/ */
if (output_intf) pim_upstream_update_join_desired(pim, up);
pim_upstream_switch(pim, up, PIM_UPSTREAM_JOINED);
else if (!output_intf)
forward_on(up); forward_on(up);
return output_intf; return output_intf;

View File

@ -262,6 +262,9 @@ int pim_upstream_evaluate_join_desired(struct pim_instance *pim,
int pim_upstream_evaluate_join_desired_interface(struct pim_upstream *up, int pim_upstream_evaluate_join_desired_interface(struct pim_upstream *up,
struct pim_ifchannel *ch, struct pim_ifchannel *ch,
struct pim_ifchannel *starch); struct pim_ifchannel *starch);
int pim_upstream_eval_inherit_if(struct pim_upstream *up,
struct pim_ifchannel *ch,
struct pim_ifchannel *starch);
void pim_upstream_update_join_desired(struct pim_instance *pim, void pim_upstream_update_join_desired(struct pim_instance *pim,
struct pim_upstream *up); struct pim_upstream *up);