diff options
Diffstat (limited to 'pimd')
| -rw-r--r-- | pimd/pim_ifchannel.c | 45 | ||||
| -rw-r--r-- | pimd/pim_join.c | 21 |
2 files changed, 60 insertions, 6 deletions
diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index 212c77c039..b2971e5f1f 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -950,14 +950,44 @@ void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr, pim_ifchannel_ifjoin_handler(ch, pim_ifp); break; case PIM_IFJOIN_PRUNE_PENDING: + /* + * 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. + */ THREAD_OFF(ch->t_ifjoin_prune_pending_timer); - if (source_flags & PIM_ENCODE_RPT_BIT) { + + /* Check if SGRpt join Received */ + if ((source_flags & PIM_ENCODE_RPT_BIT) + && (sg->src.s_addr != INADDR_ANY)) { + /* + * 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. + */ THREAD_OFF(ch->t_ifjoin_expiry_timer); pim_ifchannel_ifjoin_switch(__func__, ch, PIM_IFJOIN_NOINFO); - } else { - pim_ifchannel_ifjoin_handler(ch, pim_ifp); + 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; + } + break; case PIM_IFJOIN_PRUNE_TMP: break; @@ -1034,7 +1064,14 @@ void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream, /* nothing to do */ break; case PIM_IFJOIN_JOIN: - THREAD_OFF(ch->t_ifjoin_expiry_timer); + /* + * 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. + */ pim_ifchannel_ifjoin_switch(__func__, ch, PIM_IFJOIN_PRUNE_PENDING); diff --git a/pimd/pim_join.c b/pimd/pim_join.c index 3a88de2070..f54d5bf9bf 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -173,6 +173,8 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, uint8_t *pastend; int remain; int group; + struct pim_ifchannel *child = NULL; + struct listnode *ch_node, *nch_node; buf = tlv_buf; pastend = tlv_buf + tlv_buf_size; @@ -337,9 +339,24 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, */ sg_ch = pim_ifchannel_find(ifp, &sg); + if (!sg_ch) + continue; + + /* (*,G) prune received */ + for (ALL_LIST_ELEMENTS(sg_ch->sources, ch_node, + nch_node, child)) { + if (PIM_IF_FLAG_TEST_S_G_RPT(child->flags)) { + if (child->ifjoin_state + == PIM_IFJOIN_PRUNE_PENDING_TMP) + THREAD_OFF( + child->t_ifjoin_prune_pending_timer); + PIM_IF_FLAG_UNSET_S_G_RPT(child->flags); + child->ifjoin_state = PIM_IFJOIN_NOINFO; + } + } + /* Received SG-RPT Prune delete oif from specific S,G */ - if (starg_ch && sg_ch - && (msg_source_flags & PIM_RPT_BIT_MASK) + if (starg_ch && (msg_source_flags & PIM_RPT_BIT_MASK) && !(msg_source_flags & PIM_WILDCARD_BIT_MASK)) { struct pim_upstream *up = sg_ch->upstream; PIM_IF_FLAG_SET_S_G_RPT(sg_ch->flags); |
