diff --git a/TODO b/TODO index d82bf811..a1c7dc3c 100644 --- a/TODO +++ b/TODO @@ -48,12 +48,10 @@ shutdown # order system shutdown configure [] debug # dump debugging information to log show # show everything you know about symbol - route [] [table ] [filter ( | { })] [where ] [all] - status # router id, version etc. + route [] [table ] [filter ( | { })] [where ] [all] <-- WHERE rip ??? [] ospf ??? [] static ??? [] - neighbors # ??? filters [] (disable|enable|restart) # or ALL? diff --git a/conf/confbase.Y b/conf/confbase.Y index 02a86e94..2a76decc 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -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 diff --git a/doc/reply_codes b/doc/reply_codes index 3bafd745..abc2e6f6 100644 --- a/doc/reply_codes +++ b/doc/reply_codes @@ -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 diff --git a/nest/config.Y b/nest/config.Y index b807085a..89177a7a 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -28,6 +28,7 @@ CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIREC %type rtable %type

password_list password_begin %type optsym +%type r_args CF_GRAMMAR @@ -201,12 +202,49 @@ CF_CLI(SHOW PROTOCOLS, optsym, [], [[Show routing protocols]]) CF_CLI(SHOW PROTOCOLS VERBOSE, optsym, [], [[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, [] [table ] [filter ] [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, , [[Tests different subsystems]]) CF_CLI(TEST LEDS, NUM, , [[Flash each LED 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 */ diff --git a/nest/route.h b/nest/route.h index c2b21d13..41d188da 100644 --- a/nest/route.h +++ b/nest/route.h @@ -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 diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 2c50f4d2..04dcf516 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -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) { diff --git a/nest/rt-table.c b/nest/rt-table.c index 353473d1..edbf154d 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -1,7 +1,7 @@ /* * BIRD -- Routing Table * - * (c) 1998 Martin Mares + * (c) 1998--1999 Martin Mares * * 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"); + } +}