0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2025-03-11 17:08:46 +00:00

Nest: Dropping global rte_update_pool

This commit is contained in:
Jan Maria Matejka 2018-01-24 16:00:42 +01:00
parent d4cebc6bbe
commit 9a5557ea8f
5 changed files with 78 additions and 114 deletions

View File

@ -295,7 +295,7 @@ rte *rte_find(net *net, struct rte_src *src);
rte *rte_get_temp(struct rta *);
void rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
/* rte_update() moved to protocol.h to avoid dependency conflicts */
int rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter);
int rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter, struct linpool *pool);
rte *rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int silent);
void rt_refresh_begin(rtable *t, struct channel *c);
void rt_refresh_end(rtable *t, struct channel *c);
@ -626,12 +626,12 @@ void rta_dump_all(void);
void rta_show(struct cli *, rta *);
struct hostentry * rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep);
void rta_apply_hostentry(rta *a, struct hostentry *he, mpls_label_stack *mls);
void rta_apply_hostentry(rta *a, struct hostentry *he, mpls_label_stack *mls, struct linpool *lp);
static inline void
rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr gw, ip_addr ll, mpls_label_stack *mls)
rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr gw, ip_addr ll, mpls_label_stack *mls, struct linpool *lp)
{
rta_apply_hostentry(a, rt_get_hostentry(tab, gw, ll, dep), mls);
rta_apply_hostentry(a, rt_get_hostentry(tab, gw, ll, dep), mls, lp);
}
/*

View File

@ -46,7 +46,6 @@
pool *rt_table_pool;
static slab *rte_slab;
static linpool *rte_update_pool;
static list routing_tables;
@ -393,8 +392,8 @@ rte_trace_out(uint flag, struct proto *p, rte *e, char *msg)
rte_trace(p, e, '<', msg);
}
static rte *
export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int silent)
rte *
export_filter(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int silent)
{
struct proto *p = c->proto;
struct filter *filter = c->out_filter;
@ -450,12 +449,6 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si
return NULL;
}
static inline rte *
export_filter(struct channel *c, rte *rt0, rte **rt_free, int silent)
{
return export_filter_(c, rt0, rt_free, rte_update_pool, silent);
}
static void
do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed)
{
@ -534,7 +527,7 @@ do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed)
}
static void
rt_notify_basic(struct channel *c, net *net, rte *new0, rte *old0, int refeed)
rt_notify_basic(struct channel *c, net *net, rte *new0, rte *old0, struct linpool *lp, int refeed)
{
struct proto *p = c->proto;
@ -569,10 +562,10 @@ rt_notify_basic(struct channel *c, net *net, rte *new0, rte *old0, int refeed)
*/
if (new)
new = export_filter(c, new, &new_free, 0);
new = export_filter(c, new, &new_free, lp, 0);
if (old && !(refeed || (old->lastmod <= c->last_tx_filter_change)))
old = export_filter(c, old, &old_free, 1);
old = export_filter(c, old, &old_free, lp, 1);
if (!new && !old)
{
@ -605,7 +598,7 @@ rt_notify_basic(struct channel *c, net *net, rte *new0, rte *old0, int refeed)
}
static void
rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_changed, rte *before_old, int feed)
rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_changed, rte *before_old, struct linpool *lp, int feed)
{
// struct proto *p = c->proto;
@ -631,7 +624,7 @@ rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_chang
/* First, find the new_best route - first accepted by filters */
for (r=net->routes; rte_is_valid(r); r=r->next)
{
if (new_best = export_filter(c, r, &new_free, 0))
if (new_best = export_filter(c, r, &new_free, lp, 0))
break;
/* Note if we walked around the position of old_changed route */
@ -692,7 +685,7 @@ rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_chang
/* First case */
if (old_meet)
if (old_best = export_filter(c, old_changed, &old_free, 1))
if (old_best = export_filter(c, old_changed, &old_free, lp, 1))
goto found;
/* Second case */
@ -710,11 +703,11 @@ rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_chang
/* Fourth case */
for (r=r->next; rte_is_valid(r); r=r->next)
{
if (old_best = export_filter(c, r, &old_free, 1))
if (old_best = export_filter(c, r, &old_free, lp, 1))
goto found;
if (r == before_old)
if (old_best = export_filter(c, old_changed, &old_free, 1))
if (old_best = export_filter(c, old_changed, &old_free, lp, 1))
goto found;
}
@ -750,7 +743,7 @@ rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int
if (!rte_is_valid(best0))
return NULL;
best = export_filter_(c, best0, rt_free, pool, silent);
best = export_filter(c, best0, rt_free, pool, silent);
if (!best || !rte_is_reachable(best))
return best;
@ -760,7 +753,7 @@ rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int
if (!rte_mergable(best0, rt0))
continue;
rt = export_filter_(c, rt0, &tmp, pool, 1);
rt = export_filter(c, rt0, &tmp, pool, 1);
if (!rt)
continue;
@ -792,7 +785,7 @@ rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int
static void
rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed,
rte *new_best, rte*old_best, int refeed)
rte *new_best, rte *old_best, struct linpool *lp, int refeed)
{
// struct proto *p = c->proto;
@ -811,10 +804,10 @@ rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed
if ((new_best == old_best) && !refeed)
{
new_changed = rte_mergable(new_best, new_changed) ?
export_filter(c, new_changed, &new_changed_free, 1) : NULL;
export_filter(c, new_changed, &new_changed_free, lp, 1) : NULL;
old_changed = rte_mergable(old_best, old_changed) ?
export_filter(c, old_changed, &old_changed_free, 1) : NULL;
export_filter(c, old_changed, &old_changed_free, lp, 1) : NULL;
if (!new_changed && !old_changed)
return;
@ -827,12 +820,12 @@ rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed
/* Prepare new merged route */
if (new_best)
new_best = rt_export_merged(c, net, &new_best_free, rte_update_pool, 0);
new_best = rt_export_merged(c, net, &new_best_free, lp, 0);
/* Prepare old merged route (without proper merged next hops) */
/* There are some issues with running filter on old route - see rt_notify_basic() */
if (old_best && !refeed)
old_best = export_filter(c, old_best, &old_best_free, 1);
old_best = export_filter(c, old_best, &old_best_free, lp, 1);
if (new_best || old_best)
do_rt_notify(c, net, new_best, old_best, refeed);
@ -883,7 +876,7 @@ rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed
*/
static void
rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old,
rte *new_best, rte *old_best, rte *before_old)
rte *new_best, rte *old_best, rte *before_old, struct linpool *lp)
{
if (!rte_is_valid(new))
new = NULL;
@ -911,11 +904,11 @@ rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old,
if (c->ra_mode == type)
if (type == RA_ACCEPTED)
rt_notify_accepted(c, net, new, old, before_old, 0);
rt_notify_accepted(c, net, new, old, before_old, lp, 0);
else if (type == RA_MERGED)
rt_notify_merged(c, net, new, old, new_best, old_best, 0);
rt_notify_merged(c, net, new, old, new_best, old_best, lp, 0);
else
rt_notify_basic(c, net, new, old, 0);
rt_notify_basic(c, net, new, old, lp, 0);
}
}
@ -994,7 +987,7 @@ rte_same(rte *x, rte *y)
static inline int rte_is_ok(rte *e) { return e && !rte_is_filtered(e); }
static void
rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src, struct linpool *lp)
{
struct proto *p = c->proto;
struct rtable *table = c->table;
@ -1229,12 +1222,12 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
}
/* Propagate the route change */
rte_announce(table, RA_ANY, net, new, old, NULL, NULL, NULL);
rte_announce(table, RA_ANY, net, new, old, NULL, NULL, NULL, lp);
if (net->routes != old_best)
rte_announce(table, RA_OPTIMAL, net, net->routes, old_best, NULL, NULL, NULL);
rte_announce(table, RA_OPTIMAL, net, net->routes, old_best, NULL, NULL, NULL, lp);
if (table->config->sorted)
rte_announce(table, RA_ACCEPTED, net, new, old, NULL, NULL, before_old);
rte_announce(table, RA_MERGED, net, new, old, net->routes, old_best, NULL);
rte_announce(table, RA_ACCEPTED, net, new, old, NULL, NULL, before_old, lp);
rte_announce(table, RA_MERGED, net, new, old, net->routes, old_best, NULL, lp);
if (!net->routes &&
(table->gc_counter++ >= table->config->gc_max_ops) &&
@ -1250,21 +1243,6 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
rte_free_quick(old);
}
static int rte_update_nest_cnt; /* Nesting counter to allow recursive updates */
static inline void
rte_update_lock(void)
{
rte_update_nest_cnt++;
}
static inline void
rte_update_unlock(void)
{
if (!--rte_update_nest_cnt)
lp_flush(rte_update_pool);
}
static inline void
rte_hide_dummy_routes(net *net, rte **dummy)
{
@ -1333,12 +1311,12 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
struct proto *p = c->proto;
struct proto_stats *stats = &c->stats;
struct filter *filter = c->in_filter;
struct linpool *lp = lp_new(c->proto->pool, 1024);
rte *dummy = NULL;
net *nn;
ASSERT(c->channel_state == CS_UP);
rte_update_lock();
if (new)
{
nn = net_get(c->table, n);
@ -1370,11 +1348,11 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
}
else
{
rte_make_tmp_attrs(&new, rte_update_pool);
rte_make_tmp_attrs(&new, lp);
if (filter && (filter != FILTER_REJECT))
{
ea_list *oldea = new->attrs->eattrs;
int fr = f_run(filter, &new, rte_update_pool, 0);
int fr = f_run(filter, &new, lp, 0);
if (fr > F_ACCEPT)
{
stats->imp_updates_filtered++;
@ -1400,16 +1378,16 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
if (!(nn = net_find(c->table, n)) || !src)
{
stats->imp_withdraws_ignored++;
rte_update_unlock();
return;
goto done;
}
}
recalc:
rte_hide_dummy_routes(nn, &dummy);
rte_recalculate(c, nn, new, src);
rte_recalculate(c, nn, new, src, lp);
rte_unhide_dummy_routes(nn, &dummy);
rte_update_unlock();
done:
rfree(lp);
return;
drop:
@ -1418,32 +1396,11 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
goto recalc;
}
/* Independent call to rte_announce(), used from next hop
recalculation, outside of rte_update(). new must be non-NULL */
static inline void
rte_announce_i(rtable *tab, unsigned type, net *net, rte *new, rte *old,
rte *new_best, rte *old_best)
{
rte_update_lock();
rte_announce(tab, type, net, new, old, new_best, old_best, NULL);
rte_update_unlock();
}
static inline void
rte_discard(rte *old) /* Non-filtered route deletion, used during garbage collection */
{
rte_update_lock();
rte_recalculate(old->sender, old->net, NULL, old->attrs->src);
rte_update_unlock();
}
/* Modify existing route by protocol hook, used for long-lived graceful restart */
static inline void
rte_modify(rte *old)
rte_modify(rte *old, struct linpool *lp)
{
rte_update_lock();
rte *new = old->sender->proto->rte_modify(old, rte_update_pool);
rte *new = old->sender->proto->rte_modify(old, lp);
if (new != old)
{
if (new)
@ -1453,15 +1410,13 @@ rte_modify(rte *old)
new->flags = (old->flags & ~REF_MODIFY) | REF_COW;
}
rte_recalculate(old->sender, old->net, new, old->attrs->src);
rte_recalculate(old->sender, old->net, new, old->attrs->src, lp);
}
rte_update_unlock();
}
/* Check rtable for best route to given net whether it would be exported do p */
int
rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter)
rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter, struct linpool *lp)
{
net *n = net_find(t, a);
rte *rt = n ? n->routes : NULL;
@ -1469,20 +1424,16 @@ rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter)
if (!rte_is_valid(rt))
return 0;
rte_update_lock();
/* Rest is stripped down export_filter() */
rte_make_tmp_attrs(&rt, rte_update_pool);
int v = p->import_control ? p->import_control(p, &rt, rte_update_pool) : 0;
rte_make_tmp_attrs(&rt, lp);
int v = p->import_control ? p->import_control(p, &rt, lp) : 0;
if (v == RIC_PROCESS)
v = (f_run(filter, &rt, rte_update_pool, FF_SILENT) <= F_ACCEPT);
v = (f_run(filter, &rt, lp, FF_SILENT) <= F_ACCEPT);
/* Discard temporary rte */
if (rt != n->routes)
rte_free(rt);
rte_update_unlock();
return v > 0;
}
@ -1699,7 +1650,6 @@ rt_init(void)
{
rta_init();
rt_table_pool = rp_new(&root_pool, "Routing tables");
rte_update_pool = lp_new_default(rt_table_pool);
rte_slab = sl_new(rt_table_pool, sizeof(rte));
init_list(&routing_tables);
}
@ -1764,7 +1714,10 @@ again:
return;
}
rte_discard(e);
/* Non-filtered route deletion */
struct linpool *lp = lp_new(e->sender->proto->pool, 1024);
rte_recalculate(e->sender, e->net, NULL, e->attrs->src, lp);
rfree(lp);
limit--;
goto rescan;
@ -1779,7 +1732,9 @@ again:
return;
}
rte_modify(e);
struct linpool *lp = lp_new(e->sender->proto->pool, 1024);
rte_modify(e, lp);
rfree(lp);
limit--;
goto rescan;
@ -1853,7 +1808,7 @@ rta_next_hop_outdated(rta *a)
}
void
rta_apply_hostentry(rta *a, struct hostentry *he, mpls_label_stack *mls)
rta_apply_hostentry(rta *a, struct hostentry *he, mpls_label_stack *mls, struct linpool *lp)
{
a->hostentry = he;
a->dest = he->dest;
@ -1888,7 +1843,7 @@ no_nexthop:
else
{
nhr = nhp;
nhp = (nhp ? (nhp->next = lp_allocz(rte_update_pool, NEXTHOP_MAX_SIZE)) : &(a->nh));
nhp = (nhp ? (nhp->next = lp_allocz(lp, NEXTHOP_MAX_SIZE)) : &(a->nh));
}
nhp->iface = nh->iface;
@ -1933,7 +1888,7 @@ no_nexthop:
}
static inline rte *
rt_next_hop_update_rte(rtable *tab UNUSED, rte *old)
rt_next_hop_update_rte(rtable *tab UNUSED, rte *old, struct linpool *lp)
{
rta *a = alloca(RTA_MAX_SIZE);
memcpy(a, old->attrs, rta_size(old->attrs));
@ -1941,7 +1896,7 @@ rt_next_hop_update_rte(rtable *tab UNUSED, rte *old)
mpls_label_stack mls = { .len = a->nh.labels_orig };
memcpy(mls.stack, &a->nh.label[a->nh.labels - mls.len], mls.len * sizeof(u32));
rta_apply_hostentry(a, old->attrs->hostentry, &mls);
rta_apply_hostentry(a, old->attrs->hostentry, &mls, lp);
a->aflags = 0;
rte *e = sl_alloc(rte_slab);
@ -1962,13 +1917,15 @@ rt_next_hop_update_net(rtable *tab, net *n)
if (!old_best)
return 0;
struct linpool *lp = lp_new(rt_table_pool, 1024); /* TODO: screw it */
for (k = &n->routes; e = *k; k = &e->next)
if (rta_next_hop_outdated(e->attrs))
{
new = rt_next_hop_update_rte(tab, e);
new = rt_next_hop_update_rte(tab, e, lp);
*k = new;
rte_announce_i(tab, RA_ANY, n, new, e, NULL, NULL);
rte_announce(tab, RA_ANY, n, new, e, NULL, NULL, NULL, lp);
rte_trace_in(D_ROUTES, new->sender->proto, new, "updated");
/* Call a pre-comparison hook */
@ -1986,7 +1943,10 @@ rt_next_hop_update_net(rtable *tab, net *n)
}
if (!count)
return 0;
{
rfree(lp);
return 0;
}
/* Find the new best route */
new_best = NULL;
@ -2008,12 +1968,14 @@ rt_next_hop_update_net(rtable *tab, net *n)
/* Announce the new best route */
if (new != old_best)
{
rte_announce_i(tab, RA_OPTIMAL, n, new, old_best, NULL, NULL);
rte_announce(tab, RA_OPTIMAL, n, new, old_best, NULL, NULL, NULL, lp);
rte_trace_in(D_ROUTES, new->sender->proto, new, "updated [best]");
}
/* FIXME: Better announcement of merged routes */
rte_announce_i(tab, RA_MERGED, n, new, old_best, new, old_best);
rte_announce(tab, RA_MERGED, n, new, old_best, new, old_best, NULL, lp);
rfree(lp);
if (free_old_best)
rte_free_quick(old_best);
@ -2194,14 +2156,14 @@ rt_commit(struct config *new, struct config *old)
static inline void
do_feed_channel(struct channel *c, net *n, rte *e)
{
rte_update_lock();
struct linpool *lp = lp_new(c->proto->pool, 1024);
if (c->ra_mode == RA_ACCEPTED)
rt_notify_accepted(c, n, e, NULL, NULL, c->refeeding ? 2 : 1);
rt_notify_accepted(c, n, e, NULL, NULL, lp, c->refeeding ? 2 : 1);
else if (c->ra_mode == RA_MERGED)
rt_notify_merged(c, n, NULL, NULL, e, c->refeeding ? e : NULL, c->refeeding);
rt_notify_merged(c, n, NULL, NULL, e, c->refeeding ? e : NULL, lp, c->refeeding);
else /* RA_BASIC */
rt_notify_basic(c, n, e, c->refeeding ? e : NULL, c->refeeding);
rte_update_unlock();
rt_notify_basic(c, n, e, c->refeeding ? e : NULL, lp, c->refeeding);
rfree(lp);
}
/**

View File

@ -832,7 +832,7 @@ bgp_apply_next_hop(struct bgp_parse_state *s, rta *a, ip_addr gw, ip_addr ll)
s->hostentry = rt_get_hostentry(tab, gw, ll, c->c.table);
if (!s->mpls)
rta_apply_hostentry(a, s->hostentry, NULL);
rta_apply_hostentry(a, s->hostentry, NULL, s->pool);
/* With MPLS, hostentry is applied later in bgp_apply_mpls_labels() */
}
@ -866,7 +866,7 @@ bgp_apply_mpls_labels(struct bgp_parse_state *s, rta *a, u32 *labels, uint lnum)
ms.len = lnum;
memcpy(ms.stack, labels, 4*lnum);
rta_apply_hostentry(a, s->hostentry, &ms);
rta_apply_hostentry(a, s->hostentry, &ms, s->pool);
}
}

View File

@ -560,7 +560,9 @@ radv_check_active(struct radv_proto *p)
return 1;
struct channel *c = p->p.main_channel;
return rt_examine(c->table, &cf->trigger, &p->p, c->out_filter);
struct linpool *lp = lp_new(p->p.pool, 1024);
return rt_examine(c->table, &cf->trigger, &p->p, c->out_filter, lp);
rfree(lp);
}
static void

View File

@ -91,7 +91,7 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
if (r->dest == RTDX_RECURSIVE)
{
rtable *tab = ipa_is_ip4(r->via) ? p->igp_table_ip4 : p->igp_table_ip6;
rta_set_recursive_next_hop(p->p.main_channel->table, a, tab, r->via, IPA_NONE, r->mls);
rta_set_recursive_next_hop(p->p.main_channel->table, a, tab, r->via, IPA_NONE, r->mls, static_lp);
}
/* Already announced */