diff options
Diffstat (limited to 'nest')
-rw-r--r-- | nest/config.Y | 25 | ||||
-rw-r--r-- | nest/route.h | 25 | ||||
-rw-r--r-- | nest/rt-table.c | 132 |
3 files changed, 143 insertions, 39 deletions
diff --git a/nest/config.Y b/nest/config.Y index e6b0927b..15bc0f30 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -70,7 +70,7 @@ CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6) CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED) CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES) CF_KEYWORDS(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512) -CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, NOEXPORT, GENERATE) +CF_KEYWORDS(PRIMARY, STATS, COUNT, BY, FOR, COMMANDS, PREEXPORT, NOEXPORT, GENERATE) CF_KEYWORDS(LISTEN, BGP, V6ONLY, DUAL, ADDRESS, PORT, PASSWORDS, DESCRIPTION, SORTED) CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP) CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS) @@ -512,6 +512,7 @@ CF_CLI(SHOW ROUTE, r_args, [[[<prefix>|for <prefix>|for <ip>] [table <t>] [filte r_args: /* empty */ { $$ = cfg_allocz(sizeof(struct rt_show_data)); + init_list(&($$->table)); $$->filter = FILTER_ACCEPT; } | r_args net_any { @@ -529,7 +530,15 @@ r_args: | r_args TABLE SYM { $$ = $1; if ($3->class != SYM_TABLE) cf_error("%s is not a table", $3->name); - $$->table = ((struct rtable_config *)$3->def)->table; + rt_show_add_table($$, ((struct rtable_config *)$3->def)->table); + $$->tables_defined_by = RSD_TDB_DIRECT; + } + | r_args TABLE ALL { + struct rtable_config *t; + $$ = $1; + WALK_LIST(t, config->tables) + rt_show_add_table($$, t->table); + $$->tables_defined_by = RSD_TDB_ALL; } | r_args FILTER filter { $$ = $1; @@ -561,6 +570,7 @@ r_args: $$->export_mode = $2; $$->export_protocol = c->proto; $$->running_on_config = c->proto->cf->global; + $$->tables_defined_by = RSD_TDB_INDIRECT; } | r_args PROTOCOL SYM { struct proto_config *c = (struct proto_config *) $3->def; @@ -569,6 +579,7 @@ r_args: if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name); $$->show_protocol = c->proto; $$->running_on_config = c->proto->cf->global; + $$->tables_defined_by = RSD_TDB_INDIRECT; } | r_args STATS { $$ = $1; @@ -578,6 +589,16 @@ r_args: $$ = $1; $$->stats = 2; } + | r_args STATS BY TABLE { + $$ = $1; + $$->stats = 1; + $$->stats_by_table = 1; + } + | r_args COUNT BY TABLE { + $$ = $1; + $$->stats = 2; + $$->stats_by_table = 1; + } ; export_mode: diff --git a/nest/route.h b/nest/route.h index d7d4df69..4d784858 100644 --- a/nest/route.h +++ b/nest/route.h @@ -308,21 +308,38 @@ void rt_feed_channel_abort(struct channel *c); struct rtable_config *rt_new_table(struct symbol *s, uint addr_type); +struct rt_show_data_rtable { + node n; + rtable *table; +}; + struct rt_show_data { net_addr *addr; - rtable *table; + list table; + struct rt_show_data_rtable *tit; struct filter *filter; - int verbose; + int verbose, tables_defined_by; struct fib_iterator fit; struct proto *show_protocol; struct proto *export_protocol; struct channel *export_channel; int export_mode, primary_only, filtered; struct config *running_on_config; - int net_counter, rt_counter, show_counter; - int stats, show_for; + int net_counter, rt_counter, show_counter, table_counter; + int net_counter_last, rt_counter_last, show_counter_last; + int stats, show_for, stats_by_table; }; void rt_show(struct rt_show_data *); +void rt_show_add_table(struct rt_show_data *d, rtable *t); + +/* Value of table definition mode in struct rt_show_data */ +#define RSD_TDB_DEFAULT 0 /* no table specified */ +#define RSD_TDB_INDIRECT 0 /* show route ... protocol P ... */ +#define RSD_TDB_ALL RSD_TDB_SET /* show route ... table all ... */ +#define RSD_TDB_DIRECT RSD_TDB_SET | RSD_TDB_NMN /* show route ... table X table Y ... */ + +#define RSD_TDB_SET 0x1 /* internal: show empty tables */ +#define RSD_TDB_NMN 0x2 /* internal: need matching net */ /* Value of export_mode in struct rt_show_data */ #define RSEM_NONE 0 /* Export mode not used */ diff --git a/nest/rt-table.c b/nest/rt-table.c index 8be7520c..73cfc9e2 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -2531,6 +2531,9 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm else bsprintf(info, " (%d)", e->pref); + if (!d->show_counter) + cli_printf(c, -1007, "Table %s:", d->tit->table->name); + cli_printf(c, -1007, "%-18s %s [%s %s%s]%s%s", ia, rta_dest_name(a->dest), a->src->proto->name, tm, from, primary ? (sync_error ? " !" : " *") : "", info); @@ -2630,9 +2633,10 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) if (f_run(d->filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT) goto skip; - d->show_counter++; if (d->stats < 2) rt_show_rte(c, ia, e, d, tmpa); + + d->show_counter++; ia[0] = 0; skip: @@ -2654,7 +2658,19 @@ rt_show_export_channel(struct rt_show_data *d) if (! d->export_protocol->rt_notify) return NULL; - return proto_find_channel_by_table(d->export_protocol, d->table); + return proto_find_channel_by_table(d->export_protocol, d->tit->table); +} + +static void +rt_show_cleanup(struct cli *c) +{ + struct rt_show_data *d = c->rover; + + /* Unlink the iterator */ + fit_get(&d->tit->table->fib, &d->fit); + rt_unlock_table(d->tit->table); + while (NODE_VALID(NODE_NEXT(d->tit))) + rt_unlock_table((d->tit = NODE_NEXT(d->tit))->table); } static void @@ -2666,7 +2682,7 @@ rt_show_cont(struct cli *c) #else unsigned max = 64; #endif - struct fib *fib = &d->table->fib; + struct fib *fib = &d->tit->table->fib; struct fib_iterator *it = &d->fit; if (d->export_mode) @@ -2676,6 +2692,7 @@ rt_show_cont(struct cli *c) if (!d->export_channel || (d->export_channel->export_state == ES_DOWN)) { cli_printf(c, 8005, "Channel is down"); + rt_show_cleanup(c); goto done; } } @@ -2690,35 +2707,65 @@ rt_show_cont(struct cli *c) rt_show_net(c, n, d); } FIB_ITERATE_END; + + if (!d->show_counter && (d->tables_defined_by & RSD_TDB_SET)) + cli_printf(c, -1007, "Table %s:", d->tit->table->name); + + if (d->stats && d->stats_by_table) + cli_printf(c, -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->tit->table->name); + + rt_unlock_table(d->tit->table); + d->table_counter++; + if (NODE_VALID(NODE_NEXT(d->tit))) + { + d->tit = NODE_NEXT(d->tit); + FIB_ITERATE_INIT(&d->fit, &d->tit->table->fib); + d->show_counter_last = d->show_counter; + d->rt_counter_last = d->rt_counter; + d->net_counter_last = d->net_counter; + d->show_counter = 0; + d->rt_counter = 0; + d->net_counter = 0; + return; + } + if (d->stats) - cli_printf(c, 14, "%d of %d routes for %d networks", d->show_counter, d->rt_counter, d->net_counter); + cli_printf(c, 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 cli_printf(c, 0, ""); done: c->cont = c->cleanup = NULL; } -static void -rt_show_cleanup(struct cli *c) +void rt_show_add_table(struct rt_show_data *d, rtable *t) { - struct rt_show_data *d = c->rover; - - /* Unlink the iterator */ - fit_get(&d->table->fib, &d->fit); + struct rt_show_data_rtable *rsdr = cfg_alloc(sizeof(struct rt_show_data_rtable)); + rsdr->table = t; + add_tail(&(d->table), &(rsdr->n)); } -static inline rtable * -rt_show_get_table(struct proto *p) +static inline void +rt_show_get_table(struct proto *p, struct rt_show_data *d) { - /* FIXME: Use a better way to handle multi-channel protocols */ + struct channel *c; + WALK_LIST(c, p->channels) + if (c->table) + rt_show_add_table(d, c->table); - if (p->main_channel) - return p->main_channel->table; +} - if (!EMPTY_LIST(p->channels)) - return ((struct channel *) HEAD(p->channels))->table; +static inline void +rt_show_get_default_table(struct rt_show_data *d) +{ + if (d->export_protocol || d->show_protocol) + { + rt_show_get_table(d->export_protocol ?: d->show_protocol, d); + return; + } - return NULL; + for (int i=1; i<NET_MAX; i++) + if (config->def_tables[i]) + rt_show_add_table(d, config->def_tables[i]->table); } void @@ -2726,10 +2773,8 @@ rt_show(struct rt_show_data *d) { net *n; - /* Default is either a master table or a table related to a respective protocol */ - if (!d->table && d->export_protocol) d->table = rt_show_get_table(d->export_protocol); - if (!d->table && d->show_protocol) d->table = rt_show_get_table(d->show_protocol); - if (!d->table) d->table = config->def_tables[NET_IP4]->table; /* FIXME: iterate through all tables ? */ + /* There may be implicit tables. */ + if (EMPTY_LIST(d->table)) rt_show_get_default_table(d); /* Filtered routes are neither exported nor have sensible ordering */ if (d->filtered && (d->export_mode || d->primary_only)) @@ -2737,7 +2782,13 @@ rt_show(struct rt_show_data *d) if (!d->addr) { - FIB_ITERATE_INIT(&d->fit, &d->table->fib); + struct rt_show_data_rtable *rsdr; + WALK_LIST(rsdr, d->table) + { + rt_lock_table(rsdr->table); + } + d->tit = HEAD(d->table); + FIB_ITERATE_INIT(&d->fit, &d->tit->table->fib); this_cli->cont = rt_show_cont; this_cli->cleanup = rt_show_cleanup; this_cli->rover = d; @@ -2755,24 +2806,39 @@ rt_show(struct rt_show_data *d) } } - if (d->table->addr_type != d->addr->type) + struct rt_show_data_rtable *rsdr, *rn; + WALK_LIST_DELSAFE(rsdr, rn, d->table) { - cli_msg(8001, "Incompatible type of prefix/ip with table"); - return; + /* Check table net types matching to query */ + if (rsdr->table->addr_type == d->addr->type) + continue; + + if (d->tables_defined_by & RSD_TDB_NMN) + { + cli_msg(8001, "Incompatible type of prefix/ip with table %s", rsdr->table->name); + return; + } + + rem_node(&(rsdr->n)); } - if (d->show_for) - n = net_route(d->table, d->addr); - else - n = net_find(d->table, d->addr); + WALK_LIST(rsdr, d->table) + { + d->tit = rsdr; - if (n) - rt_show_net(this_cli, n, d); + if (d->show_for) + n = net_route(rsdr->table, d->addr); + else + n = net_find(rsdr->table, d->addr); + + if (n) + rt_show_net(this_cli, n, d); + } if (d->rt_counter) cli_msg(0, ""); else - cli_msg(8001, "Network not in table"); + cli_msg(8001, "Network not found in any specified table"); } } |