diff options
Diffstat (limited to 'nest')
-rw-r--r-- | nest/proto.c | 17 | ||||
-rw-r--r-- | nest/rt-attr.c | 41 | ||||
-rw-r--r-- | nest/rt-table.c | 72 | ||||
-rw-r--r-- | nest/rt.h | 4 |
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; } @@ -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 { |