diff options
author | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2019-08-13 18:22:07 +0200 |
---|---|---|
committer | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2019-08-14 06:02:33 +0200 |
commit | b7d7599ce3576f28310af18b403fed49a0840b67 (patch) | |
tree | 7d7dc8f052d564c3fdbc49eea529f22850ab44ff /nest/rt-table.c | |
parent | dfe63ed84d42178a53b01071c64f23250e74d6d9 (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.c | 90 |
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) { |