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