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 <sharpd@cumulusnetworks.com>
This commit is contained in:
Donald Sharp 2018-03-17 21:13:09 -04:00
parent 78c16071f9
commit da11e32521
7 changed files with 110 additions and 149 deletions

View file

@ -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, static void show_rpf_refresh_stats(struct vty *vty, struct pim_instance *pim,
json_object *json) time_t now, json_object *json)
{ {
char refresh_uptime[10]; 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); qpim_rpf_cache_refresh_delay_msec);
json_object_int_add( json_object_int_add(
json, "rpfCacheRefreshTimer", 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", json_object_int_add(json, "rpfCacheRefreshRequests",
qpim_rpf_cache_refresh_requests); qpim_rpf_cache_refresh_requests);
json_object_int_add(json, "rpfCacheRefreshEvents", 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: %lld\n"
"Nexthop Lookups Avoided: %lld\n", "Nexthop Lookups Avoided: %lld\n",
qpim_rpf_cache_refresh_delay_msec, 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_requests,
(long long)qpim_rpf_cache_refresh_events, (long long)qpim_rpf_cache_refresh_events,
refresh_uptime, (long long)qpim_nexthop_lookups, 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) { if (uj) {
json = json_object_new_object(); json = json_object_new_object();
show_rpf_refresh_stats(vty, now, json); show_rpf_refresh_stats(vty, pim, now, json);
} else { } else {
show_rpf_refresh_stats(vty, now, json); show_rpf_refresh_stats(vty, pim, now, json);
vty_out(vty, "\n"); vty_out(vty, "\n");
vty_out(vty, vty_out(vty,
"Source Group RpfIface RpfAddress RibNextHop Metric Pref\n"); "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"); vty_out(vty, "\n");
show_rpf_refresh_stats(vty, now, NULL); show_rpf_refresh_stats(vty, pim, now, NULL);
vty_out(vty, "\n"); vty_out(vty, "\n");

View file

@ -94,6 +94,9 @@ struct pim_instance {
unsigned int keep_alive_time; unsigned int keep_alive_time;
unsigned int rp_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); void pim_vrf_init(void);

View file

@ -545,7 +545,7 @@ pim_neighbor_add(struct interface *ifp, struct in_addr source_addr,
pim_rp_setup(pim_ifp->pim); pim_rp_setup(pim_ifp->pim);
sched_rpf_cache_refresh(); sched_rpf_cache_refresh(pim_ifp->pim);
return neigh; return neigh;
} }
@ -667,7 +667,7 @@ void pim_neighbor_delete(struct interface *ifp, struct pim_neighbor *neigh,
pim_neighbor_free(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) void pim_neighbor_delete_all(struct interface *ifp, const char *delete_message)

View file

@ -394,23 +394,15 @@ static int pim_zebra_if_address_del(int command, struct zclient *client,
return 0; 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_node;
struct listnode *up_nextnode; struct listnode *up_nextnode;
struct listnode *node; struct listnode *node;
struct pim_upstream *up; struct pim_upstream *up;
struct interface *ifp; struct interface *ifp;
struct vrf *vrf;
struct pim_instance *pim;
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) {
pim = vrf->info;
if (!pim)
continue;
for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode,
up)) {
enum pim_rpf_result rpf_result; enum pim_rpf_result rpf_result;
struct pim_rpf old; struct pim_rpf old;
struct prefix nht_p; struct prefix nht_p;
@ -420,8 +412,7 @@ static void scan_upstream_rpf_cache()
nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr; nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr;
pim_resolve_upstream_nh(pim, &nht_p); pim_resolve_upstream_nh(pim, &nht_p);
old.source_nexthop.interface = old.source_nexthop.interface = up->rpf.source_nexthop.interface;
up->rpf.source_nexthop.interface;
old.source_nexthop.nbr = up->rpf.source_nexthop.nbr; old.source_nexthop.nbr = up->rpf.source_nexthop.nbr;
rpf_result = pim_rpf_update(pim, up, &old, 0); rpf_result = pim_rpf_update(pim, up, &old, 0);
@ -431,12 +422,11 @@ static void scan_upstream_rpf_cache()
if (rpf_result == PIM_RPF_CHANGED) { if (rpf_result == PIM_RPF_CHANGED) {
struct pim_neighbor *nbr; struct pim_neighbor *nbr;
nbr = pim_neighbor_find( nbr = pim_neighbor_find(old.source_nexthop.interface,
old.source_nexthop.interface,
old.rpf_addr.u.prefix4); old.rpf_addr.u.prefix4);
if (nbr) if (nbr)
pim_jp_agg_remove_group( pim_jp_agg_remove_group(nbr->upstream_jp_agg,
nbr->upstream_jp_agg, up); up);
/* /*
* We have detected a case where we might need * We have detected a case where we might need
@ -444,23 +434,18 @@ static void scan_upstream_rpf_cache()
* the inherited o_list so do it. * the inherited o_list so do it.
*/ */
if (up->channel_oil->oil_inherited_rescan) { if (up->channel_oil->oil_inherited_rescan) {
pim_upstream_inherited_olist_decide(pim, pim_upstream_inherited_olist_decide(pim, up);
up); up->channel_oil->oil_inherited_rescan = 0;
up->channel_oil->oil_inherited_rescan =
0;
} }
if (up->join_state == PIM_UPSTREAM_JOINED) { if (up->join_state == PIM_UPSTREAM_JOINED) {
/* /*
* If we come up real fast we can be * If we come up real fast we can be here
* here * where the mroute has not been installed
* where the mroute has not been
* installed
* so install it. * so install it.
*/ */
if (!up->channel_oil->installed) if (!up->channel_oil->installed)
pim_mroute_add( pim_mroute_add(up->channel_oil,
up->channel_oil,
__PRETTY_FUNCTION__); __PRETTY_FUNCTION__);
/* /*
@ -469,25 +454,19 @@ static void scan_upstream_rpf_cache()
* *
* Transitions from Joined State * Transitions from Joined State
* *
* RPF'(S,G) changes not due to an * RPF'(S,G) changes not due to an Assert
* Assert
* *
* The upstream (S,G) state machine * The upstream (S,G) state machine remains
* remains in Joined * in Joined state. Send Join(S,G) to the new
* state. Send Join(S,G) to the new * upstream neighbor, which is the new value
* upstream neighbor, which is * of RPF'(S,G). Send Prune(S,G) to the old
* the new value of RPF'(S,G). Send * upstream neighbor, which is the old value
* Prune(S,G) to the old * of RPF'(S,G). Set the Join Timer (JT) to
* upstream neighbor, which is the old * expire after t_periodic seconds.
* value of RPF'(S,G). Set
* the Join Timer (JT) to expire after
* t_periodic seconds.
*/ */
pim_jp_agg_switch_interface( pim_jp_agg_switch_interface(&old, &up->rpf, up);
&old, &up->rpf, up);
pim_upstream_join_timer_restart(up, pim_upstream_join_timer_restart(up, &old);
&old);
} /* up->join_state == PIM_UPSTREAM_JOINED */ } /* up->join_state == PIM_UPSTREAM_JOINED */
/* FIXME can join_desired actually be changed by /* FIXME can join_desired actually be changed by
@ -498,22 +477,16 @@ static void scan_upstream_rpf_cache()
} /* PIM_RPF_CHANGED */ } /* PIM_RPF_CHANGED */
} /* for (qpim_upstream_list) */ } /* for (qpim_upstream_list) */
}
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
pim = vrf->info;
if (!pim)
continue;
FOR_ALL_INTERFACES (pim->vrf, ifp) FOR_ALL_INTERFACES (pim->vrf, ifp)
if (ifp->info) { if (ifp->info) {
struct pim_interface *pim_ifp = ifp->info; struct pim_interface *pim_ifp = ifp->info;
struct pim_iface_upstream_switch *us; struct pim_iface_upstream_switch *us;
for (ALL_LIST_ELEMENTS_RO( for (ALL_LIST_ELEMENTS_RO(pim_ifp->upstream_switch_list,
pim_ifp->upstream_switch_list,
node, us)) { node, us)) {
struct pim_rpf rpf; struct pim_rpf rpf;
rpf.source_nexthop.interface = ifp; rpf.source_nexthop.interface = ifp;
rpf.rpf_addr.u.prefix4 = us->address; rpf.rpf_addr.u.prefix4 = us->address;
pim_joinprune_send(&rpf, us->us); pim_joinprune_send(&rpf, us->us);
@ -521,7 +494,6 @@ static void scan_upstream_rpf_cache()
} }
} }
} }
}
void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index) 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 *node;
struct listnode *nextnode; struct listnode *nextnode;
struct channel_oil *c_oil; struct channel_oil *c_oil;
ifindex_t ifindex; ifindex_t ifindex;
int vif_index = 0; int vif_index = 0;
struct vrf *vrf;
struct pim_instance *pim;
qpim_scan_oil_last = pim_time_monotonic_sec(); qpim_scan_oil_last = pim_time_monotonic_sec();
++qpim_scan_oil_events; ++qpim_scan_oil_events;
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { for (ALL_LIST_ELEMENTS(pim->channel_oil_list, node, nextnode, c_oil)) {
pim = vrf->info; if (c_oil->up && c_oil->up->rpf.source_nexthop.interface) {
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 ifindex = c_oil->up->rpf.source_nexthop
.interface->ifindex; .interface->ifindex;
vif_index = pim_if_find_vifindex_by_ifindex( vif_index =
pim, ifindex); pim_if_find_vifindex_by_ifindex(pim, ifindex);
/* Pass Current selected NH vif index to mroute /* Pass Current selected NH vif index to mroute
* download */ * download */
if (vif_index) if (vif_index)
pim_scan_individual_oil(c_oil, pim_scan_individual_oil(c_oil, vif_index);
vif_index);
} else } else
pim_scan_individual_oil(c_oil, 0); pim_scan_individual_oil(c_oil, 0);
} }
} }
}
static int on_rpf_cache_refresh(struct thread *t) static int on_rpf_cache_refresh(struct thread *t)
{ {
struct pim_instance *pim = THREAD_ARG(t);
/* update PIM protocol state */ /* update PIM protocol state */
scan_upstream_rpf_cache(); scan_upstream_rpf_cache(pim);
/* update kernel multicast forwarding cache (MFC) */ /* 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_last = pim_time_monotonic_sec();
++qpim_rpf_cache_refresh_events; ++qpim_rpf_cache_refresh_events;
@ -713,13 +673,13 @@ static int on_rpf_cache_refresh(struct thread *t)
return 0; return 0;
} }
void sched_rpf_cache_refresh(void) void sched_rpf_cache_refresh(struct pim_instance *pim)
{ {
++qpim_rpf_cache_refresh_requests; ++qpim_rpf_cache_refresh_requests;
pim_rpf_set_refresh_time(); pim_rpf_set_refresh_time();
if (qpim_rpf_cache_refresher) { if (pim->rpf_cache_refresher) {
/* Refresh timer is already running */ /* Refresh timer is already running */
return; return;
} }
@ -731,9 +691,9 @@ void sched_rpf_cache_refresh(void)
qpim_rpf_cache_refresh_delay_msec); 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_refresh_delay_msec,
&qpim_rpf_cache_refresher); &pim->rpf_cache_refresher);
} }
static void pim_zebra_connected(struct zclient *zclient) static void pim_zebra_connected(struct zclient *zclient)

