summaryrefslogtreecommitdiff
path: root/nest/rt-table.c
diff options
context:
space:
mode:
authorOndrej Zajicek (work) <santiago@crfreenet.org>2019-08-13 18:22:07 +0200
committerOndrej Zajicek (work) <santiago@crfreenet.org>2019-08-14 06:02:33 +0200
commitb7d7599ce3576f28310af18b403fed49a0840b67 (patch)
tree7d7dc8f052d564c3fdbc49eea529f22850ab44ff /nest/rt-table.c
parentdfe63ed84d42178a53b01071c64f23250e74d6d9 (diff)
BGP: implement Adj-RIB-Out
The patch implements optional internal export table to a channel and hooks it to BGP so it can be used as Adj-RIB-Out. When enabled, all exported (post-filtered) routes are stored there. An export table can be examined using e.g. 'show route export table bgp1.ipv4'.
Diffstat (limited to 'nest/rt-table.c')
-rw-r--r--nest/rt-table.c90
1 files changed, 89 insertions, 1 deletions
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 53f5d979..ff995cce 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -633,7 +633,6 @@ do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed)
struct proto *p = c->proto;
struct proto_stats *stats = &c->stats;
-
/*
* First, apply export limit.
*
@@ -679,6 +678,8 @@ do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed)
}
}
+ if (c->out_table && !rte_update_out(c, net->n.addr, new, old, refeed))
+ return;
if (new)
stats->exp_updates_accepted++;
@@ -2507,6 +2508,10 @@ rt_feed_channel_abort(struct channel *c)
}
+/*
+ * Import table
+ */
+
int
rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
{
@@ -2668,6 +2673,89 @@ rt_prune_sync(rtable *t, int all)
}
+/*
+ * Export table
+ */
+
+int
+rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int refeed)
+{
+ struct rtable *tab = c->out_table;
+ struct rte_src *src;
+ rte *old, **pos;
+ net *net;
+
+ if (new)
+ {
+ net = net_get(tab, n);
+ src = new->attrs->src;
+ }
+ else
+ {
+ net = net_find(tab, n);
+ src = old0->attrs->src;
+
+ if (!net)
+ goto drop_withdraw;
+ }
+
+ /* Find the old rte */
+ for (pos = &net->routes; old = *pos; pos = &old->next)
+ if (old->attrs->src == src)
+ {
+ if (new && rte_same(old, new))
+ {
+ /* REF_STALE / REF_DISCARD not used in export table */
+ /*
+ if (old->flags & (REF_STALE | REF_DISCARD | REF_MODIFY))
+ {
+ old->flags &= ~(REF_STALE | REF_DISCARD | REF_MODIFY);
+ return 1;
+ }
+ */
+
+ goto drop_update;
+ }
+
+ /* Remove the old rte */
+ *pos = old->next;
+ rte_free_quick(old);
+ tab->rt_count--;
+
+ break;
+ }
+
+ if (!new)
+ {
+ if (!old)
+ goto drop_withdraw;
+
+ return 1;
+ }
+
+ /* 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;
+ tab->rt_count++;
+ return 1;
+
+drop_update:
+ return refeed;
+
+drop_withdraw:
+ return 0;
+}
+
+
+/*
+ * Hostcache
+ */
+
static inline u32
hc_hash(ip_addr a, rtable *dep)
{