diff options
author | Maria Matejka <mq@ucw.cz> | 2022-09-05 06:58:42 +0200 |
---|---|---|
committer | Maria Matejka <mq@ucw.cz> | 2022-09-05 12:19:38 +0200 |
commit | 636bc44e61b5361b675ddd1ad7edb0b5ff2c2f2f (patch) | |
tree | 80e47d4c10c1f3c3518508d8d5e6da9912cb2873 | |
parent | 66ccdc2a0c8f10263679e7fac37c1db1adf64b4f (diff) |
Exporter routine refactoring to allow for nicer table locking
-rw-r--r-- | nest/config.Y | 2 | ||||
-rw-r--r-- | nest/proto.c | 12 | ||||
-rw-r--r-- | nest/rt-show.c | 8 | ||||
-rw-r--r-- | nest/rt-table.c | 284 | ||||
-rw-r--r-- | nest/rt.h | 65 | ||||
-rw-r--r-- | proto/bgp/attrs.c | 62 | ||||
-rw-r--r-- | proto/bgp/bgp.c | 2 |
7 files changed, 254 insertions, 181 deletions
diff --git a/nest/config.Y b/nest/config.Y index ea7846e2..e8c4aa9a 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -702,7 +702,7 @@ r_args: } | r_args IMPORT TABLE channel_arg { if (!($4->in_keep & RIK_PREFILTER)) cf_error("No import table in channel %s.%s", $4->proto->name, $4->name); - rt_show_add_exporter($$, &$4->table->exporter, "import")->prefilter = $4; + rt_show_add_exporter($$, &$4->table->exporter.e, "import")->prefilter = $4; $$->tables_defined_by = RSD_TDB_DIRECT; } | r_args EXPORT TABLE channel_arg { diff --git a/nest/proto.c b/nest/proto.c index 783672ec..5f4b7b2d 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -376,7 +376,7 @@ channel_dump_roa_req(struct rt_export_request *req) { struct roa_subscription *s = SKIP_BACK(struct roa_subscription, req, req); struct channel *c = s->c; - rtable *tab = SKIP_BACK(rtable, exporter, req->hook->table); + rtable *tab = SKIP_BACK(rtable, exporter.e, req->hook->table); debug(" Channel %s.%s ROA %s change notifier from table %s request %p\n", c->proto->name, c->name, @@ -394,7 +394,7 @@ channel_roa_is_subscribed(struct channel *c, rtable *tab, int dir) node *n; WALK_LIST2(s, n, c->roa_subscriptions, roa_node) - if ((s->req.hook->table == &tab->exporter) && (s->t.hook == hook)) + if ((s->req.hook->table == &tab->exporter.e) && (s->t.hook == hook)) return 1; return 0; @@ -422,7 +422,7 @@ channel_roa_subscribe(struct channel *c, rtable *tab, int dir) }; add_tail(&c->roa_subscriptions, &s->roa_node); - rt_request_export(&tab->exporter, &s->req); + rt_request_export(tab, &s->req); } static void @@ -575,7 +575,7 @@ channel_start_export(struct channel *c) } DBG("%s.%s: Channel start export req=%p\n", c->proto->name, c->name, &c->out_req); - rt_request_export(&c->table->exporter, &c->out_req); + rt_request_export(c->table, &c->out_req); } static void @@ -629,7 +629,7 @@ channel_export_stopped(struct rt_export_request *req) { c->refeeding = 1; c->refeed_pending = 0; - rt_request_export(&c->table->exporter, req); + rt_request_export(c->table, req); return; } @@ -673,7 +673,7 @@ channel_schedule_reload(struct channel *c) { ASSERT(c->in_req.hook); - rt_request_export(&c->table->exporter, &c->reload_req); + rt_request_export(c->table, &c->reload_req); } static void diff --git a/nest/rt-show.c b/nest/rt-show.c index 5d7723cf..d17818db 100644 --- a/nest/rt-show.c +++ b/nest/rt-show.c @@ -301,7 +301,7 @@ rt_show_cont(struct rt_show_data *d) if (d->tables_defined_by & RSD_TDB_SET) rt_show_table(d); - rt_request_export(d->tab->table, &d->req); + rt_request_export_other(d->tab->table, &d->req); } static void @@ -356,7 +356,7 @@ rt_show_add_exporter(struct rt_show_data *d, struct rt_exporter *t, const char * struct rt_show_data_rtable * rt_show_add_table(struct rt_show_data *d, struct rtable *t) { - struct rt_show_data_rtable *rsdr = rt_show_add_exporter(d, &t->exporter, t->name); + struct rt_show_data_rtable *rsdr = rt_show_add_exporter(d, &t->exporter.e, t->name); struct proto_config *krt = t->config->krt_attached; if (krt) @@ -419,11 +419,11 @@ rt_show_prepare_tables(struct rt_show_data *d) if (d->export_mode) { if (!tab->export_channel && d->export_channel && - (tab->table == &d->export_channel->table->exporter)) + (tab->table == &d->export_channel->table->exporter.e)) tab->export_channel = d->export_channel; if (!tab->export_channel && d->export_protocol) - tab->export_channel = proto_find_channel_by_table(d->export_protocol, SKIP_BACK(rtable, exporter, tab->table)); + tab->export_channel = proto_find_channel_by_table(d->export_protocol, SKIP_BACK(rtable, exporter.e, tab->table)); if (!tab->export_channel) { diff --git a/nest/rt-table.c b/nest/rt-table.c index 3188ddf8..de955ebb 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -138,13 +138,13 @@ static void rt_feed_by_fib(void *); static void rt_feed_by_trie(void *); static void rt_feed_equal(void *); static void rt_feed_for(void *); -static uint rt_feed_net(struct rt_export_hook *c, net *n); +static uint rt_feed_net(struct rt_table_export_hook *c, net *n); static void rt_check_cork_low(rtable *tab); static void rt_check_cork_high(rtable *tab); static void rt_cork_release_hook(void *); -static inline void rt_export_used(struct rt_exporter *); -static void rt_export_cleanup(rtable *tab); +static void rt_export_used(struct rt_table_exporter *); +static void rt_export_cleanup(rtable *); static int rte_same(rte *x, rte *y); @@ -1162,9 +1162,10 @@ rpe_next(struct rt_pending_export *rpe, struct rte_src *src) } static struct rt_pending_export * rt_next_export_fast(struct rt_pending_export *last); -static void -rte_export(struct rt_export_hook *hook, struct rt_pending_export *rpe) +static int +rte_export(struct rt_table_export_hook *th, struct rt_pending_export *rpe) { + struct rt_export_hook *hook = &th->h; if (bmap_test(&hook->seq_map, rpe->seq)) goto ignore; /* Seen already */ @@ -1216,15 +1217,16 @@ rte_export(struct rt_export_hook *hook, struct rt_pending_export *rpe) ignore: /* Get the next export if exists */ - hook->rpe_next = rt_next_export_fast(rpe); + th->rpe_next = rt_next_export_fast(rpe); /* The last block may be available to free */ - if (PAGE_HEAD(hook->rpe_next) != PAGE_HEAD(rpe)) - CALL(hook->table->used, hook->table); + int used = (PAGE_HEAD(th->rpe_next) != PAGE_HEAD(rpe)); /* Releasing this export for cleanup routine */ DBG("store hook=%p last_export=%p seq=%lu\n", hook, rpe, rpe->seq); - atomic_store_explicit(&hook->last_export, rpe, memory_order_release); + atomic_store_explicit(&th->last_export, rpe, memory_order_release); + + return used; } /** @@ -1273,7 +1275,7 @@ rte_announce(rtable *tab, net *net, struct rte_storage *new, struct rte_storage if (old_best_valid) old_best->rte.sender->stats.pref--; - if (EMPTY_LIST(tab->exporter.hooks) && EMPTY_LIST(tab->exporter.pending)) + if (EMPTY_LIST(tab->exporter.e.hooks) && EMPTY_LIST(tab->exporter.pending)) { /* No export hook and no pending exports to cleanup. We may free the route immediately. */ if (!old) @@ -1382,7 +1384,7 @@ rt_next_export_fast(struct rt_pending_export *last) } static struct rt_pending_export * -rt_next_export(struct rt_export_hook *hook, struct rt_exporter *tab) +rt_next_export(struct rt_table_export_hook *hook, struct rt_table_exporter *tab) { /* As the table is locked, it is safe to reload the last export pointer */ struct rt_pending_export *last = atomic_load_explicit(&hook->last_export, memory_order_acquire); @@ -1399,7 +1401,7 @@ rt_next_export(struct rt_export_hook *hook, struct rt_exporter *tab) static inline void rt_send_export_event(struct rt_export_hook *hook) { - ev_send(hook->req->list, hook->event); + ev_send(hook->req->list, &hook->event); } static void @@ -1411,7 +1413,7 @@ rt_announce_exports(timer *tm) return; struct rt_export_hook *c; node *n; - WALK_LIST2(c, n, tab->exporter.hooks, n) + WALK_LIST2(c, n, tab->exporter.e.hooks, n) { if (atomic_load_explicit(&c->export_state, memory_order_acquire) != TES_READY) continue; @@ -1443,7 +1445,7 @@ rt_import_announce_exports(void *_hook) } static struct rt_pending_export * -rt_last_export(struct rt_exporter *tab) +rt_last_export(struct rt_table_exporter *tab) { struct rt_pending_export *rpe = NULL; @@ -1463,31 +1465,33 @@ rt_last_export(struct rt_exporter *tab) static void rt_export_hook(void *_data) { - struct rt_export_hook *c = _data; + struct rt_table_export_hook *c = _data; - ASSERT_DIE(atomic_load_explicit(&c->export_state, memory_order_relaxed) == TES_READY); + ASSERT_DIE(atomic_load_explicit(&c->h.export_state, memory_order_relaxed) == TES_READY); if (!c->rpe_next) { c->rpe_next = rt_next_export(c, c->table); if (!c->rpe_next) - { - CALL(c->table->used, c->table); - return; - } + return rt_export_used(c->table); } + int used = 0; + /* Process the export */ for (uint i=0; i<RT_EXPORT_BULK; i++) { - rte_export(c, c->rpe_next); + used += rte_export(c, c->rpe_next); if (!c->rpe_next) break; } - rt_send_export_event(c); + if (used) + rt_export_used(c->table); + + rt_send_export_event(&c->h); } @@ -1909,28 +1913,27 @@ rt_examine(rtable *t, net_addr *a, struct channel *c, const struct filter *filte } static void -rt_table_export_done(struct rt_export_hook *hook) +rt_table_export_done(void *hh) { - struct rt_exporter *re = hook->table; - struct rtable *tab = SKIP_BACK(struct rtable, exporter, re); + struct rt_table_export_hook *hook = hh; + struct rtable *tab = SKIP_BACK(struct rtable, exporter, hook->table); DBG("Export hook %p in table %s finished uc=%u\n", hook, tab->name, tab->use_count); - /* Free the hook before unlocking the table */ - rfree(hook->pool); + /* Drop pending exports */ + rt_export_used(&tab->exporter); + + /* Do the common code */ + rt_export_stopped(&hook->h); /* Unlock the table; this may free it */ rt_unlock_table(tab); } -static void +void rt_export_stopped(void *data) { struct rt_export_hook *hook = data; - struct rt_exporter *tab = hook->table; - - /* Drop pending exports */ - CALL(tab->used, tab); /* Unlist */ rem_node(&hook->n); @@ -1938,8 +1941,8 @@ rt_export_stopped(void *data) /* Report the channel as stopped. */ CALL(hook->stopped, hook->req); - /* Reporting the hook as finished. */ - CALL(tab->done, hook); + /* Free the hook itself together with its pool */ + rfree(hook->pool); } static inline void @@ -1991,15 +1994,16 @@ rt_stop_import(struct rt_import_request *req, void (*stopped)(struct rt_import_r hook->stopped = stopped; } -static struct rt_export_hook * +static void rt_table_export_start(struct rt_exporter *re, struct rt_export_request *req) { - rtable *tab = SKIP_BACK(rtable, exporter, re); + rtable *tab = SKIP_BACK(rtable, exporter.e, re); rt_lock_table(tab); - pool *p = rp_new(tab->rp, "Export hook"); - struct rt_export_hook *hook = mb_allocz(p, sizeof(struct rt_export_hook)); - hook->pool = p; + req->hook = rt_alloc_export(re, sizeof(struct rt_table_export_hook)); + req->hook->req = req; + + struct rt_table_export_hook *hook = SKIP_BACK(struct rt_table_export_hook, h, req->hook); /* stats zeroed by mb_allocz */ switch (req->addr_mode) @@ -2007,24 +2011,24 @@ rt_table_export_start(struct rt_exporter *re, struct rt_export_request *req) case TE_ADDR_IN: if (tab->trie && net_val_match(tab->addr_type, NB_IP)) { - hook->walk_state = mb_allocz(p, sizeof (struct f_trie_walk_state)); + hook->walk_state = mb_allocz(hook->h.pool, sizeof (struct f_trie_walk_state)); hook->walk_lock = rt_lock_trie(tab); trie_walk_init(hook->walk_state, tab->trie, req->addr); - hook->event = ev_new_init(p, rt_feed_by_trie, hook); + hook->h.event.hook = rt_feed_by_trie; break; } /* fall through */ case TE_ADDR_NONE: FIB_ITERATE_INIT(&hook->feed_fit, &tab->fib); - hook->event = ev_new_init(p, rt_feed_by_fib, hook); + hook->h.event.hook = rt_feed_by_fib; break; case TE_ADDR_EQUAL: - hook->event = ev_new_init(p, rt_feed_equal, hook); + hook->h.event.hook = rt_feed_equal; break; case TE_ADDR_FOR: - hook->event = ev_new_init(p, rt_feed_for, hook); + hook->h.event.hook = rt_feed_for; break; default: @@ -2033,22 +2037,42 @@ rt_table_export_start(struct rt_exporter *re, struct rt_export_request *req) DBG("New export hook %p req %p in table %s uc=%u\n", hook, req, tab->name, tab->use_count); - return hook; + struct rt_pending_export *rpe = rt_last_export(hook->table); + DBG("store hook=%p last_export=%p seq=%lu\n", hook, rpe, rpe ? rpe->seq : 0); + atomic_store_explicit(&hook->last_export, rpe, memory_order_relaxed); + + rt_init_export(re, req->hook); +} + +void rt_request_export(rtable *tab, struct rt_export_request *req) +{ + rt_table_export_start(&tab->exporter.e, req); } void -rt_request_export(struct rt_exporter *re, struct rt_export_request *req) +rt_request_export_other(struct rt_exporter *re, struct rt_export_request *req) { - struct rt_export_hook *hook = req->hook = re->start(re, req); + return re->class->start(re, req); +} - hook->req = req; +struct rt_export_hook * +rt_alloc_export(struct rt_exporter *re, uint size) +{ + pool *p = rp_new(re->rp, "Export hook"); + struct rt_export_hook *hook = mb_allocz(p, size); + + hook->pool = p; hook->table = re; - bmap_init(&hook->seq_map, hook->pool, 1024); + return hook; +} - struct rt_pending_export *rpe = rt_last_export(hook->table); - DBG("store hook=%p last_export=%p seq=%lu\n", hook, rpe, rpe ? rpe->seq : 0); - atomic_store_explicit(&hook->last_export, rpe, memory_order_relaxed); +void +rt_init_export(struct rt_exporter *re, struct rt_export_hook *hook) +{ + hook->event.data = hook; + + bmap_init(&hook->seq_map, hook->pool, 1024); hook->n = (node) {}; add_tail(&re->hooks, &hook->n); @@ -2059,14 +2083,15 @@ rt_request_export(struct rt_exporter *re, struct rt_export_request *req) } static void -rt_table_export_stop(struct rt_export_hook *hook) +rt_table_export_stop(struct rt_export_hook *hh) { + struct rt_table_export_hook *hook = SKIP_BACK(struct rt_table_export_hook, h, hh); rtable *tab = SKIP_BACK(rtable, exporter, hook->table); - if (atomic_load_explicit(&hook->export_state, memory_order_relaxed) != TES_FEEDING) + if (atomic_load_explicit(&hh->export_state, memory_order_relaxed) != TES_FEEDING) return; - switch (hook->req->addr_mode) + switch (hh->req->addr_mode) { case TE_ADDR_IN: if (hook->walk_lock) @@ -2087,17 +2112,18 @@ rt_table_export_stop(struct rt_export_hook *hook) void rt_stop_export(struct rt_export_request *req, void (*stopped)(struct rt_export_request *)) { + ASSERT_DIE(birdloop_inside(req->list->loop)); ASSERT_DIE(req->hook); struct rt_export_hook *hook = req->hook; /* Cancel the feeder event */ - ev_postpone(hook->event); + ev_postpone(&hook->event); /* Stop feeding from the exporter */ - CALL(hook->table->stop, hook); + CALL(hook->table->class->stop, hook); /* Reset the event as the stopped event */ - hook->event->hook = rt_export_stopped; + hook->event.hook = hook->table->class->done; hook->stopped = stopped; /* Update export state */ @@ -2253,13 +2279,14 @@ rt_dump_hooks(rtable *tab) ih->last_state_change, ih->import_state, ih->stopped); } - struct rt_export_hook *eh; - WALK_LIST(eh, tab->exporter.hooks) + struct rt_table_export_hook *eh; + WALK_LIST(eh, tab->exporter.e.hooks) { - eh->req->dump_req(eh->req); + eh->h.req->dump_req(eh->h.req); debug(" Export hook %p requested by %p:" " refeed_pending=%u last_state_change=%t export_state=%u\n", - eh, eh->req, eh->refeed_pending, eh->last_state_change, atomic_load_explicit(&eh->export_state, memory_order_relaxed)); + eh, eh->h.req, eh->refeed_pending, eh->h.last_state_change, + atomic_load_explicit(&eh->h.export_state, memory_order_relaxed)); } debug("\n"); } @@ -2303,7 +2330,7 @@ rt_schedule_prune(rtable *tab) } static void -rt_export_used(struct rt_exporter *e) +rt_export_used(struct rt_table_exporter *e) { rtable *tab = SKIP_BACK(rtable, exporter, e); @@ -2426,15 +2453,15 @@ rt_flowspec_dump_req(struct rt_export_request *req) static struct rt_flowspec_link * rt_flowspec_find_link(rtable *src, rtable *dst) { - struct rt_export_hook *hook; node *n; - WALK_LIST2(hook, n, src->exporter.hooks, n) - switch (atomic_load_explicit(&hook->export_state, memory_order_acquire)) + struct rt_table_export_hook *hook; node *n; + WALK_LIST2(hook, n, src->exporter.e.hooks, h.n) + switch (atomic_load_explicit(&hook->h.export_state, memory_order_acquire)) { case TES_FEEDING: case TES_READY: - if (hook->req->export_one == rt_flowspec_export_one) + if (hook->h.req->export_one == rt_flowspec_export_one) { - struct rt_flowspec_link *ln = SKIP_BACK(struct rt_flowspec_link, req, hook->req); + struct rt_flowspec_link *ln = SKIP_BACK(struct rt_flowspec_link, req, hook->h.req); if (ln->dst == dst) return ln; } @@ -2467,7 +2494,7 @@ rt_flowspec_link(rtable *src, rtable *dst) .export_one = rt_flowspec_export_one, }; - rt_request_export(&src->exporter, &ln->req); + rt_request_export(src, &ln->req); } ln->uc++; @@ -2544,6 +2571,18 @@ static struct resclass rt_class = { .memsize = NULL, }; +static const struct rt_exporter_class rt_table_exporter_class = { + .start = rt_table_export_start, + .stop = rt_table_export_stop, + .done = rt_table_export_done, +}; + +void +rt_exporter_init(struct rt_exporter *e) +{ + init_list(&e->hooks); +} + rtable * rt_setup(pool *pp, struct rtable_config *cf) { @@ -2568,17 +2607,6 @@ rt_setup(pool *pp, struct rtable_config *cf) t->fib.init = net_init_with_trie; } - t->exporter = (struct rt_exporter) { - .addr_type = t->addr_type, - .start = rt_table_export_start, - .stop = rt_table_export_stop, - .done = rt_table_export_done, - .used = rt_export_used, - }; - - init_list(&t->exporter.hooks); - init_list(&t->exporter.pending); - init_list(&t->imports); hmap_init(&t->id_map, p, 1024); @@ -2587,9 +2615,21 @@ rt_setup(pool *pp, struct rtable_config *cf) t->rt_event = ev_new_init(p, rt_event, t); t->uncork_event = ev_new_init(p, rt_uncork_event, t); t->prune_timer = tm_new_init(p, rt_prune_timer, t, 0, 0); - t->exporter.export_timer = tm_new_init(p, rt_announce_exports, t, 0, 0); t->last_rt_change = t->gc_time = current_time(); - t->exporter.next_seq = 1; + + t->exporter = (struct rt_table_exporter) { + .e = { + .class = &rt_table_exporter_class, + .addr_type = t->addr_type, + .rp = t->rp, + }, + .export_timer = tm_new_init(p, rt_announce_exports, t, 0, 0), + .next_seq = 1, + }; + + rt_exporter_init(&t->exporter.e); + + init_list(&t->exporter.pending); t->cork_threshold = cf->cork_threshold; @@ -2781,7 +2821,7 @@ again: } /* In some cases, we may want to directly proceed to export cleanup */ - if (EMPTY_LIST(tab->exporter.hooks) && flushed_channels) + if (EMPTY_LIST(tab->exporter.e.hooks) && flushed_channels) rt_export_cleanup(tab); } @@ -2795,11 +2835,11 @@ rt_export_cleanup(rtable *tab) struct rt_pending_export *first = tab->exporter.first; int want_prune = 0; - struct rt_export_hook *eh; + struct rt_table_export_hook *eh; node *n; - WALK_LIST2(eh, n, tab->exporter.hooks, n) + WALK_LIST2(eh, n, tab->exporter.e.hooks, h.n) { - switch (atomic_load_explicit(&eh->export_state, memory_order_acquire)) + switch (atomic_load_explicit(&eh->h.export_state, memory_order_acquire)) { case TES_DOWN: continue; @@ -2832,9 +2872,9 @@ rt_export_cleanup(rtable *tab) tab->exporter.first ? tab->exporter.first->seq : 0, min_seq); - WALK_LIST2(eh, n, tab->exporter.hooks, n) + WALK_LIST2(eh, n, tab->exporter.e.hooks, h.n) { - if (atomic_load_explicit(&eh->export_state, memory_order_acquire) != TES_READY) + if (atomic_load_explicit(&eh->h.export_state, memory_order_acquire) != TES_READY) continue; struct rt_pending_export *last = atomic_load_explicit(&eh->last_export, memory_order_acquire); @@ -2908,13 +2948,13 @@ rt_export_cleanup(rtable *tab) rt_trace(tab, D_EVENTS, "Resetting export seq"); node *n; - WALK_LIST2(eh, n, tab->exporter.hooks, n) + WALK_LIST2(eh, n, tab->exporter.e.hooks, h.n) { - if (atomic_load_explicit(&eh->export_state, memory_order_acquire) != TES_READY) + if (atomic_load_explicit(&eh->h.export_state, memory_order_acquire) != TES_READY) continue; ASSERT_DIE(atomic_load_explicit(&eh->last_export, memory_order_acquire) == NULL); - bmap_reset(&eh->seq_map, 1024); + bmap_reset(&eh->h.seq_map, 1024); } tab->exporter.next_seq = 1; @@ -3667,10 +3707,10 @@ rt_reconfigure(rtable *tab, struct rtable_config *new, struct rtable_config *old if (tab->hostcache) tab->hostcache->req.trace_routes = new->debug; - struct rt_export_hook *hook; node *n; - WALK_LIST2(hook, n, tab->exporter.hooks, n) - if (hook->req->export_one == rt_flowspec_export_one) - hook->req->trace_routes = new->debug; + struct rt_table_export_hook *hook; node *n; + WALK_LIST2(hook, n, tab->exporter.e.hooks, h.n) + if (hook->h.req->export_one == rt_flowspec_export_one) + hook->h.req->trace_routes = new->debug; tab->cork_threshold = new->cork_threshold; @@ -3745,7 +3785,7 @@ rt_commit(struct config *new, struct config *old) static void rt_feed_done(struct rt_export_hook *c) { - c->event->hook = rt_export_hook; + c->event.hook = rt_export_hook; rt_set_export_state(c, TES_READY); @@ -3764,12 +3804,12 @@ rt_feed_done(struct rt_export_hook *c) static void rt_feed_by_fib(void *data) { - struct rt_export_hook *c = data; + struct rt_table_export_hook *c = data; struct fib_iterator *fit = &c->feed_fit; int max_feed = 256; - ASSERT(atomic_load_explicit(&c->export_state, memory_order_relaxed) == TES_FEEDING); + ASSERT(atomic_load_explicit(&c->h.export_state, memory_order_relaxed) == TES_FEEDING); rtable *tab = SKIP_BACK(rtable, exporter, c->table); @@ -3778,25 +3818,25 @@ rt_feed_by_fib(void *data) if (max_feed <= 0) { FIB_ITERATE_PUT(fit); - rt_send_export_event(c); + rt_send_export_event(&c->h); return; } - if (atomic_load_explicit(&c->export_state, memory_order_acquire) != TES_FEEDING) + if (atomic_load_explicit(&c->h.export_state, memory_order_acquire) != TES_FEEDING) return; - if ((c->req->addr_mode == TE_ADDR_NONE) || net_in_netX(n->n.addr, c->req->addr)) + if ((c->h.req->addr_mode == TE_ADDR_NONE) || net_in_netX(n->n.addr, c->h.req->addr)) max_feed -= rt_feed_net(c, n); } FIB_ITERATE_END; - rt_feed_done(c); + rt_feed_done(&c->h); } static void rt_feed_by_trie(void *data) { - struct rt_export_hook *c = data; + struct rt_table_export_hook *c = data; rtable *tab = SKIP_BACK(rtable, exporter, c->table); ASSERT_DIE(c->walk_state); @@ -3804,7 +3844,7 @@ rt_feed_by_trie(void *data) int max_feed = 256; - ASSERT(atomic_load_explicit(&c->export_state, memory_order_relaxed) == TES_FEEDING); + ASSERT(atomic_load_explicit(&c->h.export_state, memory_order_relaxed) == TES_FEEDING); net_addr addr; while (trie_walk_next(ws, &addr)) @@ -3816,7 +3856,7 @@ rt_feed_by_trie(void *data) if ((max_feed -= rt_feed_net(c, n)) <= 0) return; - if (atomic_load_explicit(&c->export_state, memory_order_acquire) != TES_FEEDING) + if (atomic_load_explicit(&c->h.export_state, memory_order_acquire) != TES_FEEDING) return; } @@ -3826,65 +3866,65 @@ rt_feed_by_trie(void *data) mb_free(c->walk_state); c->walk_state = NULL; - rt_feed_done(c); + rt_feed_done(&c->h); } static void rt_feed_equal(void *data) { - struct rt_export_hook *c = data; + struct rt_table_export_hook *c = data; rtable *tab = SKIP_BACK(rtable, exporter, c->table); - ASSERT_DIE(atomic_load_explicit(&c->export_state, memory_order_relaxed) == TES_FEEDING); - ASSERT_DIE(c->req->addr_mode == TE_ADDR_EQUAL); + ASSERT_DIE(atomic_load_explicit(&c->h.export_state, memory_order_relaxed) == TES_FEEDING); + ASSERT_DIE(c->h.req->addr_mode == TE_ADDR_EQUAL); - net *n = net_find(tab, c->req->addr); + net *n = net_find(tab, c->h.req->addr); if (n) rt_feed_net(c, n); - rt_feed_done(c); + rt_feed_done(&c->h); } static void rt_feed_for(void *data) { - struct rt_export_hook *c = data; + struct rt_table_export_hook *c = data; rtable *tab = SKIP_BACK(rtable, exporter, c->table); - ASSERT_DIE(atomic_load_explicit(&c->export_state, memory_order_relaxed) == TES_FEEDING); - ASSERT_DIE(c->req->addr_mode == TE_ADDR_FOR); + ASSERT_DIE(atomic_load_explicit(&c->h.export_state, memory_order_relaxed) == TES_FEEDING); + ASSERT_DIE(c->h.req->addr_mode == TE_ADDR_FOR); - net *n = net_route(tab, c->req->addr); + net *n = net_route(tab, c->h.req->addr); if (n) rt_feed_net(c, n); - rt_feed_done(c); + rt_feed_done(&c->h); } static uint -rt_feed_net(struct rt_export_hook *c, net *n) +rt_feed_net(struct rt_table_export_hook *c, net *n) { uint count = 0; - if (c->req->export_bulk) + if (c->h.req->export_bulk) { count = rte_feed_count(n); if (count) { rte **feed = alloca(count * sizeof(rte *)); rte_feed_obtain(n, feed, count); - c->req->export_bulk(c->req, n->n.addr, NULL, feed, count); + c->h.req->export_bulk(c->h.req, n->n.addr, NULL, feed, count); } } else if (n->routes) { struct rt_pending_export rpe = { .new = n->routes, .new_best = n->routes }; - c->req->export_one(c->req, n->n.addr, &rpe); + c->h.req->export_one(c->h.req, n->n.addr, &rpe); count = 1; } - rpe_mark_seen_all(c, n->first, NULL); + rpe_mark_seen_all(&c->h, n->first, NULL); return count; } @@ -4072,7 +4112,7 @@ rt_init_hostcache(rtable *tab) .export_one = hc_notify_export_one, }; - rt_request_export(&tab->exporter, &hc->req); + rt_request_export(tab, &hc->req); tab->hostcache = hc; } @@ -67,16 +67,23 @@ struct rtable_config { struct rt_export_hook; struct rt_export_request; +struct rt_exporter; + +struct rt_exporter_class { + void (*start)(struct rt_exporter *, struct rt_export_request *); + void (*stop)(struct rt_export_hook *); + void (*done)(void *_rt_export_hook); +}; struct rt_exporter { + const struct rt_exporter_class *class; + pool *rp; list hooks; /* Registered route export hooks */ uint addr_type; /* Type of address data exported (NET_*) */ +}; - struct rt_export_hook *(*start)(struct rt_exporter *, struct rt_export_request *); - void (*stop)(struct rt_export_hook *); - void (*done)(struct rt_export_hook *); - void (*used)(struct rt_exporter *); - +struct rt_table_exporter { + struct rt_exporter e; list pending; /* List of packed struct rt_pending_export */ struct timer *export_timer; @@ -97,7 +104,7 @@ typedef struct rtable { u32 rt_count; /* Number of routes in the table */ list imports; /* Registered route importers */ - struct rt_exporter exporter; /* Exporter API structure */ + struct rt_table_exporter exporter; /* Exporter API structure */ struct hmap id_map; struct hostcache *hostcache; @@ -266,29 +273,39 @@ struct rt_export_hook { u32 withdraws_received; /* Number of route withdraws received */ } stats; + btime last_state_change; /* Time of last state transition */ + + _Atomic u8 export_state; /* Route export state (TES_*, see below) */ + struct event event; /* Event running all the export operations */ + + struct bmap seq_map; /* Keep track which exports were already procesed */ + + void (*stopped)(struct rt_export_request *); /* Stored callback when export is stopped */ +}; + +struct rt_table_export_hook { + union { + struct rt_export_hook h; + struct { /* Overriding the parent structure beginning */ + node _n; + struct rt_table_exporter *table; + }; + }; + union { struct fib_iterator feed_fit; /* Routing table iterator used during feeding */ struct { struct f_trie_walk_state *walk_state; /* Iterator over networks in trie */ struct f_trie *walk_lock; /* Locked trie for walking */ }; - u32 hash_iter; /* Iterator over hash */ }; - struct bmap seq_map; /* Keep track which exports were already procesed */ - - struct rt_pending_export * _Atomic last_export;/* Last export processed */ + struct rt_pending_export *_Atomic last_export;/* Last export processed */ struct rt_pending_export *rpe_next; /* Next pending export to process */ - btime last_state_change; /* Time of last state transition */ - u8 refeed_pending; /* Refeeding and another refeed is scheduled */ - _Atomic u8 export_state; /* Route export state (TES_*, see below) */ u8 feed_type; /* Which feeding method is used (TFT_*, see below) */ - struct event *event; /* Event running all the export operations */ - - void (*stopped)(struct rt_export_request *); /* Stored callback when export is stopped */ }; #define TIS_DOWN 0 @@ -317,7 +334,8 @@ struct rt_export_hook { #define TFT_HASH 3 void rt_request_import(rtable *tab, struct rt_import_request *req); -void rt_request_export(struct rt_exporter *tab, struct rt_export_request *req); +void rt_request_export(rtable *tab, struct rt_export_request *req); +void rt_request_export_other(struct rt_exporter *tab, struct rt_export_request *req); void rt_export_once(struct rt_exporter *tab, struct rt_export_request *req); @@ -334,6 +352,10 @@ void rt_set_export_state(struct rt_export_hook *hook, u8 state); void rte_import(struct rt_import_request *req, const net_addr *net, rte *new, struct rte_src *src); +/* + * For table export processing + */ + /* Get next rpe. If src is given, it must match. */ struct rt_pending_export *rpe_next(struct rt_pending_export *rpe, struct rte_src *src); @@ -350,6 +372,15 @@ void rpe_mark_seen(struct rt_export_hook *hook, struct rt_pending_export *rpe); /* Get pending export seen status */ int rpe_get_seen(struct rt_export_hook *hook, struct rt_pending_export *rpe); +/* + * For rt_export_hook and rt_exporter inheritance + */ + +void rt_init_export(struct rt_exporter *re, struct rt_export_hook *hook); +struct rt_export_hook *rt_alloc_export(struct rt_exporter *re, uint size); +void rt_export_stopped(void *data); +void rt_exporter_init(struct rt_exporter *re); + /* Types of route announcement, also used as flags */ #define RA_UNDEF 0 /* Undefined RA type */ #define RA_OPTIMAL 1 /* Announcement of optimal route change */ diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 84a0b023..dcced164 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -1867,25 +1867,30 @@ bgp_free_pending_tx(struct bgp_channel *c) * Prefix hash table exporter */ +struct bgp_out_export_hook { + struct rt_export_hook h; + u32 hash_iter; /* Iterator over hash */ +}; + static void bgp_out_table_feed(void *data) { - struct rt_export_hook *hook = data; - struct bgp_channel *bc = SKIP_BACK(struct bgp_channel, prefix_exporter, hook->table); + struct bgp_out_export_hook *hook = data; + struct bgp_channel *bc = SKIP_BACK(struct bgp_channel, prefix_exporter, hook->h.table); struct bgp_pending_tx *c = bc->ptx; int max = 512; - const net_addr *neq = (hook->req->addr_mode == TE_ADDR_EQUAL) ? hook->req->addr : NULL; + const net_addr *neq = (hook->h.req->addr_mode == TE_ADDR_EQUAL) ? hook->h.req->addr : NULL; const net_addr *cand = NULL; do { HASH_WALK_ITER(c->prefix_hash, PXH, n, hook->hash_iter) { - switch (hook->req->addr_mode) + switch (hook->h.req->addr_mode) { case TE_ADDR_IN: - if (!net_in_netX(n->net, hook->req->addr)) + if (!net_in_netX(n->net, hook->h.req->addr)) continue; /* fall through */ case TE_ADDR_NONE: @@ -1897,7 +1902,7 @@ bgp_out_table_feed(void *data) case TE_ADDR_FOR: if (!neq) { - if (net_in_netX(hook->req->addr, n->net) && (!cand || (n->net->length > cand->length))) + if (net_in_netX(hook->h.req->addr, n->net) && (!cand || (n->net->length > cand->length))) cand = n->net; continue; } @@ -1942,13 +1947,13 @@ bgp_out_table_feed(void *data) .new = &es, .new_best = &es, }; - if (hook->req->export_bulk) + if (hook->h.req->export_bulk) { rte *feed = &es.rte; - hook->req->export_bulk(hook->req, n->net, &rpe, &feed, 1); + hook->h.req->export_bulk(hook->h.req, n->net, &rpe, &feed, 1); } - else if (hook->req->export_one) - hook->req->export_one(hook->req, n->net, &rpe); + else if (hook->h.req->export_one) + hook->h.req->export_one(hook->h.req, n->net, &rpe); else bug("No export method in export request"); } @@ -1959,43 +1964,40 @@ bgp_out_table_feed(void *data) } while (neq); if (hook->hash_iter) - ev_schedule_work(hook->event); + ev_schedule_work(&hook->h.event); else - rt_set_export_state(hook, TES_READY); + rt_set_export_state(&hook->h, TES_READY); } -static struct rt_export_hook * -bgp_out_table_export_start(struct rt_exporter *re, struct rt_export_request *req UNUSED) +static void +bgp_out_table_export_start(struct rt_exporter *re, struct rt_export_request *req) { - struct bgp_channel *bc = SKIP_BACK(struct bgp_channel, prefix_exporter, re); - pool *p = rp_new(bc->c.proto->pool, "Export hook"); - struct rt_export_hook *hook = mb_allocz(p, sizeof(struct rt_export_hook)); - hook->pool = p; - hook->event = ev_new_init(p, bgp_out_table_feed, hook); - hook->feed_type = TFT_HASH; + req->hook = rt_alloc_export(re, sizeof(struct bgp_out_export_hook)); + req->hook->req = req; - return hook; -} + struct bgp_out_export_hook *hook = SKIP_BACK(struct bgp_out_export_hook, h, req->hook); -static void -bgp_out_table_export_done(struct rt_export_hook *hook) -{ - rfree(hook->pool); + hook->h.event.hook = bgp_out_table_feed; + rt_init_export(re, req->hook); } +static const struct rt_exporter_class bgp_out_table_export_class = { + .start = bgp_out_table_export_start, + .done = rt_export_stopped, +}; + void bgp_setup_out_table(struct bgp_channel *c) { ASSERT_DIE(c->c.out_table == NULL); c->prefix_exporter = (struct rt_exporter) { + .class = &bgp_out_table_export_class, .addr_type = c->c.table->addr_type, - .start = bgp_out_table_export_start, - .done = bgp_out_table_export_done, + .rp = c->c.proto->pool, }; - init_list(&c->prefix_exporter.hooks); - init_list(&c->prefix_exporter.pending); + rt_exporter_init(&c->prefix_exporter); c->c.out_table = &c->prefix_exporter; } diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 97b18fcf..573e3d25 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -847,7 +847,7 @@ bgp_graceful_restart_feed(struct bgp_channel *c) .export_one = bgp_graceful_restart_drop_export, }; - rt_request_export(&c->c.table->exporter, &c->stale_feed); + rt_request_export(c->c.table, &c->stale_feed); } |