From a19d0de42f3b8c58878dbbec88c4b1ae03db12e5 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Tue, 4 Jun 2024 21:38:05 +0200 Subject: [PATCH] Table: Freeing routes deferred to save rcu synchronization --- nest/route.h | 1 + nest/rt-table.c | 36 +++++++++++++++++++++++++++++++++--- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/nest/route.h b/nest/route.h index 6c1e9da5..12fce5e4 100644 --- a/nest/route.h +++ b/nest/route.h @@ -408,6 +408,7 @@ struct rtable_private { struct f_trie *flowspec_trie; /* Trie for evaluation of flowspec notifications */ struct roa_digestor *roa_digest; /* Digest of changed ROAs export */ // struct mpls_domain *mpls_domain; /* Label allocator for MPLS */ + u32 rte_free_deferred; /* Counter of deferred rte_free calls */ }; /* The final union private-public rtable structure */ diff --git a/nest/rt-table.c b/nest/rt-table.c index 8b7c16ac..ffa4a84c 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -530,8 +530,16 @@ rte_store(const rte *r, struct netindex *i, struct rtable_private *tab) return s; } +static void rte_free_deferred(struct deferred_call *dc); + +struct rte_free_deferred_item { + struct deferred_call dc; + struct rte_storage *e; + rtable *tab; +}; + /** - * rte_free - delete a &rte + * rte_free_defer - delete a &rte (happens later) * @e: &struct rte_storage to be deleted * @tab: the table which the rte belongs to * @@ -541,8 +549,27 @@ rte_store(const rte *r, struct netindex *i, struct rtable_private *tab) static void rte_free(struct rte_storage *e, struct rtable_private *tab) { - /* Wait for very slow table readers */ - synchronize_rcu(); + struct rte_free_deferred_item rfdi = { + .dc.hook = rte_free_deferred, + .e = e, + .tab = RT_PUB(tab), + }; + + if (!tab->rte_free_deferred++) + rt_lock_table(tab); + + defer_call(&rfdi.dc, sizeof rfdi); +} + +static void +rte_free_deferred(struct deferred_call *dc) +{ + SKIP_BACK_DECLARE(struct rte_free_deferred_item, rfdi, dc, dc); + + struct rte_storage *e = rfdi->e; + RT_LOCK(rfdi->tab, tab); + + /* No need for synchronize_rcu, implied by the deferred_call */ rt_rte_trace_in(D_ROUTES, e->rte.sender->req, &e->rte, "freeing"); @@ -553,6 +580,9 @@ rte_free(struct rte_storage *e, struct rtable_private *tab) ea_free(e->rte.attrs); sl_free(e); + + if (!--tab->rte_free_deferred) + rt_unlock_table(tab); } static int /* Actually better or at least as good as */