From 216abcb12e4ade097ce06a9853f1dca46cf8f98b Mon Sep 17 00:00:00 2001 From: "katerina.kubecova" Date: Tue, 3 Oct 2023 11:07:46 +0200 Subject: [PATCH 1/2] ROA notifications store the affected nets into trie --- nest/proto.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/nest/proto.c b/nest/proto.c index b06f7b72..1257a7e4 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -289,6 +289,7 @@ struct roa_subscription { struct settle settle; struct channel *c; struct rt_export_request req; + struct f_trie* trie; }; static void @@ -309,16 +310,29 @@ channel_roa_out_changed(struct settle *se) CD(c, "Feeding triggered by RPKI change"); + /* TODO feed by trie */ + c->refeed_pending = 1; channel_stop_export(c); } static void -channel_export_one_roa(struct rt_export_request *req, const net_addr *net UNUSED, struct rt_pending_export *first) +channel_export_one_roa(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *first) { struct roa_subscription *s = SKIP_BACK(struct roa_subscription, req, req); - /* TODO: use the information about what roa has changed */ + switch (net->type) + { + case NET_ROA4: + trie_add_prefix(s->trie, net, net_pxlen(net), 32); + break; + case NET_ROA6: + trie_add_prefix(s->trie, net, net_pxlen(net), 128); + break; + default: + bug("ROA table sent us a non-roa export"); + } + settle_kick(&s->settle, s->c->proto->loop); rpe_mark_seen_all(req->hook, first, NULL, NULL); @@ -365,6 +379,7 @@ channel_roa_subscribe(struct channel *c, rtable *tab, int dir) *s = (struct roa_subscription) { .settle = SETTLE_INIT(&c->roa_settle, dir ? channel_roa_in_changed : channel_roa_out_changed, NULL), .c = c, + .trie = f_new_trie(lp_new(c->proto->pool), 0), .req = { .name = mb_sprintf(c->proto->pool, "%s.%s.roa-%s.%s", c->proto->name, c->name, dir ? "in" : "out", tab->name), @@ -395,6 +410,7 @@ channel_roa_unsubscribed(struct rt_export_request *req) static void channel_roa_unsubscribe(struct roa_subscription *s) { + rfree(s->trie->lp); rt_stop_export(&s->req, channel_roa_unsubscribed); settle_cancel(&s->settle); } From 93509af4c1cc508c57873dcb0de6babbf424825c Mon Sep 17 00:00:00 2001 From: "katerina.kubecova" Date: Tue, 3 Oct 2023 11:08:28 +0200 Subject: [PATCH 2/2] Table preexport net-filter refactoring Also added a possibility for filtering by trie. --- nest/proto.c | 8 +++++--- nest/rt-show.c | 4 ++-- nest/rt-table.c | 46 ++++++++++++++++++---------------------------- nest/rt.h | 42 +++++++++++++++++++++++++++++++++--------- proto/bgp/attrs.c | 9 +++++---- 5 files changed, 63 insertions(+), 46 deletions(-) diff --git a/nest/proto.c b/nest/proto.c index 1257a7e4..a7419c96 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -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; diff --git a/nest/rt-show.c b/nest/rt-show.c index 7a8b629b..cb91b5b5 100644 --- a/nest/rt-show.c +++ b/nest/rt-show.c @@ -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++; diff --git a/nest/rt-table.c b/nest/rt-table.c index 1c7c5da6..d84afdc0 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -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; + /* Check export eligibility of this net */ + if (!rt_prefilter_net(&hook->req->prefilter, n)) + goto ignore; - 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; - - 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)); } diff --git a/nest/rt.h b/nest/rt.h index a251b3a5..f88a446c 100644 --- 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 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 */ + TE_ADDR_FOR, /* Longest prefix match - show route for */ + TE_ADDR_IN, /* Interval query - show route in */ + 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 */ -#define TE_ADDR_FOR 2 /* Longest prefix match - show route for */ -#define TE_ADDR_IN 3 /* Interval query - show route in */ - #define TFT_FIB 1 #define TFT_TRIE 2 diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 46145fc5..d33aa6a7 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -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; }