Commit 730f2e2c authored by Martin Mareš's avatar Martin Mareš

Added dumping of routing tables (`show route'). This includes filtering.

parent 04a60c68
......@@ -48,12 +48,10 @@ shutdown # order system shutdown
configure [<file>]
debug <what> # dump debugging information to log
show <name> # show everything you know about symbol <name>
route [<route>] [table <name>] [filter (<name> | { <inline> })] [where <condition>] [all]
status # router id, version etc.
route [<route>] [table <name>] [filter (<name> | { <inline> })] [where <condition>] [all] <-- WHERE
rip ??? [<name>]
ospf ??? [<name>]
static ??? [<name>]
neighbors # ???
filters [<name>]
(disable|enable|restart) <protocol> # or ALL?
......
......@@ -33,6 +33,7 @@ CF_DECLS
struct f_tree *e;
struct f_val v;
struct password_item *p;
struct rt_show_data *ra;
}
%token END CLI_MARKER
......
......@@ -18,8 +18,11 @@ Reply codes of BIRD command-line interface
1004 Interface flags
1005 Interface summary
1006 Protocol details
1007 Route list
1008 Route details
8000 Reply too long
8001 Route not found
9000 Command too long
9001 Parse error
......
......@@ -28,6 +28,7 @@ CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIREC
%type <r> rtable
%type <p> password_list password_begin
%type <s> optsym
%type <ra> r_args
CF_GRAMMAR
......@@ -201,12 +202,49 @@ CF_CLI(SHOW PROTOCOLS, optsym, [<name>], [[Show routing protocols]])
CF_CLI(SHOW PROTOCOLS VERBOSE, optsym, [<name>], [[Show routing protocol details]])
{ proto_show($4, 1); } ;
optsym:
SYM
| /* empty */ { $$ = NULL; }
;
CF_CLI(SHOW INTERFACES,,, [[Show network interfaces]])
{ if_show(); } ;
CF_CLI(SHOW INTERFACES SUMMARY,,, [[Show summary of network interfaces]])
{ if_show_summary(); } ;
CF_CLI(SHOW ROUTE, r_args, [<prefix>] [table <t>] [filter <f>] [all], [[Show routing table]])
{ rt_show($3); } ;
r_args:
/* empty */ {
$$ = cfg_allocz(sizeof(struct rt_show_data));
$$->pxlen = 256;
$$->filter = FILTER_ACCEPT;
$$->table = config->master_rtc->table;
}
| r_args IPA pxlen {
$$ = $1;
if ($$->pxlen != 256) cf_error("Only one prefix expected");
if (!ip_is_prefix($2, $3)) cf_error("Invalid prefix");
$$->prefix = $2;
$$->pxlen = $3;
}
| 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;
}
| r_args FILTER filter {
$$ = $1;
$$->filter = $3;
}
| r_args ALL {
$$ = $1;
$$->verbose = 1;
}
;
/* FIXME: These are examples. Remove them soon. */
CF_CLI_HELP(TEST, <subsystem>, [[Tests different subsystems]])
CF_CLI(TEST LEDS, NUM, <N>, [[Flash each LED <N> times]]) { cli_msg(0, "%d", $3); } ;
......@@ -218,11 +256,6 @@ CF_CLI(TEST LONG,,, [[Test long replies]]) {
cli_msg(-2, "Start");
} ;
optsym:
SYM
| /* empty */ { $$ = NULL; }
;
CF_CODE
/* FIXME: Test only, remove */
......
......@@ -15,6 +15,9 @@
struct protocol;
struct proto;
struct symbol;
struct filter;
struct cli;
/*
* Generic data structure for storing network prefixes. Also used
......@@ -186,6 +189,16 @@ void rt_feed_baby(struct proto *p);
void rt_prune(rtable *tab);
void rt_prune_all(void);
struct rt_show_data {
ip_addr prefix;
unsigned pxlen;
rtable *table;
struct filter *filter;
int verbose;
struct fib_iterator fit;
};
void rt_show(struct rt_show_data *);
/*
* Route Attributes
*
......@@ -311,6 +324,7 @@ static inline void rta_free(rta *r) { if (r && !--r->uc) rta__free(r); }
void rta_dump(rta *);
void rta_dump_all(void);
static inline eattr * rta_find(rta *a, unsigned ea) { return ea_find(a->eattrs, ea); }
void rta_show(struct cli *, rta *);
/*
* Default protocol preferences
......
......@@ -13,6 +13,7 @@
#include "nest/route.h"
#include "nest/protocol.h"
#include "nest/iface.h"
#include "nest/cli.h"
#include "lib/resource.h"
/*
......@@ -347,12 +348,11 @@ rta_dump(rta *a)
"RTS_STAT_DEV", "RTS_REDIR", "RTS_RIP", "RTS_RIP_EXT",
"RTS_OSPF", "RTS_OSPF_EXT", "RTS_OSPF_IA",
"RTS_OSPF_BOUNDARY", "RTS_BGP" };
static char *sco[] = { "HOST", "LINK", "SITE", "UNIV" };
static char *rtc[] = { "", " BC", " MC", " AC" };
static char *rtd[] = { "", " DEV", " HOLE", " UNREACH", " PROHIBIT" };
debug("p=%s uc=%d %s %s%s%s",
a->proto->name, a->uc, rts[a->source], sco[a->scope], rtc[a->cast],
a->proto->name, a->uc, rts[a->source], ip_scope_text(a->scope), rtc[a->cast],
rtd[a->dest]);
if (a->flags & RTF_EXTERIOR)
debug(" EXT");
......@@ -387,6 +387,18 @@ rta_dump_all(void)
debug("\n");
}
void
rta_show(struct cli *c, rta *a)
{
static char *src_names[] = { "dummy", "static", "inherit", "device", "static-device", "redirect",
"RIP", "RIP-ext", "OSPF", "OSPF-ext", "OSPF-IA", "OSPF-boundary",
"BGP" };
static char *cast_names[] = { "unicast", "broadcast", "multicast", "anycast" };
cli_printf(c, -1008, "\tType: %s %s %s", src_names[a->source], cast_names[a->cast], ip_scope_text(a->scope));
/* FIXME: Here we probably should print the dynamic attributes... */
}
void
rta_init(void)
{
......
/*
* BIRD -- Routing Table
*
* (c) 1998 Martin Mares <mj@ucw.cz>
* (c) 1998--1999 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
......@@ -13,8 +13,11 @@
#include "nest/bird.h"
#include "nest/route.h"
#include "nest/protocol.h"
#include "nest/cli.h"
#include "nest/iface.h"
#include "lib/resource.h"
#include "lib/event.h"
#include "lib/string.h"
#include "conf/conf.h"
#include "filter/filter.h"
......@@ -489,3 +492,122 @@ rt_commit(struct config *c)
r->table = t;
}
}
/*
* CLI commands
*/
static void
rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d)
{
byte via[STD_ADDRESS_P_LENGTH+32], from[STD_ADDRESS_P_LENGTH];
byte tm[TM_RELTIME_BUFFER_SIZE], info[256];
rta *a = e->attrs;
switch (a->dest)
{
case RTD_ROUTER: bsprintf(via, "via %I on %s", a->gw, a->iface->name); break;
case RTD_DEVICE: bsprintf(via, "dev %s", a->iface->name); break;
case RTD_BLACKHOLE: bsprintf(via, "blackhole"); break;
case RTD_UNREACHABLE: bsprintf(via, "unreachable"); break;
case RTD_PROHIBIT: bsprintf(via, "prohibited"); break;
default: bsprintf(via, "???");
}
tm_format_reltime(tm, e->lastmod);
if (ipa_nonzero(a->from) && !ipa_equal(a->from, a->gw))
bsprintf(from, " from %I", a->from);
else
from[0] = 0;
if (a->proto->proto->get_route_info)
a->proto->proto->get_route_info(e, info);
else
bsprintf(info, " (%d)", e->pref);
cli_printf(c, -1007, "%-18s %s [%s %s%s]%s", ia, via, a->proto->name, tm, from, info);
if (d->verbose)
{
rta_show(c, a);
if (a->proto->proto->show_route_data)
a->proto->proto->show_route_data(e);
}
}
static void
rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
{
rte *e, *ee;
byte ia[STD_ADDRESS_P_LENGTH+8];
bsprintf(ia, "%I/%d", n->n.prefix, n->n.pxlen);
for(e=n->routes; e; e=e->next)
{
struct ea_list *tmpa = NULL;
ee = e;
rte_update_lock(); /* We use the update buffer for filtering */
if (d->filter == FILTER_ACCEPT || f_run(d->filter, &ee, &tmpa, rte_update_pool) <= F_MODIFY)
{
rt_show_rte(c, ia, e, d);
ia[0] = 0;
}
if (e != ee)
rte_free(ee);
rte_update_unlock();
}
}
static void
rt_show_cont(struct cli *c)
{
struct rt_show_data *d = c->rover;
unsigned max = 1; /* FIXME: After some debugging, increase to reasonable amount */
struct fib *fib = &d->table->fib;
struct fib_iterator *it = &d->fit;
FIB_ITERATE_START(fib, it, f)
{
net *n = (net *) f;
if (!max--)
{
FIB_ITERATE_PUT(it, f);
return;
}
rt_show_net(c, n, d);
}
FIB_ITERATE_END(f);
cli_printf(c, 0, "");
c->cont = c->cleanup = NULL;
}
static void
rt_show_cleanup(struct cli *c)
{
struct rt_show_data *d = c->rover;
/* Unlink the iterator */
fit_get(&d->table->fib, &d->fit);
}
void
rt_show(struct rt_show_data *d)
{
struct rtable_config *tc;
net *n;
if (d->pxlen == 256)
{
FIB_ITERATE_INIT(&d->fit, &d->table->fib);
this_cli->cont = rt_show_cont;
this_cli->cleanup = rt_show_cleanup;
this_cli->rover = d;
}
else
{
n = fib_find(&d->table->fib, &d->prefix, d->pxlen);
if (n)
{
rt_show_net(this_cli, n, d);
cli_msg(0, "");
}
else
cli_msg(8001, "Network not in table");
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment