summaryrefslogtreecommitdiff
path: root/pimd
diff options
context:
space:
mode:
Diffstat (limited to 'pimd')
-rw-r--r--pimd/pim_ifchannel.c45
-rw-r--r--pimd/pim_join.c21
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);