Also added a possibility for filtering by trie.
.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,
// 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;
}
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++;
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++;
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;
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)
}
/* 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;
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))
{
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));
}
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));
}
#include "lib/io-loop.h"
#include "lib/settle.h"
+#include "filter/data.h"
+
#include <stdatomic.h>
struct ea_list;
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 */
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 */
#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
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:
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;
}