Merge branch 'int-new' of gitlab.labs.nic.cz:labs/bird into int-new

This commit is contained in:
Jan Moskyto Matejka 2017-04-26 12:30:22 +02:00
commit 69fddac052
12 changed files with 344 additions and 226 deletions

View file

@ -124,7 +124,7 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
} }
{DIGIT}+:{DIGIT}+ { {DIGIT}+:{DIGIT}+ {
unsigned long int l, len1, len2; unsigned long int l, len1 UNUSED, len2;
char *e; char *e;
errno = 0; errno = 0;

View file

@ -924,13 +924,10 @@ This argument can be omitted if there exists only a single instance.
Show the list of symbols defined in the configuration (names of Show the list of symbols defined in the configuration (names of
protocols, routing tables etc.). protocols, routing tables etc.).
<tag><label id="cli-show-route">show route [[for] <m/prefix/|<m/IP/] [table (<m/t/ | all)] [filter <m/f/|where <m/c/] [(export|preexport|noexport) <m/p/] [protocol <m/p/] [(stats|count) [by table]] [<m/options/]</tag> <tag><label id="cli-show-route">show route [[for] <m/prefix/|<m/IP/] [table (<m/t/ | all)] [filter <m/f/|where <m/c/] [(export|preexport|noexport) <m/p/] [protocol <m/p/] [(stats|count)] [<m/options/]</tag>
Show contents of specified routing tables, that is routes, their metrics Show contents of specified routing tables, that is routes, their metrics
and (in case the <cf/all/ switch is given) all their attributes. and (in case the <cf/all/ switch is given) all their attributes.
<p>More tables can be specified by repeating the <cf>table <m/t/></cf> clause.
To cycle over all tables, specify <cf>table all</cf>.
<p>You can specify a <m/prefix/ if you want to print routes for a <p>You can specify a <m/prefix/ if you want to print routes for a
specific network. If you use <cf>for <m/prefix or IP/</cf>, you'll get specific network. If you use <cf>for <m/prefix or IP/</cf>, you'll get
the entry which will be used for forwarding of packets to the given the entry which will be used for forwarding of packets to the given
@ -938,57 +935,39 @@ This argument can be omitted if there exists only a single instance.
the selected one at the top, unless <cf/primary/ is given in which case the selected one at the top, unless <cf/primary/ is given in which case
only the selected route is shown. only the selected route is shown.
<p>The <cf/show route/ command can process one or multiple routing
tables. The set of selected tables is determined on three levels: First,
tables can be explicitly selected by <cf/table/ switch, which could be
used multiple times, all tables are specified by <cf/table all/. Second,
tables can be implicitly selected by channels or protocols that are
arguments of several other switches (e.g., <cf/export/, <cf/protocol/).
Last, the set of default tables is used: <cf/master4/, <cf/master6/ and
each first table of any other network type.
<p>You can also ask for printing only routes processed and accepted by <p>You can also ask for printing only routes processed and accepted by
a given filter (<cf>filter <m/name/</cf> or <cf>filter { <m/filter/ } a given filter (<cf>filter <m/name/</cf> or <cf>filter { <m/filter/ }
</cf> or matching a given condition (<cf>where <m/condition/</cf>). </cf> or matching a given condition (<cf>where <m/condition/</cf>).
The <cf/export/, <cf/preexport/ and <cf/noexport/ switches ask for The <cf/export/, <cf/preexport/ and <cf/noexport/ switches ask for
printing of routes that are exported to the specified protocol. printing of routes that are exported to the specified protocol or
With <cf/preexport/, the export filter of the protocol is skipped. channel. With <cf/preexport/, the export filter of the channel is
With <cf/noexport/, routes rejected by the export filter are printed skipped. With <cf/noexport/, routes rejected by the export filter are
instead. Note that routes not exported to the protocol for other reasons printed instead. Note that routes not exported for other reasons
(e.g. secondary routes or routes imported from that protocol) are not (e.g. secondary routes or routes imported from that protocol) are not
printed even with <cf/noexport/. These switches magically cycle over printed even with <cf/noexport/. These switches also imply that
all tables connected to the protocol. associated routing tables are selected instead of default ones.
<p>You can also select just routes added by a specific protocol. <p>You can also select just routes added by a specific protocol.
<cf>protocol <m/p/</cf>. This switch also magically cycles over <cf>protocol <m/p/</cf>. This switch also implies that associated
all tables connected to the protocol. routing tables are selected instead of default ones.
<p>If BIRD is configured to keep filtered routes (see <cf/import keep <p>If BIRD is configured to keep filtered routes (see <cf/import keep
filtered/ option), you can show them instead of routes by using filtered/ option), you can show them instead of routes by using
<cf/filtered/ switch. <cf/filtered/ switch.
<p>If no table is specified in any way (<cf/table/, <cf/export/, <cf/preexport/, <cf/noexport/, <cf/protocol/),
the default tables are listed: <cf/master4/, <cf/master6/
and first declared table of any other net type.
<p>The <cf/stats/ switch requests showing of route statistics (the <p>The <cf/stats/ switch requests showing of route statistics (the
number of networks, number of routes before and after filtering). If number of networks, number of routes before and after filtering). If
you use <cf/count/ instead, only the statistics will be printed. you use <cf/count/ instead, only the statistics will be printed.
If you use <cf/stats by table/ or <cf/count by table/, the statistics
will be printed also per-table.
<tag><label id="cli-show-roa">show roa [<m/prefix/ | in <m/prefix/ | for <m/prefix/] [as <m/num/] [table <m/t/]</tag>
Show contents of a ROA table (by default of the first one). You can
specify a <m/prefix/ to print ROA entries for a specific network. If you
use <cf>for <m/prefix/</cf>, you'll get all entries relevant for route
validation of the network prefix; i.e., ROA entries whose prefixes cover
the network prefix. Or you can use <cf>in <m/prefix/</cf> to get ROA
entries covered by the network prefix. You could also use <cf/as/ option
to show just entries for given AS.
<tag><label id="cli-add-roa">add roa <m/prefix/ max <m/num/ as <m/num/ [table <m/t/]</tag>
Add a new ROA entry to a ROA table. Such entry is called <it/dynamic/
compared to <it/static/ entries specified in the config file. These
dynamic entries survive reconfiguration.
<tag><label id="cli-delete-roa">delete roa <m/prefix/ max <m/num/ as <m/num/ [table <m/t/]</tag>
Delete the specified ROA entry from a ROA table. Only dynamic ROA
entries (i.e., the ones added by <cf/add roa/ command) can be deleted.
<tag><label id="cli-flush-roa">flush roa [table <m/t/]</tag>
Remove all dynamic ROA entries from a ROA table.
<tag><label id="cli-configure">configure [soft] ["<m/config file/"] [timeout [<m/num/]]</tag> <tag><label id="cli-configure">configure [soft] ["<m/config file/"] [timeout [<m/num/]]</tag>
Reload configuration from a given file. BIRD will smoothly switch itself Reload configuration from a given file. BIRD will smoothly switch itself

View file

@ -1693,15 +1693,13 @@ i_same(struct f_inst *f1, struct f_inst *f2)
case P('a','f'): case P('a','f'):
case P('a','l'): case P('a','l'):
case P('a','L'): ONEARG; break; case P('a','L'): ONEARG; break;
#if 0
case P('R','C'): case P('R','C'):
TWOARGS; TWOARGS;
/* Does not really make sense - ROA check resuls may change anyway */ /* Does not really make sense - ROA check results may change anyway */
if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name, if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name,
((struct f_inst_roa_check *) f2)->rtc->name)) ((struct f_inst_roa_check *) f2)->rtc->name))
return 0; return 0;
break; break;
#endif
default: default:
bug( "Unknown instruction %d in same (%c)", f1->code, f1->code & 0xff); bug( "Unknown instruction %d in same (%c)", f1->code, f1->code & 0xff);
} }

