diff options
author | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2018-09-27 22:57:55 +0200 |
---|---|---|
committer | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2018-12-12 14:46:24 +0100 |
commit | 682d3f7de0905ca2e853844734cce7ff65f7d77d (patch) | |
tree | e84ab31b4c5b7e99a283cf4c2faf2523dd5d884c /nest/rt-table.c | |
parent | 01fd00f5ed9298ab5829403cd7a8a9ba22bcc96a (diff) |
BGP: implement Adj-RIB-In
The patch implements optional internal import table to a channel and
hooks it to BGP so it can be used as Adj-RIB-In. When enabled, all
received (pre-filtered) routes are stored there and import filters can
be re-evaluated without explicit route refresh. An import table can be
examined using e.g. 'show route import table bgp1.ipv4'.
Diffstat (limited to 'nest/rt-table.c')
-rw-r--r-- | nest/rt-table.c | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/nest/rt-table.c b/nest/rt-table.c index 21b6622e..5beb1be9 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -2288,6 +2288,127 @@ rt_feed_channel_abort(struct channel *c) } } + +int +rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *src) +{ + rte *old, **pos; + net *net; + + if (new) + { + net = net_get(c->in_table, n); + + if (!new->pref) + new->pref = c->preference; + + if (!rta_is_cached(new->attrs)) + new->attrs = rta_lookup(new->attrs); + } + else + { + net = net_find(c->in_table, n); + + if (!net) + return 0; + } + + /* Find the old rte */ + for (pos = &net->routes; old = *pos; pos = &old->next) + if (old->attrs->src == src) + { + if (new && rte_same(old, new)) + return 0; + + /* Remove the old rte */ + *pos = old->next; + rte_free_quick(old); + + break; + } + + if (!new) + return !!old; + + /* Insert the new rte */ + rte *e = rte_do_cow(new); + e->flags |= REF_COW; + e->net = net; + e->sender = c; + e->lastmod = current_time(); + e->next = *pos; + *pos = e; + + return 1; +} + +int +rt_reload_channel(struct channel *c) +{ + struct rtable *tab = c->in_table; + struct fib_iterator *fit = &c->reload_fit; + int max_feed = 64; + + ASSERT(c->channel_state == CS_UP); + + if (!c->reload_active) + { + FIB_ITERATE_INIT(fit, &tab->fib); + c->reload_active = 1; + } + + FIB_ITERATE_START(&tab->fib, fit, net, n) + { + if (max_feed <= 0) + { + FIB_ITERATE_PUT(fit); + return 0; + } + + for (rte *e = n->routes; e; e = e->next) + { + rte_update2(c, n->n.addr, rte_do_cow(e), e->attrs->src); + max_feed--; + } + } + FIB_ITERATE_END; + + c->reload_active = 0; + return 1; +} + +void +rt_reload_channel_abort(struct channel *c) +{ + if (c->reload_active) + { + /* Unlink the iterator */ + fit_get(&c->in_table->fib, &c->reload_fit); + c->reload_active = 0; + } +} + +void +rt_prune_sync(rtable *t, int all) +{ + FIB_WALK(&t->fib, net, n) + { + rte *e, **ee = &n->routes; + while (e = *ee) + { + if (all || (e->flags & (REF_STALE | REF_DISCARD))) + { + *ee = e->next; + rte_free_quick(e); + } + else + ee = &e->next; + } + } + FIB_WALK_END; +} + + static inline u32 hc_hash(ip_addr a, rtable *dep) { |