summaryrefslogtreecommitdiff
path: root/nest
diff options
context:
space:
mode:
Diffstat (limited to 'nest')
-rw-r--r--nest/config.Y3
-rw-r--r--nest/route.h8
-rw-r--r--nest/rt-table.c91
3 files changed, 67 insertions, 35 deletions
diff --git a/nest/config.Y b/nest/config.Y
index 92a80589..1bebc084 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -112,7 +112,7 @@ proto_postconfig(void)
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(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, SADR, MPLS)
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 CHANNELS debug_mask { new_config->channel_default_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 */
diff --git a/nest/route.h b/nest/route.h
index c7fb67aa..98d030a9 100644
--- a/nest/route.h
+++ b/nest/route.h
@@ -167,7 +167,6 @@ typedef struct rtable {
char *name; /* Name of this table */
list channels; /* List of attached channels (struct channel) */
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 */
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 */
u32 trie_lock_count; /* 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 */
struct timer *settle_timer; /* Settle time for notifications */
@@ -262,6 +262,9 @@ typedef struct rte {
u32 id; /* Table specific route id */
byte flags; /* Table-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;
struct rte_storage {
@@ -373,8 +376,9 @@ int rt_feed_channel(struct channel *c);
void rt_feed_channel_abort(struct channel *c);
int rt_reload_channel(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);
-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);
static inline int rt_is_ip(rtable *tab)
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 2fa4f516..36414ed4 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -739,8 +739,11 @@ do_rt_notify(struct channel *c, const net_addr *net, rte *new, rte *old, int ref
struct rte_storage *old_exported = NULL;
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;
+ }
}
if (new)
@@ -1129,7 +1132,6 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
struct proto *p = c->proto;
struct rtable *table = c->table;
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;
rte *old_best = old_best_stored ? &old_best_stored->rte : NULL;
rte *old = NULL;
@@ -1141,22 +1143,22 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
{
old = &(old_stored = (*before_old))->rte;
- /* If there is the same route in the routing table but from
- * a different sender, then there are two paths from the
- * source protocol to this routing table through transparent
- * pipes, which is not allowed.
- *
- * 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 (new)
- log_rl(&rl_pipe, L_ERR "Pipe collision detected when sending %N to table %s",
- net->n.addr, table->name);
- return;
- }
+ /* If there is the same route in the routing table but from
+ * a different sender, then there are two paths from the
+ * source protocol to this routing table through transparent
+ * pipes, which is not allowed.
+ * We log that and ignore the route. */
+ if (old->sender->proto != p)
+ {
+ if (!old->generation && !new->generation)
+ bug("Two protocols claim to author a route with the same rte_src 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);
+
+ 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;
+ }
if (new && rte_same(old, new))
{
@@ -1167,14 +1169,15 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
if (!rte_is_filtered(new))
{
stats->imp_updates_ignored++;
- rte_trace_in(D_ROUTES, c, new, "ignored");
+ rte_trace_in(D_ROUTES, c, new, "ignored");
}
- return;
- }
+ return;
+ }
+
- *before_old = (*before_old)->next;
- table->rt_count--;
+ *before_old = (*before_old)->next;
+ table->rt_count--;
}
if (!old && !new)
@@ -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))
return;
- // struct proto *p = c->proto;
struct proto_stats *stats = &c->stats;
const struct filter *filter = c->in_filter;
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->last_rt_change = t->gc_time = current_time();
+ t->rl_pipe = (struct tbf) TBF_DEFAULT_LOG_LIMITS;
+
if (rt_is_flow(t))
{
t->flowspec_trie = f_new_trie(lp_new_default(p), 0);
@@ -3065,7 +3069,7 @@ again:
*/
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 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;
if (!net)
- goto drop_withdraw;
+ goto drop;
}
/* 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 (new && rte_same(&(*pos)->rte, new))
- goto drop_update;
+ goto drop;
/* Remove the old rte */
*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 (!old)
- goto drop_withdraw;
+ goto drop;
if (!net->routes)
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++;
return 1;
-drop_update:
- return refeed;
-
-drop_withdraw:
+drop:
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