diff options
Diffstat (limited to 'pimd/pim_ifchannel.c')
| -rw-r--r-- | pimd/pim_ifchannel.c | 142 |
1 files changed, 108 insertions, 34 deletions
diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index ebd36f8782..f4fe609605 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -27,6 +27,7 @@ #include "vrf.h" #include "hash.h" #include "jhash.h" +#include "prefix.h" #include "pimd.h" #include "pim_str.h" @@ -49,30 +50,25 @@ pim_ifchannel_compare (struct pim_ifchannel *ch1, struct pim_ifchannel *ch2) struct pim_interface *pim_ifp1; struct pim_interface *pim_ifp2; - if (ntohl(ch1->sg.grp.s_addr) < ntohl(ch2->sg.grp.s_addr)) - return -1; - - if (ntohl(ch1->sg.grp.s_addr) > ntohl(ch2->sg.grp.s_addr)) - return 1; + pim_ifp1 = ch1->interface->info; + pim_ifp2 = ch2->interface->info; - if (ntohl(ch1->sg.src.s_addr) < ntohl(ch2->sg.src.s_addr)) + if (pim_ifp1->mroute_vif_index < pim_ifp2->mroute_vif_index) return -1; - if (ntohl(ch1->sg.src.s_addr) > ntohl(ch2->sg.src.s_addr)) + if (pim_ifp1->mroute_vif_index > pim_ifp2->mroute_vif_index) return 1; - pim_ifp1 = ch1->interface->info; - pim_ifp2 = ch2->interface->info; - if (ntohl(pim_ifp1->primary_address.s_addr) < ntohl(pim_ifp2->primary_address.s_addr)) + if (ntohl(ch1->sg.grp.s_addr) < ntohl(ch2->sg.grp.s_addr)) return -1; - if (ntohl(pim_ifp1->primary_address.s_addr) > ntohl(pim_ifp2->primary_address.s_addr)) + if (ntohl(ch1->sg.grp.s_addr) > ntohl(ch2->sg.grp.s_addr)) return 1; - if (pim_ifp1->mroute_vif_index < pim_ifp2->mroute_vif_index) + if (ntohl(ch1->sg.src.s_addr) < ntohl(ch2->sg.src.s_addr)) return -1; - if (pim_ifp1->mroute_vif_index > pim_ifp2->mroute_vif_index) + if (ntohl(ch1->sg.src.s_addr) > ntohl(ch2->sg.src.s_addr)) return 1; return 0; @@ -149,6 +145,9 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch) if (ch->upstream->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP) mask = PIM_OIF_FLAG_PROTO_IGMP; + /* SGRpt entry could have empty oil */ + if (ch->upstream->channel_oil) + pim_channel_del_oif (ch->upstream->channel_oil, ch->interface, mask); pim_channel_del_oif (ch->upstream->channel_oil, ch->interface, mask); /* * Do we have any S,G's that are inheriting? @@ -174,6 +173,8 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch) if (ch->sources) list_delete (ch->sources); + listnode_delete(ch->upstream->ifchannels, ch); + if (ch->ifjoin_state != PIM_IFJOIN_NOINFO) { pim_upstream_update_join_desired(ch->upstream); } @@ -568,6 +569,8 @@ pim_ifchannel_add(struct interface *ifp, ch = hash_get (pim_ifp->pim_ifchannel_hash, ch, hash_alloc_intern); listnode_add_sort(pim_ifchannel_list, ch); + listnode_add_sort(up->ifchannels, ch); + return ch; } @@ -610,6 +613,7 @@ static int on_ifjoin_prune_pending_timer(struct thread *t) pim_ifp = ifp->info; send_prune_echo = (listcount(pim_ifp->pim_neighbor_list) > 1); + //ch->ifjoin_state transition to NOINFO ifjoin_to_noinfo(ch); /* from here ch may have been deleted */ @@ -790,6 +794,16 @@ void pim_ifchannel_join_add(struct interface *ifp, pim_upstream_inherited_olist (ch->upstream); pim_forward_start(ch); } + /* + * If we are going to be a LHR, we need to note it + */ + if (ch->upstream->parent && + (ch->upstream->parent->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP) && + !(ch->upstream->flags & PIM_UPSTREAM_FLAG_MASK_SRC_LHR)) + { + pim_upstream_ref (ch->upstream, PIM_UPSTREAM_FLAG_MASK_SRC_LHR); + pim_upstream_keep_alive_timer_start (ch->upstream, qpim_keep_alive_time); + } break; case PIM_IFJOIN_JOIN: zassert(!ch->t_ifjoin_prune_pending_timer); @@ -958,7 +972,7 @@ int pim_ifchannel_local_membership_add(struct interface *ifp, struct prefix_sg *sg) { - struct pim_ifchannel *ch; + struct pim_ifchannel *ch, *starch; struct pim_interface *pim_ifp; /* PIM enabled on interface? */ @@ -993,21 +1007,41 @@ pim_ifchannel_local_membership_add(struct interface *ifp, struct pim_upstream *child; struct listnode *up_node; + starch = ch; + for (ALL_LIST_ELEMENTS_RO (up->sources, up_node, child)) { - if (PIM_DEBUG_EVENTS) - zlog_debug("%s %s: IGMP (S,G)=%s(%s) from %s", - __FILE__, __PRETTY_FUNCTION__, - child->sg_str, ifp->name, up->sg_str); + if (PIM_DEBUG_EVENTS) + zlog_debug("%s %s: IGMP (S,G)=%s(%s) from %s", + __FILE__, __PRETTY_FUNCTION__, + child->sg_str, ifp->name, up->sg_str); - if (pim_upstream_evaluate_join_desired_interface (child, ch)) - { - pim_channel_add_oif (child->channel_oil, ifp, PIM_OIF_FLAG_PROTO_STAR); - pim_upstream_switch (child, PIM_UPSTREAM_JOINED); - } + 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, PIM_OIF_FLAG_PROTO_STAR); + pim_upstream_switch (child, PIM_UPSTREAM_JOINED); + } } - if (pimg->spt_switchover != PIM_SPT_INFINITY) - pim_channel_add_oif(up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP); + + if (pimg->spt.switchover == PIM_SPT_INFINITY) + { + if (pimg->spt.plist) + { + struct prefix_list *plist = prefix_list_lookup (AFI_IP, pimg->spt.plist); + struct prefix g; + g.family = AF_INET; + g.prefixlen = IPV4_MAX_PREFIXLEN; + g.u.prefix4 = up->sg.grp; + + if (prefix_list_apply (plist, &g) == PREFIX_DENY) + { + pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP); + } + } + } + else + pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP); } return 1; @@ -1016,7 +1050,7 @@ pim_ifchannel_local_membership_add(struct interface *ifp, void pim_ifchannel_local_membership_del(struct interface *ifp, struct prefix_sg *sg) { - struct pim_ifchannel *ch; + struct pim_ifchannel *starch, *ch, *orig; struct pim_interface *pim_ifp; /* PIM enabled on interface? */ @@ -1026,7 +1060,7 @@ void pim_ifchannel_local_membership_del(struct interface *ifp, if (!PIM_IF_TEST_PIM(pim_ifp->options)) return; - ch = pim_ifchannel_find(ifp, sg); + orig = ch = pim_ifchannel_find(ifp, sg); if (!ch) return; @@ -1036,9 +1070,11 @@ void pim_ifchannel_local_membership_del(struct interface *ifp, { struct pim_upstream *up = pim_upstream_find (sg); struct pim_upstream *child; - struct listnode *up_node; + struct listnode *up_node, *up_nnode; - for (ALL_LIST_ELEMENTS_RO (up->sources, up_node, child)) + starch = ch; + + for (ALL_LIST_ELEMENTS (up->sources, up_node, up_nnode, child)) { struct channel_oil *c_oil = child->channel_oil; struct pim_ifchannel *chchannel = pim_ifchannel_find (ifp, &child->sg); @@ -1049,7 +1085,8 @@ void pim_ifchannel_local_membership_del(struct interface *ifp, __FILE__, __PRETTY_FUNCTION__, up->sg_str, ifp->name, child->sg_str); - if (c_oil && !pim_upstream_evaluate_join_desired_interface (child, ch)) + ch = pim_ifchannel_find (ifp, &child->sg); + if (c_oil && !pim_upstream_evaluate_join_desired_interface (child, ch, starch)) pim_channel_del_oif (c_oil, ifp, PIM_OIF_FLAG_PROTO_STAR); /* @@ -1059,9 +1096,11 @@ void pim_ifchannel_local_membership_del(struct interface *ifp, */ if (!chchannel && c_oil && c_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index]) pim_channel_del_oif (c_oil, ifp, PIM_OIF_FLAG_PROTO_STAR); + + /* Child node removal/ref count-- will happen as part of parent' delete_no_info */ } } - delete_on_noinfo(ch); + delete_on_noinfo(orig); } void pim_ifchannel_update_could_assert(struct pim_ifchannel *ch) @@ -1223,20 +1262,55 @@ pim_ifchannel_scan_forward_start (struct interface *new_ifp) * we get End of Message */ void -pim_ifchannel_set_star_g_join_state (struct pim_ifchannel *ch, int eom) +pim_ifchannel_set_star_g_join_state (struct pim_ifchannel *ch, int eom, uint8_t source_flags, uint8_t join) { struct pim_ifchannel *child; struct listnode *ch_node; if (PIM_DEBUG_PIM_TRACE) - zlog_debug ("%s: %s %s eom: %d", __PRETTY_FUNCTION__, + zlog_debug ("%s: %s %s eom: %d join %u", __PRETTY_FUNCTION__, pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags), - ch->sg_str, eom); + ch->sg_str, eom, join); if (!ch->sources) return; for (ALL_LIST_ELEMENTS_RO (ch->sources, ch_node, child)) { + /* Only *,G Join received and no (SG-RPT) prune. + Scan all S,G associated to G and if any SG-RPT + remove the SG-RPT flag. + */ + if (join && (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: clearing SGRpt flag, 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); + } + } + } + /* Received SG-RPT Prune delete oif from S,G */ + else if (join == 0 && (source_flags & PIM_RPT_BIT_MASK) && + !(source_flags & PIM_WILDCARD_BIT_MASK)) + { + struct pim_upstream *up = child->upstream; + + PIM_IF_FLAG_SET_S_G_RPT(child->flags); + if (up) + { + if (PIM_DEBUG_TRACE) + zlog_debug ("%s: del inherit oif from up %s", __PRETTY_FUNCTION__, up->sg_str); + pim_channel_del_oif (up->channel_oil, ch->interface, PIM_OIF_FLAG_PROTO_STAR); + } + } + if (!PIM_IF_FLAG_TEST_S_G_RPT(child->flags)) continue; |
