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.
This commit is contained in:
parent
84f0700205
commit
ce1da96ee7
8 changed files with 103 additions and 20 deletions
6
TODO
6
TODO
|
@ -13,11 +13,9 @@ Core
|
||||||
- filter-defined internal attributes
|
- filter-defined internal attributes
|
||||||
- netlink: realms
|
- netlink: realms
|
||||||
|
|
||||||
- bgp: wait on restart
|
- filters: deletion of mandatory attributes?
|
||||||
|
|
||||||
Commands
|
- bgp: wait on restart
|
||||||
~~~~~~~~
|
|
||||||
- showing of routing table as seen by given protocol
|
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
|
|
@ -41,6 +41,8 @@ Reply codes of BIRD command-line interface
|
||||||
8001 Route not found
|
8001 Route not found
|
||||||
8002 Configuration file error
|
8002 Configuration file error
|
||||||
8003 No protocols match
|
8003 No protocols match
|
||||||
|
8004 Stopped due to reconfiguration
|
||||||
|
8005 Protocol is down => cannot dump
|
||||||
|
|
||||||
9000 Command too long
|
9000 Command too long
|
||||||
9001 Parse error
|
9001 Parse error
|
||||||
|
|
|
@ -22,6 +22,7 @@ CF_DECLS
|
||||||
CF_KEYWORDS(ROUTER, ID, PROTOCOL, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
|
CF_KEYWORDS(ROUTER, ID, PROTOCOL, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
|
||||||
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS)
|
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS)
|
||||||
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
|
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,
|
CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
|
||||||
RIP, OSPF, OSPF_EXT, OSPF_IA, OSPF_BOUNDARY, BGP, PIPE)
|
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 <p> password_list password_begin
|
||||||
%type <s> optsym
|
%type <s> optsym
|
||||||
%type <ra> r_args
|
%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
|
%type <t> proto_patt
|
||||||
|
|
||||||
CF_GRAMMAR
|
CF_GRAMMAR
|
||||||
|
@ -239,7 +240,7 @@ CF_CLI(SHOW INTERFACES,,, [[Show network interfaces]])
|
||||||
CF_CLI(SHOW INTERFACES SUMMARY,,, [[Show summary of network interfaces]])
|
CF_CLI(SHOW INTERFACES SUMMARY,,, [[Show summary of network interfaces]])
|
||||||
{ if_show_summary(); } ;
|
{ 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); } ;
|
{ rt_show($3); } ;
|
||||||
|
|
||||||
r_args:
|
r_args:
|
||||||
|
@ -275,6 +276,25 @@ r_args:
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
$$->verbose = 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]])
|
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 (*start)(struct proto *); /* Start the instance */
|
||||||
int (*shutdown)(struct proto *); /* Stop 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_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_*) */
|
int (*get_attr)(struct eattr *, byte *buf); /* ASCIIfy dynamic attribute (returns GA_*) */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -206,6 +206,9 @@ struct rt_show_data {
|
||||||
struct filter *filter;
|
struct filter *filter;
|
||||||
int verbose;
|
int verbose;
|
||||||
struct fib_iterator fit;
|
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 *);
|
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 */
|
unsigned int ea_hash(ea_list *e); /* Calculate 16-bit hash value */
|
||||||
void ea_format(eattr *e, byte *buf);
|
void ea_format(eattr *e, byte *buf);
|
||||||
#define EA_FORMAT_BUF_SIZE 256
|
#define EA_FORMAT_BUF_SIZE 256
|
||||||
|
ea_list *ea_append(ea_list *to, ea_list *what);
|
||||||
|
|
||||||
void rta_init(void);
|
void rta_init(void);
|
||||||
rta *rta_lookup(rta *); /* Get rta equivalent to this one, uc++ */
|
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(rta *);
|
||||||
void rta_dump_all(void);
|
void rta_dump_all(void);
|
||||||
static inline eattr * rta_find(rta *a, unsigned ea) { return ea_find(a->eattrs, ea); }
|
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];
|
extern struct protocol *attr_class_to_protocol[EAP_MAX];
|
||||||
|
|
||||||
|
|
|
@ -380,6 +380,20 @@ ea_hash(ea_list *e)
|
||||||
return h;
|
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
|
* rta's
|
||||||
*/
|
*/
|
||||||
|
@ -551,18 +565,19 @@ rta_dump_all(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
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",
|
static char *src_names[] = { "dummy", "static", "inherit", "device", "static-device", "redirect",
|
||||||
"RIP", "RIP-ext", "OSPF", "OSPF-ext", "OSPF-IA", "OSPF-boundary",
|
"RIP", "RIP-ext", "OSPF", "OSPF-ext", "OSPF-IA", "OSPF-boundary",
|
||||||
"BGP" };
|
"BGP" };
|
||||||
static char *cast_names[] = { "unicast", "broadcast", "multicast", "anycast" };
|
static char *cast_names[] = { "unicast", "broadcast", "multicast", "anycast" };
|
||||||
ea_list *eal;
|
|
||||||
int i;
|
int i;
|
||||||
byte buf[EA_FORMAT_BUF_SIZE];
|
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));
|
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++)
|
for(i=0; i<eal->count; i++)
|
||||||
{
|
{
|
||||||
ea_format(&eal->attrs[i], buf);
|
ea_format(&eal->attrs[i], buf);
|
||||||
|
|
|
@ -683,7 +683,7 @@ rt_format_via(rte *e, byte *via)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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 via[STD_ADDRESS_P_LENGTH+32], from[STD_ADDRESS_P_LENGTH+6];
|
||||||
byte tm[TM_RELTIME_BUFFER_SIZE], info[256];
|
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);
|
bsprintf(from, " from %I", a->from);
|
||||||
else
|
else
|
||||||
from[0] = 0;
|
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)
|
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
|
else
|
||||||
bsprintf(info, " (%d)", e->pref);
|
bsprintf(info, " (%d)", e->pref);
|
||||||
cli_printf(c, -1007, "%-18s %s [%s %s%s]%s", ia, via, a->proto->name, tm, from, info);
|
cli_printf(c, -1007, "%-18s %s [%s %s%s]%s", ia, via, a->proto->name, tm, from, info);
|
||||||
if (d->verbose)
|
if (d->verbose)
|
||||||
rta_show(c, a);
|
rta_show(c, a, tmpa);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -709,21 +717,40 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
|
||||||
{
|
{
|
||||||
rte *e, *ee;
|
rte *e, *ee;
|
||||||
byte ia[STD_ADDRESS_P_LENGTH+8];
|
byte ia[STD_ADDRESS_P_LENGTH+8];
|
||||||
|
int ok;
|
||||||
|
|
||||||
bsprintf(ia, "%I/%d", n->n.prefix, n->n.pxlen);
|
bsprintf(ia, "%I/%d", n->n.prefix, n->n.pxlen);
|
||||||
for(e=n->routes; e; e=e->next)
|
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;
|
ee = e;
|
||||||
rte_update_lock(); /* We use the update buffer for filtering */
|
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;
|
ia[0] = 0;
|
||||||
}
|
}
|
||||||
if (e != ee)
|
if (e != ee)
|
||||||
rte_free(ee);
|
rte_free(ee);
|
||||||
rte_update_unlock();
|
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)
|
FIB_ITERATE_START(fib, it, f)
|
||||||
{
|
{
|
||||||
net *n = (net *) 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--)
|
if (!max--)
|
||||||
{
|
{
|
||||||
FIB_ITERATE_PUT(it, f);
|
FIB_ITERATE_PUT(it, f);
|
||||||
|
@ -751,6 +790,7 @@ rt_show_cont(struct cli *c)
|
||||||
}
|
}
|
||||||
FIB_ITERATE_END(f);
|
FIB_ITERATE_END(f);
|
||||||
cli_printf(c, 0, "");
|
cli_printf(c, 0, "");
|
||||||
|
done:
|
||||||
c->cont = c->cleanup = NULL;
|
c->cont = c->cleanup = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -535,10 +535,14 @@ rip_dump(struct proto *p)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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 );
|
eattr *metric = ea_find(attrs, EA_RIP_METRIC);
|
||||||
bsprintf(buf, " t%04x", rte->u.rip.tag );
|
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
|
static int
|
||||||
|
|
Loading…
Reference in a new issue