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