Merge branch 'int-new' of gitlab.labs.nic.cz:labs/bird into int-new
This commit is contained in:
commit
69fddac052
12 changed files with 344 additions and 226 deletions
|
@ -124,7 +124,7 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
|
|||
}
|
||||
|
||||
{DIGIT}+:{DIGIT}+ {
|
||||
unsigned long int l, len1, len2;
|
||||
unsigned long int l, len1 UNUSED, len2;
|
||||
char *e;
|
||||
|
||||
errno = 0;
|
||||
|
|
|
@ -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
|
||||
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
|
||||
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
|
||||
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
|
||||
|
@ -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
|
||||
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
|
||||
a given filter (<cf>filter <m/name/</cf> or <cf>filter { <m/filter/ }
|
||||
</cf> or matching a given condition (<cf>where <m/condition/</cf>).
|
||||
|
||||
The <cf/export/, <cf/preexport/ and <cf/noexport/ switches ask for
|
||||
printing of routes that are exported to the specified protocol.
|
||||
With <cf/preexport/, the export filter of the protocol is skipped.
|
||||
With <cf/noexport/, routes rejected by the export filter are printed
|
||||
instead. Note that routes not exported to the protocol for other reasons
|
||||
printing of routes that are exported to the specified protocol or
|
||||
channel. With <cf/preexport/, the export filter of the channel is
|
||||
skipped. With <cf/noexport/, routes rejected by the export filter are
|
||||
printed instead. Note that routes not exported for other reasons
|
||||
(e.g. secondary routes or routes imported from that protocol) are not
|
||||
printed even with <cf/noexport/. These switches magically cycle over
|
||||
all tables connected to the protocol.
|
||||
printed even with <cf/noexport/. These switches also imply that
|
||||
associated routing tables are selected instead of default ones.
|
||||
|
||||
<p>You can also select just routes added by a specific protocol.
|
||||
<cf>protocol <m/p/</cf>. This switch also magically cycles over
|
||||
all tables connected to the protocol.
|
||||
<cf>protocol <m/p/</cf>. This switch also implies that associated
|
||||
routing tables are selected instead of default ones.
|
||||
|
||||
<p>If BIRD is configured to keep filtered routes (see <cf/import keep
|
||||
filtered/ option), you can show them instead of routes by using
|
||||
<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
|
||||
number of networks, number of routes before and after filtering). If
|
||||
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>
|
||||
Reload configuration from a given file. BIRD will smoothly switch itself
|
||||
|
|
|
@ -1693,15 +1693,13 @@ i_same(struct f_inst *f1, struct f_inst *f2)
|
|||
case P('a','f'):
|
||||
case P('a','l'):
|
||||
case P('a','L'): ONEARG; break;
|
||||
#if 0
|
||||
case P('R','C'):
|
||||
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,
|
||||
((struct f_inst_roa_check *) f2)->rtc->name))
|
||||
return 0;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
bug( "Unknown instruction %d in same (%c)", f1->code, f1->code & 0xff);
|
||||
}
|
||||
|
|
34
lib/net.c
34
lib/net.c
|
@ -177,33 +177,29 @@ net_hash(const net_addr *n)
|
|||
case NET_ROA6: return NET_HASH(n, roa6);
|
||||
case NET_FLOW4: return NET_HASH(n, flow4);
|
||||
case NET_FLOW6: return NET_HASH(n, flow6);
|
||||
case NET_MPLS: return NET_HASH(n, mpls);
|
||||
default: bug("invalid type");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define NET_VALIDATE(a,t) net_validate_##t((const net_addr_##t *) a)
|
||||
|
||||
int
|
||||
net_validate(const net_addr *N)
|
||||
net_validate(const net_addr *n)
|
||||
{
|
||||
switch (N->type)
|
||||
switch (n->type)
|
||||
{
|
||||
case NET_IP4:
|
||||
case NET_VPN4:
|
||||
case NET_ROA4:
|
||||
case NET_FLOW4:
|
||||
return net_validate_ip4((net_addr_ip4 *) N);
|
||||
|
||||
case NET_IP6:
|
||||
case NET_VPN6:
|
||||
case NET_ROA6:
|
||||
case NET_FLOW6:
|
||||
return net_validate_ip6((net_addr_ip6 *) N);
|
||||
|
||||
case NET_MPLS:
|
||||
return net_validate_mpls((net_addr_mpls *) N);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
case NET_IP4: return NET_VALIDATE(n, ip4);
|
||||
case NET_IP6: return NET_VALIDATE(n, ip6);
|
||||
case NET_VPN4: return NET_VALIDATE(n, vpn4);
|
||||
case NET_VPN6: return NET_VALIDATE(n, vpn6);
|
||||
case NET_ROA4: return NET_VALIDATE(n, roa4);
|
||||
case NET_ROA6: return NET_VALIDATE(n, roa6);
|
||||
case NET_FLOW4: return NET_VALIDATE(n, flow4);
|
||||
case NET_FLOW6: return NET_VALIDATE(n, flow6);
|
||||
case NET_MPLS: return NET_VALIDATE(n, mpls);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
44
lib/net.h
44
lib/net.h
|
@ -37,6 +37,7 @@
|
|||
#define NB_IP (NB_IP4 | NB_IP6)
|
||||
#define NB_VPN (NB_VPN4 | NB_VPN6)
|
||||
#define NB_FLOW (NB_FLOW4 | NB_FLOW6)
|
||||
#define NB_DEST (NB_IP | NB_VPN | NB_MPLS)
|
||||
#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);
|
||||
|
||||
|
||||
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) &&
|
||||
ip4_zero(ip4_and(n->prefix, ip4_not(ip4_mkmask(n->pxlen))));
|
||||
return (pxlen <= IP4_MAX_PREFIX_LENGTH) &&
|
||||
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)
|
||||
{ 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) &&
|
||||
ip6_zero(ip6_and(n->prefix, ip6_not(ip6_mkmask(n->pxlen))));
|
||||
return net_validate_px4(n->prefix, 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);
|
||||
|
||||
|
||||
|
|
|
@ -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(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,
|
||||
RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE, BABEL)
|
||||
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 <net> r_args_for_val
|
||||
%type <net_ptr> r_args_for
|
||||
%type <t> r_args_channel
|
||||
|
||||
CF_GRAMMAR
|
||||
|
||||
|
@ -514,7 +518,7 @@ CF_CLI(SHOW ROUTE, r_args, [[[<prefix>|for <prefix>|for <ip>] [table <t>] [filte
|
|||
r_args:
|
||||
/* empty */ {
|
||||
$$ = cfg_allocz(sizeof(struct rt_show_data));
|
||||
init_list(&($$->table));
|
||||
init_list(&($$->tables));
|
||||
$$->filter = FILTER_ACCEPT;
|
||||
}
|
||||
| r_args net_any {
|
||||
|
@ -566,13 +570,24 @@ r_args:
|
|||
| r_args export_mode SYM {
|
||||
struct proto_config *c = (struct proto_config *) $3->def;
|
||||
$$ = $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);
|
||||
$$->export_mode = $2;
|
||||
$$->export_protocol = c->proto;
|
||||
$$->running_on_config = c->proto->cf->global;
|
||||
$$->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 {
|
||||
struct proto_config *c = (struct proto_config *) $3->def;
|
||||
$$ = $1;
|
||||
|
@ -590,16 +605,6 @@ r_args:
|
|||
$$ = $1;
|
||||
$$->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:
|
||||
|
@ -642,6 +647,28 @@ export_mode:
|
|||
| 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(SHOW SYMBOLS, sym_args, [table|filter|function|protocol|template|<symbol>], [[Show all known symbolic names]])
|
||||
|
|
19
nest/proto.c
19
nest/proto.c
|
@ -104,6 +104,25 @@ proto_find_channel_by_table(struct proto *p, struct rtable *t)
|
|||
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
|
||||
* @p: protocol instance
|
||||
|
|
|
@ -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 *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);
|
||||
int proto_configure_channel(struct proto *p, struct channel **c, struct channel_config *cf);
|
||||
|
||||
|
|
18
nest/route.h
18
nest/route.h
|
@ -313,26 +313,30 @@ struct rtable_config *rt_new_table(struct symbol *s, uint addr_type);
|
|||
struct rt_show_data_rtable {
|
||||
node n;
|
||||
rtable *table;
|
||||
struct channel *export_channel;
|
||||
};
|
||||
|
||||
struct rt_show_data {
|
||||
net_addr *addr;
|
||||
list table;
|
||||
struct rt_show_data_rtable *tit;
|
||||
struct filter *filter;
|
||||
list tables;
|
||||
struct rt_show_data_rtable *tab; /* Iterator over table list */
|
||||
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;
|
||||
struct fib_iterator fit;
|
||||
struct filter *filter;
|
||||
struct proto *show_protocol;
|
||||
struct proto *export_protocol;
|
||||
struct channel *export_channel;
|
||||
int export_mode, primary_only, filtered;
|
||||
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_last, rt_counter_last, show_counter_last;
|
||||
int stats, show_for, stats_by_table;
|
||||
};
|
||||
|
||||
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 */
|
||||
#define RSD_TDB_DEFAULT 0 /* no table specified */
|
||||
|
|
262
nest/rt-table.c
262
nest/rt-table.c
|
@ -900,7 +900,6 @@ rte_validate(rte *e)
|
|||
int c;
|
||||
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))
|
||||
{
|
||||
log(L_WARN "Ignoring bogus prefix %N received via %s",
|
||||
|
@ -916,6 +915,13 @@ rte_validate(rte *e)
|
|||
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)))
|
||||
{
|
||||
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
|
||||
*/
|
||||
|
||||
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
|
||||
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
|
||||
bsprintf(info, " (%d)", e->pref);
|
||||
|
||||
if (!d->show_counter)
|
||||
cli_printf(c, -1007, "Table %s:", d->tit->table->name);
|
||||
if (d->last_table != d->tab)
|
||||
rt_show_table(c, d);
|
||||
|
||||
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);
|
||||
|
@ -2564,7 +2582,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
|
|||
rte *e, *ee;
|
||||
byte ia[NET_MAX_TEXT_LENGTH+1];
|
||||
struct ea_list *tmpa;
|
||||
struct channel *ec = d->export_channel;
|
||||
struct channel *ec = d->tab->export_channel;
|
||||
int first = 1;
|
||||
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 */
|
||||
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 */
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
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
|
||||
rt_show_cleanup(struct cli *c)
|
||||
{
|
||||
struct rt_show_data *d = c->rover;
|
||||
struct rt_show_data_rtable *tab;
|
||||
|
||||
/* Unlink the iterator */
|
||||
fit_get(&d->tit->table->fib, &d->fit);
|
||||
rt_unlock_table(d->tit->table);
|
||||
while (NODE_VALID(NODE_NEXT(d->tit)))
|
||||
rt_unlock_table((d->tit = NODE_NEXT(d->tit))->table);
|
||||
if (d->table_open)
|
||||
fit_get(&d->tab->table->fib, &d->fit);
|
||||
|
||||
/* Unlock referenced tables */
|
||||
WALK_LIST(tab, d->tables)
|
||||
rt_unlock_table(tab->table);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2680,19 +2696,27 @@ rt_show_cont(struct cli *c)
|
|||
#else
|
||||
unsigned max = 64;
|
||||
#endif
|
||||
struct fib *fib = &d->tit->table->fib;
|
||||
struct fib *fib = &d->tab->table->fib;
|
||||
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 */
|
||||
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);
|
||||
cli_printf(c, 8004, "Stopped due to reconfiguration");
|
||||
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)
|
||||
|
@ -2706,58 +2730,76 @@ rt_show_cont(struct cli *c)
|
|||
}
|
||||
FIB_ITERATE_END;
|
||||
|
||||
if (!d->show_counter && (d->tables_defined_by & RSD_TDB_SET))
|
||||
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)))
|
||||
if (d->stats)
|
||||
{
|
||||
d->tit = NODE_NEXT(d->tit);
|
||||
FIB_ITERATE_INIT(&d->fit, &d->tit->table->fib);
|
||||
d->show_counter_last = d->show_counter;
|
||||
d->rt_counter_last = d->rt_counter;
|
||||
d->net_counter_last = d->net_counter;
|
||||
d->show_counter = 0;
|
||||
d->rt_counter = 0;
|
||||
d->net_counter = 0;
|
||||
return;
|
||||
if (d->last_table != d->tab)
|
||||
rt_show_table(c, d);
|
||||
|
||||
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->tab->table->name);
|
||||
}
|
||||
|
||||
if (d->stats)
|
||||
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->table_open = 0;
|
||||
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
|
||||
cli_printf(c, 0, "");
|
||||
|
||||
done:
|
||||
rt_show_cleanup(c);
|
||||
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));
|
||||
rsdr->table = t;
|
||||
add_tail(&(d->table), &(rsdr->n));
|
||||
struct rt_show_data_rtable *tab = cfg_allocz(sizeof(struct rt_show_data_rtable));
|
||||
tab->table = t;
|
||||
add_tail(&(d->tables), &(tab->n));
|
||||
return tab;
|
||||
}
|
||||
|
||||
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;
|
||||
WALK_LIST(c, p->channels)
|
||||
if (c->table)
|
||||
rt_show_add_table(d, c->table);
|
||||
struct rt_show_data_rtable *tab;
|
||||
|
||||
if (d->export_channel)
|
||||
{
|
||||
c = d->export_channel;
|
||||
tab = rt_show_add_table(d, c->table);
|
||||
tab->export_channel = c;
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void
|
||||
rt_show_get_default_table(struct rt_show_data *d)
|
||||
if (d->export_protocol)
|
||||
{
|
||||
if (d->export_protocol || d->show_protocol)
|
||||
WALK_LIST(c, d->export_protocol->channels)
|
||||
{
|
||||
rt_show_get_table(d->export_protocol ?: d->show_protocol, d);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -2766,68 +2808,86 @@ rt_show_get_default_table(struct rt_show_data *d)
|
|||
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
|
||||
rt_show(struct rt_show_data *d)
|
||||
{
|
||||
struct rt_show_data_rtable *tab;
|
||||
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 */
|
||||
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)
|
||||
{
|
||||
struct rt_show_data_rtable *rsdr;
|
||||
WALK_LIST(rsdr, d->table)
|
||||
{
|
||||
rt_lock_table(rsdr->table);
|
||||
}
|
||||
d->tit = HEAD(d->table);
|
||||
FIB_ITERATE_INIT(&d->fit, &d->tit->table->fib);
|
||||
WALK_LIST(tab, d->tables)
|
||||
rt_lock_table(tab->table);
|
||||
|
||||
/* There is at least one table */
|
||||
d->tab = HEAD(d->tables);
|
||||
this_cli->cont = rt_show_cont;
|
||||
this_cli->cleanup = rt_show_cleanup;
|
||||
this_cli->rover = d;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (d->export_mode)
|
||||
WALK_LIST(tab, d->tables)
|
||||
{
|
||||
/* Find channel associated with the export protocol */
|
||||
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;
|
||||
d->tab = tab;
|
||||
|
||||
if (d->show_for)
|
||||
n = net_route(rsdr->table, d->addr);
|
||||
n = net_route(tab->table, d->addr);
|
||||
else
|
||||
n = net_find(rsdr->table, d->addr);
|
||||
n = net_find(tab->table, d->addr);
|
||||
|
||||
if (n)
|
||||
rt_show_net(this_cli, n, d);
|
||||
|
@ -2836,7 +2896,7 @@ rt_show(struct rt_show_data *d)
|
|||
if (d->rt_counter)
|
||||
cli_msg(0, "");
|
||||
else
|
||||
cli_msg(8001, "Network not found in any specified table");
|
||||
cli_msg(8001, "Network not found");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -903,7 +903,7 @@ rpki_postconfig(struct proto_config *CF)
|
|||
}
|
||||
|
||||
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 */
|
||||
}
|
||||
|
|
|
@ -36,7 +36,10 @@ static_nexthop_new(void)
|
|||
|
||||
static 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
|
||||
|
||||
|
@ -119,6 +122,7 @@ stat_route:
|
|||
this_srt->via = $3;
|
||||
this_srt->mls = $5;
|
||||
}
|
||||
| stat_route0 { this_srt->dest = RTD_NONE; }
|
||||
| stat_route0 DROP { this_srt->dest = RTD_BLACKHOLE; }
|
||||
| stat_route0 REJECT { this_srt->dest = RTD_UNREACHABLE; }
|
||||
| stat_route0 BLACKHOLE { this_srt->dest = RTD_BLACKHOLE; }
|
||||
|
|
Loading…
Reference in a new issue