summaryrefslogtreecommitdiff
path: root/nest
diff options
context:
space:
mode:
Diffstat (limited to 'nest')
-rw-r--r--nest/proto.c17
-rw-r--r--nest/rt-attr.c41
-rw-r--r--nest/rt-table.c72
-rw-r--r--nest/rt.h4
4 files changed, 55 insertions, 79 deletions
diff --git a/nest/proto.c b/nest/proto.c
index e64cef28..853b1cf9 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -313,9 +313,9 @@ proto_remove_channels(struct proto *p)
}
static void
-channel_roa_in_changed(struct rt_subscription *s)
+channel_roa_in_changed(void *_data)
{
- struct channel *c = s->data;
+ struct channel *c = _data;
int active = !!c->reload_req.hook;
CD(c, "Reload triggered by RPKI change%s", active ? " - already active" : "");
@@ -327,9 +327,9 @@ channel_roa_in_changed(struct rt_subscription *s)
}
static void
-channel_roa_out_changed(struct rt_subscription *s)
+channel_roa_out_changed(void *_data)
{
- struct channel *c = s->data;
+ struct channel *c = _data;
CD(c, "Feeding triggered by RPKI change");
c->refeed_pending = 1;
@@ -347,14 +347,14 @@ struct roa_subscription {
static int
channel_roa_is_subscribed(struct channel *c, rtable *tab, int dir)
{
- void (*hook)(struct rt_subscription *) =
+ void (*hook)(void *) =
dir ? channel_roa_in_changed : channel_roa_out_changed;
struct roa_subscription *s;
node *n;
WALK_LIST2(s, n, c->roa_subscriptions, roa_node)
- if ((s->s.tab == tab) && (s->s.hook == hook))
+ if ((s->s.tab == tab) && (s->s.event->hook == hook))
return 1;
return 0;
@@ -368,9 +368,9 @@ channel_roa_subscribe(struct channel *c, rtable *tab, int dir)
return;
struct roa_subscription *s = mb_allocz(c->proto->pool, sizeof(struct roa_subscription));
+ s->s.event = ev_new_init(c->proto->pool, dir ? channel_roa_in_changed : channel_roa_out_changed, c);
+ s->s.list = proto_work_list(c->proto);
- s->s.hook = dir ? channel_roa_in_changed : channel_roa_out_changed;
- s->s.data = c;
rt_subscribe(tab, &s->s);
add_tail(&c->roa_subscriptions, &s->roa_node);
@@ -381,6 +381,7 @@ channel_roa_unsubscribe(struct roa_subscription *s)
{
rt_unsubscribe(&s->s);
rem_node(&s->roa_node);
+ rfree(s->s.event);
mb_free(s);
}
diff --git a/nest/rt-attr.c b/nest/rt-attr.c
index b3a4c7a1..471209ee 100644
--- a/nest/rt-attr.c
+++ b/nest/rt-attr.c
@@ -1043,6 +1043,8 @@ ea_list_ref(ea_list *l)
}
}
+static void ea_free_nested(ea_list *l);
+
static void
ea_list_unref(ea_list *l)
{
@@ -1063,7 +1065,7 @@ ea_list_unref(ea_list *l)
}
if (l->next)
- ea_free(l->next);
+ ea_free_nested(l->next);
}
void
@@ -1472,9 +1474,15 @@ ea_lookup(ea_list *o, int overlay)
o = ea_normalize(o, overlay);
h = ea_hash(o);
+ RTA_LOCK;
+
for(r=rta_hash_table[h & rta_cache_mask]; r; r=r->next_hash)
if (r->hash_key == h && ea_same(r->l, o))
- return ea_clone(r->l);
+ {
+ atomic_fetch_add_explicit(&r->uc, 1, memory_order_acq_rel);
+ RTA_UNLOCK;
+ return r->l;
+ }
uint elen = ea_list_size(o);
r = mb_alloc(rta_pool, elen + sizeof(struct ea_storage));
@@ -1490,12 +1498,17 @@ ea_lookup(ea_list *o, int overlay)
if (++rta_cache_count > rta_cache_limit)
rta_rehash();
+ RTA_UNLOCK;
return r->l;
}
-void
-ea__free(struct ea_storage *a)
+static void
+ea_free_locked(struct ea_storage *a)
{
+ /* Somebody has cloned this rta inbetween. This sometimes happens. */
+ if (atomic_load_explicit(&a->uc, memory_order_acquire))
+ return;
+
ASSERT(rta_cache_count);
rta_cache_count--;
*a->pprev_hash = a->next_hash;
@@ -1506,6 +1519,22 @@ ea__free(struct ea_storage *a)
mb_free(a);
}
+static void
+ea_free_nested(struct ea_list *l)
+{
+ struct ea_storage *r = ea_get_storage(l);
+ if (1 == atomic_fetch_sub_explicit(&r->uc, 1, memory_order_acq_rel))
+ ea_free_locked(r);
+}
+
+void
+ea__free(struct ea_storage *a)
+{
+ RTA_LOCK;
+ ea_free_locked(a);
+ RTA_UNLOCK;
+}
+
/**
* rta_dump_all - dump attribute cache
*
@@ -1515,6 +1544,8 @@ ea__free(struct ea_storage *a)
void
ea_dump_all(void)
{
+ RTA_LOCK;
+
debug("Route attribute cache (%d entries, rehash at %d):\n", rta_cache_count, rta_cache_limit);
for (uint h=0; h < rta_cache_size; h++)
for (struct ea_storage *a = rta_hash_table[h]; a; a = a->next_hash)
@@ -1524,6 +1555,8 @@ ea_dump_all(void)
debug("\n");
}
debug("\n");
+
+ RTA_UNLOCK;
}
void
diff --git a/nest/rt-table.c b/nest/rt-table.c
index b8f0e61d..3ade4237 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -114,8 +114,6 @@
pool *rt_table_pool;
-static linpool *rte_update_pool;
-
list routing_tables;
list deleted_routing_tables;
@@ -153,9 +151,6 @@ static void rt_cork_release_hook(void *);
static inline void rt_export_used(struct rt_exporter *);
static void rt_export_cleanup(rtable *tab);
-static inline void rte_update_lock(void);
-static inline void rte_update_unlock(void);
-
static int rte_same(rte *x, rte *y);
const char *rt_import_state_name_array[TIS_MAX] = {
@@ -966,13 +961,10 @@ done:
}
/* Nothing to export */
- if (!new_best && !old_best)
- {
+ if (new_best || old_best)
+ do_rt_notify(c, n, new_best, old_best);
+ else
DBG("rt_notify_accepted: nothing to export\n");
- return;
- }
-
- do_rt_notify(c, n, new_best, old_best);
}
rte *
@@ -1079,7 +1071,7 @@ rt_notify_merged(struct rt_export_request *req, const net_addr *n, struct rt_pen
}
/* Prepare new merged route */
- rte *new_merged = count ? rt_export_merged(c, feed, count, rte_update_pool, 0) : NULL;
+ rte *new_merged = count ? rt_export_merged(c, feed, count, tmp_linpool, 0) : NULL;
if (new_merged || old_best)
do_rt_notify(c, n, new_merged, old_best);
@@ -1089,7 +1081,6 @@ void
rt_notify_optimal(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe)
{
struct channel *c = SKIP_BACK(struct channel, out_req, req);
-
rte *o = RTE_VALID_OR_NULL(rpe->old_best);
struct rte_storage *new_best = rpe->new_best;
@@ -1482,14 +1473,10 @@ rt_export_hook(void *_data)
/* Process the export */
for (uint i=0; i<RT_EXPORT_BULK; i++)
{
- rte_update_lock();
-
rte_export(c, c->rpe_next);
if (!c->rpe_next)
break;
-
- rte_update_unlock();
}
rt_send_export_event(c);
@@ -1775,21 +1762,6 @@ rte_recalculate(struct rt_import_hook *c, net *net, rte *new, struct rte_src *sr
}
-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);
-}
-
int
channel_preimport(struct rt_import_request *req, rte *new, rte *old)
{
@@ -1839,7 +1811,6 @@ rte_update(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
const struct filter *filter = c->in_filter;
struct channel_import_stats *stats = &c->import_stats;
- rte_update_lock();
if (new)
{
new->net = n;
@@ -1890,7 +1861,6 @@ rte_update(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
ea_free(a);
}
- rte_update_unlock();
}
void
@@ -1921,25 +1891,6 @@ rte_import(struct rt_import_request *req, const net_addr *n, rte *new, struct rt
rte_recalculate(hook, nn, new, src);
}
-/* 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, net *net, struct rte_storage *new, struct rte_storage *old,
- struct rte_storage *new_best, struct rte_storage *old_best)
-{
- rte_update_lock();
- rte_announce(tab, net, new, old, new_best, old_best);
- rte_update_unlock();
-}
-
-static inline void
-rte_discard(net *net, rte *old) /* Non-filtered route deletion, used during garbage collection */
-{
- rte_update_lock();
- rte_recalculate(old->sender, net, NULL, old->src);
- 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 channel *c, const struct filter *filter)
@@ -1951,15 +1902,11 @@ rt_examine(rtable *t, net_addr *a, struct channel *c, const struct filter *filte
rte rt = n->routes->rte;
- rte_update_lock();
-
/* Rest is stripped down export_filter() */
int v = c->proto->preexport ? c->proto->preexport(c, &rt) : 0;
if (v == RIC_PROCESS)
v = (f_run(filter, &rt, FF_SILENT) <= F_ACCEPT);
- rte_update_unlock();
-
return v > 0;
}
@@ -2489,7 +2436,7 @@ rt_settle_timer(timer *t)
struct rt_subscription *s;
WALK_LIST(s, tab->subscribers)
- s->hook(s);
+ ev_send(s->list, s->event);
}
static void
@@ -2731,7 +2678,6 @@ rt_init(void)
{
rta_init();
rt_table_pool = rp_new(&root_pool, "Routing tables");
- rte_update_pool = lp_new_default(rt_table_pool);
init_list(&routing_tables);
init_list(&deleted_routing_tables);
ev_init_list(&rt_cork.queue, &main_birdloop, "Route cork release");
@@ -2816,7 +2762,7 @@ again:
(e->rte.stale_cycle < s->stale_valid) ||
(e->rte.stale_cycle > s->stale_set))
{
- rte_discard(n, &e->rte);
+ rte_recalculate(e->rte.sender, n, NULL, e->rte.src);
limit--;
goto rescan;
@@ -3590,7 +3536,7 @@ rt_next_hop_update_net(rtable *tab, net *n)
{ "autoupdated [+best]", "autoupdated [best]" }
};
rt_rte_trace_in(D_ROUTES, updates[i].new->rte.sender->req, &updates[i].new->rte, best_indicator[nb][ob]);
- rte_announce_i(tab, n, updates[i].new, updates[i].old, new, old_best);
+ rte_announce(tab, n, updates[i].new, updates[i].old, new, old_best);
}
return count;
@@ -3940,20 +3886,16 @@ rt_feed_net(struct rt_export_hook *c, net *n)
count = rte_feed_count(n);
if (count)
{
- rte_update_lock();
rte **feed = alloca(count * sizeof(rte *));
rte_feed_obtain(n, feed, count);
c->req->export_bulk(c->req, n->n.addr, NULL, feed, count);
- rte_update_unlock();
}
}
else if (n->routes)
{
- rte_update_lock();
struct rt_pending_export rpe = { .new = n->routes, .new_best = n->routes };
c->req->export_one(c->req, n->n.addr, &rpe);
- rte_update_unlock();
count = 1;
}
diff --git a/nest/rt.h b/nest/rt.h
index 66111dde..1a6b7a93 100644
--- a/nest/rt.h
+++ b/nest/rt.h
@@ -139,8 +139,8 @@ typedef struct rtable {
struct rt_subscription {
node n;
rtable *tab;
- void (*hook)(struct rt_subscription *b);
- void *data;
+ event *event;
+ event_list *list;
};
struct rt_flowspec_link {