]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Partial import reload
authorKaterina Kubecova <katerina.kubecova@nic.cz>
Thu, 12 Oct 2023 11:16:54 +0000 (13:16 +0200)
committerKaterina Kubecova <katerina.kubecova@nic.cz>
Thu, 12 Oct 2023 11:16:54 +0000 (13:16 +0200)
nest/proto.c
nest/protocol.h
nest/rt-table.c
nest/rt.h

index 38228c12ce30537ba0e12096c99b93f52173ff57..318aaac458c3c7ae9356f48fc87edf41988fdb69 100644 (file)
@@ -52,6 +52,7 @@ static void channel_init_limit(struct channel *c, struct limit *l, int dir, stru
 static void channel_update_limit(struct channel *c, struct limit *l, int dir, struct channel_limit *cf);
 static void channel_reset_limit(struct channel *c, struct limit *l, int dir);
 static int channel_refeed_prefilter(const struct rt_prefilter *p, const net_addr *n);
+static int channel_import_prefilter(const struct rt_prefilter *p, const net_addr *n);
 static void channel_feed_end(struct channel *c);
 static void channel_stop_export(struct channel *c);
 static void channel_export_stopped(struct rt_export_request *req);
@@ -557,6 +558,10 @@ channel_start_import(struct channel *c)
     .dump_req = channel_dump_import_req,
     .log_state_change = channel_import_log_state_change,
     .preimport = channel_preimport,
+    .prefilter = {
+      .mode = c->out_subprefix ? TE_ADDR_IN : TE_ADDR_NONE,
+      .addr = c->out_subprefix,
+    },
   };
 
   ASSERT(c->channel_state == CS_UP);
@@ -752,11 +757,30 @@ channel_refeed_prefilter(const struct rt_prefilter *p, const net_addr *n)
 
   for (struct channel_feeding_request *cfr = c->refeeding; cfr; cfr = cfr->next)
     if (!cfr->trie || trie_match_net(cfr->trie, n))
+    {
+      log(L_TRACE "Export this one");
       return 1;
-
+    }
+  log(L_TRACE "%N filtered out of export", n);
   return 0;
 }
 
+static int
+channel_import_prefilter(const struct rt_prefilter *p, const net_addr *n)
+{
+  const struct channel *c =
+    SKIP_BACK(struct channel, reload_req,
+       SKIP_BACK(struct rt_export_request, prefilter, p)
+       );
+  for (struct channel_import_request *cir = c->importing; cir; cir = cir->next)
+    if (!cir->trie || trie_match_net(cir->trie, n))
+     {
+      log(L_TRACE "Export this one");
+      return 1;
+     }
+  log(L_TRACE "%N filtered out of import", n);
+  return 0;
+}
 
 static void
 channel_feed_end(struct channel *c)
@@ -808,18 +832,44 @@ channel_feed_end(struct channel *c)
 
 /* Called by protocol for reload from in_table */
 void
-channel_schedule_reload(struct channel *c)
+channel_schedule_reload(struct channel *c, struct channel_import_request *cir)
 {
+  log(L_TRACE "channel_schedule_reload %i %i",cir, (cir && cir->trie));
   ASSERT(c->in_req.hook);
-
-  if (c->reload_req.hook)
+  int no_trie = 0;
+  if (cir)
+  {
+    struct channel_import_request* last = c->import_pending;
+    while (last)
+    {
+      if (!last->trie)
+        no_trie = 1;
+      last = last->next;
+    }
+    last = cir;
+    no_trie = !last->trie;
+  }
+  if (c->reload_req.hook) 
   {
     CD(c, "Reload triggered before the previous one has finished");
     c->reload_pending = 1;
     return;
   }
+  c->importing = c->import_pending;
+  c->import_pending = NULL;
+
+  if (no_trie)
+  {
+    c->reload_req.prefilter.mode = TE_ADDR_NONE;
+    c->reload_req.prefilter.hook = NULL;
+  }
+  else
+  {
+    CD(c, "Import with trie");
+    c->reload_req.prefilter.mode = TE_ADDR_HOOK;
+    c->reload_req.prefilter.hook = channel_import_prefilter;
+  }
 
-  rt_refresh_begin(&c->in_req);
   rt_request_export(c->table, &c->reload_req);
 }
 
@@ -1081,12 +1131,32 @@ channel_request_reload(struct channel *c)
 
   CD(c, "Reload requested");
 
-  if ((c->in_keep & RIK_PREFILTER) == RIK_PREFILTER)
-    channel_schedule_reload(c);
+  if ((c->in_keep & RIK_PREFILTER) == RIK_PREFILTER) {
+    struct channel_import_request* cir = mb_alloc(c->proto->pool, sizeof *cir);;
+    cir->trie = NULL;
+    channel_schedule_reload(c, cir);
+  }
   else
     c->proto->reload_routes(c);
 }
 
