mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-10 05:08:42 +00:00
Merge commit '56c8f2f0' into haugesund
Conflicts: nest/route.h nest/rt-table.c
This commit is contained in:
commit
4eeae48214
@ -45,6 +45,7 @@ struct config {
|
|||||||
|
|
||||||
int cli_debug; /* Tracing of CLI connections and commands */
|
int cli_debug; /* Tracing of CLI connections and commands */
|
||||||
int latency_debug; /* I/O loop tracks duration of each event */
|
int latency_debug; /* I/O loop tracks duration of each event */
|
||||||
|
int pipe_debug; /* Track route propagation through pipes */
|
||||||
u32 latency_limit; /* Events with longer duration are logged (us) */
|
u32 latency_limit; /* Events with longer duration are logged (us) */
|
||||||
u32 watchdog_warning; /* I/O loop watchdog limit for warning (us) */
|
u32 watchdog_warning; /* I/O loop watchdog limit for warning (us) */
|
||||||
u32 watchdog_timeout; /* Watchdog timeout (in seconds, 0 = disabled) */
|
u32 watchdog_timeout; /* Watchdog timeout (in seconds, 0 = disabled) */
|
||||||
|
@ -4211,6 +4211,14 @@ include standard channel config options; see the example below.
|
|||||||
<tag><label id="pipe-peer-table">peer table <m/table/</tag>
|
<tag><label id="pipe-peer-table">peer table <m/table/</tag>
|
||||||
Defines secondary routing table to connect to. The primary one is
|
Defines secondary routing table to connect to. The primary one is
|
||||||
selected by the <cf/table/ keyword.
|
selected by the <cf/table/ keyword.
|
||||||
|
|
||||||
|
<tag><label id="pipe-max-generation">max generation <m/expr/</tag>
|
||||||
|
Sets maximal generation of route that may pass through this pipe.
|
||||||
|
The generation value is increased by one by each pipe on its path.
|
||||||
|
Not meeting this requirement causes an error message complaining about
|
||||||
|
an overpiped route. If you have long chains of pipes, you probably want
|
||||||
|
to raise this value; anyway the default of 16 should be enough for even
|
||||||
|
most strange uses. Maximum is 254.
|
||||||
</descrip>
|
</descrip>
|
||||||
|
|
||||||
<sect1>Attributes
|
<sect1>Attributes
|
||||||
|
@ -112,7 +112,7 @@ proto_postconfig(void)
|
|||||||
|
|
||||||
CF_DECLS
|
CF_DECLS
|
||||||
|
|
||||||
CF_KEYWORDS(ROUTER, ID, HOSTNAME, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
|
CF_KEYWORDS(ROUTER, ID, HOSTNAME, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT, PIPE)
|
||||||
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, VRF, DEFAULT, TABLE, STATES, ROUTES, FILTERS)
|
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, VRF, DEFAULT, TABLE, STATES, ROUTES, FILTERS)
|
||||||
CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, SADR, MPLS)
|
CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, SADR, MPLS)
|
||||||
CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED, RPKI)
|
CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED, RPKI)
|
||||||
@ -371,6 +371,7 @@ debug_default:
|
|||||||
DEBUG PROTOCOLS debug_mask { new_config->proto_default_debug = $3; }
|
DEBUG PROTOCOLS debug_mask { new_config->proto_default_debug = $3; }
|
||||||
| DEBUG CHANNELS debug_mask { new_config->channel_default_debug = $3; }
|
| DEBUG CHANNELS debug_mask { new_config->channel_default_debug = $3; }
|
||||||
| DEBUG COMMANDS expr { new_config->cli_debug = $3; }
|
| DEBUG COMMANDS expr { new_config->cli_debug = $3; }
|
||||||
|
| DEBUG PIPE bool { new_config->pipe_debug = $3; }
|
||||||
;
|
;
|
||||||
|
|
||||||
/* MRTDUMP PROTOCOLS is in systep/unix/config.Y */
|
/* MRTDUMP PROTOCOLS is in systep/unix/config.Y */
|
||||||
|
@ -167,7 +167,6 @@ typedef struct rtable {
|
|||||||
char *name; /* Name of this table */
|
char *name; /* Name of this table */
|
||||||
list channels; /* List of attached channels (struct channel) */
|
list channels; /* List of attached channels (struct channel) */
|
||||||
uint addr_type; /* Type of address data stored in table (NET_*) */
|
uint addr_type; /* Type of address data stored in table (NET_*) */
|
||||||
int pipe_busy; /* Pipe loop detection */
|
|
||||||
int use_count; /* Number of protocols using this table */
|
int use_count; /* Number of protocols using this table */
|
||||||
u32 rt_count; /* Number of routes in the table */
|
u32 rt_count; /* Number of routes in the table */
|
||||||
|
|
||||||
@ -195,6 +194,7 @@ typedef struct rtable {
|
|||||||
struct f_trie *trie_old; /* Old prefix trie waiting to be freed */
|
struct f_trie *trie_old; /* Old prefix trie waiting to be freed */
|
||||||
u32 trie_lock_count; /* Prefix trie locked by walks */
|
u32 trie_lock_count; /* Prefix trie locked by walks */
|
||||||
u32 trie_old_lock_count; /* Old prefix trie locked by walks */
|
u32 trie_old_lock_count; /* Old prefix trie locked by walks */
|
||||||
|
struct tbf rl_pipe; /* Rate limiting token buffer for pipe collisions */
|
||||||
|
|
||||||
list subscribers; /* Subscribers for notifications */
|
list subscribers; /* Subscribers for notifications */
|
||||||
struct timer *settle_timer; /* Settle time for notifications */
|
struct timer *settle_timer; /* Settle time for notifications */
|
||||||
@ -262,6 +262,9 @@ typedef struct rte {
|
|||||||
u32 id; /* Table specific route id */
|
u32 id; /* Table specific route id */
|
||||||
byte flags; /* Table-specific flags */
|
byte flags; /* Table-specific flags */
|
||||||
byte pflags; /* Protocol-specific flags */
|
byte pflags; /* Protocol-specific flags */
|
||||||
|
u8 generation; /* If this route import is based on other previously exported route,
|
||||||
|
this value should be 1 + MAX(generation of the parent routes).
|
||||||
|
Otherwise the route is independent and this value is zero. */
|
||||||
} rte;
|
} rte;
|
||||||
|
|
||||||
struct rte_storage {
|
struct rte_storage {
|
||||||
@ -373,8 +376,9 @@ int rt_feed_channel(struct channel *c);
|
|||||||
void rt_feed_channel_abort(struct channel *c);
|
void rt_feed_channel_abort(struct channel *c);
|
||||||
int rt_reload_channel(struct channel *c);
|
int rt_reload_channel(struct channel *c);
|
||||||
void rt_reload_channel_abort(struct channel *c);
|
void rt_reload_channel_abort(struct channel *c);
|
||||||
|
void rt_refeed_channel(struct channel *c);
|
||||||
void rt_prune_sync(rtable *t, int all);
|
void rt_prune_sync(rtable *t, int all);
|
||||||
int rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old, struct rte_storage **old_exported, int refeed);
|
int rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old, struct rte_storage **old_exported);
|
||||||
struct rtable_config *rt_new_table(struct symbol *s, uint addr_type);
|
struct rtable_config *rt_new_table(struct symbol *s, uint addr_type);
|
||||||
|
|
||||||
static inline int rt_is_ip(rtable *tab)
|
static inline int rt_is_ip(rtable *tab)
|
||||||
|
@ -739,9 +739,12 @@ do_rt_notify(struct channel *c, const net_addr *net, rte *new, rte *old, int ref
|
|||||||
struct rte_storage *old_exported = NULL;
|
struct rte_storage *old_exported = NULL;
|
||||||
if (c->out_table)
|
if (c->out_table)
|
||||||
{
|
{
|
||||||
if (!rte_update_out(c, net, new, old, &old_exported, refeed))
|
if (!rte_update_out(c, net, new, old, &old_exported))
|
||||||
|
{
|
||||||
|
rte_trace_out(D_ROUTES, c, new, "idempotent");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (new)
|
if (new)
|
||||||
stats->exp_updates_accepted++;
|
stats->exp_updates_accepted++;
|
||||||
@ -1129,7 +1132,6 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
|
|||||||
struct proto *p = c->proto;
|
struct proto *p = c->proto;
|
||||||
struct rtable *table = c->table;
|
struct rtable *table = c->table;
|
||||||
struct proto_stats *stats = &c->stats;
|
struct proto_stats *stats = &c->stats;
|
||||||
static struct tbf rl_pipe = TBF_DEFAULT_LOG_LIMITS;
|
|
||||||
struct rte_storage *old_best_stored = net->routes, *old_stored = NULL;
|
struct rte_storage *old_best_stored = net->routes, *old_stored = NULL;
|
||||||
rte *old_best = old_best_stored ? &old_best_stored->rte : NULL;
|
rte *old_best = old_best_stored ? &old_best_stored->rte : NULL;
|
||||||
rte *old = NULL;
|
rte *old = NULL;
|
||||||
@ -1145,16 +1147,16 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
|
|||||||
* a different sender, then there are two paths from the
|
* a different sender, then there are two paths from the
|
||||||
* source protocol to this routing table through transparent
|
* source protocol to this routing table through transparent
|
||||||
* pipes, which is not allowed.
|
* pipes, which is not allowed.
|
||||||
*
|
* We log that and ignore the route. */
|
||||||
* We log that and ignore the route. If it is withdraw, we
|
|
||||||
* ignore it completely (there might be 'spurious withdraws',
|
|
||||||
* see FIXME in do_rte_announce())
|
|
||||||
*/
|
|
||||||
if (old->sender->proto != p)
|
if (old->sender->proto != p)
|
||||||
{
|
{
|
||||||
if (new)
|
if (!old->generation && !new->generation)
|
||||||
log_rl(&rl_pipe, L_ERR "Pipe collision detected when sending %N to table %s",
|
bug("Two protocols claim to author a route with the same rte_src in table %s: %N %s/%u:%u",
|
||||||
net->n.addr, table->name);
|
c->table->name, net->n.addr, old->src->proto->name, old->src->private_id, old->src->global_id);
|
||||||
|
|
||||||
|
log_rl(&table->rl_pipe, L_ERR "Route source collision in table %s: %N %s/%u:%u",
|
||||||
|
c->table->name, net->n.addr, old->src->proto->name, old->src->private_id, old->src->global_id);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1173,6 +1175,7 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
*before_old = (*before_old)->next;
|
*before_old = (*before_old)->next;
|
||||||
table->rt_count--;
|
table->rt_count--;
|
||||||
}
|
}
|
||||||
@ -1420,7 +1423,6 @@ rte_update(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
|
|||||||
if (c->in_table && !rte_update_in(c, n, new, src))
|
if (c->in_table && !rte_update_in(c, n, new, src))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// struct proto *p = c->proto;
|
|
||||||
struct proto_stats *stats = &c->stats;
|
struct proto_stats *stats = &c->stats;
|
||||||
const struct filter *filter = c->in_filter;
|
const struct filter *filter = c->in_filter;
|
||||||
net *nn;
|
net *nn;
|
||||||
@ -1978,6 +1980,8 @@ rt_setup(pool *pp, struct rtable_config *cf)
|
|||||||
t->rt_event = ev_new_init(p, rt_event, t);
|
t->rt_event = ev_new_init(p, rt_event, t);
|
||||||
t->last_rt_change = t->gc_time = current_time();
|
t->last_rt_change = t->gc_time = current_time();
|
||||||
|
|
||||||
|
t->rl_pipe = (struct tbf) TBF_DEFAULT_LOG_LIMITS;
|
||||||
|
|
||||||
if (rt_is_flow(t))
|
if (rt_is_flow(t))
|
||||||
{
|
{
|
||||||
t->flowspec_trie = f_new_trie(lp_new_default(p), 0);
|
t->flowspec_trie = f_new_trie(lp_new_default(p), 0);
|
||||||
@ -3065,7 +3069,7 @@ again:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, struct rte_storage **old_exported, int refeed)
|
rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, struct rte_storage **old_exported)
|
||||||
{
|
{
|
||||||
struct rtable *tab = c->out_table;
|
struct rtable *tab = c->out_table;
|
||||||
struct rte_src *src;
|
struct rte_src *src;
|
||||||
@ -3082,7 +3086,7 @@ rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, struct
|
|||||||
src = old0->src;
|
src = old0->src;
|
||||||
|
|
||||||
if (!net)
|
if (!net)
|
||||||
goto drop_withdraw;
|
goto drop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find the old rte */
|
/* Find the old rte */
|
||||||
@ -3092,7 +3096,7 @@ rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, struct
|
|||||||
if (old = *pos)
|
if (old = *pos)
|
||||||
{
|
{
|
||||||
if (new && rte_same(&(*pos)->rte, new))
|
if (new && rte_same(&(*pos)->rte, new))
|
||||||
goto drop_update;
|
goto drop;
|
||||||
|
|
||||||
/* Remove the old rte */
|
/* Remove the old rte */
|
||||||
*pos = old->next;
|
*pos = old->next;
|
||||||
@ -3103,7 +3107,7 @@ rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, struct
|
|||||||
if (!new)
|
if (!new)
|
||||||
{
|
{
|
||||||
if (!old)
|
if (!old)
|
||||||
goto drop_withdraw;
|
goto drop;
|
||||||
|
|
||||||
if (!net->routes)
|
if (!net->routes)
|
||||||
fib_delete(&tab->fib, net);
|
fib_delete(&tab->fib, net);
|
||||||
@ -3119,13 +3123,36 @@ rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, struct
|
|||||||
tab->rt_count++;
|
tab->rt_count++;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
drop_update:
|
drop:
|
||||||
return refeed;
|
|
||||||
|
|
||||||
drop_withdraw:
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rt_refeed_channel(struct channel *c)
|
||||||
|
{
|
||||||
|
if (!c->out_table)
|
||||||
|
{
|
||||||
|
channel_request_feeding(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_DIE(c->ra_mode != RA_ANY);
|
||||||
|
|
||||||
|
c->proto->feed_begin(c, 0);
|
||||||
|
|
||||||
|
FIB_WALK(&c->out_table->fib, net, n)
|
||||||
|
{
|
||||||
|
if (!n->routes)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
rte e = n->routes->rte;
|
||||||
|
c->proto->rt_notify(c->proto, c, n->n.addr, &e, NULL);
|
||||||
|
}
|
||||||
|
FIB_WALK_END;
|
||||||
|
|
||||||
|
c->proto->feed_end(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hostcache
|
* Hostcache
|
||||||
|
@ -2732,7 +2732,7 @@ bgp_rx_route_refresh(struct bgp_conn *conn, byte *pkt, uint len)
|
|||||||
{
|
{
|
||||||
case BGP_RR_REQUEST:
|
case BGP_RR_REQUEST:
|
||||||
BGP_TRACE(D_PACKETS, "Got ROUTE-REFRESH");
|
BGP_TRACE(D_PACKETS, "Got ROUTE-REFRESH");
|
||||||
channel_request_feeding(&c->c);
|
rt_refeed_channel(&c->c);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BGP_RR_BEGIN:
|
case BGP_RR_BEGIN:
|
||||||
|
@ -16,7 +16,7 @@ CF_DEFINES
|
|||||||
|
|
||||||
CF_DECLS
|
CF_DECLS
|
||||||
|
|
||||||
CF_KEYWORDS(PIPE, PEER, TABLE)
|
CF_KEYWORDS(PIPE, PEER, TABLE, MAX, GENERATION)
|
||||||
|
|
||||||
CF_GRAMMAR
|
CF_GRAMMAR
|
||||||
|
|
||||||
@ -25,6 +25,7 @@ proto: pipe_proto '}' { this_channel = NULL; } ;
|
|||||||
pipe_proto_start: proto_start PIPE
|
pipe_proto_start: proto_start PIPE
|
||||||
{
|
{
|
||||||
this_proto = proto_config_new(&proto_pipe, $1);
|
this_proto = proto_config_new(&proto_pipe, $1);
|
||||||
|
PIPE_CFG->max_generation = 16;
|
||||||
}
|
}
|
||||||
proto_name
|
proto_name
|
||||||
{
|
{
|
||||||
@ -41,6 +42,10 @@ pipe_proto:
|
|||||||
| pipe_proto proto_item ';'
|
| pipe_proto proto_item ';'
|
||||||
| pipe_proto channel_item_ ';'
|
| pipe_proto channel_item_ ';'
|
||||||
| pipe_proto PEER TABLE rtable ';' { PIPE_CFG->peer = $4; }
|
| pipe_proto PEER TABLE rtable ';' { PIPE_CFG->peer = $4; }
|
||||||
|
| pipe_proto MAX GENERATION expr ';' {
|
||||||
|
if (($4 < 1) || ($4 > 254)) cf_error("Max generation must be in range 1..254, got %u", $4);
|
||||||
|
PIPE_CFG->max_generation = $4;
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
CF_CODE
|
CF_CODE
|
||||||
|
@ -56,15 +56,6 @@ pipe_rt_notify(struct proto *P, struct channel *src_ch, const net_addr *n, rte *
|
|||||||
if (!new && !old)
|
if (!new && !old)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (dst->table->pipe_busy)
|
|
||||||
{
|
|
||||||
log(L_ERR "Pipe loop detected when sending %N to table %s",
|
|
||||||
n, dst->table->name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
src_ch->table->pipe_busy = 1;
|
|
||||||
|
|
||||||
if (new)
|
if (new)
|
||||||
{
|
{
|
||||||
rta *a = alloca(rta_size(new->attrs));
|
rta *a = alloca(rta_size(new->attrs));
|
||||||
@ -76,23 +67,34 @@ pipe_rt_notify(struct proto *P, struct channel *src_ch, const net_addr *n, rte *
|
|||||||
rte e0 = {
|
rte e0 = {
|
||||||
.attrs = a,
|
.attrs = a,
|
||||||
.src = new->src,
|
.src = new->src,
|
||||||
|
.generation = new->generation + 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
rte_update(dst, n, &e0, new->src);
|
rte_update(dst, n, &e0, new->src);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
rte_update(dst, n, NULL, old->src);
|
rte_update(dst, n, NULL, old->src);
|
||||||
|
|
||||||
src_ch->table->pipe_busy = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
pipe_preexport(struct channel *c, rte *e)
|
pipe_preexport(struct channel *c, rte *e)
|
||||||
{
|
{
|
||||||
struct proto *pp = e->sender->proto;
|
struct pipe_proto *p = (void *) c->proto;
|
||||||
|
|
||||||
if (pp == c->proto)
|
/* Avoid direct loopbacks */
|
||||||
return -1; /* Avoid local loops automatically */
|
if (e->sender == c)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Indirection check */
|
||||||
|
uint max_generation = ((struct pipe_config *) p->p.cf)->max_generation;
|
||||||
|
if (e->generation >= max_generation)
|
||||||
|
{
|
||||||
|
log_rl(&p->rl_gen, L_ERR "Route overpiped (%u hops of %u configured in %s) in table %s: %N %s/%u:%u",
|
||||||
|
e->generation, max_generation, c->proto->name,
|
||||||
|
c->table->name, e->net, e->src->proto->name, e->src->private_id, e->src->global_id);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -177,6 +179,8 @@ pipe_init(struct proto_config *CF)
|
|||||||
P->preexport = pipe_preexport;
|
P->preexport = pipe_preexport;
|
||||||
P->reload_routes = pipe_reload_routes;
|
P->reload_routes = pipe_reload_routes;
|
||||||
|
|
||||||
|
p->rl_gen = (struct tbf) TBF_DEFAULT_LOG_LIMITS;
|
||||||
|
|
||||||
pipe_configure_channels(p, cf);
|
pipe_configure_channels(p, cf);
|
||||||
|
|
||||||
return P;
|
return P;
|
||||||
|
@ -12,12 +12,14 @@
|
|||||||
struct pipe_config {
|
struct pipe_config {
|
||||||
struct proto_config c;
|
struct proto_config c;
|
||||||
struct rtable_config *peer; /* Table we're connected to */
|
struct rtable_config *peer; /* Table we're connected to */
|
||||||
|
u8 max_generation;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pipe_proto {
|
struct pipe_proto {
|
||||||
struct proto p;
|
struct proto p;
|
||||||
struct channel *pri;
|
struct channel *pri;
|
||||||
struct channel *sec;
|
struct channel *sec;
|
||||||
|
struct tbf rl_gen;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user