pimd: Cleanup S,GRPt prune handling on Mroute Loss

1) Clean up display of S,GRPt prune state to be more meaningful
2) Upon receipt of a S,GRPt prune make sure we transition to
   the correct state
3) Upon loss of a S,GRPt prune make sure we transition to
   the correct state as well as immediately send a *,G
   join upstream to propagate the loss of the prune.
4) Removal of a weird S,G state being installed upon
   loss of a S,G RPt prune.

Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
This commit is contained in:
Donald Sharp 2017-08-24 09:55:19 -04:00
parent 6c65db5f99
commit c206937b91
4 changed files with 70 additions and 67 deletions

View file

@ -1666,7 +1666,7 @@ static void pim_show_join_helper(struct vty *vty,
json_row); json_row);
} else { } else {
vty_out(vty, vty_out(vty,
"%-9s %-15s %-15s %-15s %-6s %8s %-6s %5s\n", "%-9s %-15s %-15s %-15s %-10s %8s %-6s %5s\n",
ch->interface->name, inet_ntoa(ifaddr), ch->interface->name, inet_ntoa(ifaddr),
ch_src_str, ch_grp_str, ch_src_str, ch_grp_str,
pim_ifchannel_ifjoin_name(ch->ifjoin_state, pim_ifchannel_ifjoin_name(ch->ifjoin_state,
@ -1690,7 +1690,7 @@ static void pim_show_join(struct pim_instance *pim, struct vty *vty, u_char uj)
json = json_object_new_object(); json = json_object_new_object();
else else
vty_out(vty, vty_out(vty,
"Interface Address Source Group State Uptime Expire Prune\n"); "Interface Address Source Group State Uptime Expire Prune\n");
for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), if_node, ifp)) { for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), if_node, ifp)) {
pim_ifp = ifp->info; pim_ifp = ifp->info;

View file

@ -42,6 +42,7 @@
#include "pim_oil.h" #include "pim_oil.h"
#include "pim_upstream.h" #include "pim_upstream.h"
#include "pim_ssm.h" #include "pim_ssm.h"
#include "pim_rp.h"
RB_GENERATE(pim_ifchannel_rb, pim_ifchannel, RB_GENERATE(pim_ifchannel_rb, pim_ifchannel,
pim_ifp_rb, pim_ifchannel_compare); pim_ifp_rb, pim_ifchannel_compare);
@ -348,7 +349,7 @@ const char *pim_ifchannel_ifjoin_name(enum pim_ifjoin_state ifjoin_state,
switch (ifjoin_state) { switch (ifjoin_state) {
case PIM_IFJOIN_NOINFO: case PIM_IFJOIN_NOINFO:
if (PIM_IF_FLAG_TEST_S_G_RPT(flags)) if (PIM_IF_FLAG_TEST_S_G_RPT(flags))
return "SGRpt"; return "SGRpt(NI)";
else else
return "NOINFO"; return "NOINFO";
break; break;
@ -356,16 +357,28 @@ const char *pim_ifchannel_ifjoin_name(enum pim_ifjoin_state ifjoin_state,
return "JOIN"; return "JOIN";
break; break;
case PIM_IFJOIN_PRUNE: case PIM_IFJOIN_PRUNE:
return "PRUNE"; if (PIM_IF_FLAG_TEST_S_G_RPT(flags))
return "SGRpt(P)";
else
return "PRUNE";
break; break;
case PIM_IFJOIN_PRUNE_PENDING: case PIM_IFJOIN_PRUNE_PENDING:
return "PRUNEP"; if (PIM_IF_FLAG_TEST_S_G_RPT(flags))
return "SGRpt(PP)";
else
return "PRUNEP";
break; break;
case PIM_IFJOIN_PRUNE_TMP: case PIM_IFJOIN_PRUNE_TMP:
return "PRUNET"; if (PIM_IF_FLAG_TEST_S_G_RPT(flags))
return "SGRpt(P')";
else
return "PRUNET";
break; break;
case PIM_IFJOIN_PRUNE_PENDING_TMP: case PIM_IFJOIN_PRUNE_PENDING_TMP:
return "PRUNEPT"; if (PIM_IF_FLAG_TEST_S_G_RPT(flags))
return "SGRpt(PP')";
else
return "PRUNEPT";
break; break;
} }
@ -628,33 +641,34 @@ static int on_ifjoin_prune_pending_timer(struct thread *t)
ch = THREAD_ARG(t); ch = THREAD_ARG(t);
if (ch->ifjoin_state == PIM_IFJOIN_PRUNE_PENDING) { if (ch->ifjoin_state == PIM_IFJOIN_PRUNE_PENDING) {
/* Send PruneEcho(S,G) ? */
ifp = ch->interface; ifp = ch->interface;
pim_ifp = ifp->info; pim_ifp = ifp->info;
send_prune_echo = (listcount(pim_ifp->pim_neighbor_list) > 1); 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) { if (send_prune_echo) {
struct pim_rpf rpf; struct pim_rpf rpf;
rpf.source_nexthop.interface = ifp; rpf.source_nexthop.interface = ifp;
rpf.rpf_addr.u.prefix4 = pim_ifp->primary_address; rpf.rpf_addr.u.prefix4 =
pim_jp_agg_single_upstream_send(&rpf, ch->upstream, 0); pim_ifp->primary_address;
} pim_jp_agg_single_upstream_send(&rpf,
/* If SGRpt flag is set on ifchannel, Trigger SGRpt ch->upstream,
message on RP path upon prune timer expiry. 0);
*/ }
if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)) {
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;
if (ch->upstream) if (ch->upstream)
pim_upstream_update_join_desired(pim_ifp->pim, pim_upstream_update_join_desired(pim_ifp->pim,
ch->upstream); ch->upstream);
/* }
ch->ifjoin_state transition to NOINFO state
ch_del is set to 0 for not deleteing from here.
Holdtime expiry (ch_del set to 1) delete the entry.
*/
ifjoin_to_noinfo(ch, false);
} else
ifjoin_to_noinfo(ch, true);
/* from here ch may have been deleted */ /* from here ch may have been deleted */
} else { } else {
zlog_warn( zlog_warn(
@ -1104,7 +1118,6 @@ void pim_ifchannel_local_membership_del(struct interface *ifp,
orig = ch = pim_ifchannel_find(ifp, sg); orig = ch = pim_ifchannel_find(ifp, sg);
if (!ch) if (!ch)
return; return;
ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO); ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO);
if (sg->src.s_addr == INADDR_ANY) { if (sg->src.s_addr == INADDR_ANY) {
@ -1311,11 +1324,12 @@ void pim_ifchannel_scan_forward_start(struct interface *new_ifp)
* we get End of Message * we get End of Message
*/ */
void pim_ifchannel_set_star_g_join_state(struct pim_ifchannel *ch, int eom, void pim_ifchannel_set_star_g_join_state(struct pim_ifchannel *ch, int eom,
uint8_t source_flags, uint8_t join, uint8_t join)
uint8_t starg_alone)
{ {
struct pim_ifchannel *child; struct pim_ifchannel *child;
struct listnode *ch_node; struct listnode *ch_node;
struct pim_instance *pim =
((struct pim_interface *)ch->interface->info)->pim;
if (PIM_DEBUG_PIM_TRACE) if (PIM_DEBUG_PIM_TRACE)
zlog_debug( zlog_debug(
@ -1326,33 +1340,6 @@ void pim_ifchannel_set_star_g_join_state(struct pim_ifchannel *ch, int eom,
return; return;
for (ALL_LIST_ELEMENTS_RO(ch->sources, ch_node, child)) { for (ALL_LIST_ELEMENTS_RO(ch->sources, ch_node, child)) {
/* Only *,G Join received and no (SG-RPT) prune.
eom = 1, only (W,G) join_alone is true, WC and RPT are set.
Scan all S,G associated to G and if any SG-RPT
remove the SG-RPT flag.
*/
if (eom && starg_alone && (source_flags & PIM_RPT_BIT_MASK)
&& (source_flags & PIM_WILDCARD_BIT_MASK)) {
if (PIM_IF_FLAG_TEST_S_G_RPT(child->flags)) {
struct pim_upstream *up = child->upstream;
PIM_IF_FLAG_UNSET_S_G_RPT(child->flags);
if (up) {
if (PIM_DEBUG_TRACE)
zlog_debug(
"%s: SGRpt flag is cleared, add inherit oif to up %s",
__PRETTY_FUNCTION__,
up->sg_str);
pim_channel_add_oif(
up->channel_oil, ch->interface,
PIM_OIF_FLAG_PROTO_STAR);
pim_ifchannel_ifjoin_switch(
__PRETTY_FUNCTION__, child,
PIM_IFJOIN_JOIN);
}
}
}
if (!PIM_IF_FLAG_TEST_S_G_RPT(child->flags)) if (!PIM_IF_FLAG_TEST_S_G_RPT(child->flags))
continue; continue;
@ -1371,8 +1358,30 @@ void pim_ifchannel_set_star_g_join_state(struct pim_ifchannel *ch, int eom,
break; break;
case PIM_IFJOIN_PRUNE_TMP: case PIM_IFJOIN_PRUNE_TMP:
case PIM_IFJOIN_PRUNE_PENDING_TMP: case PIM_IFJOIN_PRUNE_PENDING_TMP:
if (eom) if (eom) {
struct pim_upstream *parent =
child->upstream->parent;
PIM_IF_FLAG_UNSET_S_G_RPT(child->flags);
child->ifjoin_state = PIM_IFJOIN_NOINFO; child->ifjoin_state = PIM_IFJOIN_NOINFO;
if (I_am_RP(pim, child->sg.grp)) {
pim_channel_add_oif(
child->upstream->channel_oil,
ch->interface,
PIM_OIF_FLAG_PROTO_STAR);
pim_upstream_switch(
pim, child->upstream,
PIM_UPSTREAM_JOINED);
pim_jp_agg_single_upstream_send(
&child->upstream->rpf,
child->upstream, true);
}
if (parent)
pim_jp_agg_single_upstream_send(
&parent->rpf,
parent, true);
}
break; break;
} }
} }

View file

@ -151,8 +151,7 @@ void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch);
void pim_ifchannel_scan_forward_start(struct interface *new_ifp); void pim_ifchannel_scan_forward_start(struct interface *new_ifp);
void pim_ifchannel_set_star_g_join_state(struct pim_ifchannel *ch, int eom, void pim_ifchannel_set_star_g_join_state(struct pim_ifchannel *ch, int eom,
uint8_t source_flags, uint8_t join, uint8_t join);
uint8_t starg_alone);
int pim_ifchannel_compare(const struct pim_ifchannel *ch1, int pim_ifchannel_compare(const struct pim_ifchannel *ch1,
const struct pim_ifchannel *ch2); const struct pim_ifchannel *ch2);

View file

@ -231,7 +231,6 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh,
uint16_t msg_num_pruned_sources; uint16_t msg_num_pruned_sources;
int source; int source;
struct pim_ifchannel *starg_ch = NULL, *sg_ch = NULL; struct pim_ifchannel *starg_ch = NULL, *sg_ch = NULL;
uint8_t starg_alone = 0;
memset(&sg, 0, sizeof(struct prefix_sg)); memset(&sg, 0, sizeof(struct prefix_sg));
addr_offset = pim_parse_addr_group(&sg, buf, pastend - buf); addr_offset = pim_parse_addr_group(&sg, buf, pastend - buf);
@ -289,12 +288,10 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh,
msg_source_flags); msg_source_flags);
if (sg.src.s_addr == INADDR_ANY) { if (sg.src.s_addr == INADDR_ANY) {
starg_alone = 1;
starg_ch = pim_ifchannel_find(ifp, &sg); starg_ch = pim_ifchannel_find(ifp, &sg);
if (starg_ch) if (starg_ch)
pim_ifchannel_set_star_g_join_state( pim_ifchannel_set_star_g_join_state(
starg_ch, 0, msg_source_flags, starg_ch, 0, 1);
1, starg_alone);
} }
} }
@ -307,7 +304,6 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh,
} }
buf += addr_offset; buf += addr_offset;
starg_alone = 0;
recv_prune(ifp, neigh, msg_holdtime, recv_prune(ifp, neigh, msg_holdtime,
msg_upstream_addr.u.prefix4, &sg, msg_upstream_addr.u.prefix4, &sg,
msg_source_flags); msg_source_flags);
@ -340,8 +336,7 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh,
} }
} }
if (starg_ch) if (starg_ch)
pim_ifchannel_set_star_g_join_state( pim_ifchannel_set_star_g_join_state(starg_ch, 1, 0);
starg_ch, 1, msg_source_flags, 0, starg_alone);
starg_ch = NULL; starg_ch = NULL;
} /* scan groups */ } /* scan groups */