diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index b19118f3ac..5afb8e7737 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -959,7 +959,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? */ @@ -994,18 +994,21 @@ 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) @@ -1034,7 +1037,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? */ @@ -1044,7 +1047,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; @@ -1056,6 +1059,8 @@ void pim_ifchannel_local_membership_del(struct interface *ifp, struct pim_upstream *child; struct listnode *up_node, *up_nnode; + starch = ch; + for (ALL_LIST_ELEMENTS (up->sources, up_node, up_nnode, child)) { struct channel_oil *c_oil = child->channel_oil; @@ -1067,7 +1072,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); /* @@ -1082,7 +1088,7 @@ void pim_ifchannel_local_membership_del(struct interface *ifp, pim_upstream_del (child, __PRETTY_FUNCTION__); } } - delete_on_noinfo(ch); + delete_on_noinfo(orig); } void pim_ifchannel_update_could_assert(struct pim_ifchannel *ch) diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 167588daef..b9db75f148 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -794,38 +794,34 @@ struct pim_upstream *pim_upstream_add(struct prefix_sg *sg, return up; } +/* + * Passed in up must be the upstream for ch. starch is NULL if no + * information + */ 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_upstream *parent = up->parent; - - if (ch->upstream == up) + if (ch) { if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)) - return 0; + return 0; if (!pim_macro_ch_lost_assert(ch) && pim_macro_chisin_joins_or_include(ch)) - return 1; + return 1; } /* * joins (*,G) */ - if (parent && ch->upstream == parent) + if (starch) { - struct listnode *ch_node; - struct pim_ifchannel *child; - for (ALL_LIST_ELEMENTS_RO (ch->sources, ch_node, child)) - { - if (child->upstream == up) - { - if (PIM_IF_FLAG_TEST_S_G_RPT(child->flags)) - return 0; - } - } - if (!pim_macro_ch_lost_assert (ch) && pim_macro_chisin_joins_or_include (ch)) - return 1; + if (PIM_IF_FLAG_TEST_S_G_RPT (starch->upstream->flags)) + return 0; + + if (!pim_macro_ch_lost_assert (starch) && pim_macro_chisin_joins_or_include (starch)) + return 1; } return 0; @@ -856,20 +852,28 @@ pim_upstream_evaluate_join_desired_interface (struct pim_upstream *up, */ int pim_upstream_evaluate_join_desired(struct pim_upstream *up) { - struct listnode *chnode; - struct listnode *chnextnode; - struct pim_interface *pim_ifp; - struct pim_ifchannel *ch; + struct interface *ifp; + struct listnode *node; + struct pim_ifchannel *ch, *starch; + struct pim_upstream *starup = up->parent; int ret = 0; - /* scan per-interface (S,G) state */ - for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) + for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp)) { - pim_ifp = ch->interface->info; - if (!pim_ifp) - continue; + if (!ifp->info) + continue; - ret += pim_upstream_evaluate_join_desired_interface (up, ch); + ch = pim_ifchannel_find (ifp, &up->sg); + + if (starup) + starch = pim_ifchannel_find (ifp, &starup->sg); + else + starch = NULL; + + if (!ch && !starch) + continue; + + ret += pim_upstream_evaluate_join_desired_interface (up, ch, starch); } /* scan iface channel list */ return ret; /* false */ @@ -1433,31 +1437,42 @@ pim_upstream_start_register_stop_timer (struct pim_upstream *up, int null_regist int pim_upstream_inherited_olist_decide (struct pim_upstream *up) { - struct pim_interface *pim_ifp; - struct listnode *chnextnode; - struct pim_ifchannel *ch; - struct listnode *chnode; + struct interface *ifp; + struct pim_interface *pim_ifp = NULL; + struct pim_ifchannel *ch, *starch; + struct listnode *node; + struct pim_upstream *starup = up->parent; int output_intf = 0; pim_ifp = up->rpf.source_nexthop.interface->info; if (pim_ifp && !up->channel_oil) up->channel_oil = pim_channel_oil_add (&up->sg, pim_ifp->mroute_vif_index); - for (ALL_LIST_ELEMENTS (pim_ifchannel_list, chnode, chnextnode, ch)) + for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp)) { - pim_ifp = ch->interface->info; - if (!pim_ifp) - continue; + if (!ifp->info) + continue; - if (pim_upstream_evaluate_join_desired_interface (up, ch)) - { + ch = pim_ifchannel_find (ifp, &up->sg); + + if (starup) + starch = pim_ifchannel_find (ifp, &starup->sg); + else + starch = NULL; + + if (!ch && !starch) + continue; + + if (pim_upstream_evaluate_join_desired_interface (up, ch, starch)) + { int flag = PIM_OIF_FLAG_PROTO_PIM; - if (ch->sg.src.s_addr == INADDR_ANY && ch->upstream != up) + if (!ch) flag = PIM_OIF_FLAG_PROTO_STAR; - pim_channel_add_oif (up->channel_oil, ch->interface, flag); - output_intf++; - } + + pim_channel_add_oif (up->channel_oil, ifp, flag); + output_intf++; + } } return output_intf; diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h index ec40f3c243..e74ee37a12 100644 --- a/pimd/pim_upstream.h +++ b/pimd/pim_upstream.h @@ -149,7 +149,8 @@ struct pim_upstream *pim_upstream_del(struct pim_upstream *up, const char *name) int pim_upstream_evaluate_join_desired(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); void pim_upstream_update_join_desired(struct pim_upstream *up); void pim_upstream_join_suppress(struct pim_upstream *up,