View file

@ -177,33 +177,29 @@ net_hash(const net_addr *n)
case NET_ROA6: return NET_HASH(n, roa6); case NET_ROA6: return NET_HASH(n, roa6);
case NET_FLOW4: return NET_HASH(n, flow4); case NET_FLOW4: return NET_HASH(n, flow4);
case NET_FLOW6: return NET_HASH(n, flow6); case NET_FLOW6: return NET_HASH(n, flow6);
case NET_MPLS: return NET_HASH(n, mpls);
default: bug("invalid type"); default: bug("invalid type");
} }
} }
#define NET_VALIDATE(a,t) net_validate_##t((const net_addr_##t *) a)
int int
net_validate(const net_addr *N) net_validate(const net_addr *n)
{ {
switch (N->type) switch (n->type)
{ {
case NET_IP4: case NET_IP4: return NET_VALIDATE(n, ip4);
case NET_VPN4: case NET_IP6: return NET_VALIDATE(n, ip6);
case NET_ROA4: case NET_VPN4: return NET_VALIDATE(n, vpn4);
case NET_FLOW4: case NET_VPN6: return NET_VALIDATE(n, vpn6);
return net_validate_ip4((net_addr_ip4 *) N); case NET_ROA4: return NET_VALIDATE(n, roa4);
case NET_ROA6: return NET_VALIDATE(n, roa6);
case NET_IP6: case NET_FLOW4: return NET_VALIDATE(n, flow4);
case NET_VPN6: case NET_FLOW6: return NET_VALIDATE(n, flow6);
case NET_ROA6: case NET_MPLS: return NET_VALIDATE(n, mpls);
case NET_FLOW6: default: return 0;
return net_validate_ip6((net_addr_ip6 *) N);
case NET_MPLS:
return net_validate_mpls((net_addr_mpls *) N);
default:
return 0;
} }
} }

