From df94f9a91dbff3e0b04928d564484dfc4bf55aed Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 7 Apr 2017 10:16:23 -0400 Subject: [PATCH 1/6] pimd: Add prefix list handling to spt-switchover To the 'ip pim spt-switchover infinity-and-beyond' command add 'prefix-list '. To the command. Use this as the basis to deny (Not immediate switchover) or permit (Immediate switchover), based upon matching the group address and the prefix-list. Signed-off-by: Donald Sharp --- pimd/pim_cmd.c | 62 +++++++++++++++++++++++++++++++++++++++----- pimd/pim_ifchannel.c | 22 ++++++++++++++-- pimd/pim_memory.c | 1 + pimd/pim_memory.h | 1 + pimd/pim_upstream.c | 45 ++++++++++++++++++++++++++++++-- pimd/pim_upstream.h | 4 ++- pimd/pim_vty.c | 10 ++++--- pimd/pimd.c | 5 +++- pimd/pimd.h | 5 +++- 9 files changed, 139 insertions(+), 16 deletions(-) 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..fc84a5c2fe 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" @@ -1006,8 +1007,25 @@ pim_ifchannel_local_membership_add(struct interface *ifp, 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; 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..167588daef 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -1695,10 +1695,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 +1739,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..ec40f3c243 100644 --- a/pimd/pim_upstream.h +++ b/pimd/pim_upstream.h @@ -200,5 +200,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 */ From cf528e4f26a9a43c39f6569509b6753c07fd5fa3 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 18 Apr 2017 09:01:00 -0400 Subject: [PATCH 2/6] pimd: When loosing *,G igmp report notify S,G too When we have a S,G that was created due to the *,G IGMP report going away, safely remove the S,G as well. Ticket: CM-15838 Signed-off-by: Donald Sharp Reviewed-by: Anuradha Karuppiah --- pimd/pim_ifchannel.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index fc84a5c2fe..b19118f3ac 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -1054,9 +1054,9 @@ 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)) + 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); @@ -1077,6 +1077,9 @@ 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); From c8fc07cb03a2b56ee97d23671185e6de2bd7a643 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 20 Apr 2017 09:03:47 -0400 Subject: [PATCH 3/6] pimd: Limit search to relevant ifchannels in some cases When we are determining an inherited_olist, let's be allot smarter about what we look at. Before this code change we are looping over the entirety of all ifchannels in the system to find the relevant ones. Convert the code to *find*(hash table lookup) the specific ifchannels we are interested in. Ticket: CM-15629 Signed-off-by: Donald Sharp --- pimd/pim_ifchannel.c | 34 +++++++++------ pimd/pim_upstream.c | 101 +++++++++++++++++++++++++------------------ pimd/pim_upstream.h | 3 +- 3 files changed, 80 insertions(+), 58 deletions(-) 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, From 2a28f7a0b9e7d73df353ff296e7990ced524e223 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 20 Apr 2017 07:48:27 -0400 Subject: [PATCH 4/6] pimd: Add ability for upstream to know it's ifchannels Add a list structure to track the ifchannels associated with a particular upstream. We are not doing anything with this particular knowledge yet but it will be come useful in the near future. Ticket: CM-15629 Signed-off-by: Donald Sharp --- pimd/pim_ifchannel.c | 4 ++++ pimd/pim_upstream.c | 5 +++++ pimd/pim_upstream.h | 1 + 3 files changed, 10 insertions(+) diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index 5afb8e7737..ab01c7f13e 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -175,6 +175,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); } @@ -569,6 +571,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; } diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index b9db75f148..5f98348c3e 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 @@ -673,6 +675,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); diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h index e74ee37a12..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; From b5e6281b6551736f381bae4d4f8072f5255ca51c Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 20 Apr 2017 10:12:41 -0400 Subject: [PATCH 5/6] pimd: Convert pim_ifchannel_list to use up->ifchannels We have a bunch of places where we iterate over the pim_ifchannel_list to find those ifchannels that match a certain upstream. Since we already know in the upstream the list of ifchannels associated with it, just look at those instead. Functions changed: forward_on forward_off pim_upstream_rpf_interface_changed pim_upstream_update_could_assert pim_upstream_update_my_assert_metric pim_upstream_update_assert_tracking_desired pim_upstream_is_sg_rpt Ticket: CM-15629 Signed-off-by: Donald Sharp --- pimd/pim_upstream.c | 64 +++++++-------------------------------------- 1 file changed, 10 insertions(+), 54 deletions(-) diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 5f98348c3e..9f645cace3 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -441,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); @@ -463,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); @@ -965,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 */ @@ -997,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 */ } @@ -1017,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 */ @@ -1042,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 */ @@ -1219,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; From e3a55f03bf83ff637ab12d997376fb6442a07163 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 20 Apr 2017 12:21:02 -0400 Subject: [PATCH 6/6] pimd: Tweak pim_ifchannel_compare to be faster Tweak the ifchannel compare to sort based upon interface first Ticket: CM-15629 Signed-off-by: Donald Sharp --- pimd/pim_ifchannel.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index ab01c7f13e..c87320d0f8 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -50,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; @@ -62,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; }