zebra: remove useless deleted route_entries promptly

Zebra accumulates route-entry objects and then processes them
as a group. If that rib processing is delayed, because the
dataplane/fib programming has built up a queue e.g., zebra can
hold multiple deleted route objects in memory. At scale, this can
be a problem. Delete unneeded route entries promptly, if they
can't contribute to rib processing.

Signed-off-by: Mark Stapp <mjs@voltanet.io>
This commit is contained in:
Mark Stapp 2020-07-22 12:25:05 -04:00
parent e8678e2c51
commit 0ca6f3b1e6

View File

@ -2933,8 +2933,10 @@ int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
struct nhg_hash_entry *nhe = NULL; struct nhg_hash_entry *nhe = NULL;
struct route_table *table; struct route_table *table;
struct route_node *rn; struct route_node *rn;
struct route_entry *same = NULL; struct route_entry *same = NULL, *first_same = NULL;
int ret = 0; int ret = 0;
int same_count = 0;
rib_dest_t *dest;
if (!re || !re_nhe) if (!re || !re_nhe)
return -1; return -1;
@ -3002,14 +3004,22 @@ int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
* for the install don't do a route replace. * for the install don't do a route replace.
*/ */
RNODE_FOREACH_RE (rn, same) { RNODE_FOREACH_RE (rn, same) {
if (CHECK_FLAG(same->status, ROUTE_ENTRY_REMOVED)) if (CHECK_FLAG(same->status, ROUTE_ENTRY_REMOVED)) {
same_count++;
continue; continue;
}
/* Compare various route_entry properties */ /* Compare various route_entry properties */
if (rib_compare_routes(re, same)) if (rib_compare_routes(re, same)) {
break; same_count++;
if (first_same == NULL)
first_same = same;
}
} }
same = first_same;
/* If this route is kernel/connected route, notify the dataplane. */ /* If this route is kernel/connected route, notify the dataplane. */
if (RIB_SYSTEM_ROUTE(re)) { if (RIB_SYSTEM_ROUTE(re)) {
/* Notify dataplane */ /* Notify dataplane */
@ -3019,8 +3029,9 @@ int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
/* Link new re to node.*/ /* Link new re to node.*/
if (IS_ZEBRA_DEBUG_RIB) { if (IS_ZEBRA_DEBUG_RIB) {
rnode_debug(rn, re->vrf_id, rnode_debug(rn, re->vrf_id,
"Inserting route rn %p, re %p (%s) existing %p", "Inserting route rn %p, re %p (%s) existing %p, same_count %d",
rn, re, zebra_route_string(re->type), same); rn, re, zebra_route_string(re->type), same,
same_count);
if (IS_ZEBRA_DEBUG_RIB_DETAILED) if (IS_ZEBRA_DEBUG_RIB_DETAILED)
route_entry_dump(p, src_p, re); route_entry_dump(p, src_p, re);
@ -3034,6 +3045,24 @@ int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
if (same) if (same)
rib_delnode(rn, same); rib_delnode(rn, same);
/* See if we can remove some RE entries that are queued for
* removal, but won't be considered in rib processing.
*/
dest = rib_dest_from_rnode(rn);
RNODE_FOREACH_RE_SAFE (rn, re, same) {
if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) {
/* If the route was used earlier, must retain it. */
if (dest && re == dest->selected_fib)
continue;
if (IS_ZEBRA_DEBUG_RIB)
rnode_debug(rn, re->vrf_id, "rn %p, removing unneeded re %p",
rn, re);
rib_unlink(rn, re);
}
}
route_unlock_node(rn); route_unlock_node(rn);
return ret; return ret;
} }