View file

@ -37,6 +37,7 @@
#define NB_IP (NB_IP4 | NB_IP6) #define NB_IP (NB_IP4 | NB_IP6)
#define NB_VPN (NB_VPN4 | NB_VPN6) #define NB_VPN (NB_VPN4 | NB_VPN6)
#define NB_FLOW (NB_FLOW4 | NB_FLOW6) #define NB_FLOW (NB_FLOW4 | NB_FLOW6)
#define NB_DEST (NB_IP | NB_VPN | NB_MPLS)
#define NB_ANY 0xffffffff #define NB_ANY 0xffffffff
@ -457,23 +458,52 @@ static inline u32 net_hash_mpls(const net_addr_mpls *n)
u32 net_hash(const net_addr *a); u32 net_hash(const net_addr *a);
static inline int net_validate_ip4(const net_addr_ip4 *n) static inline int net_validate_px4(const ip4_addr prefix, uint pxlen)
{ {
return (n->pxlen <= IP4_MAX_PREFIX_LENGTH) && return (pxlen <= IP4_MAX_PREFIX_LENGTH) &&
ip4_zero(ip4_and(n->prefix, ip4_not(ip4_mkmask(n->pxlen)))); ip4_zero(ip4_and(prefix, ip4_not(ip4_mkmask(pxlen))));
} }
static inline int net_validate_px6(const ip6_addr prefix, uint pxlen)
{
return (pxlen <= IP6_MAX_PREFIX_LENGTH) &&
ip6_zero(ip6_and(prefix, ip6_not(ip6_mkmask(pxlen))));
}
static inline int net_validate_ip4(const net_addr_ip4 *n)
{ return net_validate_px4(n->prefix, n->pxlen); }
static inline int net_validate_ip6(const net_addr_ip6 *n) static inline int net_validate_ip6(const net_addr_ip6 *n)
{ return net_validate_px6(n->prefix, n->pxlen); }
static inline int net_validate_vpn4(const net_addr_vpn4 *n)
{ return net_validate_px4(n->prefix, n->pxlen); }
static inline int net_validate_vpn6(const net_addr_vpn6 *n)
{ return net_validate_px6(n->prefix, n->pxlen); }
static inline int net_validate_roa4(const net_addr_roa4 *n)
{ {
return (n->pxlen <= IP6_MAX_PREFIX_LENGTH) && return net_validate_px4(n->prefix, n->pxlen) &&
ip6_zero(ip6_and(n->prefix, ip6_not(ip6_mkmask(n->pxlen)))); (n->pxlen <= n->max_pxlen) && (n->max_pxlen <= IP4_MAX_PREFIX_LENGTH);
} }
static inline int net_validate_mpls(const net_addr_mpls *n) static inline int net_validate_roa6(const net_addr_roa6 *n)
{ {
return n->label < (1 << 20); return net_validate_px6(n->prefix, n->pxlen) &&
(n->pxlen <= n->max_pxlen) && (n->max_pxlen <= IP6_MAX_PREFIX_LENGTH);
} }
// FIXME: Better check, call flow_validate?
static inline int net_validate_flow4(const net_addr_flow4 *n)
{ return net_validate_px4(n->prefix, n->pxlen); }
static inline int net_validate_flow6(const net_addr_flow6 *n)
{ return net_validate_px6(n->prefix, n->pxlen); }
static inline int net_validate_mpls(const net_addr_mpls *n)
{ return n->label < (1 << 20); }
int net_validate(const net_addr *N); int net_validate(const net_addr *N);

View file

