mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-08 12:18:42 +00:00
Client: multitable version of show route
This commit is contained in:
parent
bff21441dd
commit
2faf519cf9
@ -276,6 +276,8 @@ net_or_ipa:
|
||||
| net_vpn6_ { $$ = *$1; }
|
||||
| IP4 { net_fill_ip4(&($$), $1, IP4_MAX_PREFIX_LENGTH); }
|
||||
| IP6 { net_fill_ip6(&($$), $1, IP6_MAX_PREFIX_LENGTH); }
|
||||
| VPN_RD IP4 { net_fill_vpn4(&($$), $2, IP4_MAX_PREFIX_LENGTH, $1); }
|
||||
| VPN_RD IP6 { net_fill_vpn6(&($$), $2, IP6_MAX_PREFIX_LENGTH, $1); }
|
||||
| SYM {
|
||||
if ($1->class == (SYM_CONSTANT | T_IP))
|
||||
net_fill_ip_host(&($$), SYM_VAL($1).ip);
|
||||
|
@ -924,11 +924,13 @@ This argument can be omitted if there exists only a single instance.
|
||||
Show the list of symbols defined in the configuration (names of
|
||||
protocols, routing tables etc.).
|
||||
|
||||
<tag><label id="cli-show-route">show route [[for] <m/prefix/|<m/IP/] [table <m/t/] [filter <m/f/|where <m/c/] [(export|preexport|noexport) <m/p/] [protocol <m/p/] [<m/options/]</tag>
|
||||
Show contents of a routing table (by default of the main one or the
|
||||
table attached to a respective protocol), that is routes, their metrics
|
||||
<tag><label id="cli-show-route">show route [[for] <m/prefix/|<m/IP/] [table (<m/t/ | all)] [filter <m/f/|where <m/c/] [(export|preexport|noexport) <m/p/] [protocol <m/p/] [(stats|count) [by table]] [<m/options/]</tag>
|
||||
Show contents of specified routing tables, that is routes, their metrics
|
||||
and (in case the <cf/all/ switch is given) all their attributes.
|
||||
|
||||
<p>More tables can be specified by repeating the <cf>table <m/t/></cf> clause.
|
||||
To cycle over all tables, specify <cf>table all</cf>.
|
||||
|
||||
<p>You can specify a <m/prefix/ if you want to print routes for a
|
||||
specific network. If you use <cf>for <m/prefix or IP/</cf>, you'll get
|
||||
the entry which will be used for forwarding of packets to the given
|
||||
@ -946,18 +948,26 @@ This argument can be omitted if there exists only a single instance.
|
||||
With <cf/noexport/, routes rejected by the export filter are printed
|
||||
instead. Note that routes not exported to the protocol for other reasons
|
||||
(e.g. secondary routes or routes imported from that protocol) are not
|
||||
printed even with <cf/noexport/.
|
||||
printed even with <cf/noexport/. These switches magically cycle over
|
||||
all tables connected to the protocol.
|
||||
|
||||
<p>You can also select just routes added by a specific protocol.
|
||||
<cf>protocol <m/p/</cf>.
|
||||
<cf>protocol <m/p/</cf>. This switch also magically cycles over
|
||||
all tables connected to the protocol.
|
||||
|
||||
<p>If BIRD is configured to keep filtered routes (see <cf/import keep
|
||||
filtered/ option), you can show them instead of routes by using
|
||||
<cf/filtered/ switch.
|
||||
|
||||
<p>If no table is specified in any way (<cf/table/, <cf/export/, <cf/preexport/, <cf/noexport/, <cf/protocol/),
|
||||
the default tables are listed: <cf/master4/, <cf/master6/
|
||||
and first declared table of any other net type.
|
||||
|
||||
<p>The <cf/stats/ switch requests showing of route statistics (the
|
||||
number of networks, number of routes before and after filtering). If
|
||||
you use <cf/count/ instead, only the statistics will be printed.
|
||||
If you use <cf/stats by table/ or <cf/count by table/, the statistics
|
||||
will be printed also per-table.
|
||||
|
||||
<tag><label id="cli-show-roa">show roa [<m/prefix/ | in <m/prefix/ | for <m/prefix/] [as <m/num/] [table <m/t/]</tag>
|
||||
Show contents of a ROA table (by default of the first one). You can
|
||||
|
@ -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:
|
||||
|
25
nest/route.h
25
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 */
|
||||
|
132
nest/rt-table.c
132
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user