summaryrefslogtreecommitdiff
path: root/nest/rt-table.c
diff options
context:
space:
mode:
authorOndrej Zajicek (work) <santiago@crfreenet.org>2018-09-27 22:57:55 +0200
committerOndrej Zajicek (work) <santiago@crfreenet.org>2018-12-12 14:46:24 +0100
commit682d3f7de0905ca2e853844734cce7ff65f7d77d (patch)
treee84ab31b4c5b7e99a283cf4c2faf2523dd5d884c /nest/rt-table.c
parent01fd00f5ed9298ab5829403cd7a8a9ba22bcc96a (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.c121
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)
{