diff --git a/nest/proto.c b/nest/proto.c index f4615c2f..783672ec 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -511,6 +511,7 @@ channel_start_import(struct channel *c) c->in_req = (struct rt_import_request) { .name = mb_sprintf(c->proto->pool, "%s.%s", c->proto->name, c->name), .trace_routes = c->debug | c->proto->debug, + .list = proto_work_list(c->proto), .dump_req = channel_dump_import_req, .log_state_change = channel_import_log_state_change, .preimport = channel_preimport, diff --git a/nest/rt-table.c b/nest/rt-table.c index 2fa736e2..3188ddf8 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -1354,9 +1354,6 @@ rte_announce(rtable *tab, net *net, struct rte_storage *new, struct rte_storage tab->exporter.first = rpe; rt_check_cork_high(tab); - - if (!tm_active(tab->exporter.export_timer)) - tm_start(tab->exporter.export_timer, tab->config->export_settle_time); } static struct rt_pending_export * @@ -1410,6 +1407,9 @@ rt_announce_exports(timer *tm) { rtable *tab = tm->data; + if (EMPTY_LIST(tab->exporter.pending)) + return; + struct rt_export_hook *c; node *n; WALK_LIST2(c, n, tab->exporter.hooks, n) { @@ -1420,6 +1420,28 @@ rt_announce_exports(timer *tm) } } +static void +rt_import_announce_exports(void *_hook) +{ + struct rt_import_hook *hook = _hook; + rtable *tab = hook->table; + + + if (hook->import_state == TIS_CLEARED) + { + rt_trace(tab, D_EVENTS, "Hook %s stopped", hook->req->name); + hook->stopped(hook->req); + rem_node(&hook->n); + mb_free(hook); + rt_unlock_table(tab); + } + + rt_trace(tab, D_EVENTS, "Announcing exports after imports from %s", hook->req->name); + + if (!tm_active(tab->exporter.export_timer)) + tm_start(tab->exporter.export_timer, tab->config->export_settle_time); +} + static struct rt_pending_export * rt_last_export(struct rt_exporter *tab) { @@ -1535,7 +1557,7 @@ rte_same(rte *x, rte *y) static inline int rte_is_ok(rte *e) { return e && !rte_is_filtered(e); } -static void +static int rte_recalculate(struct rt_import_hook *c, net *net, rte *new, struct rte_src *src) { struct rt_import_request *req = c->req; @@ -1588,7 +1610,7 @@ rte_recalculate(struct rt_import_hook *c, net *net, rte *new, struct rte_src *sr /* We need to free the already stored route here before returning */ rte_free(new_stored); - return; + return 0; } *before_old = (*before_old)->next; @@ -1598,7 +1620,7 @@ rte_recalculate(struct rt_import_hook *c, net *net, rte *new, struct rte_src *sr if (!old && !new) { stats->withdraws_ignored++; - return; + return 0; } /* If rejected by import limit, we need to pretend there is no route */ @@ -1734,14 +1756,7 @@ rte_recalculate(struct rt_import_hook *c, net *net, rte *new, struct rte_src *sr rte_announce(table, net, new_stored, old_stored, net->routes, old_best_stored); -#if 0 - /* Enable and reimplement these callbacks if anybody wants to use them */ - if (old_ok && p->rte_remove) - p->rte_remove(net, old); - if (new_ok && p->rte_insert) - p->rte_insert(net, &new_stored->rte); -#endif - + return 1; } int @@ -1869,8 +1884,9 @@ rte_import(struct rt_import_request *req, const net_addr *n, rte *new, struct rt return; } - /* And recalculate the best route */ - rte_recalculate(hook, nn, new, src); + /* Recalculate the best route */ + if (rte_recalculate(hook, nn, new, src)) + ev_send(req->list, &hook->announce_event); } /* Check rtable for best route to given net whether it would be exported do p */ @@ -1951,14 +1967,14 @@ rt_request_import(rtable *tab, struct rt_import_request *req) struct rt_import_hook *hook = req->hook = mb_allocz(tab->rp, sizeof(struct rt_import_hook)); + hook->announce_event = (event) { .hook = rt_import_announce_exports, .data = hook }; + DBG("Lock table %s for import %p req=%p uc=%u\n", tab->name, hook, req, tab->use_count); hook->req = req; hook->table = tab; rt_set_import_state(hook, TIS_UP); - - hook->n = (node) {}; add_tail(&tab->imports, &hook->n); } @@ -2313,7 +2329,13 @@ rt_event(void *ptr) if (tab->nhu_corked || tab->nhu_state && rt_cork_check(tab->uncork_event)) { if (!tab->nhu_corked) + { rt_trace(tab, D_STATES, "Next hop updater corked"); + if ((tab->nhu_state & NHU_RUNNING) + && !EMPTY_LIST(tab->exporter.pending) + && !tm_active(tab->exporter.export_timer)) + tm_start(tab->exporter.export_timer, tab->config->export_settle_time); + } tab->nhu_corked |= tab->nhu_state; tab->nhu_state = 0; @@ -2699,6 +2721,10 @@ again: } FIB_ITERATE_END; + rt_trace(tab, D_EVENTS, "Prune done, scheduling export timer"); + if (!tm_active(tab->exporter.export_timer)) + tm_start(tab->exporter.export_timer, tab->config->export_settle_time); + #ifdef DEBUGGING fib_check(&tab->fib); #endif @@ -2912,10 +2938,7 @@ done:; if (!first || (first->seq >= ih->flush_seq)) { ih->import_state = TIS_CLEARED; - ih->stopped(ih->req); - rem_node(&ih->n); - mb_free(ih); - rt_unlock_table(tab); + ev_send(ih->req->list, &ih->announce_event); } if ((tab->gc_counter += want_prune) >= tab->config->gc_threshold) @@ -3497,6 +3520,11 @@ rt_next_hop_update(rtable *tab) } FIB_ITERATE_END; + rt_trace(tab, D_EVENTS, "NHU done, scheduling export timer"); + + if (!tm_active(tab->exporter.export_timer)) + tm_start(tab->exporter.export_timer, tab->config->export_settle_time); + /* State change: * NHU_DIRTY -> NHU_SCHEDULED * NHU_RUNNING -> NHU_CLEAN diff --git a/nest/rt.h b/nest/rt.h index c5948512..78585c79 100644 --- a/nest/rt.h +++ b/nest/rt.h @@ -187,6 +187,8 @@ struct rt_import_request { char *name; u8 trace_routes; + event_list *list; /* Where to schedule announce events */ + void (*dump_req)(struct rt_import_request *req); void (*log_state_change)(struct rt_import_request *req, u8 state); /* Preimport is called when the @new route is just-to-be inserted, replacing @old. @@ -218,6 +220,7 @@ struct rt_import_hook { u8 stale_pruning; /* Last prune started when this value was set at stale_valid */ void (*stopped)(struct rt_import_request *); /* Stored callback when import is stopped */ + event announce_event; /* This event announces table updates */ }; struct rt_pending_export {