From da11e32521af32b4db39eeb48f2725e9f3db824d Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 17 Mar 2018 21:13:09 -0400 Subject: [PATCH] pimd: Make the rpf scan per vrf. We know the vrf that we are in when we need to initiate a rescan of the rpf cache. So pass it in and use that information. This should help the rescan at scale with several vrf's cutting out a lot of unnecessary work. Signed-off-by: Donald Sharp --- pimd/pim_cmd.c | 14 +-- pimd/pim_instance.h | 3 + pimd/pim_neighbor.c | 4 +- pimd/pim_zebra.c | 234 ++++++++++++++++++-------------------------- pimd/pim_zebra.h | 2 +- pimd/pimd.c | 1 - pimd/pimd.h | 1 - 7 files changed, 110 insertions(+), 149 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 803e7bb013..a8935bf80d 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -2566,8 +2566,8 @@ static void pim_show_upstream_rpf(struct pim_instance *pim, struct vty *vty, } } -static void show_rpf_refresh_stats(struct vty *vty, time_t now, - json_object *json) +static void show_rpf_refresh_stats(struct vty *vty, struct pim_instance *pim, + time_t now, json_object *json) { char refresh_uptime[10]; @@ -2579,7 +2579,7 @@ static void show_rpf_refresh_stats(struct vty *vty, time_t now, qpim_rpf_cache_refresh_delay_msec); json_object_int_add( json, "rpfCacheRefreshTimer", - pim_time_timer_remain_msec(qpim_rpf_cache_refresher)); + pim_time_timer_remain_msec(pim->rpf_cache_refresher)); json_object_int_add(json, "rpfCacheRefreshRequests", qpim_rpf_cache_refresh_requests); json_object_int_add(json, "rpfCacheRefreshEvents", @@ -2600,7 +2600,7 @@ static void show_rpf_refresh_stats(struct vty *vty, time_t now, "Nexthop Lookups: %lld\n" "Nexthop Lookups Avoided: %lld\n", qpim_rpf_cache_refresh_delay_msec, - pim_time_timer_remain_msec(qpim_rpf_cache_refresher), + pim_time_timer_remain_msec(pim->rpf_cache_refresher), (long long)qpim_rpf_cache_refresh_requests, (long long)qpim_rpf_cache_refresh_events, refresh_uptime, (long long)qpim_nexthop_lookups, @@ -2642,9 +2642,9 @@ static void pim_show_rpf(struct pim_instance *pim, struct vty *vty, u_char uj) if (uj) { json = json_object_new_object(); - show_rpf_refresh_stats(vty, now, json); + show_rpf_refresh_stats(vty, pim, now, json); } else { - show_rpf_refresh_stats(vty, now, json); + show_rpf_refresh_stats(vty, pim, now, json); vty_out(vty, "\n"); vty_out(vty, "Source Group RpfIface RpfAddress RibNextHop Metric Pref\n"); @@ -4337,7 +4337,7 @@ static void pim_cmd_show_ip_multicast_helper(struct pim_instance *pim, vty_out(vty, "\n"); - show_rpf_refresh_stats(vty, now, NULL); + show_rpf_refresh_stats(vty, pim, now, NULL); vty_out(vty, "\n"); diff --git a/pimd/pim_instance.h b/pimd/pim_instance.h index 5422e8fe0d..e672c39fdc 100644 --- a/pimd/pim_instance.h +++ b/pimd/pim_instance.h @@ -94,6 +94,9 @@ struct pim_instance { unsigned int keep_alive_time; unsigned int rp_keep_alive_time; + + /* If we need to rescan all our upstreams */ + struct thread *rpf_cache_refresher; }; void pim_vrf_init(void); diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index 134dbd8712..20a942b4fd 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -545,7 +545,7 @@ pim_neighbor_add(struct interface *ifp, struct in_addr source_addr, pim_rp_setup(pim_ifp->pim); - sched_rpf_cache_refresh(); + sched_rpf_cache_refresh(pim_ifp->pim); return neigh; } @@ -667,7 +667,7 @@ void pim_neighbor_delete(struct interface *ifp, struct pim_neighbor *neigh, pim_neighbor_free(neigh); - sched_rpf_cache_refresh(); + sched_rpf_cache_refresh(pim_ifp->pim); } void pim_neighbor_delete_all(struct interface *ifp, const char *delete_message) diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 81c0cb6efb..ecb97e8e44 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -394,133 +394,105 @@ static int pim_zebra_if_address_del(int command, struct zclient *client, return 0; } -static void scan_upstream_rpf_cache() +static void scan_upstream_rpf_cache(struct pim_instance *pim) { struct listnode *up_node; struct listnode *up_nextnode; struct listnode *node; struct pim_upstream *up; struct interface *ifp; - struct vrf *vrf; - struct pim_instance *pim; - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - pim = vrf->info; - if (!pim) + for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) { + enum pim_rpf_result rpf_result; + struct pim_rpf old; + struct prefix nht_p; + + nht_p.family = AF_INET; + nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr; + pim_resolve_upstream_nh(pim, &nht_p); + + old.source_nexthop.interface = up->rpf.source_nexthop.interface; + old.source_nexthop.nbr = up->rpf.source_nexthop.nbr; + rpf_result = pim_rpf_update(pim, up, &old, 0); + + if (rpf_result == PIM_RPF_FAILURE) continue; - for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, - up)) { - enum pim_rpf_result rpf_result; - struct pim_rpf old; - struct prefix nht_p; + if (rpf_result == PIM_RPF_CHANGED) { + struct pim_neighbor *nbr; - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr; - pim_resolve_upstream_nh(pim, &nht_p); + nbr = pim_neighbor_find(old.source_nexthop.interface, + old.rpf_addr.u.prefix4); + if (nbr) + pim_jp_agg_remove_group(nbr->upstream_jp_agg, + up); - old.source_nexthop.interface = - up->rpf.source_nexthop.interface; - old.source_nexthop.nbr = up->rpf.source_nexthop.nbr; - rpf_result = pim_rpf_update(pim, up, &old, 0); + /* + * We have detected a case where we might need + * to rescan + * the inherited o_list so do it. + */ + if (up->channel_oil->oil_inherited_rescan) { + pim_upstream_inherited_olist_decide(pim, up); + up->channel_oil->oil_inherited_rescan = 0; + } - if (rpf_result == PIM_RPF_FAILURE) - continue; - - if (rpf_result == PIM_RPF_CHANGED) { - struct pim_neighbor *nbr; - - nbr = pim_neighbor_find( - old.source_nexthop.interface, - old.rpf_addr.u.prefix4); - if (nbr) - pim_jp_agg_remove_group( - nbr->upstream_jp_agg, up); + if (up->join_state == PIM_UPSTREAM_JOINED) { + /* + * If we come up real fast we can be here + * where the mroute has not been installed + * so install it. + */ + if (!up->channel_oil->installed) + pim_mroute_add(up->channel_oil, + __PRETTY_FUNCTION__); /* - * We have detected a case where we might need - * to rescan - * the inherited o_list so do it. + * RFC 4601: 4.5.7. Sending (S,G) + * Join/Prune Messages + * + * Transitions from Joined State + * + * RPF'(S,G) changes not due to an Assert + * + * The upstream (S,G) state machine remains + * in Joined state. Send Join(S,G) to the new + * upstream neighbor, which is the new value + * of RPF'(S,G). Send Prune(S,G) to the old + * upstream neighbor, which is the old value + * of RPF'(S,G). Set the Join Timer (JT) to + * expire after t_periodic seconds. */ - if (up->channel_oil->oil_inherited_rescan) { - pim_upstream_inherited_olist_decide(pim, - up); - up->channel_oil->oil_inherited_rescan = - 0; - } + pim_jp_agg_switch_interface(&old, &up->rpf, up); - if (up->join_state == PIM_UPSTREAM_JOINED) { - /* - * If we come up real fast we can be - * here - * where the mroute has not been - * installed - * so install it. - */ - if (!up->channel_oil->installed) - pim_mroute_add( - up->channel_oil, - __PRETTY_FUNCTION__); + pim_upstream_join_timer_restart(up, &old); + } /* up->join_state == PIM_UPSTREAM_JOINED */ - /* - * RFC 4601: 4.5.7. Sending (S,G) - * Join/Prune Messages - * - * Transitions from Joined State - * - * RPF'(S,G) changes not due to an - * Assert - * - * The upstream (S,G) state machine - * remains in Joined - * state. Send Join(S,G) to the new - * upstream neighbor, which is - * the new value of RPF'(S,G). Send - * Prune(S,G) to the old - * upstream neighbor, which is the old - * value of RPF'(S,G). Set - * the Join Timer (JT) to expire after - * t_periodic seconds. - */ - pim_jp_agg_switch_interface( - &old, &up->rpf, up); + /* FIXME can join_desired actually be changed by + pim_rpf_update() + returning PIM_RPF_CHANGED ? */ + pim_upstream_update_join_desired(pim, up); - pim_upstream_join_timer_restart(up, - &old); - } /* up->join_state == PIM_UPSTREAM_JOINED */ + } /* PIM_RPF_CHANGED */ - /* FIXME can join_desired actually be changed by - pim_rpf_update() - returning PIM_RPF_CHANGED ? */ - pim_upstream_update_join_desired(pim, up); + } /* for (qpim_upstream_list) */ - } /* PIM_RPF_CHANGED */ + FOR_ALL_INTERFACES (pim->vrf, ifp) + if (ifp->info) { + struct pim_interface *pim_ifp = ifp->info; + struct pim_iface_upstream_switch *us; - } /* for (qpim_upstream_list) */ - } + for (ALL_LIST_ELEMENTS_RO(pim_ifp->upstream_switch_list, + node, us)) { + struct pim_rpf rpf; - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - pim = vrf->info; - if (!pim) - continue; - - FOR_ALL_INTERFACES (pim->vrf, ifp) - if (ifp->info) { - struct pim_interface *pim_ifp = ifp->info; - struct pim_iface_upstream_switch *us; - - for (ALL_LIST_ELEMENTS_RO( - pim_ifp->upstream_switch_list, - node, us)) { - struct pim_rpf rpf; - rpf.source_nexthop.interface = ifp; - rpf.rpf_addr.u.prefix4 = us->address; - pim_joinprune_send(&rpf, us->us); - pim_jp_agg_clear_group(us->us); - } + rpf.source_nexthop.interface = ifp; + rpf.rpf_addr.u.prefix4 = us->address; + pim_joinprune_send(&rpf, us->us); + pim_jp_agg_clear_group(us->us); } - } + } } void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index) @@ -657,53 +629,41 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index) } } -void pim_scan_oil(struct pim_instance *pim_matcher) +void pim_scan_oil(struct pim_instance *pim) { struct listnode *node; struct listnode *nextnode; struct channel_oil *c_oil; ifindex_t ifindex; int vif_index = 0; - struct vrf *vrf; - struct pim_instance *pim; qpim_scan_oil_last = pim_time_monotonic_sec(); ++qpim_scan_oil_events; - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - pim = vrf->info; - if (!pim) - continue; - - if (pim_matcher && pim != pim_matcher) - continue; - - for (ALL_LIST_ELEMENTS(pim->channel_oil_list, node, nextnode, - c_oil)) { - if (c_oil->up - && c_oil->up->rpf.source_nexthop.interface) { - ifindex = c_oil->up->rpf.source_nexthop - .interface->ifindex; - vif_index = pim_if_find_vifindex_by_ifindex( - pim, ifindex); - /* Pass Current selected NH vif index to mroute - * download */ - if (vif_index) - pim_scan_individual_oil(c_oil, - vif_index); - } else - pim_scan_individual_oil(c_oil, 0); - } + for (ALL_LIST_ELEMENTS(pim->channel_oil_list, node, nextnode, c_oil)) { + if (c_oil->up && c_oil->up->rpf.source_nexthop.interface) { + ifindex = c_oil->up->rpf.source_nexthop + .interface->ifindex; + vif_index = + pim_if_find_vifindex_by_ifindex(pim, ifindex); + /* Pass Current selected NH vif index to mroute + * download */ + if (vif_index) + pim_scan_individual_oil(c_oil, vif_index); + } else + pim_scan_individual_oil(c_oil, 0); } } static int on_rpf_cache_refresh(struct thread *t) { + struct pim_instance *pim = THREAD_ARG(t); + /* update PIM protocol state */ - scan_upstream_rpf_cache(); + scan_upstream_rpf_cache(pim); /* update kernel multicast forwarding cache (MFC) */ - pim_scan_oil(NULL); + pim_scan_oil(pim); qpim_rpf_cache_refresh_last = pim_time_monotonic_sec(); ++qpim_rpf_cache_refresh_events; @@ -713,13 +673,13 @@ static int on_rpf_cache_refresh(struct thread *t) return 0; } -void sched_rpf_cache_refresh(void) +void sched_rpf_cache_refresh(struct pim_instance *pim) { ++qpim_rpf_cache_refresh_requests; pim_rpf_set_refresh_time(); - if (qpim_rpf_cache_refresher) { + if (pim->rpf_cache_refresher) { /* Refresh timer is already running */ return; } @@ -731,9 +691,9 @@ void sched_rpf_cache_refresh(void) qpim_rpf_cache_refresh_delay_msec); } - thread_add_timer_msec(master, on_rpf_cache_refresh, 0, + thread_add_timer_msec(master, on_rpf_cache_refresh, pim, qpim_rpf_cache_refresh_delay_msec, - &qpim_rpf_cache_refresher); + &pim->rpf_cache_refresher); } static void pim_zebra_connected(struct zclient *zclient) diff --git a/pimd/pim_zebra.h b/pimd/pim_zebra.h index d9b17cb82d..dd8aed0d20 100644 --- a/pimd/pim_zebra.h +++ b/pimd/pim_zebra.h @@ -44,6 +44,6 @@ void igmp_source_forward_reevaluate_all(void); void pim_forward_start(struct pim_ifchannel *ch); void pim_forward_stop(struct pim_ifchannel *ch, bool install_it); -void sched_rpf_cache_refresh(void); +void sched_rpf_cache_refresh(struct pim_instance *pim); struct zclient *pim_zebra_zclient_get(void); #endif /* PIM_ZEBRA_H */ diff --git a/pimd/pimd.c b/pimd/pimd.c index 52e0920f1f..0532ce873a 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -52,7 +52,6 @@ int qpim_t_periodic = PIM_DEFAULT_T_PERIODIC; /* Period between Join/Prune Messages */ struct pim_assert_metric qpim_infinite_assert_metric; long qpim_rpf_cache_refresh_delay_msec = 50; -struct thread *qpim_rpf_cache_refresher = NULL; int64_t qpim_rpf_cache_refresh_requests = 0; int64_t qpim_rpf_cache_refresh_events = 0; int64_t qpim_rpf_cache_refresh_last = 0; diff --git a/pimd/pimd.h b/pimd/pimd.h index de7f259319..89582b991e 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -140,7 +140,6 @@ struct in_addr qpim_all_pim_routers_addr; int qpim_t_periodic; /* Period between Join/Prune Messages */ struct pim_assert_metric qpim_infinite_assert_metric; long qpim_rpf_cache_refresh_delay_msec; -struct thread *qpim_rpf_cache_refresher; int64_t qpim_rpf_cache_refresh_requests; int64_t qpim_rpf_cache_refresh_events; int64_t qpim_rpf_cache_refresh_last;