Commit ce1da96e authored by Martin Mareš's avatar Martin Mareš

Added commands `show route protocol <p>' and `show route import <p>' 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 <filter>' 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.
parent 84f07002
......@@ -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
~~~~~~~~~~~~~
......
......@@ -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
......
......@@ -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 <p> password_list password_begin
%type <s> optsym
%type <ra> r_args
%type <i> echo_mask echo_size debug_mask debug_list debug_flag
%type <i> echo_mask echo_size debug_mask debug_list debug_flag import_or_proto
%type <t> 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, [<prefix>] [table <t>] [filter <f>] [all], [[Show routing table]])
CF_CLI(SHOW ROUTE, r_args, [<prefix>] [table <t>] [filter <f>] [all] [primary] [(import|protocol) <p>], [[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, [<symbol>], [[Show all known symbolic names]])
......
......@@ -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_*) */
};
......
......@@ -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];
......
......@@ -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; i<eal->count; i++)
{
ea_format(&eal->attrs[i], buf);
......
......@@ -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)
{
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);
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;
}
......
......@@ -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
......
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