forked from Mirror/frr
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:
parent
78c16071f9
commit
da11e32521
|
@ -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");
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
234
pimd/pim_zebra.c
234
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)
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue