]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Table preexport net-filter refactoring
authorkaterina.kubecova <katerina.kubecova@nic.cz>
Tue, 3 Oct 2023 09:08:28 +0000 (11:08 +0200)
committerMaria Matejka <mq@ucw.cz>
Tue, 3 Oct 2023 09:08:28 +0000 (11:08 +0200)
Also added a possibility for filtering by trie.

nest/proto.c
nest/rt-show.c
nest/rt-table.c
nest/rt.h
proto/bgp/attrs.c

index 1257a7e4f7d0954e54896a535b62ab730dcdf085..a7419c9611021e3c54a6a314cd1c8fc9e9a23e2c 100644 (file)
@@ -516,8 +516,10 @@ channel_start_export(struct channel *c)
     .list = proto_work_list(c->proto),
     .pool = c->proto->pool,
     .feed_block_size = c->feed_block_size,
-    .addr = c->out_subprefix,
-    .addr_mode = c->out_subprefix ? TE_ADDR_IN : TE_ADDR_NONE,
+    .prefilter = {
+      .mode = c->out_subprefix ? TE_ADDR_IN : TE_ADDR_NONE,
+      .addr = c->out_subprefix,
+    },
     .trace_routes = c->debug | c->proto->debug,
     .dump_req = channel_dump_export_req,
     .log_state_change = channel_export_log_state_change,
@@ -1025,7 +1027,7 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
   // c->ra_mode = cf->ra_mode;
   c->merge_limit = cf->merge_limit;
   c->preference = cf->preference;
-  c->out_req.addr = c->out_subprefix = cf->out_subprefix;
+  c->out_req.prefilter.addr = c->out_subprefix = cf->out_subprefix;
   c->debug = cf->debug;
   c->in_req.trace_routes = c->out_req.trace_routes = c->debug | c->proto->debug;
   c->rpki_reload = cf->rpki_reload;
index 7a8b629b962a6a5ac37a896d647690b5316bcc87..cb91b5b5008972e24722cc00f3a8e5625dd6fdb8 100644 (file)
@@ -285,14 +285,14 @@ rt_show_cont(struct rt_show_data *d)
   }
 
   d->req = (struct rt_export_request) {
-    .addr = d->addr,
+    .prefilter.addr = d->addr,
     .name = "CLI Show Route",
     .list = &global_work_list,
     .pool = c->pool,
     .export_bulk = rt_show_net_export_bulk,
     .dump_req = rt_show_dump_req,
     .log_state_change = rt_show_log_state_change,
-    .addr_mode = d->addr_mode,
+    .prefilter.mode = d->addr_mode,
   };
 
   d->table_counter++;
index 1c7c5da6dd1ebdd17db3317c32934635bf5d218d..d84afdc0dbd1e7ceaeeaae7cf10990954c1afe52 100644 (file)
@@ -1205,27 +1205,12 @@ rte_export(struct rt_table_export_hook *th, struct rt_pending_export *rpe)
 
   const net_addr *n = rpe->new_best ? rpe->new_best->rte.net : rpe->old_best->rte.net;
 
-  switch (hook->req->addr_mode)
-    {
-      case TE_ADDR_NONE:
-       break;
-
-      case TE_ADDR_IN:
-       if (!net_in_netX(n, hook->req->addr))
-         goto ignore;
-       break;
-
-      case TE_ADDR_EQUAL:
-       if (!net_equal(n, hook->req->addr))
-         goto ignore;
-       break;
+  /* Check export eligibility of this net */
+  if (!rt_prefilter_net(&hook->req->prefilter, n))
+    goto ignore;
 
-      case TE_ADDR_FOR:
-       bug("Continuos export of best prefix match not implemented yet.");
-
-      default:
-       bug("Strange table export address mode: %d", hook->req->addr_mode);
-    }
+  if (hook->req->prefilter.mode == TE_ADDR_FOR)
+    bug("Continuos export of best prefix match not implemented yet.");
 
   if (rpe->new)
     hook->stats.updates_received++;
