From ce1da96ee7efc9310f138e4234495557cdef59e2 Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Sat, 6 May 2000 22:57:39 +0000 Subject: [PATCH] Added commands `show route protocol

' and `show route import

' which show the routing table as exported to the protocol given resp. as returned from its import control hook. To get handling of filtered extended attributes right (even in the old `show route where ' command), the get_route_info hook gets an attribute list and all protocol specific rte attributes are contained there as temporary ones. Updated RIP to do that. Added ea_append() which joins two ea_list's. --- TODO | 6 ++---- doc/reply_codes | 2 ++ nest/config.Y | 24 +++++++++++++++++++++-- nest/protocol.h | 2 +- nest/route.h | 6 +++++- nest/rt-attr.c | 21 +++++++++++++++++--- nest/rt-table.c | 52 +++++++++++++++++++++++++++++++++++++++++++------ proto/rip/rip.c | 10 +++++++--- 8 files changed, 103 insertions(+), 20 deletions(-) diff --git a/TODO b/TODO index 29a93dc6..6faae87e 100644 --- a/TODO +++ b/TODO @@ -13,11 +13,9 @@ Core - filter-defined internal attributes - netlink: realms -- bgp: wait on restart +- filters: deletion of mandatory attributes? -Commands -~~~~~~~~ -- showing of routing table as seen by given protocol +- bgp: wait on restart Documentation ~~~~~~~~~~~~~ diff --git a/doc/reply_codes b/doc/reply_codes index 91466bee..def809e9 100644 --- a/doc/reply_codes +++ b/doc/reply_codes @@ -41,6 +41,8 @@ Reply codes of BIRD command-line interface 8001 Route not found 8002 Configuration file error 8003 No protocols match +8004 Stopped due to reconfiguration +8005 Protocol is down => cannot dump 9000 Command too long 9001 Parse error diff --git a/nest/config.Y b/nest/config.Y index 26df2902..5ac9c213 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -22,6 +22,7 @@ CF_DECLS CF_KEYWORDS(ROUTER, ID, PROTOCOL, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT) CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS) CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES) +CF_KEYWORDS(PRIMARY) CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT, RIP, OSPF, OSPF_EXT, OSPF_IA, OSPF_BOUNDARY, BGP, PIPE) @@ -32,7 +33,7 @@ CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIREC %type