@ -75,6 +75,9 @@ CF_KEYWORDS(LISTEN, BGP, V6ONLY, DUAL, ADDRESS, PORT, PASSWORDS, DESCRIPTION, SO
CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP) CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP)
CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS) CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS)
/* For r_args_channel */
CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, VPN4, VPN4_MC, VPN4_MPLS, VPN6, VPN6_MC, VPN6_MPLS, ROA4, ROA6, FLOW4, FLOW6, MPLS, PRI, SEC)
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_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE, BABEL) RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE, BABEL)
CF_ENUM(T_ENUM_SCOPE, SCOPE_, HOST, LINK, SITE, ORGANIZATION, UNIVERSE, UNDEFINED) CF_ENUM(T_ENUM_SCOPE, SCOPE_, HOST, LINK, SITE, ORGANIZATION, UNIVERSE, UNDEFINED)
@ -93,6 +96,7 @@ CF_ENUM(T_ENUM_ROA, ROA_, UNKNOWN, VALID, INVALID)
%type <cl> limit_spec %type <cl> limit_spec
%type <net> r_args_for_val %type <net> r_args_for_val
%type <net_ptr> r_args_for %type <net_ptr> r_args_for
%type <t> r_args_channel
CF_GRAMMAR CF_GRAMMAR
@ -514,7 +518,7 @@ CF_CLI(SHOW ROUTE, r_args, [[[<prefix>|for <prefix>|for <ip>] [table <t>] [filte
r_args: r_args:
/* empty */ { /* empty */ {
$$ = cfg_allocz(sizeof(struct rt_show_data)); $$ = cfg_allocz(sizeof(struct rt_show_data));
init_list(&($$->table)); init_list(&($$->tables));
$$->filter = FILTER_ACCEPT; $$->filter = FILTER_ACCEPT;
} }
| r_args net_any { | r_args net_any {
@ -566,13 +570,24 @@ r_args:
| r_args export_mode SYM { | r_args export_mode SYM {
struct proto_config *c = (struct proto_config *) $3->def; struct proto_config *c = (struct proto_config *) $3->def;
$$ = $1; $$ = $1;
if ($$->export_mode) cf_error("Protocol specified twice"); if ($$->export_mode) cf_error("Export specified twice");
if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name); if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name);
$$->export_mode = $2; $$->export_mode = $2;
$$->export_protocol = c->proto; $$->export_protocol = c->proto;
$$->running_on_config = c->proto->cf->global; $$->running_on_config = c->proto->cf->global;
$$->tables_defined_by = RSD_TDB_INDIRECT; $$->tables_defined_by = RSD_TDB_INDIRECT;
} }
| r_args export_mode SYM '.' r_args_channel {
struct proto_config *c = (struct proto_config *) $3->def;
$$ = $1;
if ($$->export_mode) cf_error("Export specified twice");
if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name);
$$->export_mode = $2;
$$->export_channel = proto_find_channel_by_name(c->proto, $5);
if (!$$->export_channel) cf_error("Export channel not found");
$$->running_on_config = c->proto->cf->global;
$$->tables_defined_by = RSD_TDB_INDIRECT;
}
| r_args PROTOCOL SYM { | r_args PROTOCOL SYM {
struct proto_config *c = (struct proto_config *) $3->def; struct proto_config *c = (struct proto_config *) $3->def;
$$ = $1; $$ = $1;
@ -590,16 +605,6 @@ r_args:
$$ = $1; $$ = $1;
$$->stats = 2; $$->stats = 2;
} }
| r_args STATS BY TABLE {
$$ = $1;
$$->stats = 1;
$$->stats_by_table = 1;
}
| r_args COUNT BY TABLE {
$$ = $1;
$$->stats = 2;
$$->stats_by_table = 1;
}
; ;
r_args_for: r_args_for:
@ -642,6 +647,28 @@ export_mode:
| NOEXPORT { $$ = RSEM_NOEXPORT; } | NOEXPORT { $$ = RSEM_NOEXPORT; }
; ;
/* This is ugly hack */
r_args_channel:
IPV4 { $$ = "ipv4"; }
| IPV4_MC { $$ = "ipv4-mc"; }
| IPV4_MPLS { $$ = "ipv4-mpls"; }
| IPV6 { $$ = "ipv6"; }
| IPV6_MC { $$ = "ipv6-mc"; }
| IPV6_MPLS { $$ = "ipv6-mpls"; }
| VPN4 { $$ = "vpn4"; }
| VPN4_MC { $$ = "vpn4-mc"; }
| VPN4_MPLS { $$ = "vpn4-mpls"; }
| VPN6 { $$ = "vpn6"; }
| VPN6_MC { $$ = "vpn6-mc"; }
| VPN6_MPLS { $$ = "vpn6-mpls"; }
| ROA4 { $$ = "roa4"; }
| ROA6 { $$ = "roa6"; }
| FLOW4 { $$ = "flow4"; }
| FLOW6 { $$ = "flow6"; }
| MPLS { $$ = "mpls"; }
| PRI { $$ = "pri"; }
| SEC { $$ = "sec"; }
;
CF_CLI_HELP(SHOW SYMBOLS, ..., [[Show all known symbolic names]]) CF_CLI_HELP(SHOW SYMBOLS, ..., [[Show all known symbolic names]])
CF_CLI(SHOW SYMBOLS, sym_args, [table|filter|function|protocol|template|<symbol>], [[Show all known symbolic names]]) CF_CLI(SHOW SYMBOLS, sym_args, [table|filter|function|protocol|template|<symbol>], [[Show all known symbolic names]])

View file

@ -104,6 +104,25 @@ proto_find_channel_by_table(struct proto *p, struct rtable *t)
return NULL; return NULL;
} }
/**
* proto_find_channel_by_name - find channel by its name
* @p: protocol instance
* @n: channel name
*
* Returns pointer to channel or NULL
*/
struct channel *
proto_find_channel_by_name(struct proto *p, const char *n)
{
struct channel *c;
WALK_LIST(c, p->channels)
if (!strcmp(c->name, n))
return c;
return NULL;
}
/** /**
* proto_add_channel - connect protocol to a routing table * proto_add_channel - connect protocol to a routing table
* @p: protocol instance * @p: protocol instance

View file

@ -563,6 +563,7 @@ static inline struct channel_config *proto_cf_main_channel(struct proto_config *
{ struct channel_config *cc = HEAD(pc->channels); return NODE_VALID(cc) ? cc : NULL; } { struct channel_config *cc = HEAD(pc->channels); return NODE_VALID(cc) ? cc : NULL; }
struct channel *proto_find_channel_by_table(struct proto *p, struct rtable *t); struct channel *proto_find_channel_by_table(struct proto *p, struct rtable *t);
struct channel *proto_find_channel_by_name(struct proto *p, const char *n);
struct channel *proto_add_channel(struct proto *p, struct channel_config *cf); struct channel *proto_add_channel(struct proto *p, struct channel_config *cf);
int proto_configure_channel(struct proto *p, struct channel **c, struct channel_config *cf); int proto_configure_channel(struct proto *p, struct channel **c, struct channel_config *cf);

View file

@ -313,26 +313,30 @@ struct rtable_config *rt_new_table(struct symbol *s, uint addr_type);
struct rt_show_data_rtable { struct rt_show_data_rtable {
node n; node n;
rtable *table; rtable *table;
struct channel *export_channel;
}; };
struct rt_show_data { struct rt_show_data {
net_addr *addr; net_addr *addr;
list table; list tables;
struct rt_show_data_rtable *tit; struct rt_show_data_rtable *tab; /* Iterator over table list */
struct filter *filter; struct rt_show_data_rtable *last_table; /* Last table in output */
struct fib_iterator fit; /* Iterator over networks in table */
int verbose, tables_defined_by; int verbose, tables_defined_by;
struct fib_iterator fit; struct filter *filter;
struct proto *show_protocol; struct proto *show_protocol;
struct proto *export_protocol; struct proto *export_protocol;
struct channel *export_channel; struct channel *export_channel;
int export_mode, primary_only, filtered;
struct config *running_on_config; struct config *running_on_config;
int export_mode, primary_only, filtered, stats, show_for;
int table_open; /* Iteration (fit) is open */
int net_counter, rt_counter, show_counter, table_counter; int net_counter, rt_counter, show_counter, table_counter;
int net_counter_last, rt_counter_last, show_counter_last; int net_counter_last, rt_counter_last, show_counter_last;
int stats, show_for, stats_by_table;
}; };
void rt_show(struct rt_show_data *); void rt_show(struct rt_show_data *);
void rt_show_add_table(struct rt_show_data *d, rtable *t); struct rt_show_data_rtable * rt_show_add_table(struct rt_show_data *d, rtable *t);
/* Value of table definition mode in struct rt_show_data */ /* Value of table definition mode in struct rt_show_data */
#define RSD_TDB_DEFAULT 0 /* no table specified */ #define RSD_TDB_DEFAULT 0 /* no table specified */

