diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index de2b7cbba6..f04fafdafa 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -3416,6 +3416,33 @@ pim_rp_cmd_worker (struct vty *vty, const char *rp, const char *group, const cha return CMD_SUCCESS; } +static int +pim_cmd_spt_switchover (enum pim_spt_switchover spt, const char *plist) +{ + pimg->spt.switchover = spt; + + switch (pimg->spt.switchover) + { + case PIM_SPT_IMMEDIATE: + if (pimg->spt.plist) + XFREE (MTYPE_PIM_SPT_PLIST_NAME, pimg->spt.plist); + + pim_upstream_add_lhr_star_pimreg (); + break; + case PIM_SPT_INFINITY: + pim_upstream_remove_lhr_star_pimreg (plist); + + if (pimg->spt.plist) + XFREE (MTYPE_PIM_SPT_PLIST_NAME, pimg->spt.plist); + + if (plist) + pimg->spt.plist = XSTRDUP (MTYPE_PIM_SPT_PLIST_NAME, plist); + break; + } + + return CMD_SUCCESS; +} + DEFUN (ip_pim_spt_switchover_infinity, ip_pim_spt_switchover_infinity_cmd, "ip pim spt-switchover infinity-and-beyond", @@ -3424,10 +3451,20 @@ DEFUN (ip_pim_spt_switchover_infinity, "SPT-Switchover\n" "Never switch to SPT Tree\n") { - pimg->spt_switchover = PIM_SPT_INFINITY; + return pim_cmd_spt_switchover (PIM_SPT_INFINITY, NULL); +} - pim_upstream_remove_lhr_star_pimreg(); - return CMD_SUCCESS; +DEFUN (ip_pim_spt_switchover_infinity_plist, + ip_pim_spt_switchover_infinity_plist_cmd, + "ip pim spt-switchover infinity-and-beyond prefix-list WORD", + IP_STR + PIM_STR + "SPT-Switchover\n" + "Never switch to SPT Tree\n" + "Prefix-List to control which groups to switch\n" + "Prefix-List name\n") +{ + return pim_cmd_spt_switchover (PIM_SPT_INFINITY, argv[5]->arg); } DEFUN (no_ip_pim_spt_switchover_infinity, @@ -3439,10 +3476,21 @@ DEFUN (no_ip_pim_spt_switchover_infinity, "SPT_Switchover\n" "Never switch to SPT Tree\n") { - pimg->spt_switchover = PIM_SPT_IMMEDIATE; + return pim_cmd_spt_switchover (PIM_SPT_IMMEDIATE, NULL); +} - pim_upstream_add_lhr_star_pimreg(); - return CMD_SUCCESS; +DEFUN (no_ip_pim_spt_switchover_infinity_plist, + no_ip_pim_spt_switchover_infinity_plist_cmd, + "no ip pim spt-switchover infinity-and-beyond prefix-list WORD", + NO_STR + IP_STR + PIM_STR + "SPT_Switchover\n" + "Never switch to SPT Tree\n" + "Prefix-List to control which groups to switch\n" + "Prefix-List name\n") +{ + return pim_cmd_spt_switchover (PIM_SPT_IMMEDIATE, NULL); } DEFUN (ip_pim_joinprune_time, @@ -6217,7 +6265,9 @@ void pim_cmd_init() install_element (CONFIG_NODE, &ip_pim_register_suppress_cmd); install_element (CONFIG_NODE, &no_ip_pim_register_suppress_cmd); install_element (CONFIG_NODE, &ip_pim_spt_switchover_infinity_cmd); + install_element (CONFIG_NODE, &ip_pim_spt_switchover_infinity_plist_cmd); install_element (CONFIG_NODE, &no_ip_pim_spt_switchover_infinity_cmd); + install_element (CONFIG_NODE, &no_ip_pim_spt_switchover_infinity_plist_cmd); install_element (CONFIG_NODE, &ip_pim_joinprune_time_cmd); install_element (CONFIG_NODE, &no_ip_pim_joinprune_time_cmd); install_element (CONFIG_NODE, &ip_pim_keep_alive_cmd); diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index ebd36f8782..c87320d0f8 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,6 +50,15 @@ pim_ifchannel_compare (struct pim_ifchannel *ch1, struct pim_ifchannel *ch2) struct pim_interface *pim_ifp1; struct pim_interface *pim_ifp2; + pim_ifp1 = ch1->interface->info; + pim_ifp2 = ch2->interface->info; + + if (pim_ifp1->mroute_vif_index < pim_ifp2->mroute_vif_index) + return -1; + + if (pim_ifp1->mroute_vif_index > pim_ifp2->mroute_vif_index) + return 1; + if (ntohl(ch1->sg.grp.s_addr) < ntohl(ch2->sg.grp.s_addr)) return -1; @@ -61,20 +71,6 @@ pim_ifchannel_compare (struct pim_ifchannel *ch1, struct pim_ifchannel *ch2) if (ntohl(ch1->sg.src.s_addr) > ntohl(ch2->sg.src.s_addr)) 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)) - return -1; - - if (ntohl(pim_ifp1->primary_address.s_addr) > ntohl(pim_ifp2->primary_address.s_addr)) - return 1; - - if (pim_ifp1->mroute_vif_index < pim_ifp2->mroute_vif_index) - return -1; - - if (pim_ifp1->mroute_vif_index > pim_ifp2->mroute_vif_index) - return 1; - return 0; } @@ -174,6 +170,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 +566,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; } @@ -958,7 +958,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 +993,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 +1036,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 +1046,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 +1056,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 +1071,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 +1082,12 @@ 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); + + if (c_oil->oil_size == 0) + 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_memory.c b/pimd/pim_memory.c index 2acca6f49b..ab92665b97 100644 --- a/pimd/pim_memory.c +++ b/pimd/pim_memory.c @@ -52,3 +52,4 @@ DEFINE_MTYPE(PIMD, PIM_JP_AGG_SOURCE, "PIM JP AGG Source") DEFINE_MTYPE(PIMD, PIM_PIM_INSTANCE, "PIM global state") DEFINE_MTYPE(PIMD, PIM_NEXTHOP_CACHE, "PIM nexthop cache state") DEFINE_MTYPE(PIMD, PIM_SSM_INFO, "PIM SSM configuration") +DEFINE_MTYPE(PIMD, PIM_SPT_PLIST_NAME, "PIM SPT Prefix List Name") diff --git a/pimd/pim_memory.h b/pimd/pim_memory.h index 02446de46a..e366377c87 100644 --- a/pimd/pim_memory.h +++ b/pimd/pim_memory.h @@ -51,5 +51,6 @@ DECLARE_MTYPE(PIM_JP_AGG_SOURCE) DECLARE_MTYPE(PIM_PIM_INSTANCE) DECLARE_MTYPE(PIM_NEXTHOP_CACHE) DECLARE_MTYPE(PIM_SSM_INFO) +DECLARE_MTYPE(PIM_SPT_PLIST_NAME); #endif /* _QUAGGA_PIM_MEMORY_H */ diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 5743dac654..9f645cace3 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -214,6 +214,8 @@ pim_upstream_del(struct pim_upstream *up, const char *name) } up->sources = NULL; + list_delete (up->ifchannels); + /* notice that listnode_delete() can't be moved into pim_upstream_free() because the later is @@ -439,18 +441,10 @@ static void forward_on(struct pim_upstream *up) { struct listnode *chnode; struct listnode *chnextnode; - struct pim_interface *pim_ifp; - struct pim_ifchannel *ch; + struct pim_ifchannel *ch = NULL; /* scan (S,G) state */ - for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) { - pim_ifp = ch->interface->info; - if (!pim_ifp) - continue; - - if (ch->upstream != up) - continue; - + for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) { if (pim_macro_chisin_oiflist(ch)) pim_forward_start(ch); @@ -461,17 +455,10 @@ static void forward_off(struct pim_upstream *up) { struct listnode *chnode; struct listnode *chnextnode; - struct pim_interface *pim_ifp; struct pim_ifchannel *ch; /* scan per-interface (S,G) state */ - for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) { - pim_ifp = ch->interface->info; - if (!pim_ifp) - continue; - - if (ch->upstream != up) - continue; + for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) { pim_forward_stop(ch); @@ -673,6 +660,9 @@ pim_upstream_new (struct prefix_sg *sg, up->rpf.rpf_addr.family = AF_INET; up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY; + up->ifchannels = list_new(); + up->ifchannels->cmp = (int (*)(void *, void *))pim_ifchannel_compare; + if (up->sg.src.s_addr != INADDR_ANY) wheel_add_item (pim_upstream_sg_wheel, up); @@ -794,38 +784,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 +842,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 */ @@ -956,18 +950,9 @@ void pim_upstream_rpf_interface_changed(struct pim_upstream *up, struct listnode *chnode; struct listnode *chnextnode; struct pim_ifchannel *ch; - struct pim_interface *pim_ifp; /* search all ifchannels */ - for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) { - - pim_ifp = ch->interface->info; - if (!pim_ifp) - continue; - - if (ch->upstream != up) - continue; - + for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) { if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) { if ( /* RPF_interface(S) was NOT I */ @@ -988,18 +973,10 @@ void pim_upstream_update_could_assert(struct pim_upstream *up) { struct listnode *chnode; struct listnode *chnextnode; - struct pim_interface *pim_ifp; struct pim_ifchannel *ch; /* scan per-interface (S,G) state */ - for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) { - pim_ifp = ch->interface->info; - if (!pim_ifp) - continue; - - if (ch->upstream != up) - continue; - + for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) { pim_ifchannel_update_could_assert(ch); } /* scan iface channel list */ } @@ -1008,18 +985,10 @@ void pim_upstream_update_my_assert_metric(struct pim_upstream *up) { struct listnode *chnode; struct listnode *chnextnode; - struct pim_interface *pim_ifp; struct pim_ifchannel *ch; /* scan per-interface (S,G) state */ - for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) { - pim_ifp = ch->interface->info; - if (!pim_ifp) - continue; - - if (ch->upstream != up) - continue; - + for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) { pim_ifchannel_update_my_assert_metric(ch); } /* scan iface channel list */ @@ -1033,14 +1002,11 @@ static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up) struct pim_ifchannel *ch; /* scan per-interface (S,G) state */ - for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) { + for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) { pim_ifp = ch->interface->info; if (!pim_ifp) continue; - if (ch->upstream != up) - continue; - pim_ifchannel_update_assert_tracking_desired(ch); } /* scan iface channel list */ @@ -1210,11 +1176,10 @@ pim_upstream_is_sg_rpt (struct pim_upstream *up) struct listnode *chnode; struct pim_ifchannel *ch; - for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, chnode, ch)) + for (ALL_LIST_ELEMENTS_RO(up->ifchannels, chnode, ch)) { - if ((ch->upstream == up) && - (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))) - return 1; + if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)) + return 1; } return 0; @@ -1433,31 +1398,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; @@ -1695,10 +1671,41 @@ pim_upstream_add_lhr_star_pimreg (void) } void -pim_upstream_remove_lhr_star_pimreg (void) +pim_upstream_spt_prefix_list_update (struct prefix_list *pl) +{ + const char *pname = prefix_list_name (pl); + + if (pimg->spt.plist && strcmp (pimg->spt.plist, pname) == 0) + { + pim_upstream_remove_lhr_star_pimreg (pname); + } +} + +/* + * nlist -> The new prefix list + * + * Per Group Application of pimreg to the OIL + * If the prefix list tells us DENY then + * we need to Switchover to SPT immediate + * so add the pimreg. + * If the prefix list tells us to ACCEPT than + * we need to Never do the SPT so remove + * the interface + * + */ +void +pim_upstream_remove_lhr_star_pimreg (const char *nlist) { struct pim_upstream *up; struct listnode *node; + struct prefix_list *np; + struct prefix g; + enum prefix_list_type apply_new; + + np = prefix_list_lookup (AFI_IP, nlist); + + g.family = AF_INET; + g.prefixlen = IPV4_MAX_PREFIXLEN; for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, node, up)) { @@ -1708,7 +1715,17 @@ pim_upstream_remove_lhr_star_pimreg (void) if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up->flags)) continue; - pim_channel_del_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP); + if (!nlist) + { + pim_channel_del_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP); + continue; + } + g.u.prefix4 = up->sg.grp; + apply_new = prefix_list_apply (np, &g); + if (apply_new == PREFIX_DENY) + pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP); + else + pim_channel_del_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP); } } diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h index a1af4483ac..f1c8df35b1 100644 --- a/pimd/pim_upstream.h +++ b/pimd/pim_upstream.h @@ -100,6 +100,7 @@ struct pim_upstream { uint32_t flags; struct channel_oil *channel_oil; struct list *sources; + struct list *ifchannels; enum pim_upstream_state join_state; enum pim_reg_state reg_state; @@ -149,7 +150,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, @@ -200,5 +202,7 @@ int pim_upstream_compare (void *arg1, void *arg2); void pim_upstream_register_reevaluate (void); void pim_upstream_add_lhr_star_pimreg (void); -void pim_upstream_remove_lhr_star_pimreg (void); +void pim_upstream_remove_lhr_star_pimreg (const char *nlist); + +void pim_upstream_spt_prefix_list_update (struct prefix_list *pl); #endif /* PIM_UPSTREAM_H */ diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 3d52dc9c41..c8322b629a 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -182,10 +182,14 @@ int pim_global_config_write(struct vty *vty) ssm->plist_name, VTY_NEWLINE); ++writes; } - if (pimg->spt_switchover == PIM_SPT_INFINITY) + if (pimg->spt.switchover == PIM_SPT_INFINITY) { - vty_out (vty, "ip pim spt-switchover infinity-and-beyond%s", - VTY_NEWLINE); + if (pimg->spt.plist) + vty_out (vty, "ip pim spt-switchover infinity-and-beyond prefix-list %s%s", + pimg->spt.plist, VTY_NEWLINE); + else + vty_out (vty, "ip pim spt-switchover infinity-and-beyond%s", + VTY_NEWLINE); ++writes; } diff --git a/pimd/pimd.c b/pimd/pimd.c index eaef4ff5c0..a8a2a806e0 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -194,6 +194,7 @@ pim_prefix_list_update (struct prefix_list *plist) { pim_rp_prefix_list_update (plist); pim_ssm_prefix_list_update (plist); + pim_upstream_spt_prefix_list_update (plist); } static void @@ -249,7 +250,9 @@ pim_instance_init (vrf_id_t vrf_id, afi_t afi) pim->vrf_id = vrf_id; pim->afi = afi; - pim->spt_switchover = PIM_SPT_IMMEDIATE; + pim->spt.switchover = PIM_SPT_IMMEDIATE; + pim->spt.plist = NULL; + pim->rpf_hash = hash_create_size (256, pim_rpf_hash_key, pim_rpf_equal); if (PIM_DEBUG_ZEBRA) diff --git a/pimd/pimd.h b/pimd/pimd.h index 6c3dcfafca..246be17d40 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -248,7 +248,10 @@ struct pim_instance afi_t afi; vrf_id_t vrf_id; - enum pim_spt_switchover spt_switchover; + struct { + enum pim_spt_switchover switchover; + char *plist; + } spt; struct hash *rpf_hash; void *ssm_info; /* per-vrf SSM configuration */