]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Table: Freeing routes deferred to save rcu synchronization
authorMaria Matejka <mq@ucw.cz>
Tue, 4 Jun 2024 19:38:05 +0000 (21:38 +0200)
committerMaria Matejka <mq@ucw.cz>
Tue, 4 Jun 2024 20:20:18 +0000 (22:20 +0200)
nest/route.h
nest/rt-table.c

index 6c1e9da5a56fe7463fe5449f17ea8fa34c0e15a1..12fce5e422f857795785aa29963197cc90e1ca64 100644 (file)
@@ -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 */
index 8b7c16acbe8740d193b1de8439c63e98b1cd3b21..ffa4a84c735297d67572abf2ab4c8b0c796de63f 100644 (file)
@@ -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 */