View file

@ -900,7 +900,6 @@ rte_validate(rte *e)
int c; int c;
net *n = e->net; net *n = e->net;
// (n->n.pxlen > BITS_PER_IP_ADDRESS) || !ip_is_prefix(n->n.prefix,n->n.pxlen))
if (!net_validate(n->n.addr)) if (!net_validate(n->n.addr))
{ {
log(L_WARN "Ignoring bogus prefix %N received via %s", log(L_WARN "Ignoring bogus prefix %N received via %s",
@ -916,6 +915,13 @@ rte_validate(rte *e)
return 0; return 0;
} }
if (net_type_match(n->n.addr, NB_DEST) == !e->attrs->dest)
{
log(L_WARN "Ignoring route %N with invalid dest %d received via %s",
n->n.addr, e->attrs->dest, e->sender->proto->name);
return 0;
}
if ((e->attrs->dest == RTD_UNICAST) && !nexthop_is_sorted(&(e->attrs->nh))) if ((e->attrs->dest == RTD_UNICAST) && !nexthop_is_sorted(&(e->attrs->nh)))
{ {
log(L_WARN "Ignoring unsorted multipath route %N received via %s", log(L_WARN "Ignoring unsorted multipath route %N received via %s",
@ -2497,6 +2503,18 @@ rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep)
* CLI commands * CLI commands
*/ */
static void
rt_show_table(struct cli *c, struct rt_show_data *d)
{
/* No table blocks in 'show route count' */
if (d->stats == 2)
return;
if (d->last_table) cli_printf(c, -1007, "");
cli_printf(c, -1007, "Table %s:", d->tab->table->name);
d->last_table = d->tab;
}
static void static void
rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tmpa) rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tmpa)
{ {
@ -2529,8 +2547,8 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
else else
bsprintf(info, " (%d)", e->pref); bsprintf(info, " (%d)", e->pref);
if (!d->show_counter) if (d->last_table != d->tab)
cli_printf(c, -1007, "Table %s:", d->tit->table->name); rt_show_table(c, d);
cli_printf(c, -1007, "%-18s %s [%s %s%s]%s%s", ia, rta_dest_name(a->dest), cli_printf(c, -1007, "%-18s %s [%s %s%s]%s%s", ia, rta_dest_name(a->dest),
a->src->proto->name, tm, from, primary ? (sync_error ? " !" : " *") : "", info); a->src->proto->name, tm, from, primary ? (sync_error ? " !" : " *") : "", info);
@ -2564,7 +2582,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
rte *e, *ee; rte *e, *ee;
byte ia[NET_MAX_TEXT_LENGTH+1]; byte ia[NET_MAX_TEXT_LENGTH+1];
struct ea_list *tmpa; struct ea_list *tmpa;
struct channel *ec = d->export_channel; struct channel *ec = d->tab->export_channel;
int first = 1; int first = 1;
int pass = 0; int pass = 0;
@ -2586,6 +2604,10 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
rte_update_lock(); /* We use the update buffer for filtering */ rte_update_lock(); /* We use the update buffer for filtering */
tmpa = make_tmp_attrs(e, rte_update_pool); tmpa = make_tmp_attrs(e, rte_update_pool);
/* Export channel is down, do not try to export routes to it */
if (ec && (ec->export_state == ES_DOWN))
goto skip;
/* Special case for merged export */ /* Special case for merged export */
if ((d->export_mode == RSEM_EXPORT) && (ec->ra_mode == RA_MERGED)) if ((d->export_mode == RSEM_EXPORT) && (ec->ra_mode == RA_MERGED))
{ {
@ -2598,7 +2620,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
} }
else if (d->export_mode) else if (d->export_mode)
{ {
struct proto *ep = d->export_protocol; struct proto *ep = ec->proto;
int ic = ep->import_control ? ep->import_control(ep, &e, &tmpa, rte_update_pool) : 0; int ic = ep->import_control ? ep->import_control(ep, &e, &tmpa, rte_update_pool) : 0;
if (ec->ra_mode == RA_OPTIMAL || ec->ra_mode == RA_MERGED) if (ec->ra_mode == RA_OPTIMAL || ec->ra_mode == RA_MERGED)
@ -2650,25 +2672,19 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
} }
} }
static struct channel *
rt_show_export_channel(struct rt_show_data *d)
{
if (! d->export_protocol->rt_notify)
return NULL;
return proto_find_channel_by_table(d->export_protocol, d->tit->table);
}
static void static void
rt_show_cleanup(struct cli *c) rt_show_cleanup(struct cli *c)
{ {
struct rt_show_data *d = c->rover; struct rt_show_data *d = c->rover;
struct rt_show_data_rtable *tab;
/* Unlink the iterator */ /* Unlink the iterator */
fit_get(&d->tit->table->fib, &d->fit); if (d->table_open)
rt_unlock_table(d->tit->table); fit_get(&d->tab->table->fib, &d->fit);
while (NODE_VALID(NODE_NEXT(d->tit)))
rt_unlock_table((d->tit = NODE_NEXT(d->tit))->table); /* Unlock referenced tables */
WALK_LIST(tab, d->tables)
rt_unlock_table(tab->table);
} }
static void static void
@ -2680,19 +2696,27 @@ rt_show_cont(struct cli *c)
#else #else
unsigned max = 64; unsigned max = 64;
#endif #endif
struct fib *fib = &d->tit->table->fib; struct fib *fib = &d->tab->table->fib;
struct fib_iterator *it = &d->fit; struct fib_iterator *it = &d->fit;
if (d->export_mode) if (d->running_on_config && (d->running_on_config != config))
{ {
/* Ensure we have current export channel */ cli_printf(c, 8004, "Stopped due to reconfiguration");
d->export_channel = rt_show_export_channel(d);
if (!d->export_channel || (d->export_channel->export_state == ES_DOWN))
{
cli_printf(c, 8005, "Channel is down");
rt_show_cleanup(c);
goto done; goto done;
} }
if (!d->table_open)
{
FIB_ITERATE_INIT(&d->fit, &d->tab->table->fib);
d->table_open = 1;
d->table_counter++;
d->show_counter_last = d->show_counter;
d->rt_counter_last = d->rt_counter;
d->net_counter_last = d->net_counter;
if (d->tables_defined_by & RSD_TDB_SET)
rt_show_table(c, d);
} }
FIB_ITERATE_START(fib, it, net, n) FIB_ITERATE_START(fib, it, net, n)
@ -2706,58 +2730,76 @@ rt_show_cont(struct cli *c)
} }
FIB_ITERATE_END; FIB_ITERATE_END;
if (!d->show_counter && (d->tables_defined_by & RSD_TDB_SET)) if (d->stats)
cli_printf(c, -1007, "Table %s:", d->tit->table->name);
if (d->stats && d->stats_by_table)
cli_printf(c, -1007, "%d of %d routes for %d networks in table %s", d->show_counter - d->show_counter_last, d->rt_counter - d->rt_counter_last, d->net_counter - d->net_counter_last, d->tit->table->name);
rt_unlock_table(d->tit->table);
d->table_counter++;
if (NODE_VALID(NODE_NEXT(d->tit)))
{ {
d->tit = NODE_NEXT(d->tit); if (d->last_table != d->tab)
FIB_ITERATE_INIT(&d->fit, &d->tit->table->fib); rt_show_table(c, d);
d->show_counter_last = d->show_counter;
d->rt_counter_last = d->rt_counter; cli_printf(c, -1007, "%d of %d routes for %d networks in table %s",
d->net_counter_last = d->net_counter; d->show_counter - d->show_counter_last, d->rt_counter - d->rt_counter_last,
d->show_counter = 0; d->net_counter - d->net_counter_last, d->tab->table->name);
d->rt_counter = 0;
d->net_counter = 0;
return;
} }
if (d->stats) d->table_open = 0;
cli_printf(c, 14, "Total: %d of %d routes for %d networks in %d tables", d->show_counter, d->rt_counter, d->net_counter, d->table_counter); d->tab = NODE_NEXT(d->tab);
if (NODE_VALID(d->tab))
return;
if (d->stats && (d->table_counter > 1))
{
if (d->last_table) cli_printf(c, -1007, "");
cli_printf(c, 14, "Total: %d of %d routes for %d networks in %d tables",
d->show_counter, d->rt_counter, d->net_counter, d->table_counter);
}
else else
cli_printf(c, 0, ""); cli_printf(c, 0, "");
done: done:
rt_show_cleanup(c);
c->cont = c->cleanup = NULL; c->cont = c->cleanup = NULL;
} }
void rt_show_add_table(struct rt_show_data *d, rtable *t) struct rt_show_data_rtable *
rt_show_add_table(struct rt_show_data *d, rtable *t)
{ {
struct rt_show_data_rtable *rsdr = cfg_alloc(sizeof(struct rt_show_data_rtable)); struct rt_show_data_rtable *tab = cfg_allocz(sizeof(struct rt_show_data_rtable));
rsdr->table = t; tab->table = t;
add_tail(&(d->table), &(rsdr->n)); add_tail(&(d->tables), &(tab->n));
return tab;
} }
static inline void static inline void
rt_show_get_table(struct proto *p, struct rt_show_data *d) rt_show_get_default_tables(struct rt_show_data *d)
{ {
struct channel *c; struct channel *c;
WALK_LIST(c, p->channels) struct rt_show_data_rtable *tab;
if (c->table)
rt_show_add_table(d, c->table);
} if (d->export_channel)
static inline void
rt_show_get_default_table(struct rt_show_data *d)
{
if (d->export_protocol || d->show_protocol)
{ {
rt_show_get_table(d->export_protocol ?: d->show_protocol, d); c = d->export_channel;
tab = rt_show_add_table(d, c->table);
tab->export_channel = c;
return;
}
if (d->export_protocol)
{
WALK_LIST(c, d->export_protocol->channels)
{
if (c->export_state == ES_DOWN)
continue;
tab = rt_show_add_table(d, c->table);
tab->export_channel = c;
}
return;
}
if (d->show_protocol)
{
WALK_LIST(c, d->show_protocol->channels)
rt_show_add_table(d, c->table);
return; return;
} }
@ -2766,68 +2808,86 @@ rt_show_get_default_table(struct rt_show_data *d)
rt_show_add_table(d, config->def_tables[i]->table); rt_show_add_table(d, config->def_tables[i]->table);
} }
static inline void
rt_show_prepare_tables(struct rt_show_data *d)
{
struct rt_show_data_rtable *tab, *tabx;
/* Add implicit tables if no table is specified */
if (EMPTY_LIST(d->tables))
rt_show_get_default_tables(d);
WALK_LIST_DELSAFE(tab, tabx, d->tables)
{
/* Ensure there is defined export_channel for each table */
if (d->export_mode)
{
if (!tab->export_channel && d->export_channel &&
(tab->table == d->export_channel->table))
tab->export_channel = d->export_channel;
if (!tab->export_channel && d->export_protocol)
tab->export_channel = proto_find_channel_by_table(d->export_protocol, tab->table);
if (!tab->export_channel)
{
if (d->tables_defined_by & RSD_TDB_NMN)
cf_error("No export channel for table %s", tab->table->name);
rem_node(&(tab->n));
continue;
}
}
/* Ensure specified network is compatible with each table */
if (d->addr && (tab->table->addr_type != d->addr->type))
{
if (d->tables_defined_by & RSD_TDB_NMN)
cf_error("Incompatible type of prefix/ip for table %s", tab->table->name);
rem_node(&(tab->n));
continue;
}
}
/* Ensure there is at least one table */
if (EMPTY_LIST(d->tables))
cf_error("No valid tables");
}
void void
rt_show(struct rt_show_data *d) rt_show(struct rt_show_data *d)
{ {
struct rt_show_data_rtable *tab;
net *n; net *n;
/* There may be implicit tables. */
if (EMPTY_LIST(d->table)) rt_show_get_default_table(d);
/* Filtered routes are neither exported nor have sensible ordering */ /* Filtered routes are neither exported nor have sensible ordering */
if (d->filtered && (d->export_mode || d->primary_only)) if (d->filtered && (d->export_mode || d->primary_only))
cli_msg(0, ""); cf_error("Incompatible show route options");
rt_show_prepare_tables(d);
if (!d->addr) if (!d->addr)
{ {
struct rt_show_data_rtable *rsdr; WALK_LIST(tab, d->tables)
WALK_LIST(rsdr, d->table) rt_lock_table(tab->table);
{
rt_lock_table(rsdr->table); /* There is at least one table */
} d->tab = HEAD(d->tables);
d->tit = HEAD(d->table);
FIB_ITERATE_INIT(&d->fit, &d->tit->table->fib);
this_cli->cont = rt_show_cont; this_cli->cont = rt_show_cont;
this_cli->cleanup = rt_show_cleanup; this_cli->cleanup = rt_show_cleanup;
this_cli->rover = d; this_cli->rover = d;
} }
else else
{ {
if (d->export_mode) WALK_LIST(tab, d->tables)
{ {
/* Find channel associated with the export protocol */ d->tab = tab;
d->export_channel = rt_show_export_channel(d);
if (!d->export_channel || (d->export_channel->export_state == ES_DOWN))
{
cli_msg(8005, "Channel is down");
return;
}
}
struct rt_show_data_rtable *rsdr, *rn;
WALK_LIST_DELSAFE(rsdr, rn, d->table)
{
/* Check table net types matching to query */
if (rsdr->table->addr_type == d->addr->type)
continue;
if (d->tables_defined_by & RSD_TDB_NMN)
{
cli_msg(8001, "Incompatible type of prefix/ip with table %s", rsdr->table->name);
return;
}
rem_node(&(rsdr->n));
}
WALK_LIST(rsdr, d->table)
{
d->tit = rsdr;
if (d->show_for) if (d->show_for)
n = net_route(rsdr->table, d->addr); n = net_route(tab->table, d->addr);
else else
n = net_find(rsdr->table, d->addr); n = net_find(tab->table, d->addr);
if (n) if (n)
rt_show_net(this_cli, n, d); rt_show_net(this_cli, n, d);
@ -2836,7 +2896,7 @@ rt_show(struct rt_show_data *d)
if (d->rt_counter) if (d->rt_counter)
cli_msg(0, ""); cli_msg(0, "");
else else
cli_msg(8001, "Network not found in any specified table"); cli_msg(8001, "Network not found");
} }
} }

View file

@ -903,7 +903,7 @@ rpki_postconfig(struct proto_config *CF)
} }
static void static void
rpki_copy_config(struct proto_config *dest, struct proto_config *src) rpki_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUSED)
{ {
/* FIXME: Should copy transport */ /* FIXME: Should copy transport */
} }

View file

@ -36,7 +36,10 @@ static_nexthop_new(void)
static void static void
static_route_finish(void) static_route_finish(void)
{ } {
if (net_type_match(this_srt->net, NB_DEST) == !this_srt->dest)
cf_error("Unexpected or missing nexthop/type");
}
CF_DECLS CF_DECLS
@ -119,6 +122,7 @@ stat_route:
this_srt->via = $3; this_srt->via = $3;
this_srt->mls = $5; this_srt->mls = $5;
} }
| stat_route0 { this_srt->dest = RTD_NONE; }
| stat_route0 DROP { this_srt->dest = RTD_BLACKHOLE; } | stat_route0 DROP { this_srt->dest = RTD_BLACKHOLE; }
| stat_route0 REJECT { this_srt->dest = RTD_UNREACHABLE; } | stat_route0 REJECT { this_srt->dest = RTD_UNREACHABLE; }
| stat_route0 BLACKHOLE { this_srt->dest = RTD_BLACKHOLE; } | stat_route0 BLACKHOLE { this_srt->dest = RTD_BLACKHOLE; }