From dc720a085f0f805891eb086bf96dac99c8a1b7da Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 27 Jun 2022 19:53:06 +0200 Subject: [PATCH] Show route uses the export request also for one-net queries --- nest/config.Y | 10 ++-- nest/proto.c | 5 +- nest/rt-show.c | 118 ++++++++++++++--------------------------------- nest/rt-table.c | 119 ++++++++++++++++++++++++++++++++++++++---------- nest/rt.h | 26 +++++++---- 5 files changed, 153 insertions(+), 125 deletions(-) diff --git a/nest/config.Y b/nest/config.Y index ec10dd69..7c163f74 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -659,20 +659,20 @@ r_args: $$ = $1; if ($$->addr) cf_error("Only one prefix expected"); $$->addr = $2; - $$->addr_mode = RSD_ADDR_EQUAL; + $$->addr_mode = TE_ADDR_EQUAL; } | r_args FOR r_args_for { $$ = $1; if ($$->addr) cf_error("Only one prefix expected"); $$->addr = $3; - $$->addr_mode = RSD_ADDR_FOR; + $$->addr_mode = TE_ADDR_FOR; } | r_args IN net_any { $$ = $1; if ($$->addr) cf_error("Only one prefix expected"); if (!net_type_match($3, NB_IP)) cf_error("Only IP networks accepted for 'in' argument"); $$->addr = $3; - $$->addr_mode = RSD_ADDR_IN; + $$->addr_mode = TE_ADDR_IN; } | r_args TABLE symbol_known { cf_assert_symbol($3, SYM_TABLE); @@ -689,12 +689,12 @@ r_args: } | r_args IMPORT TABLE channel_arg { if (!($4->in_keep & RIK_PREFILTER)) cf_error("No import table in channel %s.%s", $4->proto->name, $4->name); - rt_show_add_table($$, $4->table)->prefilter = $4; + rt_show_add_exporter($$, &$4->table->exporter, "import")->prefilter = $4; $$->tables_defined_by = RSD_TDB_DIRECT; } | r_args EXPORT TABLE channel_arg { if (!$4->out_table) cf_error("No export table in channel %s.%s", $4->proto->name, $4->name); - rt_show_add_table($$, $4->out_table); + rt_show_add_exporter($$, &$4->out_table->exporter, "export"); $$->tables_defined_by = RSD_TDB_DIRECT; } | r_args FILTER filter { diff --git a/nest/proto.c b/nest/proto.c index 0daf59f4..e7be8001 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -468,7 +468,8 @@ channel_start_export(struct channel *c) c->out_req = (struct rt_export_request) { .name = rn, - .addr_in = c->out_subprefix, + .addr = c->out_subprefix, + .addr_mode = c->out_subprefix ? TE_ADDR_IN : TE_ADDR_NONE, .trace_routes = c->debug | c->proto->debug, .dump_req = channel_dump_export_req, .log_state_change = channel_export_log_state_change, @@ -952,7 +953,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_in = c->out_subprefix = cf->out_subprefix; + c->out_req.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 ac6653ec..c3294518 100644 --- a/nest/rt-show.c +++ b/nest/rt-show.c @@ -29,24 +29,17 @@ rt_show_table(struct rt_show_data *d) if (d->last_table) cli_printf(c, -1007, ""); cli_printf(c, -1007, "Table %s:", - d->tab->prefilter ? "import" : d->tab->table->name); + d->tab->name); d->last_table = d->tab; } -static inline struct krt_proto * -rt_show_get_kernel(struct rt_show_data *d) -{ - struct proto_config *krt = d->tab->table->config->krt_attached; - return krt ? (struct krt_proto *) krt->proto : NULL; -} - static void rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, int primary) { byte from[IPA_MAX_TEXT_LENGTH+8]; byte tm[TM_DATETIME_BUFFER_SIZE], info[256]; ea_list *a = e->attrs; - int sync_error = d->kernel ? krt_get_sync_error(d->kernel, e) : 0; + int sync_error = d->tab->kernel ? krt_get_sync_error(d->tab->kernel, e) : 0; void (*get_route_info)(struct rte *, byte *buf); eattr *nhea = net_type_match(e->net, NB_DEST) ? ea_find(a, &ea_gen_nexthop) : NULL; @@ -228,11 +221,6 @@ rt_show_export_stopped_cleanup(struct rt_export_request *req) /* The hook is now invalid */ req->hook = NULL; - /* Unlock referenced tables */ - struct rt_show_data_rtable *tab; - WALK_LIST(tab, d->tables) - rt_unlock_table(tab->table); - /* And free the CLI (deferred) */ rfree(d->cli->pool); } @@ -276,11 +264,6 @@ rt_show_cont(struct rt_show_data *d) { cli_printf(c, 8004, "Stopped due to reconfiguration"); - /* Unlock referenced tables */ - struct rt_show_data_rtable *tab; - WALK_LIST(tab, d->tables) - rt_unlock_table(tab->table); - /* No more action */ c->cleanup = NULL; c->cont = NULL; @@ -290,15 +273,15 @@ rt_show_cont(struct rt_show_data *d) } d->req = (struct rt_export_request) { - .addr_in = (d->addr_mode == RSD_ADDR_IN) ? d->addr : NULL, + .addr = d->addr, .name = "CLI Show Route", .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, }; d->table_counter++; - d->kernel = rt_show_get_kernel(d); d->show_counter_last = d->show_counter; d->rt_counter_last = d->rt_counter; @@ -307,7 +290,7 @@ rt_show_cont(struct rt_show_data *d) if (d->tables_defined_by & RSD_TDB_SET) rt_show_table(d); - rt_request_export(&d->tab->table->exporter, &d->req); + rt_request_export(d->tab->table, &d->req); } static void @@ -325,19 +308,14 @@ rt_show_export_stopped(struct rt_export_request *req) cli_printf(d->cli, -1007, "%d of %d routes for %d networks in table %s", d->show_counter - d->show_counter_last, d->rt_counter - d->rt_counter_last, - d->net_counter - d->net_counter_last, d->tab->table->name); + d->net_counter - d->net_counter_last, d->tab->name); } - d->kernel = NULL; d->tab = NODE_NEXT(d->tab); if (NODE_VALID(d->tab)) return rt_show_cont(d); - /* Unlock referenced tables */ - struct rt_show_data_rtable *tab; - WALK_LIST(tab, d->tables) - rt_unlock_table(tab->table); /* Printout total stats */ if (d->stats && (d->table_counter > 1)) @@ -346,6 +324,8 @@ rt_show_export_stopped(struct rt_export_request *req) cli_printf(d->cli, 14, "Total: %d of %d routes for %d networks in %d tables", d->show_counter, d->rt_counter, d->net_counter, d->table_counter); } + else if (!d->rt_counter && ((d->addr_mode == TE_ADDR_EQUAL) || (d->addr_mode == TE_ADDR_FOR))) + cli_printf(d->cli, 8001, "Network not found"); else cli_printf(d->cli, 0, ""); @@ -353,14 +333,27 @@ rt_show_export_stopped(struct rt_export_request *req) } struct rt_show_data_rtable * -rt_show_add_table(struct rt_show_data *d, rtable *t) +rt_show_add_exporter(struct rt_show_data *d, struct rt_exporter *t, const char *name) { struct rt_show_data_rtable *tab = cfg_allocz(sizeof(struct rt_show_data_rtable)); tab->table = t; + tab->name = name; add_tail(&(d->tables), &(tab->n)); return tab; } +struct rt_show_data_rtable * +rt_show_add_table(struct rt_show_data *d, struct rtable *t) +{ + struct rt_show_data_rtable *rsdr = rt_show_add_exporter(d, &t->exporter, t->name); + + struct proto_config *krt = t->config->krt_attached; + if (krt) + rsdr->kernel = (struct krt_proto *) krt->proto; + + return rsdr; +} + static inline void rt_show_get_default_tables(struct rt_show_data *d) { @@ -415,16 +408,16 @@ rt_show_prepare_tables(struct rt_show_data *d) if (d->export_mode) { if (!tab->export_channel && d->export_channel && - (tab->table == d->export_channel->table)) + (tab->table == &d->export_channel->table->exporter)) tab->export_channel = d->export_channel; if (!tab->export_channel && d->export_protocol) - tab->export_channel = proto_find_channel_by_table(d->export_protocol, tab->table); + tab->export_channel = proto_find_channel_by_table(d->export_protocol, SKIP_BACK(rtable, exporter, tab->table)); if (!tab->export_channel) { if (d->tables_defined_by & RSD_TDB_NMN) - cf_error("No export channel for table %s", tab->table->name); + cf_error("No export channel for table %s", tab->name); rem_node(&(tab->n)); continue; @@ -435,7 +428,7 @@ rt_show_prepare_tables(struct rt_show_data *d) if (d->addr && (tab->table->addr_type != d->addr->type)) { if (d->tables_defined_by & RSD_TDB_NMN) - cf_error("Incompatible type of prefix/ip for table %s", tab->table->name); + cf_error("Incompatible type of prefix/ip for table %s", tab->name); rem_node(&(tab->n)); continue; @@ -456,65 +449,20 @@ rt_show_dummy_cont(struct cli *c UNUSED) void rt_show(struct rt_show_data *d) { - struct rt_show_data_rtable *tab; - net *n; - /* Filtered routes are neither exported nor have sensible ordering */ if (d->filtered && (d->export_mode || d->primary_only)) cf_error("Incompatible show route options"); rt_show_prepare_tables(d); - if (!d->addr || (d->addr_mode == RSD_ADDR_IN)) - { - WALK_LIST(tab, d->tables) - rt_lock_table(tab->table); + if (EMPTY_LIST(d->tables)) + cf_error("No suitable tables found"); - /* There is at least one table */ - d->tab = HEAD(d->tables); - this_cli->cleanup = rt_show_cleanup; - this_cli->rover = d; - this_cli->cont = rt_show_dummy_cont; - rt_show_cont(d); - } - else - { - uint max = 64; - rte **feed = mb_alloc(d->cli->pool, sizeof(rte *) * max); + d->tab = HEAD(d->tables); - WALK_LIST(tab, d->tables) - { - d->tab = tab; - d->kernel = rt_show_get_kernel(d); + this_cli->cleanup = rt_show_cleanup; + this_cli->rover = d; + this_cli->cont = rt_show_dummy_cont; - if (d->addr_mode == RSD_ADDR_FOR) - n = net_route(tab->table, d->addr); - else - n = net_find(tab->table, d->addr); - - uint count = 0; - for (struct rte_storage *e = n->routes; e; e = e->next) - count++; - - if (!count) - continue; - - if (count > max) - { - do max *= 2; while (count > max); - feed = mb_realloc(feed, sizeof(rte *) * max); - } - - uint i = 0; - for (struct rte_storage *e = n->routes; e; e = e->next) - feed[i++] = &e->rte; - - rt_show_net(d, n->n.addr, feed, count); - } - - if (d->rt_counter) - cli_msg(0, ""); - else - cli_msg(8001, "Network not found"); - } + rt_show_cont(d); } diff --git a/nest/rt-table.c b/nest/rt-table.c index 41b6337e..7fcc43af 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -128,6 +128,8 @@ static inline void rt_schedule_notify(rtable *tab); static void rt_flowspec_notify(rtable *tab, net *net); static void rt_feed_by_fib(void *); static void rt_feed_by_trie(void *); +static void rt_feed_equal(void *); +static void rt_feed_for(void *); static uint rt_feed_net(struct rt_export_hook *c, net *n); const char *rt_import_state_name_array[TIS_MAX] = { @@ -1189,8 +1191,27 @@ rte_announce(rtable *tab, net *net, struct rte_storage *new, struct rte_storage if (eh->export_state == TES_STOP) continue; - if (eh->req->addr_in && !net_in_netX(net->n.addr, eh->req->addr_in)) - continue; + switch (eh->req->addr_mode) + { + case TE_ADDR_NONE: + break; + + case TE_ADDR_IN: + if (!net_in_netX(net->n.addr, eh->req->addr)) + continue; + break; + + case TE_ADDR_EQUAL: + if (!net_equal(net->n.addr, eh->req->addr)) + continue; + break; + + case TE_ADDR_FOR: + bug("Continuos export of best prefix match not implemented yet."); + + default: + bug("Strange table export address mode: %d", eh->req->addr_mode); + } if (new) eh->stats.updates_received++; @@ -1788,17 +1809,33 @@ rt_table_export_start(struct rt_exporter *re, struct rt_export_request *req) hook->lp = lp_new_default(p); /* stats zeroed by mb_allocz */ - if (tab->trie && req->addr_in && net_val_match(tab->addr_type, NB_IP)) + switch (req->addr_mode) { - hook->walk_state = mb_allocz(p, sizeof (struct f_trie_walk_state)); - hook->walk_lock = rt_lock_trie(tab); - trie_walk_init(hook->walk_state, tab->trie, req->addr_in); - hook->event = ev_new_init(p, rt_feed_by_trie, hook); - } - else - { - FIB_ITERATE_INIT(&hook->feed_fit, &tab->fib); - hook->event = ev_new_init(p, rt_feed_by_fib, hook); + case TE_ADDR_IN: + if (tab->trie && net_val_match(tab->addr_type, NB_IP)) + { + hook->walk_state = mb_allocz(p, sizeof (struct f_trie_walk_state)); + hook->walk_lock = rt_lock_trie(tab); + trie_walk_init(hook->walk_state, tab->trie, req->addr); + hook->event = ev_new_init(p, rt_feed_by_trie, hook); + break; + } + /* fall through */ + case TE_ADDR_NONE: + FIB_ITERATE_INIT(&hook->feed_fit, &tab->fib); + hook->event = ev_new_init(p, rt_feed_by_fib, hook); + break; + + case TE_ADDR_EQUAL: + hook->event = ev_new_init(p, rt_feed_equal, hook); + break; + + case TE_ADDR_FOR: + hook->event = ev_new_init(p, rt_feed_for, hook); + break; + + default: + bug("Requested an unknown export address mode"); } DBG("New export hook %p req %p in table %s uc=%u\n", hook, req, tab->name, tab->use_count); @@ -1817,8 +1854,8 @@ rt_request_export(struct rt_exporter *re, struct rt_export_request *req) hook->n = (node) {}; add_tail(&re->hooks, &hook->n); + /* Regular export */ rt_set_export_state(hook, TES_FEEDING); - ev_schedule_work(hook->event); } @@ -1827,17 +1864,19 @@ rt_table_export_stop(struct rt_export_hook *hook) { rtable *tab = SKIP_BACK(rtable, exporter, hook->table); - if (hook->export_state == TES_FEEDING) - if (hook->walk_lock) - { - rt_unlock_trie(tab, hook->walk_lock); - hook->walk_lock = NULL; + if (hook->export_state != TES_FEEDING) + return; - mb_free(hook->walk_state); - hook->walk_state = NULL; - } - else - fit_get(&tab->fib, &hook->feed_fit); + if (hook->walk_lock) + { + rt_unlock_trie(tab, hook->walk_lock); + hook->walk_lock = NULL; + + mb_free(hook->walk_state); + hook->walk_state = NULL; + } + else + fit_get(&tab->fib, &hook->feed_fit); } void @@ -2317,6 +2356,7 @@ rt_setup(pool *pp, struct rtable_config *cf) init_list(&t->flowspec_links); t->exporter = (struct rt_exporter) { + .addr_type = t->addr_type, .start = rt_table_export_start, .stop = rt_table_export_stop, .done = rt_table_export_done, @@ -3222,7 +3262,7 @@ rt_feed_by_fib(void *data) ASSERT(c->export_state == TES_FEEDING); - if (!c->req->addr_in || net_in_netX(n->n.addr, c->req->addr_in)) + if ((c->req->addr_mode == TE_ADDR_NONE) || net_in_netX(n->n.addr, c->req->addr)) max_feed -= rt_feed_net(c, n); } FIB_ITERATE_END; @@ -3265,6 +3305,37 @@ rt_feed_by_trie(void *data) rt_set_export_state(c, TES_READY); } +static void +rt_feed_equal(void *data) +{ + struct rt_export_hook *c = data; + rtable *tab = SKIP_BACK(rtable, exporter, c->table); + + ASSERT_DIE(c->export_state == TES_FEEDING); + ASSERT_DIE(c->req->addr_mode == TE_ADDR_EQUAL); + + net *n = net_find(tab, c->req->addr); + if (n) + rt_feed_net(c, n); + + rt_set_export_state(c, TES_READY); +} + +static void +rt_feed_for(void *data) +{ + struct rt_export_hook *c = data; + rtable *tab = SKIP_BACK(rtable, exporter, c->table); + + ASSERT_DIE(c->export_state == TES_FEEDING); + ASSERT_DIE(c->req->addr_mode == TE_ADDR_FOR); + + net *n = net_route(tab, c->req->addr); + if (n) + rt_feed_net(c, n); + + rt_set_export_state(c, TES_READY); +} static uint rt_feed_net(struct rt_export_hook *c, net *n) diff --git a/nest/rt.h b/nest/rt.h index 745f96ef..3ed56fcc 100644 --- a/nest/rt.h +++ b/nest/rt.h @@ -61,6 +61,7 @@ struct rt_export_request; struct rt_exporter { list hooks; /* Registered route export hooks */ + uint addr_type; /* Type of address data exported (NET_*) */ struct rt_export_hook *(*start)(struct rt_exporter *, struct rt_export_request *); void (*stop)(struct rt_export_hook *); void (*done)(struct rt_export_hook *); @@ -212,9 +213,10 @@ struct rt_pending_export { struct rt_export_request { struct rt_export_hook *hook; /* Table part of the export */ - const net_addr *addr_in; /* Subnet export request */ char *name; + const net_addr *addr; /* Network prefilter address */ u8 trace_routes; + u8 addr_mode; /* Network prefilter mode (TE_ADDR_*) */ /* There are two methods of export. You can either request feeding every single change * or feeding the whole route feed. In case of regular export, &export_one is preferred. @@ -273,9 +275,18 @@ struct rt_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 */ + + void rt_request_import(rtable *tab, struct rt_import_request *req); void rt_request_export(struct rt_exporter *tab, struct rt_export_request *req); +void rt_export_once(struct rt_exporter *tab, struct rt_export_request *req); + void rt_stop_import(struct rt_import_request *, void (*stopped)(struct rt_import_request *)); void rt_stop_export(struct rt_export_request *, void (*stopped)(struct rt_export_request *)); @@ -397,9 +408,11 @@ extern const int rt_default_ecmp; struct rt_show_data_rtable { node n; - rtable *table; + const char *name; + struct rt_exporter *table; struct channel *export_channel; struct channel *prefilter; + struct krt_proto *kernel; }; struct rt_show_data { @@ -415,7 +428,6 @@ struct rt_show_data { struct proto *export_protocol; struct channel *export_channel; struct config *running_on_config; - struct krt_proto *kernel; struct rt_export_hook *kernel_export_hook; int export_mode, addr_mode, primary_only, filtered, stats; @@ -425,7 +437,8 @@ struct rt_show_data { }; void rt_show(struct rt_show_data *); -struct rt_show_data_rtable * rt_show_add_table(struct rt_show_data *d, rtable *t); +struct rt_show_data_rtable * rt_show_add_exporter(struct rt_show_data *d, struct rt_exporter *t, const char *name); +struct rt_show_data_rtable * rt_show_add_table(struct rt_show_data *d, struct rtable *t); /* Value of table definition mode in struct rt_show_data */ #define RSD_TDB_DEFAULT 0 /* no table specified */ @@ -436,11 +449,6 @@ struct rt_show_data_rtable * rt_show_add_table(struct rt_show_data *d, rtable *t #define RSD_TDB_SET 0x1 /* internal: show empty tables */ #define RSD_TDB_NMN 0x2 /* internal: need matching net */ -/* Value of addr_mode */ -#define RSD_ADDR_EQUAL 1 /* Exact query - show route */ -#define RSD_ADDR_FOR 2 /* Longest prefix match - show route for */ -#define RSD_ADDR_IN 3 /* Interval query - show route in */ - /* Value of export_mode in struct rt_show_data */ #define RSEM_NONE 0 /* Export mode not used */ #define RSEM_PREEXPORT 1 /* Routes ready for export, before filtering */