summaryrefslogtreecommitdiff
path: root/nest
diff options
context:
space:
mode:
authorMaria Matejka <mq@ucw.cz>2021-10-06 15:10:33 +0200
committerMaria Matejka <mq@ucw.cz>2021-11-22 19:05:43 +0100
commit44f26c49f966ca842ff9af55468de0b98c44b73e (patch)
tree058c474e3f82ac0a26b77cf1c62f2ffa07212145 /nest
parentf81702b7e44ba7f2b264fe14f0f4e1e30913e475 (diff)
Special table hooks rectified.
* internal tables are now more standalone, having their own import and export hooks * route refresh/reload uses stale counter instead of stale flag, allowing to drop walking the table at the beginning * route modify (by BGP LLGR) is now done by a special refeed hook, reimporting the modified routes directly without filters
Diffstat (limited to 'nest')
-rw-r--r--nest/config.Y4
-rw-r--r--nest/proto.c426
-rw-r--r--nest/protocol.h23
-rw-r--r--nest/route.h35
-rw-r--r--nest/rt-attr.c3
-rw-r--r--nest/rt-show.c7
-rw-r--r--nest/rt-table.c593
7 files changed, 541 insertions, 550 deletions
diff --git a/nest/config.Y b/nest/config.Y
index 29d6b0db..a56b25be 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -644,12 +644,12 @@ r_args:
}
| r_args IMPORT TABLE channel_arg {
if (!$4->in_table) cf_error("No import table in channel %s.%s", $4->proto->name, $4->name);
- rt_show_add_table($$, $4->in_table);
+ rt_show_add_table($$, $4->in_table->tab);
$$->tables_defined_by = RSD_TDB_DIRECT;
}
| r_args EXPORT TABLE channel_arg {
if (!$4->out_table) cf_error("No export table in channel %s.%s", $4->proto->name, $4->name);
- rt_show_add_table($$, $4->out_table);
+ rt_show_add_table($$, $4->out_table->tab);
$$->tables_defined_by = RSD_TDB_DIRECT;
}
| r_args FILTER filter {
diff --git a/nest/proto.c b/nest/proto.c
index 09582d2e..cf448fd9 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -47,7 +47,7 @@ static char *c_states[] = { "DOWN", "START", "UP", "STOP", "RESTART" };
extern struct protocol proto_unix_iface;
-static void channel_request_reload(struct channel *c);
+static void channel_aux_request_refeed(struct channel_aux_table *cat);
static void proto_shutdown_loop(timer *);
static void proto_rethink_goal(struct proto *p);
static char *proto_state_name(struct proto *p);
@@ -88,7 +88,9 @@ channel_export_log_state_change(struct rt_export_request *req, u8 state)
switch (state)
{
case TES_FEEDING:
- if (c->proto->feed_begin)
+ if (c->out_table)
+ rt_refresh_begin(&c->out_table->push);
+ else if (c->proto->feed_begin)
c->proto->feed_begin(c, !c->refeeding);
break;
case TES_READY:
@@ -179,6 +181,7 @@ proto_find_channel_by_name(struct proto *p, const char *n)
}
rte * channel_preimport(struct rt_import_request *req, rte *new, rte *old);
+rte * channel_in_preimport(struct rt_import_request *req, rte *new, rte *old);
void rt_notify_optimal(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe);
void rt_notify_any(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe);
@@ -295,14 +298,10 @@ static void
channel_roa_in_changed(struct rt_subscription *s)
{
struct channel *c = s->data;
- int active = c->reload_event && ev_active(c->reload_event);
- CD(c, "Reload triggered by RPKI change%s", active ? " - already active" : "");
+ CD(c, "Reload triggered by RPKI change");
- if (!active)
- channel_request_reload(c);
- else
- c->reload_pending = 1;
+ channel_request_reload(c);
}
static void
@@ -444,7 +443,6 @@ channel_start_import(struct channel *c)
.dump_req = channel_dump_import_req,
.log_state_change = channel_import_log_state_change,
.preimport = channel_preimport,
- .rte_modify = c->proto->rte_modify,
};
ASSERT(c->channel_state == CS_UP);
@@ -463,7 +461,8 @@ channel_start_export(struct channel *c)
{
if (c->out_req.hook)
{
- log(L_WARN "%s.%s: Attempted to start channel's already started export", c->proto->name, c->name);
+ c->restart_export = 1;
+ log(L_WARN "%s.%s: Fast channel export restart", c->proto->name, c->name);
return;
}
@@ -514,7 +513,7 @@ channel_check_stopped(struct channel *c)
switch (c->channel_state)
{
case CS_STOP:
- if (c->out_req.hook || c->in_req.hook)
+ if (c->out_req.hook || c->in_req.hook || c->out_table || c->in_table)
return;
channel_set_state(c, CS_DOWN);
@@ -541,9 +540,6 @@ channel_import_stopped(struct rt_import_request *req)
req->hook = NULL;
- if (c->in_table)
- rt_prune_sync(c->in_table, 1);
-
mb_free(c->in_req.name);
c->in_req.name = NULL;
@@ -566,14 +562,16 @@ channel_export_stopped(struct rt_export_request *req)
return;
}
- /* Free the routes from out_table */
- if (c->out_table)
- rt_prune_sync(c->out_table, 1);
-
mb_free(c->out_req.name);
c->out_req.name = NULL;
- channel_check_stopped(c);
+ if (c->restart_export)
+ {
+ c->restart_export = 0;
+ channel_start_export(c);
+ }
+ else
+ channel_check_stopped(c);
}
static void
@@ -595,72 +593,296 @@ channel_feed_end(struct channel *c)
return;
}
- if (c->proto->feed_end)
+ if (c->out_table)
+ rt_refresh_end(&c->out_table->push);
+ else if (c->proto->feed_end)
c->proto->feed_end(c);
if (c->refeed_pending)
rt_stop_export(req, channel_export_stopped);
+}
+
+#define CHANNEL_AUX_TABLE_DUMP_REQ(inout, imex, pgimex, pushget) static void \
+ channel_##inout##_##pushget##_dump_req(struct rt_##pgimex##_request *req) { \
+ struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, pushget, req); \
+ debug(" Channel %s.%s " #imex " table " #pushget " request %p\n", cat->c->proto->name, cat->c->name, req); }
+
+CHANNEL_AUX_TABLE_DUMP_REQ(in, import, import, push)
+CHANNEL_AUX_TABLE_DUMP_REQ(in, import, export, get)
+CHANNEL_AUX_TABLE_DUMP_REQ(out, export, import, push)
+CHANNEL_AUX_TABLE_DUMP_REQ(out, export, export, get)
+
+#undef CHANNEL_AUX_TABLE_DUMP_REQ
+
+static uint channel_aux_imex(struct channel_aux_table *cat)
+{
+ if (cat->c->in_table == cat)
+ return 0;
+ else if (cat->c->out_table == cat)
+ return 1;
else
- c->refeeding = 0;
+ bug("Channel aux table must be in_table or out_table");
}
-/* Called by protocol for reload from in_table */
-void
-channel_schedule_reload(struct channel *c)
+static void
+channel_aux_stopped(void *data)
{
- ASSERT(c->in_req.hook);
+ struct channel_aux_table *cat = data;
+ struct channel *c = cat->c;
+
+ if (channel_aux_imex(cat))
+ c->out_table = NULL;
+ else
+ c->in_table = NULL;
+
+ mb_free(cat);
+ return channel_check_stopped(c);
+}
+
+static void
+channel_aux_import_stopped(struct rt_import_request *req)
+{
+ struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, push, req);
+ ASSERT_DIE(cat->stop);
+}
+
+static void
+channel_aux_export_stopped(struct rt_export_request *req)
+{
+ struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, push, req);
+ req->hook = NULL;
+
+ if (cat->refeed_pending && !cat->stop)
+ {
+ cat->refeed_pending = 0;
+ rt_request_export(cat->tab, req);
+ }
+ else
+ ASSERT_DIE(cat->stop);
+}
+
+static void
+channel_aux_stop(struct channel_aux_table *cat)
+{
+ cat->stop = 1;
- rt_reload_channel_abort(c);
- ev_schedule_work(c->reload_event);
+ rt_stop_import(&cat->push, channel_aux_import_stopped);
+ rt_stop_export(&cat->get, channel_aux_export_stopped);
+
+ rt_lock_table(cat->tab);
+ cat->tab->deleted = channel_aux_stopped;
+ cat->tab->del_data = cat;
+ rt_unlock_table(cat->tab);
}
static void
-channel_reload_loop(void *ptr)
+channel_push_log_state_change(struct rt_import_request *req, u8 state)
{
- struct channel *c = ptr;
+ struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, push, req);
+ const char *imex = channel_aux_imex(cat) ? "export" : "import";
+ CD(cat->c, "Channel %s table import state changed to %s", imex, rt_import_state_name(state));
+}
- /* Start reload */
- if (!c->reload_active)
- c->reload_pending = 0;
+static void
+channel_get_log_state_change(struct rt_export_request *req, u8 state)
+{
+ struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, get, req);
+ const char *imex = channel_aux_imex(cat) ? "export" : "import";
+ CD(cat->c, "Channel %s table export state changed to %s", imex, rt_export_state_name(state));
- if (!rt_reload_channel(c))
+ switch (state)
{
- ev_schedule_work(c->reload_event);
+ case TES_FEEDING:
+ if (imex && cat->c->proto->feed_begin)
+ cat->c->proto->feed_begin(cat->c, !cat->c->refeeding);
+ else if (!imex)
+ rt_refresh_begin(&cat->c->in_req);
+ break;
+
+ case TES_READY:
+ if (imex && cat->c->proto->feed_end)
+ cat->c->proto->feed_end(cat->c);
+ else if (!imex)
+ rt_refresh_end(&cat->c->in_req);
+
+ if (cat->refeed_pending)
+ rt_stop_export(&cat->get, channel_aux_export_stopped);
+
+ break;
+ }
+}
+
+void rte_update_direct(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
+
+static void
+channel_in_export_one_any(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe)
+{
+ struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, get, req);
+
+ if (!rpe->new && !rpe->old)
+ return;
+
+ rte n0;
+ struct rte_src *src = rpe->new ? rpe->new->rte.src : rpe->old->rte.src;
+ rte_update_direct(cat->c, net, RTES_CLONE(rpe->new, &n0), src);
+}
+
+static void
+channel_in_export_one_best(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe)
+{
+ struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, get, req);
+
+ if (!rpe->new && !rpe->old)
return;
+
+ rte n0;
+ struct rte_src *src = rpe->old_best ? rpe->old_best->rte.src : rpe->new_best->rte.src;
+ rte_update_direct(cat->c, net, RTES_CLONE(rpe->new_best, &n0), src);
+}
+
+static void
+channel_in_export_bulk_any(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe UNUSED, rte **feed, uint count)
+{
+ struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, get, req);
+ for (uint i=0; i<count; i++)
+ {
+ rte n0 = *feed[i];
+ rte_update_direct(cat->c, net, &n0, n0.src);
}
+}
- /* Restart reload */
- if (c->reload_pending)
- channel_request_reload(c);
+static void
+channel_in_export_bulk_best(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe UNUSED, rte **feed, uint count)
+{
+ struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, get, req);
+ if (!count)
+ return;
+
+ rte n0 = *feed[0];
+ rte_update_direct(cat->c, net, &n0, n0.src);
+}
+
+void do_rt_notify_direct(struct channel *c, const net_addr *net, rte *new, const rte *old);
+
+static void
+channel_out_export_one_any(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe)
+{
+ struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, get, req);
+ rte n0;
+ do_rt_notify_direct(cat->c, net, RTES_CLONE(rpe->new, &n0), RTES_OR_NULL(rpe->old));
+}
+
+static void
+channel_out_export_one_best(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe)
+{
+ struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, get, req);
+ rte n0;
+ do_rt_notify_direct(cat->c, net, RTES_CLONE(rpe->new_best, &n0), RTES_OR_NULL(rpe->old_best));
+}
+
+static void
+channel_out_export_bulk(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe UNUSED, rte **feed, uint count)
+{
+ struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, get, req);
+ if (cat->c->ra_mode != RA_ANY)
+ ASSERT_DIE(count <= 1);
+
+ for (uint i=0; i<count; i++)
+ {
+ rte n0 = *feed[i];
+ do_rt_notify_direct(cat->c, net, &n0, NULL);
+ }
}
/* Called by protocol to activate in_table */
void
-channel_setup_in_table(struct channel *c)
+channel_setup_in_table(struct channel *c, int best)
{
- struct rtable_config *cf = mb_allocz(c->proto->pool, sizeof(struct rtable_config));
+ int nlen = sizeof("import") + strlen(c->name) + strlen(c->proto->name) + 3;
+
+ struct {
+ struct channel_aux_table cat;
+ struct rtable_config tab_cf;
+ char name[0];
+ } *cat = mb_allocz(c->proto->pool, sizeof(*cat) + nlen);
+
+ bsprintf(cat->name, "%s.%s.import", c->proto->name, c->name);
- cf->name = "import";
- cf->addr_type = c->net_type;
- cf->internal = 1;
+ cat->tab_cf.name = cat->name;
+ cat->tab_cf.addr_type = c->net_type;
+
+ c->in_table = &cat->cat;
+ c->in_table->push = (struct rt_import_request) {
+ .name = cat->name,
+ .trace_routes = c->debug | c->proto->debug,
+ .dump_req = channel_in_push_dump_req,
+ .log_state_change = channel_push_log_state_change,
+ .preimport = channel_in_preimport,
+ };
+ c->in_table->get = (struct rt_export_request) {
+ .name = cat->name,
+ .trace_routes = c->debug | c->proto->debug,
+ .dump_req = channel_in_get_dump_req,
+ .log_state_change = channel_get_log_state_change,
+ .export_one = best ? channel_in_export_one_best : channel_in_export_one_any,
+ .export_bulk = best ? channel_in_export_bulk_best : channel_in_export_bulk_any,
+ };
- c->in_table = rt_setup(c->proto->pool, cf);
+ c->in_table->c = c;
+ c->in_table->tab = rt_setup(c->proto->pool, &cat->tab_cf);
+ self_link(&c->in_table->tab->n);
- c->reload_event = ev_new_init(c->proto->pool, channel_reload_loop, c);
+ rt_request_import(c->in_table->tab, &c->in_table->push);
+ rt_request_export(c->in_table->tab, &c->in_table->get);
}
/* Called by protocol to activate out_table */
void
channel_setup_out_table(struct channel *c)
{
- struct rtable_config *cf = mb_allocz(c->proto->pool, sizeof(struct rtable_config));
- cf->name = "export";
- cf->addr_type = c->net_type;
- cf->internal = 1;
+ int nlen = sizeof("export") + strlen(c->name) + strlen(c->proto->name) + 3;
+
+ struct {
+ struct channel_aux_table cat;
+ struct rtable_config tab_cf;
+ char name[0];
+ } *cat = mb_allocz(c->proto->pool, sizeof(*cat) + nlen);
+
+ bsprintf(cat->name, "%s.%s.export", c->proto->name, c->name);
- c->out_table = rt_setup(c->proto->pool, cf);
+ cat->tab_cf.name = cat->name;
+ cat->tab_cf.addr_type = c->net_type;
+
+ c->out_table = &cat->cat;
+ c->out_table->push = (struct rt_import_request) {
+ .name = cat->name,
+ .trace_routes = c->debug | c->proto->debug,
+ .dump_req = channel_out_push_dump_req,
+ .log_state_change = channel_push_log_state_change,
+ };
+ c->out_table->get = (struct rt_export_request) {
+ .name = cat->name,
+ .trace_routes = c->debug | c->proto->debug,
+ .dump_req = channel_out_get_dump_req,
+ .log_state_change = channel_get_log_state_change,
+ .export_one = (c->ra_mode == RA_ANY) ? channel_out_export_one_any : channel_out_export_one_best,
+ .export_bulk = channel_out_export_bulk,
+ };
+
+ c->out_table->c = c;
+ c->out_table->tab = rt_setup(c->proto->pool, &cat->tab_cf);
+ self_link(&c->out_table->tab->n);
+
+ rt_request_import(c->out_table->tab, &c->out_table->push);
+ rt_request_export(c->out_table->tab, &c->out_table->get);
}
+static void
+channel_aux_request_refeed(struct channel_aux_table *cat)
+{
+ cat->refeed_pending = 1;
+ rt_stop_export(&cat->get, channel_aux_export_stopped);
+}
static void
channel_do_start(struct channel *c)
@@ -686,16 +908,12 @@ channel_do_up(struct channel *c)
static void
channel_do_pause(struct channel *c)
{
- /* Need to abort feeding */
- if (c->reload_event)
- {
- ev_postpone(c->reload_event);
- rt_reload_channel_abort(c);
- }
-
/* Stop export */
if (c->out_req.hook)
+ {
rt_stop_export(&c->out_req, channel_export_stopped);
+ c->refeeding = 0;
+ }
channel_roa_unsubscribe_all(c);
@@ -706,6 +924,13 @@ channel_do_pause(struct channel *c)
static void
channel_do_stop(struct channel *c)
{
+ /* Drop auxiliary tables */
+ if (c->in_table)
+ channel_aux_stop(c->in_table);
+
+ if (c->out_table)
+ channel_aux_stop(c->out_table);
+
/* Stop import */
if (c->in_req.hook)
rt_stop_import(&c->in_req, channel_import_stopped);
@@ -716,16 +941,13 @@ channel_do_stop(struct channel *c)
CALL(c->channel->shutdown, c);
- /* This have to be done in here, as channel pool is freed before channel_do_down() */
- c->in_table = NULL;
- c->reload_event = NULL;
- c->out_table = NULL;
+ channel_roa_unsubscribe_all(c);
}
static void
channel_do_down(struct channel *c)
{
- ASSERT(!c->reload_active);
+ ASSERT(!c->out_req.hook && !c->in_req.hook && !c->out_table && !c->in_table);
c->proto->active_channels--;
@@ -733,14 +955,12 @@ channel_do_down(struct channel *c)
memset(&c->import_stats, 0, sizeof(struct channel_import_stats));
memset(&c->export_stats, 0, sizeof(struct channel_export_stats));
- c->in_table = NULL;
- c->reload_event = NULL;
- c->out_table = NULL;
-
- /* The in_table and out_table are going to be freed by freeing their resource pools. */
-
CALL(c->channel->cleanup, c);
+ /* This have to be done in here, as channel pool is freed before channel_do_down() */
+ bmap_free(&c->export_map);
+ bmap_free(&c->export_reject_map);
+
/* Schedule protocol shutddown */
if (proto_is_done(c->proto))
ev_schedule(c->proto->event);
@@ -769,7 +989,7 @@ channel_set_state(struct channel *c, uint state)
break;
case CS_UP:
- ASSERT(cs == CS_DOWN || cs == CS_START);
+ ASSERT(cs == CS_DOWN || cs == CS_START || cs == CS_PAUSE);
if (cs == CS_DOWN)
channel_do_start(c);
@@ -819,8 +1039,8 @@ channel_set_state(struct channel *c, uint state)
* completed, it will switch back to ES_READY. This function can be called
* even when feeding is already running, in that case it is restarted.
*/
-void
-channel_request_feeding(struct channel *c)
+static void
+channel_request_table_feeding(struct channel *c)
{
ASSERT(c->out_req.hook);
@@ -828,7 +1048,18 @@ channel_request_feeding(struct channel *c)
rt_stop_export(&c->out_req, channel_export_stopped);
}
-static void
+void
+channel_request_feeding(struct channel *c)
+{
+ ASSERT(c->out_req.hook);
+
+ if (c->out_table)
+ channel_aux_request_refeed(c->out_table);
+ else
+ channel_request_table_feeding(c);
+}
+
+void
channel_request_reload(struct channel *c)
{
ASSERT(c->in_req.hook);
@@ -836,14 +1067,29 @@ channel_request_reload(struct channel *c)
CD(c, "Reload requested");
- c->proto->reload_routes(c);
+ if (c->in_table)
+ channel_aux_request_refeed(c->in_table);
+ else
+ c->proto->reload_routes(c);
+}
- /*
- * Should this be done before reload_routes() hook?
- * Perhaps, but routes are updated asynchronously.
- */
- channel_reset_limit(c, &c->rx_limit, PLD_RX);
- channel_reset_limit(c, &c->in_limit, PLD_IN);
+void
+channel_refresh_begin(struct channel *c)
+{
+ CD(c, "Channel route refresh begin");
+ if (c->in_table)
+ rt_refresh_begin(&c->in_table->push);
+ else
+ rt_refresh_begin(&c->in_req);
+}
+
+void
+channel_refresh_end(struct channel *c)
+{
+ if (c->in_table)
+ rt_refresh_end(&c->in_table->push);
+ else
+ rt_refresh_end(&c->in_req);
}
const struct channel_class channel_basic = {
@@ -1001,7 +1247,7 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
channel_request_reload(c);
if (export_changed)
- channel_request_feeding(c);
+ channel_request_table_feeding(c);
done:
CD(c, "Reconfigured");
@@ -1714,7 +1960,7 @@ protos_dump_all(void)
WALK_LIST(p, proto_list)
{
#define DPF(x) (p->x ? " " #x : "")
- debug(" protocol %s (%p) state %s with %d active channels flags: %s%s%s%s%s\n",
+ debug(" protocol %s (%p) state %s with %d active channels flags: %s%s%s%s\n",
p->name, p, p_states[p->proto_state], p->active_channels,
DPF(disabled), DPF(active), DPF(do_start), DPF(do_stop), DPF(reconfiguring));
#undef DPF
@@ -1730,6 +1976,20 @@ protos_dump_all(void)
debug("\tChannel state: %s/%s/%s\n", c_states[c->channel_state],
c->in_req.hook ? rt_import_state_name(rt_import_get_state(c->in_req.hook)) : "-",
c->out_req.hook ? rt_export_state_name(rt_export_get_state(c->out_req.hook)) : "-");
+ if (c->in_table)
+ {
+ debug("\tInput aux table:\n");
+ rt_dump_hooks(c->in_table->tab);
+ rt_dump(c->in_table->tab);
+ debug("\tEnd of input aux table.\n");
+ }
+ if (c->out_table)
+ {
+ debug("\tOutput aux table:\n");
+ rt_dump_hooks(c->in_table->tab);
+ rt_dump(c->in_table->tab);
+ debug("\tEnd of output aux table.\n");
+ }
}
if (p->proto->dump && (p->proto_state != PS_DOWN))
@@ -2151,11 +2411,11 @@ channel_show_stats(struct channel *c)
cli_msg(-1006, " Routes: %u imported, %u exported, %u preferred",
in_routes, out_routes, SRI(pref));
- cli_msg(-1006, " Route change stats: received rejected filtered ignored RX limit IN limit accepted");
- cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u %10u %10u",
+ cli_msg(-1006, " Route change stats: received rejected filtered ignored limited accepted");
+ cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u %10u",
SCI(updates_received), SCI(updates_invalid),
SCI(updates_filtered), SRI(updates_ignored),
- SCI(updates_limited_rx), SCI(updates_limited_in),
+ SCI(updates_limited_rx) + SCI(updates_limited_in),
SRI(updates_accepted));
cli_msg(-1006, " Import withdraws: %10u %10u --- %10u --- %10u",
SCI(withdraws_received), SCI(withdraws_invalid),
diff --git a/nest/protocol.h b/nest/protocol.h
index 7447cbf0..f9996b18 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -207,7 +207,6 @@ struct proto {
int (*rte_recalculate)(struct rtable *, struct network *, struct rte *, struct rte *, struct rte *);
int (*rte_better)(struct rte *, struct rte *);
int (*rte_mergable)(struct rte *, struct rte *);
- struct rte *(*rte_modify)(struct rte *, struct linpool *);
void (*rte_insert)(struct network *, struct rte *);
void (*rte_remove)(struct network *, struct rte *);
u32 (*rte_igp_metric)(struct rte *);
@@ -544,24 +543,29 @@ struct channel {
u8 reloadable; /* Hook reload_routes() is allowed on the channel */
u8 gr_lock; /* Graceful restart mechanism should wait for this channel */
u8 gr_wait; /* Route export to channel is postponed until graceful restart */
+ u8 restart_export; /* Route export should restart as soon as it stops */
btime last_state_change; /* Time of last state transition */
- struct rtable *in_table; /* Internal table for received routes */
- struct event *reload_event; /* Event responsible for reloading from in_table */
- struct fib_iterator reload_fit; /* FIB iterator in in_table used during reloading */
- struct rte_storage *reload_next_rte; /* Route iterator in in_table used during reloading */
- u8 reload_active; /* Iterator reload_fit is linked */
+ struct channel_aux_table *in_table; /* Internal table for received routes */
u8 reload_pending; /* Reloading and another reload is scheduled */
u8 refeed_pending; /* Refeeding and another refeed is scheduled */
u8 rpki_reload; /* RPKI changes trigger channel reload */
- struct rtable *out_table; /* Internal table for exported routes */
+ struct channel_aux_table *out_table; /* Internal table for exported routes */
list roa_subscriptions; /* List of active ROA table subscriptions based on filters roa_check() */
};
+struct channel_aux_table {
+ struct channel *c;
+ struct rt_import_request push;
+ struct rt_export_request get;
+ rtable *tab;
+ u8 stop;
+ u8 refeed_pending;
+};
/*
* Channel states
@@ -627,7 +631,7 @@ struct channel *proto_add_channel(struct proto *p, struct channel_config *cf);
int proto_configure_channel(struct proto *p, struct channel **c, struct channel_config *cf);
void channel_set_state(struct channel *c, uint state);
-void channel_setup_in_table(struct channel *c);
+void channel_setup_in_table(struct channel *c, int best);
void channel_setup_out_table(struct channel *c);
void channel_schedule_reload(struct channel *c);
@@ -636,6 +640,9 @@ static inline void channel_open(struct channel *c) { channel_set_state(c, CS_UP)
static inline void channel_close(struct channel *c) { channel_set_state(c, CS_STOP); }
void channel_request_feeding(struct channel *c);
+void channel_request_reload(struct channel *c);
+void channel_refresh_begin(struct channel *c);
+void channel_refresh_end(struct channel *c);
void *channel_config_new(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
void *channel_config_get(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
int channel_reconfigure(struct channel *c, struct channel_config *cf);
diff --git a/nest/route.h b/nest/route.h
index d0568133..cb66be2a 100644
--- a/nest/route.h
+++ b/nest/route.h
@@ -150,7 +150,6 @@ struct rtable_config {
int gc_max_ops; /* Maximum number of operations before GC is run */
int gc_min_time; /* Minimum time between two consecutive GC runs */
byte sorted; /* Routes of network are sorted according to rte_better() */
- byte internal; /* Internal table of a protocol */
btime min_settle_time; /* Minimum settle time for notifications */
btime max_settle_time; /* Maximum settle time for notifications */
};
@@ -172,10 +171,8 @@ typedef struct rtable {
struct hmap id_map;
struct hostcache *hostcache;
struct rtable_config *config; /* Configuration of this table */
- struct config *deleted; /* Table doesn't exist in current configuration,
- * delete as soon as use_count becomes 0 and remove
- * obstacle from this routing table.
- */
+ void (*deleted)(void *); /* Table should free itself. Call this when it is done. */
+ void *del_data;
struct event *rt_event; /* Routing table event */
btime last_rt_change; /* Last time when route changed */
btime base_settle_time; /* Start time of rtable settling interval */
@@ -184,7 +181,6 @@ typedef struct rtable {
byte prune_state; /* Table prune state, 1 -> scheduled, 2-> running */
byte hcu_scheduled; /* Hostcache update is scheduled */
byte nhu_state; /* Next Hop Update state */
- byte internal; /* This table is internal for some other object */
struct fib_iterator prune_fit; /* Rtable prune FIB iterator */
struct fib_iterator nhu_fit; /* Next Hop Update FIB iterator */
struct tbf rl_pipe; /* Rate limiting token buffer for pipe collisions */
@@ -249,6 +245,7 @@ typedef struct rte {
u8 generation; /* If this route import is based on other previously exported route,
this value should be 1 + MAX(generation of the parent routes).
Otherwise the route is independent and this value is zero. */
+ u8 stale_cycle; /* Auxiliary value for route refresh */
} rte;
struct rte_storage {
@@ -256,13 +253,11 @@ struct rte_storage {
struct rte rte; /* Route data */
};
-#define RTE_COPY(r, l) ((r) ? (((*(l)) = (r)->rte), (l)) : NULL)
-#define RTE_OR_NULL(r) ((r) ? &((r)->rte) : NULL)
+#define RTES_CLONE(r, l) ((r) ? (((*(l)) = (r)->rte), (l)) : NULL)
+#define RTES_OR_NULL(r) ((r) ? &((r)->rte) : NULL)
#define REF_FILTERED 2 /* Route is rejected by import filter */
-#define REF_STALE 4 /* Route is stale in a refresh cycle */
-#define REF_DISCARD 8 /* Route is scheduled for discard */
-#define REF_MODIFY 16 /* Route is scheduled for modify */
+#define REF_USE_STALE 4 /* Do not reset route's stale_cycle to the actual value */
/* Route is valid for propagation (may depend on other flags in the future), accepts NULL */
static inline int rte_is_valid(const rte *r) { return r && !(r->flags & REF_FILTERED); }
@@ -283,7 +278,6 @@ struct rt_import_request {
/* Preimport is called when the @new route is just-to-be inserted, replacing @old.
* Return a route (may be different or modified in-place) to continue or NULL to withdraw. */
struct rte *(*preimport)(struct rt_import_request *req, struct rte *new, struct rte *old);
- struct rte *(*rte_modify)(struct rte *, struct linpool *);
};
struct rt_import_hook {
@@ -303,6 +297,10 @@ struct rt_import_hook {
btime last_state_change; /* Time of last state transition */
u8 import_state; /* IS_* */
+ u8 stale_set; /* Set this stale_cycle to imported routes */
+ u8 stale_valid; /* Routes with this stale_cycle and bigger are considered valid */
+ u8 stale_pruned; /* Last prune finished when this value was set at stale_valid */
+ 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 */
};
@@ -455,9 +453,9 @@ void *net_route(rtable *tab, const net_addr *n);
int net_roa_check(rtable *tab, const net_addr *n, u32 asn);
int rt_examine(rtable *t, net_addr *a, struct channel *c, const struct filter *filter);
rte *rt_export_merged(struct channel *c, rte ** feed, uint count, linpool *pool, int silent);
-void rt_refresh_begin(rtable *t, struct rt_import_request *);
-void rt_refresh_end(rtable *t, struct rt_import_request *);
-void rt_modify_stale(rtable *t, struct rt_import_request *);
+
+void rt_refresh_begin(struct rt_import_request *);
+void rt_refresh_end(struct rt_import_request *);
void rt_schedule_prune(rtable *t);
void rte_dump(struct rte_storage *);
void rte_free(struct rte_storage *, rtable *);
@@ -466,15 +464,9 @@ void rt_dump(rtable *);
void rt_dump_all(void);
void rt_dump_hooks(rtable *);
void rt_dump_hooks_all(void);
-int rt_reload_channel(struct channel *c);
-void rt_reload_channel_abort(struct channel *c);
-void rt_refeed_channel(struct channel *c);
void rt_prune_sync(rtable *t, int all);
-int rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
-int rte_update_out(struct channel *c, const net_addr *n, rte *new, const rte *old, struct rte_storage **old_exported);
struct rtable_config *rt_new_table(struct symbol *s, uint addr_type);
-
/* Default limit for ECMP next hops, defined in sysdep code */
extern const int rt_default_ecmp;
@@ -789,6 +781,7 @@ void rta__free(rta *r);
static inline void rta_free(rta *r) { if (r && !--r->uc) rta__free(r); }
rta *rta_do_cow(rta *o, linpool *lp);
static inline rta * rta_cow(rta *r, linpool *lp) { return rta_is_cached(r) ? rta_do_cow(r, lp) : r; }
+static inline void rta_uncache(rta *r) { r->cached = 0; r->uc = 0; }
void rta_dump(rta *);
void rta_dump_all(void);
void rta_show(struct cli *, rta *);
diff --git a/nest/rt-attr.c b/nest/rt-attr.c
index 1bece201..77fd3c3b 100644
--- a/nest/rt-attr.c
+++ b/nest/rt-attr.c
@@ -1245,8 +1245,7 @@ rta_do_cow(rta *o, linpool *lp)
memcpy(*nhn, nho, nexthop_size(nho));
nhn = &((*nhn)->next);
}
- r->cached = 0;
- r->uc = 0;
+ rta_uncache(r);
return r;
}
diff --git a/nest/rt-show.c b/nest/rt-show.c
index 235d72e4..d942b8e1 100644
--- a/nest/rt-show.c
+++ b/nest/rt-show.c
@@ -95,7 +95,10 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, int primary
}
if (d->verbose)
+ {
+ cli_printf(c, -1008, "\tInternal route ID: %uL %uG %uS", e->src->private_id, e->src->global_id, e->stale_cycle);
rta_show(c, a);
+ }
}
static uint
@@ -103,7 +106,7 @@ rte_feed_count(net *n)
{
uint count = 0;
for (struct rte_storage *e = n->routes; e; e = e->next)
- if (rte_is_valid(RTE_OR_NULL(e)))
+ if (rte_is_valid(RTES_OR_NULL(e)))
count++;
return count;
}
@@ -113,7 +116,7 @@ rte_feed_obtain(net *n, rte **feed, uint count)
{
uint i = 0;
for (struct rte_storage *e = n->routes; e; e = e->next)
- if (rte_is_valid(RTE_OR_NULL(e)))
+ if (rte_is_valid(RTES_OR_NULL(e)))
{
ASSERT_DIE(i < count);
feed[i++] = &e->rte;
diff --git a/nest/rt-table.c b/nest/rt-table.c
index e7ff2816..2f480992 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -50,7 +50,6 @@ pool *rt_table_pool;
static linpool *rte_update_pool;
list routing_tables;
-list deleted_routing_tables;
static void rt_free_hostcache(rtable *tab);
static void rt_notify_hostcache(rtable *tab, net *net);
@@ -386,9 +385,11 @@ rte_mergable(rte *pri, rte *sec)
static void
rte_trace(const char *name, const rte *e, int dir, const char *msg)
{
- log(L_TRACE "%s %c %s %N %uL %uG %s",
- name, dir, msg, e->net, e->src->private_id, e->src->global_id,
- rta_dest_name(e->attrs->dest));
+ log(L_TRACE "%s %c %s %N src %uL %uG %uS %s%s",
+ name, dir, msg, e->net,
+ e->src->private_id, e->src->global_id, e->stale_cycle,
+ rta_dest_name(e->attrs->dest),
+ rte_is_filtered(e) ? " (filtered)" : "");
}
static inline void
@@ -427,7 +428,7 @@ rte_feed_count(net *n)
{
uint count = 0;
for (struct rte_storage *e = n->routes; e; e = e->next)
- if (rte_is_valid(RTE_OR_NULL(e)))
+ if (rte_is_valid(RTES_OR_NULL(e)))
count++;
return count;
}
@@ -437,7 +438,7 @@ rte_feed_obtain(net *n, struct rte **feed, uint count)
{
uint i = 0;
for (struct rte_storage *e = n->routes; e; e = e->next)
- if (rte_is_valid(RTE_OR_NULL(e)))
+ if (rte_is_valid(RTES_OR_NULL(e)))
{
ASSERT_DIE(i < count);
feed[i++] = &e->rte;
@@ -508,10 +509,11 @@ export_filter(struct channel *c, rte *rt, int silent)
return export_filter_(c, rt, rte_update_pool, silent);
}
+void do_rt_notify_direct(struct channel *c, const net_addr *net, rte *new, const rte *old);
+
static void
do_rt_notify(struct channel *c, const net_addr *net, rte *new, const rte *old)
{
- struct proto *p = c->proto;
struct channel_export_stats *stats = &c->export_stats;
if (c->refeeding && new)
@@ -528,28 +530,31 @@ do_rt_notify(struct channel *c, const net_addr *net, rte *new, const rte *old)
if (!new && old)
CHANNEL_LIMIT_POP(c, OUT);
+ /* Store route export state */
+ if (old)
+ bmap_clear(&c->export_map, old->id);
+
+ if (new)
+ bmap_set(&c->export_map, new->id);
+
/* Apply export table */
- struct rte_storage *old_exported = NULL;
if (c->out_table)
- {
- if (!rte_update_out(c, net, new, old, &old_exported))
- {
- channel_rte_trace_out(D_ROUTES, c, new, "idempotent");
- return;
- }
- }
+ rte_import(&c->out_table->push, net, new, old ? old->src : new->src);
+ else
+ do_rt_notify_direct(c, net, new, old);
+}
+
+void
+do_rt_notify_direct(struct channel *c, const net_addr *net, rte *new, const rte *old)
+{
+ struct proto *p = c->proto;
+ struct channel_export_stats *stats = &c->export_stats;
if (new)
stats->updates_accepted++;
else
stats->withdraws_accepted++;
- if (old)
- bmap_clear(&c->export_map, old->id);
-
- if (new)
- bmap_set(&c->export_map, new->id);
-
if (p->debug & D_ROUTES)
{
if (new && old)
@@ -560,10 +565,7 @@ do_rt_notify(struct channel *c, const net_addr *net, rte *new, const rte *old)
channel_rte_trace_out(D_ROUTES, c, old, "removed");
}
- p->rt_notify(p, c, net, new, old_exported ? &old_exported->rte : old);
-
- if (c->out_table && old_exported)
- rte_free(old_exported, c->out_table);
+ p->rt_notify(p, c, net, new, old);
}
static void
@@ -784,7 +786,7 @@ rt_notify_optimal(struct rt_export_request *req, const net_addr *net, struct rt_
rte n0;
if (rpe->new_best != rpe->old_best)
- rt_notify_basic(c, net, RTE_COPY(rpe->new_best, &n0), RTE_OR_NULL(rpe->old_best));
+ rt_notify_basic(c, net, RTES_CLONE(rpe->new_best, &n0), RTES_OR_NULL(rpe->old_best));
/* Drop the old stored rejection if applicable.
* new->id == old->id happens when updating hostentries. */
@@ -799,7 +801,7 @@ rt_notify_any(struct rt_export_request *req, const net_addr *net, struct rt_pend
rte n0;
if (rpe->new != rpe->old)
- rt_notify_basic(c, net, RTE_COPY(rpe->new, &n0), RTE_OR_NULL(rpe->old));
+ rt_notify_basic(c, net, RTES_CLONE(rpe->new, &n0), RTES_OR_NULL(rpe->old));
/* Drop the old stored rejection if applicable.
* new->id == old->id happens when updating hostentries. */
@@ -974,6 +976,10 @@ rte_recalculate(struct rt_import_hook *c, net *net, rte *new, struct rte_src *sr
rte *old_best = old_best_stored ? &old_best_stored->rte : NULL;
rte *old = NULL;
+ /* Set the stale cycle unless already set */
+ if (new && !(new->flags & REF_USE_STALE))
+ new->stale_cycle = c->stale_set;
+
/* Find and remove original route from the same protocol */
struct rte_storage **before_old = rte_find(net, src);
@@ -999,8 +1005,7 @@ rte_recalculate(struct rt_import_hook *c, net *net, rte *new, struct rte_src *sr
if (new && rte_same(old, new))
{
/* No changes, ignore the new route and refresh the old one */
-
- old->flags &= ~(REF_STALE | REF_DISCARD | REF_MODIFY);
+ old->stale_cycle = new->stale_cycle;
if (!rte_is_filtered(new))
{
@@ -1138,18 +1143,23 @@ rte_recalculate(struct rt_import_hook *c, net *net, rte *new, struct rte_src *sr
new_stored->rte.id = old->id;
}
+ _Bool nb = (new_stored == net->routes);
+ _Bool ob = (old_best == old);
+
/* Log the route change */
- if (new_ok)
- rt_rte_trace_in(D_ROUTES, req, &new_stored->rte, new_stored == net->routes ? "added [best]" : "added");
- else if (old_ok)
+ if (new_ok && old_ok)
{
- if (old != old_best)
- rt_rte_trace_in(D_ROUTES, req, old, "removed");
- else if (net->routes && rte_is_ok(&net->routes->rte))
- rt_rte_trace_in(D_ROUTES, req, old, "removed [replaced]");
- else
- rt_rte_trace_in(D_ROUTES, req, old, "removed [sole]");
+ const char *best_indicator[2][2] = { { "updated", "updated [-best]" }, { "updated [+best]", "updated [best]" } };
+ rt_rte_trace_in(D_ROUTES, req, &new_stored->rte, best_indicator[nb][ob]);
}
+ else if (new_ok)
+ rt_rte_trace_in(D_ROUTES, req, &new_stored->rte,
+ (!net->routes->next || !rte_is_ok(&net->routes->next->rte)) ? "added [sole]" :
+ nb ? "added [best]" : "added");
+ else if (old_ok)
+ rt_rte_trace_in(D_ROUTES, req, old,
+ (!net->routes || !rte_is_ok(&net->routes->rte)) ? "removed [sole]" :
+ ob ? "removed [best]" : "removed");
/* Propagate the route change */
rte_announce(table, net, new_stored, old_stored,
@@ -1197,12 +1207,15 @@ channel_preimport(struct rt_import_request *req, rte *new, rte *old)
{
struct channel *c = SKIP_BACK(struct channel, in_req, req);
- if (new && !old)
- if (CHANNEL_LIMIT_PUSH(c, RX))
- return NULL;
+ if (!c->in_table)
+ {
+ if (new && !old)
+ if (CHANNEL_LIMIT_PUSH(c, RX))
+ return NULL;
- if (!new && old)
- CHANNEL_LIMIT_POP(c, RX);
+ if (!new && old)
+ CHANNEL_LIMIT_POP(c, RX);
+ }
int new_in = new && !rte_is_filtered(new);
int old_in = old && !rte_is_filtered(old);
@@ -1223,7 +1236,22 @@ channel_preimport(struct rt_import_request *req, rte *new, rte *old)
return new;
}
-static void rte_update_direct(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
+rte *
+channel_in_preimport(struct rt_import_request *req, rte *new, rte *old)
+{
+ struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, push, req);
+
+ if (new && !old)
+ if (CHANNEL_LIMIT_PUSH(cat->c, RX))
+ return NULL;
+
+ if (!new && old)
+ CHANNEL_LIMIT_POP(cat->c, RX);
+
+ return new;
+}
+
+void rte_update_direct(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
void
rte_update(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
@@ -1233,13 +1261,14 @@ rte_update(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
ASSERT(c->channel_state == CS_UP);
- if (c->in_table && !rte_update_in(c, n, new, src))
- return;
- return rte_update_direct(c, n, new, src);
+ if (c->in_table)
+ rte_import(&c->in_table->push, n, new, src);
+ else
+ rte_update_direct(c, n, new, src);
}
-static void
+void
rte_update_direct(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
{
const struct filter *filter = c->in_filter;
@@ -1323,24 +1352,6 @@ rte_discard(net *net, rte *old) /* Non-filtered route deletion, used during garb
rte_update_unlock();
}
-/* Modify existing route by protocol hook, used for long-lived graceful restart */
-static inline void
-rte_modify(net *net, rte *old)
-{
- rte_update_lock();
-
- rte *new = old->sender->req->rte_modify(old, rte_update_pool);
- if (new != old)
- {
- if (new)
- new->flags = old->flags & ~REF_MODIFY;
-
- rte_recalculate(old->sender, net, new, 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)
@@ -1419,6 +1430,9 @@ rt_request_import(rtable *tab, struct rt_import_request *req)
hook->req = req;
hook->table = tab;
+ if (!hook->stale_set)
+ hook->stale_set = hook->stale_valid = hook->stale_pruning = hook->stale_pruned = 1;
+
rt_set_import_state(hook, TIS_UP);
hook->n = (node) {};
@@ -1499,20 +1513,41 @@ rt_stop_export(struct rt_export_request *req, void (*stopped)(struct rt_export_r
* routes to the routing table (by rte_update()). After that, all protocol
* routes (more precisely routes with @c as @sender) not sent during the
* refresh cycle but still in the table from the past are pruned. This is
- * implemented by marking all related routes as stale by REF_STALE flag in
- * rt_refresh_begin(), then marking all related stale routes with REF_DISCARD
- * flag in rt_refresh_end() and then removing such routes in the prune loop.
- */
+ * implemented by setting rte->stale_cycle to req->stale_set in rte_update()
+ * and then dropping all routes with old stale_cycle values in table prune loop. */
void
-rt_refresh_begin(rtable *t, struct rt_import_request *req)
+rt_refresh_begin(struct rt_import_request *req)
{
- FIB_WALK(&t->fib, net, n)
- {
- for (struct rte_storage *e = n->routes; e; e = e->next)
- if (e->rte.sender == req->hook)
- e->rte.flags |= REF_STALE;
- }
- FIB_WALK_END;
+ struct rt_import_hook *hook = req->hook;
+ ASSERT_DIE(hook);
+
+ ASSERT_DIE(hook->stale_set == hook->stale_valid);
+
+ /* If the pruning routine is too slow */
+ if ((hook->stale_pruned < hook->stale_valid) && (hook->stale_pruned + 128 < hook->stale_valid)
+ || (hook->stale_pruned > hook->stale_valid) && (hook->stale_pruned > hook->stale_valid + 128))
+ {
+ log(L_WARN "Route refresh flood in table %s", hook->table->name);
+ FIB_WALK(&hook->table->fib, net, n)
+ {
+ for (struct rte_storage *e = n->routes; e; e = e->next)
+ if (e->rte.sender == req->hook)
+ e->rte.stale_cycle = 0;
+ }
+ FIB_WALK_END;
+ hook->stale_set = 1;
+ hook->stale_valid = 0;
+ hook->stale_pruned = 0;
+ }
+ else if (!++hook->stale_set)
+ {
+ /* Let's reserve the stale_cycle zero value for always-invalid routes */
+ hook->stale_set = 1;
+ hook->stale_valid = 0;
+ }
+
+ if (req->trace_routes & D_STATES)
+ log(L_TRACE "%s: route refresh begin [%u]", req->name, hook->stale_set);
}
/**
@@ -1524,43 +1559,18 @@ rt_refresh_begin(rtable *t, struct rt_import_request *req)
* hook. See rt_refresh_begin() for description of refresh cycles.
*/
void
-rt_refresh_end(rtable *t, struct rt_import_request *req)
+rt_refresh_end(struct rt_import_request *req)
{
- int prune = 0;
-
- FIB_WALK(&t->fib, net, n)
- {
- for (struct rte_storage *e = n->routes; e; e = e->next)
- if ((e->rte.sender == req->hook) && (e->rte.flags & REF_STALE))
- {
- e->rte.flags |= REF_DISCARD;
- prune = 1;
- }
- }
- FIB_WALK_END;
-
- if (prune)
- rt_schedule_prune(t);
-}
+ struct rt_import_hook *hook = req->hook;
+ ASSERT_DIE(hook);
-void
-rt_modify_stale(rtable *t, struct rt_import_request *req)
-{
- int prune = 0;
+ hook->stale_valid++;
+ ASSERT_DIE(hook->stale_set == hook->stale_valid);
- FIB_WALK(&t->fib, net, n)
- {
- for (struct rte_storage *e = n->routes; e; e = e->next)
- if ((e->rte.sender == req->hook) && (e->rte.flags & REF_STALE) && !(e->rte.flags & REF_FILTERED))
- {
- e->rte.flags |= REF_MODIFY;
- prune = 1;
- }
- }
- FIB_WALK_END;
+ rt_schedule_prune(hook->table);
- if (prune)
- rt_schedule_prune(t);
+ if (req->trace_routes & D_STATES)
+ log(L_TRACE "%s: route refresh end [%u]", req->name, hook->stale_valid);
}
/**
@@ -1613,9 +1623,6 @@ rt_dump_all(void)
WALK_LIST2(t, n, routing_tables, n)
rt_dump(t);
-
- WALK_LIST2(t, n, deleted_routing_tables, n)
- rt_dump(t);
}
void
@@ -1658,9 +1665,6 @@ rt_dump_hooks_all(void)
WALK_LIST2(t, n, routing_tables, n)
rt_dump_hooks(t);
-
- WALK_LIST2(t, n, deleted_routing_tables, n)
- rt_dump_hooks(t);
}
static inline void
@@ -1796,9 +1800,7 @@ rt_free(resource *_r)
DBG("Deleting routing table %s\n", r->name);
ASSERT_DIE(r->use_count == 0);
-
- if (r->internal)
- return;
+ ASSERT_DIE(r->deleted);
r->config->table = NULL;
rem_node(&r->n);
@@ -1853,20 +1855,17 @@ rt_setup(pool *pp, struct rtable_config *cf)
fib_init(&t->fib, p, t->addr_type, sizeof(net), OFFSETOF(net, n), 0, NULL);
- if (!(t->internal = cf->internal))
- {
- init_list(&t->imports);
- init_list(&t->exports);
- hmap_init(&t->id_map, p, 1024);
- hmap_set(&t->id_map, 0);
+ init_list(&t->imports);
+ init_list(&t->exports);
+ hmap_init(&t->id_map, p, 1024);
+ hmap_set(&t->id_map, 0);
- init_list(&t->subscribers);
+ init_list(&t->subscribers);
- t->rt_event = ev_new_init(p, rt_event, t);
- t->last_rt_change = t->gc_time = current_time();
+ t->rt_event = ev_new_init(p, rt_event, t);
+ t->last_rt_change = t->gc_time = current_time();
- t->rl_pipe = (struct tbf) TBF_DEFAULT_LOG_LIMITS;
- }
+ t->rl_pipe = (struct tbf) TBF_DEFAULT_LOG_LIMITS;
return t;
}
@@ -1884,7 +1883,6 @@ rt_init(void)
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);
}
@@ -1925,6 +1923,13 @@ rt_prune_table(rtable *tab)
WALK_LIST2(ih, n, tab->imports, n)
if (ih->import_state == TIS_STOP)
rt_set_import_state(ih, TIS_FLUSHING);
+ else if ((ih->stale_valid != ih->stale_pruning) && (ih->stale_pruning == ih->stale_pruned))
+ {
+ ih->stale_pruning = ih->stale_valid;
+
+ if (ih->req->trace_routes & D_STATES)
+ log(L_TRACE "%s: table prune after refresh begin [%u]", ih->req->name, ih->stale_pruning);
+ }
FIB_ITERATE_INIT(fit, &tab->fib);
tab->prune_state = 2;
@@ -1936,22 +1941,11 @@ again:
rescan:
for (struct rte_storage *e=n->routes; e; e=e->next)
{
- if ((e->rte.sender->import_state == TIS_FLUSHING) || (e->rte.flags & REF_DISCARD))
- {
- if (limit <= 0)
- {
- FIB_ITERATE_PUT(fit);
- ev_schedule(tab->rt_event);
- return;
- }
-
- rte_discard(n, &e->rte);
- limit--;
-
- goto rescan;
- }
+ struct rt_import_hook *s = e->rte.sender;
- if (e->rte.flags & REF_MODIFY)
+ if ((s->import_state == TIS_FLUSHING) ||
+ (e->rte.stale_cycle < s->stale_valid) ||
+ (e->rte.stale_cycle > s->stale_set))
{
if (limit <= 0)
{
@@ -1960,7 +1954,7 @@ again:
return;
}
- rte_modify(n, &e->rte);
+ rte_discard(n, &e->rte);
limit--;
goto rescan;
@@ -1998,6 +1992,13 @@ again:
mb_free(ih);
rt_unlock_table(tab);
}
+ else if (ih->stale_pruning != ih->stale_pruned)
+ {
+ ih->stale_pruned = ih->stale_pruning;
+
+ if (ih->req->trace_routes & D_STATES)
+ log(L_TRACE "%s: table prune after refresh end [%u]", ih->req->name, ih->stale_pruned);
+ }
}
void
@@ -2204,7 +2205,10 @@ rt_next_hop_update_net(rtable *tab, net *n)
for (int i=0; i<count; i++)
{
_Bool nb = (new == updates[i].new), ob = (old_best == updates[i].old);
- const char *best_indicator[2][2] = { { "updated", "updated [-best]" }, { "updated [+best]", "updated [best]" } };
+ const char *best_indicator[2][2] = {
+ { "autoupdated", "autoupdated [-best]" },
+ { "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);
}
@@ -2308,11 +2312,12 @@ rt_unlock_table(rtable *r)
{
if (!--r->use_count && r->deleted)
{
- struct config *conf = r->deleted;
+ void *del_data = r->del_data;
+ void (*deleted)(void *) = r->deleted;
/* Delete the routing table by freeing its pool */
rt_shutdown(r);
- config_del_obstacle(conf);
+ deleted(del_data);
}
}
@@ -2323,6 +2328,8 @@ rt_find_table_config(struct config *cf, char *name)
return (sym && (sym->class == SYM_TABLE)) ? sym->table : NULL;
}
+static void rt_config_del_obstacle(void *data) { config_del_obstacle(data); }
+
/**
* rt_commit - commit new routing table configuration
* @new: new configuration
@@ -2361,9 +2368,10 @@ rt_commit(struct config *new, struct config *old)
else
{
DBG("\t%s: deleted\n", o->name);
- ot->deleted = old;
- config_add_obstacle(old);
rt_lock_table(ot);
+ ot->deleted = rt_config_del_obstacle;
+ ot->del_data = old;
+ config_add_obstacle(old);
rt_unlock_table(ot);
}
}
@@ -2442,285 +2450,6 @@ done:
/*
- * Import table
- */
-
-int
-rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
-{
- struct rtable *tab = c->in_table;
- net *net;
-
- if (new)
- net = net_get(tab, n);
- else
- {
- net = net_find(tab, n);
-
- if (!net)
- goto drop_withdraw;
- }
-
- /* Find the old rte */
- struct rte_storage **pos = rte_find(net, src);
- if (*pos)
- {
- rte *old = &(*pos)->rte;
- if (new && rte_same(old, new))
- {
- /* Refresh the old rte, continue with update to main rtable */
- if (old->flags & (REF_STALE | REF_DISCARD | REF_MODIFY))
- {
- old->flags &= ~(REF_STALE | REF_DISCARD | REF_MODIFY);
- return 1;
- }
-
- goto drop_update;
- }
-
- if (!new)
- CHANNEL_LIMIT_POP(c, RX);
-
- /* Move iterator if needed */
- if (*pos == c->reload_next_rte)
- c->reload_next_rte = (*pos)->next;
-
- /* Remove the old rte */
- struct rte_storage *del = *pos;
- *pos = (*pos)->next;
- rte_free(del, tab);
- tab->rt_count--;
- }
- else if (new)
- {
- if (CHANNEL_LIMIT_PUSH(c, RX))
- {
- /* Required by rte_trace_in() */
- new->net = n;
-
- channel_rte_trace_in(D_FILTERS, c, new, "ignored [limit]");
- goto drop_update;
- }
- }
- else
- goto drop_withdraw;
-
- if (!new)
- {
- if (!net->routes)
- fib_delete(&tab->fib, net);
-
- return 1;
- }
-
- /* Insert the new rte */
- struct rte_storage *e = rte_store(new, net, tab);
- e->rte.lastmod = current_time();
- e->next = *pos;
- *pos = e;
- tab->rt_count++;
- return 1;
-
-drop_update:
- c->import_stats.updates_received++;
- c->in_req.hook->stats.updates_ignored++;
-
- if (!net->routes)
- fib_delete(&tab->fib, net);
-
- return 0;
-
-drop_withdraw:
- c->import_stats.withdraws_received++;
- c->in_req.hook->stats.withdraws_ignored++;
- return 0;
-}
-
-int
-rt_reload_channel(struct channel *c)
-{
- struct rtable *tab = c->in_table;
- struct fib_iterator *fit = &c->reload_fit;
- int max_feed = 64;
-
- ASSERT(c->channel_state == CS_UP);
-
- if (!c->reload_active)
- {
- FIB_ITERATE_INIT(fit, &tab->fib);
- c->reload_active = 1;
- }
-
- do {
- for (struct rte_storage *e = c->reload_next_rte; e; e = e->next)
- {
- if (max_feed-- <= 0)
- {
- c->reload_next_rte = e;
- debug("%s channel reload burst split (max_feed=%d)", c->proto->name, max_feed);
- return 0;
- }
-
- rte r = e->rte;
- rte_update_direct(c, r.net, &r, r.src);
- }
-
- c->reload_next_rte = NULL;
-
- FIB_ITERATE_START(&tab->fib, fit, net, n)
- {
- if (c->reload_next_rte = n->routes)
- {
- FIB_ITERATE_PUT_NEXT(fit, &tab->fib);
- break;
- }
- }
- FIB_ITERATE_END;
- }
- while (c->reload_next_rte);
-
- c->reload_active = 0;
- return 1;
-}
-
-void
-rt_reload_channel_abort(struct channel *c)
-{
- if (c->reload_active)
- {
- /* Unlink the iterator */
- fit_get(&c->in_table->fib, &c->reload_fit);
- c->reload_next_rte = NULL;
- c->reload_active = 0;
- }
-}
-
-void
-rt_prune_sync(rtable *t, int all)
-{
- struct fib_iterator fit;
-
- FIB_ITERATE_INIT(&fit, &t->fib);
-
-again:
- FIB_ITERATE_START(&t->fib, &fit, net, n)
- {
- struct rte_storage *e, **ee = &n->routes;
-
- while (e = *ee)
- {
- if (all || (e->rte.flags & (REF_STALE | REF_DISCARD)))
- {
- *ee = e->next;
- rte_free(e, t);
- t->rt_count--;
- }
- else
- ee = &e->next;
- }
-
- if (all || !n->routes)
- {
- FIB_ITERATE_PUT(&fit);
- fib_delete(&t->fib, n);
- goto again;
- }
- }
- FIB_ITERATE_END;
-}
-
-
-/*
- * Export table
- */
-
-int
-rte_update_out(struct channel *c, const net_addr *n, rte *new, const rte *old0, struct rte_storage **old_exported)
-{
- struct rtable *tab = c->out_table;
- struct rte_src *src;
- net *net;
-
- if (new)
- {
- net = net_get(tab, n);
- src = new->src;
- }
- else
- {
- net = net_find(tab, n);
- src = old0->src;
-
- if (!net)
- goto drop;
- }
-
- /* Find the old rte */
- struct rte_storage **pos = (c->ra_mode == RA_ANY) ? rte_find(net, src) : &net->routes;
- struct rte_storage *old = NULL;
-
- if (old = *pos)
- {
- if (new && rte_same(&(*pos)->rte, new))
- goto drop;
-
- /* Remove the old rte */
- *pos = old->next;
- *old_exported = old;
- tab->rt_count--;
- }
-
- if (!new)
- {
- if (!old)
- goto drop;
-
- if (!net->routes)
- fib_delete(&tab->fib, net);
-
- return 1;
- }
-
- /* Insert the new rte */
- struct rte_storage *e = rte_store(new, net, tab);
- e->rte.lastmod = current_time();
- e->next = *pos;
- *pos = e;
- tab->rt_count++;
- return 1;
-
-drop:
- return 0;
-}
-
-void
-rt_refeed_channel(struct channel *c)
-{
- if (!c->out_table)
- {
- channel_request_feeding(c);
- return;
- }
-
- ASSERT_DIE(c->ra_mode != RA_ANY);
-
- c->proto->feed_begin(c, 0);
-
- FIB_WALK(&c->out_table->fib, net, n)
- {
- if (!n->routes)
- continue;
-
- rte e = n->routes->rte;
- c->proto->rt_notify(c->proto, c, n->n.addr, &e, NULL);
- }
- FIB_WALK_END;
-
- c->proto->feed_end(c);
-}
-
-
-/*
* Hostcache
*/