+static void
+channel_request_partial_reload(struct channel *c, struct channel_import_request *cir)
+{
+  ASSERT(c->in_req.hook);
+  ASSERT(channel_reloadable(c));
+
+  CD(c, "Partial import reload requested");
+  
+  if ((c->in_keep & RIK_PREFILTER) == RIK_PREFILTER)
+    channel_schedule_reload(c, cir);
+    /* TODO*/
+  else
+    CD(c, "Partial import reload requested, but with ric cosi");
+    /*c->proto->reload_routes(c);
+  */
+}
+
 const struct channel_class channel_basic = {
   .channel_size = sizeof(struct channel),
   .config_size = sizeof(struct channel_config)
@@ -2681,6 +2751,11 @@ struct channel_cmd_reload_feeding_request {
   struct proto_reload_request *prr;
 };
 
+struct channel_cmd_reload_import_request {
+  struct channel_import_request cir;
+  struct proto_reload_request *prr;
+};
+
 static void
 channel_reload_out_done_main(void *_prr)
 {
@@ -2698,6 +2773,14 @@ channel_reload_out_done(struct channel_feeding_request *cfr)
     ev_send_loop(&main_birdloop, &ccrfr->prr->ev);
 }
 
+static void
+channel_reload_in_done(struct channel_import_request *cir)
+{
+  struct channel_cmd_reload_import_request *ccrir = SKIP_BACK(struct channel_cmd_reload_import_request, cir, cir);
+  if (atomic_fetch_sub_explicit(&ccrir->prr->counter, 1, memory_order_acq_rel) == 1)
+    ev_send_loop(&main_birdloop, &ccrir->prr->ev);
+}
+
 void
 proto_cmd_reload(struct proto *p, uintptr_t _prr, int cnt UNUSED)
 {
@@ -2729,7 +2812,37 @@ proto_cmd_reload(struct proto *p, uintptr_t _prr, int cnt UNUSED)
   if (prr->dir != CMD_RELOAD_OUT)
     WALK_LIST(c, p->channels)
       if (c->channel_state == CS_UP)
-       channel_request_reload(c);
+      {
+        if (prr->trie)
+       {
+         /* Increase the refeed counter */
+         if (atomic_fetch_add_explicit(&prr->counter, 1, memory_order_relaxed) == 0)
+         {
+           /* First occurence */
+           ASSERT_DIE(this_cli->parser_pool == prr->trie->lp);
+           rmove(this_cli->parser_pool, &root_pool);
+           this_cli->parser_pool = lp_new(this_cli->pool);
+           prr->ev = (event) {
+             .hook = channel_reload_out_done_main,
+             .data = prr,
+           };
+         }
+         else
+           ASSERT_DIE(this_cli->parser_pool != prr->trie->lp);
+
+         struct channel_cmd_reload_import_request *req = lp_alloc(prr->trie->lp, sizeof *req);
+         *req = (struct channel_cmd_reload_import_request) {
+           .cir = {
+             .done = channel_reload_in_done,
+             .trie = prr->trie,
+           },
+           .prr = prr,
+         };
+         channel_request_partial_reload(c, &req->cir);
+        }
+        else
+         channel_request_reload(c);
+      }
 
   /* re-exporting routes */
   if (prr->dir != CMD_RELOAD_IN)
index a95e1c0461d498d97ea311c8edb5472784685f8b..00021654d5ef525b6e62bd72b060043d8fd68b97 100644 (file)
@@ -581,6 +581,8 @@ struct channel {
   struct f_trie *refeed_trie;          /* Auxiliary refeed trie */
   struct channel_feeding_request *refeeding;   /* Refeeding the channel */
   struct channel_feeding_request *refeed_pending;      /* Scheduled refeeds */
+  struct channel_import_request *importing;    /* Importing the channel */
+  struct channel_import_request *import_pending;       /* Scheduled imports */
 
   uint feed_block_size;                        /* How many routes to feed at once */
 
@@ -677,7 +679,7 @@ struct channel *proto_add_channel(struct proto *p, struct channel_config *cf);
 int proto_configure_channel(struct proto *p, struct channel **c, struct channel_config *cf);
 
 void channel_set_state(struct channel *c, uint state);
-void channel_schedule_reload(struct channel *c);
+void channel_schedule_reload(struct channel *c, struct channel_import_request *cir);
 
 static inline void channel_init(struct channel *c) { channel_set_state(c, CS_START); }
 static inline void channel_open(struct channel *c) { channel_set_state(c, CS_UP); }
@@ -698,6 +700,12 @@ struct channel_feeding_request {
   } state;
 };
 
+struct channel_import_request {
+  struct channel_import_request *next;                 /* Next in request chain */
+  void (*done)(struct channel_import_request *);       /* Called when import finishes */
+  const struct f_trie *trie;                           /* Reload only matching nets */
+};
+
 struct channel *channel_from_export_request(struct rt_export_request *req);
 void channel_request_feeding(struct channel *c, struct channel_feeding_request *);
 void channel_request_feeding_dynamic(struct channel *c, enum channel_feeding_request_type);
index 160d24b1dbe19f8fd18b20e83e64f2e6b2c4845a..5cf7b2ee6ac8d95c4f5dfeab3b6333a4eece8c2d 100644 (file)
@@ -2212,7 +2212,7 @@ rt_table_export_start_feed(struct rtable_private *tab, struct rt_table_export_ho
 {
   struct rt_exporter *re = &tab->exporter.e;
   struct rt_export_request *req = hook->h.req;
-
+  log("Hook is %x", hook);
   /* stats zeroed by mb_allocz */
   switch (req->prefilter.mode)
   {
@@ -2230,6 +2230,7 @@ rt_table_export_start_feed(struct rtable_private *tab, struct rt_table_export_ho
     case TE_ADDR_NONE:
     case TE_ADDR_TRIE:
     case TE_ADDR_HOOK:
+      log(L_TRACE "hook - we will feed by fib, not trie?");
       FIB_ITERATE_INIT(&hook->feed_fit, &tab->fib);
       hook->h.event.hook = rt_feed_by_fib;
       break;
@@ -4403,6 +4404,7 @@ rt_process_feed(struct rt_table_export_hook *c, rt_feed_block *b)
 static void
 rt_feed_by_fib(void *data)
 {
+  log(L_TRACE "rt_feed_by_fib_function - here filtering starts");
   struct rt_table_export_hook *c = data;
   struct fib_iterator *fit = &c->feed_fit;
   rt_feed_block block = {};
@@ -4546,6 +4548,7 @@ void channel_reload_export_bulk(struct rt_export_request *req, const net_addr *n
       while (new.attrs->next)
        new.attrs = new.attrs->next;
 
+      log(L_TRACE "chanel_reload_export_bulk %N", net);
       /* And reload the route */
       rte_update(c, net, &new, new.src);
     }
index bd9f9363eaa34dd85fb0eb9090662d595b03e4c8..721a7325afb1625701f678bc82d6ec7d0e4f82d2 100644 (file)
--- a/nest/rt.h
+++ b/nest/rt.h
@@ -253,10 +253,28 @@ struct rte_storage {
 
 /* Table-channel connections */
 
+struct rt_prefilter {
+  union {
+    const struct f_trie *trie;
+    const net_addr *addr;      /* Network prefilter address */
+    int (*hook)(const struct rt_prefilter *, const net_addr *);
+  };
+                               /* Network prefilter mode (TE_ADDR_*) */
+  enum {
+    TE_ADDR_NONE = 0,          /* No address matching */
+    TE_ADDR_EQUAL,             /* Exact query - show route <addr> */
+    TE_ADDR_FOR,               /* Longest prefix match - show route for <addr> */
+    TE_ADDR_IN,                        /* Interval query - show route in <addr> */
+    TE_ADDR_TRIE,              /* Query defined by trie */
+    TE_ADDR_HOOK,              /* Query processed by supplied custom hook */
+  } mode;
+} PACKED;
+
 struct rt_import_request {
   struct rt_import_hook *hook;         /* The table part of importer */
   char *name;
   u8 trace_routes;
+  struct rt_prefilter prefilter;
 
   event_list *list;                    /* Where to schedule announce events */
 
@@ -300,23 +318,6 @@ struct rt_pending_export {
   u64 seq;                             /* Sequential ID (table-local) of the pending export */
 };
 
-struct rt_prefilter {
-  union {
-    const struct f_trie *trie;
-    const net_addr *addr;      /* Network prefilter address */
-    int (*hook)(const struct rt_prefilter *, const net_addr *);
-  };
-                               /* Network prefilter mode (TE_ADDR_*) */
-  enum {
-    TE_ADDR_NONE = 0,          /* No address matching */
-    TE_ADDR_EQUAL,             /* Exact query - show route <addr> */
-    TE_ADDR_FOR,               /* Longest prefix match - show route for <addr> */
-    TE_ADDR_IN,                        /* Interval query - show route in <addr> */
-    TE_ADDR_TRIE,              /* Query defined by trie */
-    TE_ADDR_HOOK,              /* Query processed by supplied custom hook */
-  } mode;
-} PACKED;
-
 struct rt_export_request {
   struct rt_export_hook *hook;         /* Table part of the export */
   char *name;          /* Network prefilter address */