View file

@ -44,6 +44,6 @@ void igmp_source_forward_reevaluate_all(void);
void pim_forward_start(struct pim_ifchannel *ch); void pim_forward_start(struct pim_ifchannel *ch);
void pim_forward_stop(struct pim_ifchannel *ch, bool install_it); 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); struct zclient *pim_zebra_zclient_get(void);
#endif /* PIM_ZEBRA_H */ #endif /* PIM_ZEBRA_H */

View file

@ -52,7 +52,6 @@ int qpim_t_periodic =
PIM_DEFAULT_T_PERIODIC; /* Period between Join/Prune Messages */ PIM_DEFAULT_T_PERIODIC; /* Period between Join/Prune Messages */
struct pim_assert_metric qpim_infinite_assert_metric; struct pim_assert_metric qpim_infinite_assert_metric;
long qpim_rpf_cache_refresh_delay_msec = 50; 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_requests = 0;
int64_t qpim_rpf_cache_refresh_events = 0; int64_t qpim_rpf_cache_refresh_events = 0;
int64_t qpim_rpf_cache_refresh_last = 0; int64_t qpim_rpf_cache_refresh_last = 0;

View file

@ -140,7 +140,6 @@ struct in_addr qpim_all_pim_routers_addr;
int qpim_t_periodic; /* Period between Join/Prune Messages */ int qpim_t_periodic; /* Period between Join/Prune Messages */
struct pim_assert_metric qpim_infinite_assert_metric; struct pim_assert_metric qpim_infinite_assert_metric;
long qpim_rpf_cache_refresh_delay_msec; 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_requests;
int64_t qpim_rpf_cache_refresh_events; int64_t qpim_rpf_cache_refresh_events;
int64_t qpim_rpf_cache_refresh_last; int64_t qpim_rpf_cache_refresh_last;