password_list password_begin %type optsym %type r_args -%type echo_mask echo_size debug_mask debug_list debug_flag +%type echo_mask echo_size debug_mask debug_list debug_flag import_or_proto %type proto_patt CF_GRAMMAR @@ -239,7 +240,7 @@ CF_CLI(SHOW INTERFACES,,, [[Show network interfaces]]) 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]]) +CF_CLI(SHOW ROUTE, r_args, [] [table ] [filter ] [all] [primary] [(import|protocol)

], [[Show routing table]]) { rt_show($3); } ; r_args: @@ -275,6 +276,25 @@ r_args: $$ = $1; $$->verbose = 1; } + | r_args PRIMARY { + $$ = $1; + $$->primary_only = 1; + } + | r_args import_or_proto SYM { + struct proto_config *c = (struct proto_config *) $3->def; + $$ = $1; + if ($$->import_mode) cf_error("Protocol specified twice"); + if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name); + $$->import_mode = $2; + $$->primary_only = 1; + $$->import_protocol = c->proto; + $$->running_on_config = c->proto->cf->global; + } + ; + +import_or_proto: + IMPORT { $$ = 1; } + | PROTOCOL { $$ = 2; } ; CF_CLI(SHOW SYMBOLS, optsym, [], [[Show all known symbolic names]]) diff --git a/nest/protocol.h b/nest/protocol.h index 768792f2..7ba44192 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -47,7 +47,7 @@ struct protocol { int (*start)(struct proto *); /* Start the instance */ int (*shutdown)(struct proto *); /* Stop the instance */ void (*get_status)(struct proto *, byte *buf); /* Get instance status (for `show protocols' command) */ - void (*get_route_info)(struct rte *, byte *buf); /* Get route information (for `show route' command) */ + void (*get_route_info)(struct rte *, byte *buf, struct ea_list *attrs); /* Get route information (for `show route' command) */ int (*get_attr)(struct eattr *, byte *buf); /* ASCIIfy dynamic attribute (returns GA_*) */ }; diff --git a/nest/route.h b/nest/route.h index cd9e9ff7..1e6fd64b 100644 --- a/nest/route.h +++ b/nest/route.h @@ -206,6 +206,9 @@ struct rt_show_data { struct filter *filter; int verbose; struct fib_iterator fit; + struct proto *import_protocol; + int import_mode, primary_only; + struct config *running_on_config; }; void rt_show(struct rt_show_data *); @@ -326,6 +329,7 @@ int ea_same(ea_list *x, ea_list *y); /* Test whether two ea_lists are identical unsigned int ea_hash(ea_list *e); /* Calculate 16-bit hash value */ void ea_format(eattr *e, byte *buf); #define EA_FORMAT_BUF_SIZE 256 +ea_list *ea_append(ea_list *to, ea_list *what); void rta_init(void); rta *rta_lookup(rta *); /* Get rta equivalent to this one, uc++ */ @@ -335,7 +339,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 *); +void rta_show(struct cli *, rta *, ea_list *); extern struct protocol *attr_class_to_protocol[EAP_MAX]; diff --git a/nest/rt-attr.c b/nest/rt-attr.c index fd0da97e..38decb51 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -380,6 +380,20 @@ ea_hash(ea_list *e) return h; } +ea_list * +ea_append(ea_list *to, ea_list *what) +{ + ea_list *res; + + if (!to) + return what; + res = to; + while (to->next) + to = to->next; + to->next = what; + return res; +} + /* * rta's */ @@ -551,18 +565,19 @@ rta_dump_all(void) } void -rta_show(struct cli *c, rta *a) +rta_show(struct cli *c, rta *a, ea_list *eal) { 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" }; - ea_list *eal; int i; byte buf[EA_FORMAT_BUF_SIZE]; cli_printf(c, -1008, "\tType: %s %s %s", src_names[a->source], cast_names[a->cast], ip_scope_text(a->scope)); - for(eal=a->eattrs; eal; eal=eal->next) + if (!eal) + eal = a->eattrs; + for(; eal; eal=eal->next) for(i=0; icount; i++) { ea_format(&eal->attrs[i], buf); diff --git a/nest/rt-table.c b/nest/rt-table.c index 7883f2eb..1261aae1 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -683,7 +683,7 @@ rt_format_via(rte *e, byte *via) } static void -rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d) +rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tmpa) { byte via[STD_ADDRESS_P_LENGTH+32], from[STD_ADDRESS_P_LENGTH+6]; byte tm[TM_RELTIME_BUFFER_SIZE], info[256]; @@ -695,13 +695,21 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d) bsprintf(from, " from %I", a->from); else from[0] = 0; + if (a->proto->proto->get_route_info || d->verbose) + { + /* Need to normalize the extended attributes */ + ea_list *t = tmpa; + t = ea_append(t, a->eattrs); + tmpa = alloca(ea_scan(t)); + ea_merge(t, tmpa); + } if (a->proto->proto->get_route_info) - a->proto->proto->get_route_info(e, info); + a->proto->proto->get_route_info(e, info, tmpa); 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); + rta_show(c, a, tmpa); } static void @@ -709,21 +717,40 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) { rte *e, *ee; byte ia[STD_ADDRESS_P_LENGTH+8]; + int ok; bsprintf(ia, "%I/%d", n->n.prefix, n->n.pxlen); for(e=n->routes; e; e=e->next) { - struct ea_list *tmpa = NULL; + struct ea_list *tmpa, *old_tmpa; + struct proto *p0 = e->attrs->proto; + struct proto *p1 = d->import_protocol; 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, 0) <= F_ACCEPT) + old_tmpa = tmpa = p0->make_tmp_attrs ? p0->make_tmp_attrs(e, rte_update_pool) : NULL; + ok = (d->filter == FILTER_ACCEPT || f_run(d->filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT); + if (ok && d->import_mode) { - rt_show_rte(c, ia, e, d); + int ic = (p1->import_control ? p1->import_control(p1, &e, &tmpa, rte_update_pool) : 0); + if (ic < 0) + ok = 0; + else if (!ic && d->import_mode > 1) + { + if (p1->out_filter == FILTER_REJECT || + p1->out_filter && f_run(p1->out_filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT) + ok = 0; + } + } + if (ok) + { + rt_show_rte(c, ia, e, d, tmpa); ia[0] = 0; } if (e != ee) rte_free(ee); rte_update_unlock(); + if (d->import_mode) /* In import mode, accept only the primary route */ + break; } } @@ -742,6 +769,18 @@ rt_show_cont(struct cli *c) FIB_ITERATE_START(fib, it, f) { net *n = (net *) f; + if (d->running_on_config && d->running_on_config != config) + { + cli_printf(c, 8004, "Stopped due to reconfiguration"); + goto done; + } + if (d->import_protocol && + d->import_protocol->core_state != FS_HAPPY && + d->import_protocol->core_state != FS_FEEDING) + { + cli_printf(c, 8005, "Protocol is down"); + goto done; + } if (!max--) { FIB_ITERATE_PUT(it, f); @@ -751,6 +790,7 @@ rt_show_cont(struct cli *c) } FIB_ITERATE_END(f); cli_printf(c, 0, ""); +done: c->cont = c->cleanup = NULL; } diff --git a/proto/rip/rip.c b/proto/rip/rip.c index 022d499f..b3546ae4 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -535,10 +535,14 @@ rip_dump(struct proto *p) } static void -rip_get_route_info(rte *rte, byte *buf) +rip_get_route_info(rte *rte, byte *buf, ea_list *attrs) { - buf += bsprintf(buf, " (%d/%d)", rte->pref, rte->u.rip.metric ); - bsprintf(buf, " t%04x", rte->u.rip.tag ); + eattr *metric = ea_find(attrs, EA_RIP_METRIC); + eattr *tag = ea_find(attrs, EA_RIP_TAG); + + buf += bsprintf(buf, " (%d/%d)", rte->pref, metric ? metric->u.data : 0); + if (tag && tag->u.data) + bsprintf(buf, " t%04x", tag->u.data); } static int