diff options
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) { |