@@ -2156,20 +2141,21 @@ rt_table_export_start_feed(struct rtable_private *tab, struct rt_table_export_ho
   struct rt_export_request *req = hook->h.req;
 
   /* stats zeroed by mb_allocz */
-  switch (req->addr_mode)
+  switch (req->prefilter.mode)
   {
     case TE_ADDR_IN:
       if (tab->trie && net_val_match(tab->addr_type, NB_IP))
       {
        hook->walk_state = mb_allocz(hook->h.pool, sizeof (struct f_trie_walk_state));
        hook->walk_lock = rt_lock_trie(tab);
-       trie_walk_init(hook->walk_state, tab->trie, req->addr);
+       trie_walk_init(hook->walk_state, tab->trie, req->prefilter.addr);
        hook->h.event.hook = rt_feed_by_trie;
        hook->walk_last.type = 0;
        break;
       }
       /* fall through */
     case TE_ADDR_NONE:
+    case TE_ADDR_TRIE:
       FIB_ITERATE_INIT(&hook->feed_fit, &tab->fib);
       hook->h.event.hook = rt_feed_by_fib;
       break;
@@ -2253,7 +2239,7 @@ rt_table_export_stop_locked(struct rt_export_hook *hh)
       rt_trace(tab, D_EVENTS, "Stopping export hook %s must wait for uncorking", hook->h.req->name);
       return 0;
     case TES_FEEDING:
-      switch (hh->req->addr_mode)
+      switch (hh->req->prefilter.mode)
       {
        case TE_ADDR_IN:
          if (hook->walk_lock)
@@ -2266,8 +2252,12 @@ rt_table_export_stop_locked(struct rt_export_hook *hh)
          }
          /* fall through */
        case TE_ADDR_NONE:
+       case TE_ADDR_TRIE:
          fit_get(&tab->fib, &hook->feed_fit);
          break;
+       case TE_ADDR_EQUAL:
+       case TE_ADDR_FOR:
+         break;
       }
       break;
 
@@ -4346,7 +4336,7 @@ rt_feed_by_fib(void *data)
 
   FIB_ITERATE_START(&tab->fib, fit, net, n)
     {
-      if ((c->h.req->addr_mode == TE_ADDR_NONE) || net_in_netX(n->n.addr, c->h.req->addr))
+      if (rt_prefilter_net(&c->h.req->prefilter, n->n.addr))
       {
        if (!rt_prepare_feed(c, n, &block))
        {
@@ -4421,9 +4411,9 @@ rt_feed_equal(void *data)
   RT_LOCKED(RT_PUB(SKIP_BACK(struct rtable_private, exporter, c->table)), tab)
   {
     ASSERT_DIE(atomic_load_explicit(&c->h.export_state, memory_order_relaxed) == TES_FEEDING);
-    ASSERT_DIE(c->h.req->addr_mode == TE_ADDR_EQUAL);
+    ASSERT_DIE(c->h.req->prefilter.mode == TE_ADDR_EQUAL);
 
-    if (n = net_find(tab, c->h.req->addr))
+    if (n = net_find(tab, c->h.req->prefilter.addr))
       ASSERT_DIE(rt_prepare_feed(c, n, &block));
   }
 
@@ -4443,9 +4433,9 @@ rt_feed_for(void *data)
   RT_LOCKED(RT_PUB(SKIP_BACK(struct rtable_private, exporter, c->table)), tab)
   {
     ASSERT_DIE(atomic_load_explicit(&c->h.export_state, memory_order_relaxed) == TES_FEEDING);
-    ASSERT_DIE(c->h.req->addr_mode == TE_ADDR_FOR);
+    ASSERT_DIE(c->h.req->prefilter.mode == TE_ADDR_FOR);
 
-    if (n = net_route(tab, c->h.req->addr))
+    if (n = net_route(tab, c->h.req->prefilter.addr))
       ASSERT_DIE(rt_prepare_feed(c, n, &block));
   }
 
index a251b3a58ff810c141de66efc7efab213789ee88..f88a446c6151b7c2334b5937d7342eb00dccefc6 100644 (file)
--- a/nest/rt.h
+++ b/nest/rt.h
@@ -22,6 +22,8 @@
 #include "lib/io-loop.h"
 #include "lib/settle.h"
 
+#include "filter/data.h"
+
 #include <stdatomic.h>
 
 struct ea_list;
@@ -286,13 +288,27 @@ 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 */
+  };
+                               /* 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 */
+  } mode;
+} PACKED;
+
 struct rt_export_request {
   struct rt_export_hook *hook;         /* Table part of the export */
-  char *name;
-  const net_addr *addr;                        /* Network prefilter address */
+  char *name;          /* Network prefilter address */
   u8 trace_routes;
-  u8 addr_mode;                                /* Network prefilter mode (TE_ADDR_*) */
   uint feed_block_size;                        /* How many routes to feed at once */
+  struct rt_prefilter prefilter;
 
   event_list *list;                    /* Where to schedule export events */
   pool *pool;                          /* Pool to use for allocations */
@@ -313,6 +329,20 @@ struct rt_export_request {
   void (*log_state_change)(struct rt_export_request *req, u8);
 };
 
+static inline int rt_prefilter_net(const struct rt_prefilter *p, const net_addr *n)
+{
+  switch (p->mode)
+  {
+    case TE_ADDR_NONE: return 1;
+    case TE_ADDR_IN:   return net_in_netX(n, p->addr);
+    case TE_ADDR_EQUAL:        return net_equal(n, p->addr);
+    case TE_ADDR_FOR:  return net_in_netX(p->addr, n);
+    case TE_ADDR_TRIE: return trie_match_net(p->trie, n);
+  }
+
+  bug("Crazy prefilter application attempt failed wildly.");
+}
+
 struct rt_export_hook {
   node n;
   struct rt_exporter *table;           /* The connected table */
@@ -382,12 +412,6 @@ struct rt_table_export_hook {
 #define TES_STOP       4
 #define TES_MAX                5
 
-/* Value of addr_mode */
-#define TE_ADDR_NONE   0               /* No address matching */
-#define TE_ADDR_EQUAL  1               /* Exact query - show route <addr> */
-#define TE_ADDR_FOR    2               /* Longest prefix match - show route for <addr> */
-#define TE_ADDR_IN     3               /* Interval query - show route in <addr> */
-
 
 #define TFT_FIB                1
 #define TFT_TRIE       2
index 46145fc5124959d8bd5ae5c534ce9cc2d9bc0b00..d33aa6a7e53fe468c5d98e4180d1c11d250a2764 100644 (file)
@@ -1896,16 +1896,17 @@ bgp_out_table_feed(void *data)
 
   int max = 512;
 
-  const net_addr *neq = (hook->h.req->addr_mode == TE_ADDR_EQUAL) ? hook->h.req->addr : NULL;
+  const net_addr *neq = (hook->h.req->prefilter.mode == TE_ADDR_EQUAL) ? hook->h.req->prefilter.addr : NULL;
   const net_addr *cand = NULL;
 
   do {
     HASH_WALK_ITER(c->prefix_hash, PXH, n, hook->hash_iter)
     {
-      switch (hook->h.req->addr_mode)
+      switch (hook->h.req->prefilter.mode)
       {
+       case TE_ADDR_TRIE:
        case TE_ADDR_IN:
-         if (!net_in_netX(n->net, hook->h.req->addr))
+         if (!rt_prefilter_net(&hook->h.req->prefilter, n->net))
            continue;
          /* fall through */
        case TE_ADDR_NONE:
@@ -1917,7 +1918,7 @@ bgp_out_table_feed(void *data)
        case TE_ADDR_FOR:
          if (!neq)
          {
-           if (net_in_netX(hook->h.req->addr, n->net) && (!cand || (n->net->length > cand->length)))
+           if (net_in_netX(hook->h.req->prefilter.addr, n->net) && (!cand || (n->net->length > cand->length)))
              cand = n->net;
            continue;
          }