summaryrefslogtreecommitdiff
path: root/nest
diff options
context:
space:
mode:
authorMaria Matejka <mq@ucw.cz>2022-10-04 16:15:36 +0200
committerMaria Matejka <mq@ucw.cz>2022-10-04 16:15:36 +0200
commitdc9351d326b9d2d8bcb7e9a0e5126878c2b02762 (patch)
tree842b9d21cc1f4b16869cac58711902f5b1f78b91 /nest
parent00679a688a5feff7a919cbeae71dd050ccc90b22 (diff)
parent67256d50359d42aca4e64bb1cb5dcb3c63669578 (diff)
Merge commit '67256d50' into HEAD
Diffstat (limited to 'nest')
-rw-r--r--nest/Makefile7
-rw-r--r--nest/cmds.c7
-rw-r--r--nest/config.Y12
-rw-r--r--nest/iface.c13
-rw-r--r--nest/iface.h2
-rw-r--r--nest/neighbor.c10
-rw-r--r--nest/proto.c62
-rw-r--r--nest/protocol.h9
-rw-r--r--nest/rt-table.c377
-rw-r--r--nest/rt.h25
10 files changed, 343 insertions, 181 deletions
diff --git a/nest/Makefile b/nest/Makefile
index 39617350..5b27da0c 100644
--- a/nest/Makefile
+++ b/nest/Makefile
@@ -2,14 +2,13 @@ src := cli.c cmds.c iface.c locks.c neighbor.c password.c proto.c proto-build.c
obj := $(src-o-files)
$(all-daemon)
$(cf-local)
-$(call proto-build,dev_build)
-$(proto-build-c): $(lastword $(MAKEFILE_LIST))
+$(objdir)/nest/proto-build.c: $(lastword $(MAKEFILE_LIST))
$(E)echo GEN $@
$(Q)echo "#include \"lib/birdlib.h\"" > $@
- $(Q)$(patsubst %,echo 'void %(void);' >> $@;,$(PROTO_BUILD))
+ $(Q)$(patsubst %,echo 'void %_build(void);' >> $@;,$(PROTO_BUILD))
$(Q)echo "void protos_build_gen(void) {" >> $@
- $(Q)$(patsubst %,echo ' %();'>>$@;,$(PROTO_BUILD))
+ $(Q)$(patsubst %,echo ' %_build();'>>$@;,$(PROTO_BUILD))
$(Q)echo "}" >> $@
tests_src :=
diff --git a/nest/cmds.c b/nest/cmds.c
index 092be48a..8a5bbdd4 100644
--- a/nest/cmds.c
+++ b/nest/cmds.c
@@ -109,7 +109,6 @@ print_size(char *dsc, struct resmem vals)
extern pool *rt_table_pool;
extern pool *rta_pool;
-extern uint *pages_kept;
void
cmd_show_memory(void)
@@ -121,8 +120,10 @@ cmd_show_memory(void)
print_size("Protocols:", rmemsize(proto_pool));
struct resmem total = rmemsize(&root_pool);
#ifdef HAVE_MMAP
- print_size("Standby memory:", (struct resmem) { .overhead = page_size * *pages_kept });
- total.overhead += page_size * *pages_kept;
+ int pk = atomic_load_explicit(&pages_kept, memory_order_relaxed)
+ + atomic_load_explicit(&pages_kept_locally, memory_order_relaxed);
+ print_size("Standby memory:", (struct resmem) { .overhead = page_size * pk });
+ total.overhead += page_size * pk;
#endif
print_size("Total:", total);
cli_msg(0, "");
diff --git a/nest/config.Y b/nest/config.Y
index 84c76ae9..f2904882 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -125,7 +125,7 @@ CF_KEYWORDS(TIMEFORMAT, ISO, SHORT, LONG, ROUTE, PROTOCOL, BASE, LOG, S, MS, US)
CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, AS)
CF_KEYWORDS(MIN, IDLE, RX, TX, INTERVAL, MULTIPLIER, PASSIVE)
CF_KEYWORDS(CHECK, LINK)
-CF_KEYWORDS(CORK, SORTED, TRIE, MIN, MAX, SETTLE, TIME, GC, THRESHOLD, PERIOD)
+CF_KEYWORDS(CORK, SORTED, TRIE, MIN, MAX, ROA, ROUTE, REFRESH, SETTLE, TIME, GC, THRESHOLD, PERIOD)
/* For r_args_channel */
CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, IPV6_SADR, VPN4, VPN4_MC, VPN4_MPLS, VPN6, VPN6_MC, VPN6_MPLS, ROA4, ROA6, FLOW4, FLOW6, MPLS, PRI, SEC)
@@ -233,6 +233,8 @@ table_opt:
if ($3 > $4) cf_error("Cork low threshold must be lower than the high threshold.");
this_table->cork_threshold.low = $3;
this_table->cork_threshold.high = $4; }
+ | EXPORT SETTLE TIME settle { this_table->export_settle = $4; }
+ | ROUTE REFRESH EXPORT SETTLE TIME settle { this_table->export_rr_settle = $6; }
| DEBUG bool { this_table->debug = $2; }
;
@@ -294,8 +296,8 @@ proto_item:
| MRTDUMP mrtdump_mask { this_proto->mrtdump = $2; }
| ROUTER ID idval { this_proto->router_id = $3; }
| DESCRIPTION text { this_proto->dsc = $2; }
- | VRF text { this_proto->vrf = if_get_by_name($2); this_proto->vrf_set = 1; }
- | VRF DEFAULT { this_proto->vrf = NULL; this_proto->vrf_set = 1; }
+ | VRF text { this_proto->vrf = if_get_by_name($2); }
+ | VRF DEFAULT { this_proto->vrf = &default_vrf; }
;
@@ -321,8 +323,7 @@ channel_item_:
| RECEIVE LIMIT limit_spec { this_channel->rx_limit = $3; }
| IMPORT LIMIT limit_spec { this_channel->in_limit = $3; }
| EXPORT LIMIT limit_spec { this_channel->out_limit = $3; }
- | MIN SETTLE TIME expr_us { this_channel->min_settle_time = $4; }
- | MAX SETTLE TIME expr_us { this_channel->max_settle_time = $4; }
+ | ROA SETTLE TIME settle { this_channel->roa_settle = $4; }
| PREFERENCE expr { this_channel->preference = $2; check_u16($2); }
| IMPORT KEEP FILTERED bool {
if ($4)
@@ -424,7 +425,6 @@ timeformat_base:
TIMEFORMAT timeformat_spec ';'
;
-
/* Interface patterns */
iface_patt_node_init:
diff --git a/nest/iface.c b/nest/iface.c
index 682340c5..fc896e26 100644
--- a/nest/iface.c
+++ b/nest/iface.c
@@ -37,6 +37,7 @@
static pool *if_pool;
list iface_list;
+struct iface default_vrf;
static void if_recalc_preferred(struct iface *i);
@@ -147,7 +148,7 @@ ifa_send_notify(struct proto *p, unsigned c, struct ifa *a)
{
if (p->ifa_notify &&
(p->proto_state != PS_DOWN) &&
- (!p->vrf_set || p->vrf == a->iface->master))
+ (!p->vrf || p->vrf == a->iface->master))
{
if (p->debug & D_IFACES)
log(L_TRACE "%s < address %N on interface %s %s",
@@ -185,7 +186,7 @@ if_send_notify(struct proto *p, unsigned c, struct iface *i)
{
if (p->if_notify &&
(p->proto_state != PS_DOWN) &&
- (!p->vrf_set || p->vrf == i->master))
+ (!p->vrf || p->vrf == i->master))
{
if (p->debug & D_IFACES)
log(L_TRACE "%s < interface %s %s", p->name, i->name,
@@ -243,7 +244,7 @@ if_recalc_flags(struct iface *i UNUSED, uint flags)
{
if ((flags & IF_ADMIN_UP) &&
!(flags & (IF_SHUTDOWN | IF_TMP_DOWN)) &&
- !(i->master_index && !i->master))
+ !(i->master_index && i->master == &default_vrf))
flags |= IF_UP;
else
flags &= ~IF_UP;
@@ -301,6 +302,9 @@ if_update(struct iface *new)
struct iface *i;
unsigned c;
+ if (!new->master)
+ new->master = &default_vrf;
+
WALK_LIST(i, iface_list)
if (!strcmp(new->name, i->name))
{
@@ -711,6 +715,7 @@ if_init(void)
{
if_pool = rp_new(&root_pool, "Interfaces");
init_list(&iface_list);
+ strcpy(default_vrf.name, "default");
neigh_init(if_pool);
}
@@ -843,7 +848,7 @@ if_show(void)
continue;
char mbuf[16 + sizeof(i->name)] = {};
- if (i->master)
+ if (i->master != &default_vrf)
bsprintf(mbuf, " master=%s", i->master->name);
else if (i->master_index)
bsprintf(mbuf, " master=#%u", i->master_index);
diff --git a/nest/iface.h b/nest/iface.h
index 1189cdd4..13f3bd12 100644
--- a/nest/iface.h
+++ b/nest/iface.h
@@ -28,6 +28,8 @@ struct ifa { /* Interface address */
unsigned flags; /* Analogous to iface->flags */
};
+extern struct iface default_vrf;
+
struct iface {
node n;
char name[16];
diff --git a/nest/neighbor.c b/nest/neighbor.c
index 7cf9c85d..81da24d5 100644
--- a/nest/neighbor.c
+++ b/nest/neighbor.c
@@ -142,7 +142,7 @@ if_connected(ip_addr a, struct iface *i, struct ifa **ap, uint flags)
}
static inline int
-if_connected_any(ip_addr a, struct iface *vrf, uint vrf_set, struct iface **iface, struct ifa **addr, uint flags)
+if_connected_any(ip_addr a, struct iface *vrf, struct iface **iface, struct ifa **addr, uint flags)
{
struct iface *i;
struct ifa *b;
@@ -153,7 +153,7 @@ if_connected_any(ip_addr a, struct iface *vrf, uint vrf_set, struct iface **ifac
/* Prefer SCOPE_HOST or longer prefix */
WALK_LIST(i, iface_list)
- if ((!vrf_set || vrf == i->master) && ((s = if_connected(a, i, &b, flags)) >= 0))
+ if ((!vrf || vrf == i->master) && ((s = if_connected(a, i, &b, flags)) >= 0))
if (scope_better(s, scope) || (scope_remote(s, scope) && ifa_better(b, *addr)))
{
*iface = i;
@@ -245,7 +245,7 @@ neigh_find(struct proto *p, ip_addr a, struct iface *iface, uint flags)
iface = (scope < 0) ? NULL : iface;
}
else
- scope = if_connected_any(a, p->vrf, p->vrf_set, &iface, &addr, flags);
+ scope = if_connected_any(a, p->vrf, &iface, &addr, flags);
/* scope < 0 means i don't know neighbor */
/* scope >= 0 <=> iface != NULL */
@@ -369,7 +369,7 @@ neigh_update(neighbor *n, struct iface *iface)
return;
/* VRF-bound neighbors ignore changes in other VRFs */
- if (p->vrf_set && (p->vrf != iface->master))
+ if (p->vrf && (p->vrf != iface->master))
return;
scope = if_connected(n->addr, iface, &ifa, n->flags);
@@ -379,7 +379,7 @@ neigh_update(neighbor *n, struct iface *iface)
{
/* When neighbor is going down, try to respawn it on other ifaces */
if ((scope < 0) && (n->scope >= 0) && !n->ifreq && (n->flags & NEF_STICKY))
- scope = if_connected_any(n->addr, p->vrf, p->vrf_set, &iface, &ifa, n->flags);
+ scope = if_connected_any(n->addr, p->vrf, &iface, &ifa, n->flags);
}
else
{
diff --git a/nest/proto.c b/nest/proto.c
index 783a936c..319b35dd 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -315,16 +315,15 @@ proto_remove_channels(struct proto *p)
struct roa_subscription {
node roa_node;
- timer t;
- btime base_settle_time; /* Start of settling interval */
+ struct settle settle;
struct channel *c;
struct rt_export_request req;
};
static void
-channel_roa_in_changed(struct timer *t)
+channel_roa_in_changed(struct settle *se)
{
- struct roa_subscription *s = SKIP_BACK(struct roa_subscription, t, t);
+ struct roa_subscription *s = SKIP_BACK(struct roa_subscription, settle, se);
struct channel *c = s->c;
int active = !!c->reload_req.hook;
@@ -337,9 +336,9 @@ channel_roa_in_changed(struct timer *t)
}
static void
-channel_roa_out_changed(struct timer *t)
+channel_roa_out_changed(struct settle *se)
{
- struct roa_subscription *s = SKIP_BACK(struct roa_subscription, t, t);
+ struct roa_subscription *s = SKIP_BACK(struct roa_subscription, settle, se);
struct channel *c = s->c;
CD(c, "Feeding triggered by RPKI change");
@@ -356,17 +355,7 @@ channel_export_one_roa(struct rt_export_request *req, const net_addr *net UNUSED
struct roa_subscription *s = SKIP_BACK(struct roa_subscription, req, req);
/* TODO: use the information about what roa has changed */
-
- if (!tm_active(&s->t))
- {
- s->base_settle_time = current_time();
- tm_start(&s->t, s->base_settle_time + s->c->min_settle_time);
- }
- else
- tm_set(&s->t,
- MIN(s->base_settle_time + s->c->max_settle_time,
- current_time() + s->c->min_settle_time));
-
+ settle_kick(&s->settle, &main_birdloop);
rpe_mark_seen_all(req->hook, first, NULL);
}
@@ -380,14 +369,14 @@ channel_dump_roa_req(struct rt_export_request *req)
debug(" Channel %s.%s ROA %s change notifier from table %s request %p\n",
c->proto->name, c->name,
- (s->t.hook == channel_roa_in_changed) ? "import" : "export",
+ (s->settle.hook == channel_roa_in_changed) ? "import" : "export",
tab->name, req);
}
static int
channel_roa_is_subscribed(struct channel *c, rtable *tab, int dir)
{
- void (*hook)(struct timer *) =
+ void (*hook)(struct settle *) =
dir ? channel_roa_in_changed : channel_roa_out_changed;
struct roa_subscription *s;
@@ -395,7 +384,7 @@ channel_roa_is_subscribed(struct channel *c, rtable *tab, int dir)
WALK_LIST2(s, n, c->roa_subscriptions, roa_node)
if ((tab == SKIP_BACK(rtable, priv.exporter.e, s->req.hook->table))
- && (s->t.hook == hook))
+ && (s->settle.hook == hook))
return 1;
return 0;
@@ -410,7 +399,7 @@ channel_roa_subscribe(struct channel *c, rtable *tab, int dir)
struct roa_subscription *s = mb_allocz(c->proto->pool, sizeof(struct roa_subscription));
*s = (struct roa_subscription) {
- .t = { .hook = dir ? channel_roa_in_changed : channel_roa_out_changed, },
+ .settle = SETTLE_INIT(&c->roa_settle, dir ? channel_roa_in_changed : channel_roa_out_changed, NULL),
.c = c,
.req = {
.name = mb_sprintf(c->proto->pool, "%s.%s.roa-%s.%s",
@@ -934,8 +923,10 @@ channel_config_new(const struct channel_class *cc, const char *name, uint net_ty
cf->debug = new_config->channel_default_debug;
cf->rpki_reload = 1;
- cf->min_settle_time = 1 S;
- cf->max_settle_time = 20 S;
+ cf->roa_settle = (struct settle_config) {
+ .min = 1 S,
+ .max = 20 S,
+ };
add_tail(&proto->channels, &cf->n);
@@ -1017,20 +1008,20 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
c->in_req.trace_routes = c->out_req.trace_routes = c->debug | c->proto->debug;
c->rpki_reload = cf->rpki_reload;
- if ( (c->min_settle_time != cf->min_settle_time)
- || (c->max_settle_time != cf->max_settle_time))
+ if ( (c->roa_settle.min != cf->roa_settle.min)
+ || (c->roa_settle.max != cf->roa_settle.max))
{
- c->min_settle_time = cf->min_settle_time;
- c->max_settle_time = cf->max_settle_time;
+ c->roa_settle = cf->roa_settle;
struct roa_subscription *s;
node *n;
WALK_LIST2(s, n, c->roa_subscriptions, roa_node)
- if (tm_active(&s->t))
- tm_set(&s->t,
- MIN(s->base_settle_time + c->max_settle_time,
- current_time() + c->min_settle_time));
+ {
+ s->settle.cf = cf->roa_settle;
+ if (settle_active(&s->settle))
+ settle_kick(&s->settle, &main_birdloop);
+ }
}
/* Execute channel-specific reconfigure hook */
@@ -1156,6 +1147,7 @@ proto_event(void *ptr)
{
if (p->proto == &proto_unix_iface)
if_flush_ifaces(p);
+
p->do_stop = 0;
}
@@ -1208,7 +1200,6 @@ proto_init(struct proto_config *c, node *n)
p->proto_state = PS_DOWN;
p->last_state_change = current_time();
p->vrf = c->vrf;
- p->vrf_set = c->vrf_set;
insert_node(&p->n, n);
p->event = ev_new_init(proto_pool, proto_event, p);
@@ -1385,8 +1376,7 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
if ((nc->protocol != oc->protocol) ||
(nc->net_type != oc->net_type) ||
(nc->disabled != p->disabled) ||
- (nc->vrf != oc->vrf) ||
- (nc->vrf_set != oc->vrf_set))
+ (nc->vrf != oc->vrf))
return 0;
p->name = nc->name;
@@ -2305,8 +2295,8 @@ proto_cmd_show(struct proto *p, uintptr_t verbose, int cnt)
cli_msg(-1006, " Message: %s", p->message);
if (p->cf->router_id)
cli_msg(-1006, " Router ID: %R", p->cf->router_id);
- if (p->vrf_set)
- cli_msg(-1006, " VRF: %s", p->vrf ? p->vrf->name : "default");
+ if (p->vrf)
+ cli_msg(-1006, " VRF: %s", p->vrf->name);
if (p->proto->show_proto_info)
p->proto->show_proto_info(p);
diff --git a/nest/protocol.h b/nest/protocol.h
index c88598cc..892d1890 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -12,6 +12,7 @@
#include "lib/lists.h"
#include "lib/resource.h"
#include "lib/event.h"
+#include "lib/settle.h"
#include "nest/rt.h"
#include "nest/limit.h"
#include "conf/conf.h"
@@ -99,7 +100,6 @@ struct proto_config {
int class; /* SYM_PROTO or SYM_TEMPLATE */
u8 net_type; /* Protocol network type (NET_*), 0 for undefined */
u8 disabled; /* Protocol enabled/disabled by default */
- u8 vrf_set; /* Related VRF instance (below) is defined */
u8 late_if_feed; /* Delay interface feed after channels are up */
u32 debug, mrtdump; /* Debugging bitfields, both use D_* constants */
u32 router_id; /* Protocol specific router ID */
@@ -136,7 +136,6 @@ struct proto {
uint active_loops; /* Number of active IO loops */
byte net_type; /* Protocol network type (NET_*), 0 for undefined */
byte disabled; /* Manually disabled */
- byte vrf_set; /* Related VRF instance (above) is defined */
byte proto_state; /* Protocol state machine (PS_*, see below) */
byte active; /* From PS_START to cleanup after PS_STOP */
byte do_stop; /* Stop actions are scheduled */
@@ -459,8 +458,7 @@ struct channel_config {
struct channel_limit in_limit; /* Limit for importing routes from protocol */
struct channel_limit out_limit; /* Limit for exporting routes to protocol */
- btime min_settle_time; /* Minimum settle time for ROA-induced reload */
- btime max_settle_time; /* Maximum settle time for ROA-induced reload */
+ struct settle_config roa_settle; /* Settle times for ROA-induced reload */
u8 net_type; /* Routing table network type (NET_*), 0 for undefined */
u8 ra_mode; /* Mode of received route advertisements (RA_*) */
@@ -489,8 +487,7 @@ struct channel {
struct limit in_limit; /* Input limit */
struct limit out_limit; /* Output limit */
- btime min_settle_time; /* Minimum settle time for ROA-induced reload */
- btime max_settle_time; /* Maximum settle time for ROA-induced reload */
+ struct settle_config roa_settle; /* Settle times for ROA-induced reload */
u8 limit_actions[PLD_MAX]; /* Limit actions enum */
u8 limit_active; /* Flags for active limits */
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 95248635..36d69d92 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -130,7 +130,8 @@ struct rt_export_block {
static void rt_free_hostcache(struct rtable_private *tab);
static void rt_update_hostcache(void *tab);
-static void rt_next_hop_update(void *tab);
+static void rt_next_hop_update(struct rtable_private *tab);
+static void rt_nhu_uncork(void *_tab);
static inline void rt_next_hop_resolve_rte(rte *r);
static inline void rt_flowspec_resolve_rte(rte *r, struct channel *c);
static inline void rt_prune_table(struct rtable_private *tab);
@@ -142,9 +143,10 @@ static void rt_feed_for(void *);
static void rt_check_cork_low(struct rtable_private *tab);
static void rt_check_cork_high(struct rtable_private *tab);
static void rt_cork_release_hook(void *);
+static void rt_shutdown(void *);
static void rt_delete(void *);
-static void rt_export_used(struct rt_table_exporter *);
+static void rt_export_used(struct rt_table_exporter *, const char *, const char *);
static void rt_export_cleanup(struct rtable_private *tab);
static int rte_same(rte *x, rte *y);
@@ -160,6 +162,7 @@ const char *rt_import_state_name_array[TIS_MAX] = {
const char *rt_export_state_name_array[TES_MAX] = {
[TES_DOWN] = "DOWN",
+ [TES_HUNGRY] = "HUNGRY",
[TES_FEEDING] = "FEEDING",
[TES_READY] = "READY",
[TES_STOP] = "STOP"
@@ -183,8 +186,12 @@ const char *rt_export_state_name(u8 state)
static struct hostentry *rt_get_hostentry(struct rtable_private *tab, ip_addr a, ip_addr ll, rtable *dep);
+static inline rtable *rt_priv_to_pub(struct rtable_private *tab) { return RT_PUB(tab); }
+static inline rtable *rt_pub_to_pub(rtable *tab) { return tab; }
+#define RT_ANY_TO_PUB(tab) _Generic((tab),rtable*:rt_pub_to_pub,struct rtable_private*:rt_priv_to_pub)((tab))
+
#define rt_trace(tab, level, fmt, args...) do {\
- struct rtable_private *t = (tab); \
+ rtable *t = RT_ANY_TO_PUB((tab)); \
if (t->config->debug & (level)) \
log(L_TRACE "%s: " fmt, t->name, ##args); \
} while (0)
@@ -1416,9 +1423,9 @@ rt_send_export_event(struct rt_export_hook *hook)
}
static void
-rt_announce_exports(timer *tm)
+rt_announce_exports(struct settle *s)
{
- RT_LOCKED((rtable *) tm->data, tab)
+ RT_LOCKED(RT_PUB(SKIP_BACK(struct rtable_private, export_settle, s)), tab)
if (!EMPTY_LIST(tab->exporter.pending))
{
struct rt_export_hook *c; node *n;
@@ -1433,32 +1440,37 @@ rt_announce_exports(timer *tm)
}
static void
+rt_kick_export_settle(struct rtable_private *tab)
+{
+ tab->export_settle.cf = tab->rr_counter ? tab->config->export_rr_settle : tab->config->export_settle;
+ settle_kick(&tab->export_settle, tab->loop);
+}
+
+static void
rt_import_announce_exports(void *_hook)
{
struct rt_import_hook *hook = _hook;
- RT_LOCKED(hook->table, tab)
+ if (hook->import_state == TIS_CLEARED)
{
- if (hook->import_state == TIS_CLEARED)
+ void (*stopped)(struct rt_import_request *) = hook->stopped;
+ struct rt_import_request *req = hook->req;
+
+ RT_LOCKED(hook->table, tab)
{
- void (*stopped)(struct rt_import_request *) = hook->stopped;
- struct rt_import_request *req = hook->req;
req->hook = NULL;
rt_trace(tab, D_EVENTS, "Hook %s stopped", req->name);
rem_node(&hook->n);
mb_free(hook);
rt_unlock_table(tab);
- RT_UNLOCK(tab);
-
- stopped(req);
- return;
}
- 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);
+ stopped(req);
+ return;
}
+
+ rt_trace(hook->table, D_EVENTS, "Announcing exports after imports from %s", hook->req->name);
+ birdloop_flag(hook->table->loop, RTF_EXPORT);
}
static struct rt_pending_export *
@@ -1494,7 +1506,7 @@ rt_export_hook(void *_data)
if (!c->rpe_next)
{
- rt_export_used(c->table);
+ rt_export_used(c->table, c->h.req->name, "done exporting");
RT_UNLOCK(tab);
return;
}
@@ -1515,7 +1527,7 @@ rt_export_hook(void *_data)
if (used)
RT_LOCKED(tab, _)
- rt_export_used(c->table);
+ rt_export_used(c->table, c->h.req->name, "finished export bulk");
rt_send_export_event(&c->h);
}
@@ -1957,7 +1969,7 @@ rt_table_export_done(void *hh)
DBG("Export hook %p in table %s finished uc=%u\n", hook, tab->name, tab->use_count);
/* Drop pending exports */
- rt_export_used(&tab->exporter);
+ rt_export_used(&tab->exporter, hook->h.req->name, "stopped");
/* Do the common code; this frees the hook */
rt_export_stopped(&hook->h);
@@ -1996,9 +2008,10 @@ void
rt_set_export_state(struct rt_export_hook *hook, u8 state)
{
hook->last_state_change = current_time();
- atomic_store_explicit(&hook->export_state, state, memory_order_release);
+ u8 old = atomic_exchange_explicit(&hook->export_state, state, memory_order_release);
- CALL(hook->req->log_state_change, hook->req, state);
+ if (old != state)
+ CALL(hook->req->log_state_change, hook->req, state);
}
void
@@ -2033,9 +2046,46 @@ rt_stop_import(struct rt_import_request *req, void (*stopped)(struct rt_import_r
rt_schedule_prune(tab);
rt_set_import_state(hook, TIS_STOP);
hook->stopped = stopped;
+
+ if (hook->stale_set != hook->stale_pruned)
+ tab->rr_counter -= (hook->stale_set - hook->stale_pruned - 1);
+ else
+ tab->rr_counter++;
+
+ hook->stale_set = hook->stale_pruned = hook->stale_pruning = hook->stale_valid = 0;
}
}
+static void rt_table_export_start_feed(struct rtable_private *tab, struct rt_table_export_hook *hook);
+static void
+rt_table_export_uncork(void *_hook)
+{
+ ASSERT_DIE(birdloop_inside(&main_birdloop));
+
+ struct rt_table_export_hook *hook = _hook;
+ struct birdloop *loop = hook->h.req->list->loop;
+
+ if (loop != &main_birdloop)
+ birdloop_enter(loop);
+
+ u8 state;
+ switch (state = atomic_load_explicit(&hook->h.export_state, memory_order_relaxed))
+ {
+ case TES_HUNGRY:
+ RT_LOCKED(RT_PUB(SKIP_BACK(struct rtable_private, exporter, hook->table)), tab)
+ rt_table_export_start_feed(tab, hook);
+ break;
+ case TES_STOP:
+ rt_stop_export_common(&hook->h);
+ break;
+ default:
+ bug("Uncorking a table export in a strange state: %u", state);
+ }
+
+ if (loop != &main_birdloop)
+ birdloop_leave(loop);
+}
+
static void
rt_table_export_start_locked(struct rtable_private *tab, struct rt_export_request *req)
{
@@ -2046,6 +2096,22 @@ rt_table_export_start_locked(struct rtable_private *tab, struct rt_export_reques
req->hook->req = req;
struct rt_table_export_hook *hook = SKIP_BACK(struct rt_table_export_hook, h, req->hook);
+ hook->h.event = (event) {
+ .hook = rt_table_export_uncork,
+ .data = hook,
+ };
+
+ if (rt_cork_check(&hook->h.event))
+ rt_set_export_state(&hook->h, TES_HUNGRY);
+ else
+ rt_table_export_start_feed(tab, hook);
+}
+
+static void
+rt_table_export_start_feed(struct rtable_private *tab, struct rt_table_export_hook *hook)
+{
+ struct rt_exporter *re = &tab->exporter.e;
+ struct rt_export_request *req = hook->h.req;
/* stats zeroed by mb_allocz */
switch (req->addr_mode)
@@ -2133,41 +2199,54 @@ rt_init_export(struct rt_exporter *re, struct rt_export_hook *hook)
rt_send_export_event(hook);
}
-static void
+static int
rt_table_export_stop_locked(struct rt_export_hook *hh)
{
struct rt_table_export_hook *hook = SKIP_BACK(struct rt_table_export_hook, h, hh);
struct rtable_private *tab = SKIP_BACK(struct rtable_private, exporter, hook->table);
- if (atomic_load_explicit(&hh->export_state, memory_order_relaxed) == TES_FEEDING)
- switch (hh->req->addr_mode)
- {
- case TE_ADDR_IN:
- if (hook->walk_lock)
- {
- rt_unlock_trie(tab, hook->walk_lock);
- hook->walk_lock = NULL;
- mb_free(hook->walk_state);
- hook->walk_state = NULL;
+ switch (atomic_load_explicit(&hh->export_state, memory_order_relaxed))
+ {
+ case TES_HUNGRY:
+ return 0;
+ case TES_FEEDING:
+ switch (hh->req->addr_mode)
+ {
+ case TE_ADDR_IN:
+ if (hook->walk_lock)
+ {
+ rt_unlock_trie(tab, hook->walk_lock);
+ hook->walk_lock = NULL;
+ mb_free(hook->walk_state);
+ hook->walk_state = NULL;
+ break;
+ }
+ /* fall through */
+ case TE_ADDR_NONE:
+ fit_get(&tab->fib, &hook->feed_fit);
break;
- }
- /* fall through */
- case TE_ADDR_NONE:
- fit_get(&tab->fib, &hook->feed_fit);
- break;
- }
+ }
+
+ }
+ return 1;
}
static void
rt_table_export_stop(struct rt_export_hook *hh)
{
struct rt_table_export_hook *hook = SKIP_BACK(struct rt_table_export_hook, h, hh);
+ int ok = 0;
rtable *t = SKIP_BACK(rtable, priv.exporter, hook->table);
if (RT_IS_LOCKED(t))
- rt_table_export_stop_locked(hh);
+ ok = rt_table_export_stop_locked(hh);
else
RT_LOCKED(t, tab)
- rt_table_export_stop_locked(hh);
+ ok = rt_table_export_stop_locked(hh);
+
+ if (ok)
+ rt_stop_export_common(hh);
+ else
+ rt_set_export_state(&hook->h, TES_STOP);
}
void
@@ -2177,19 +2256,25 @@ rt_stop_export(struct rt_export_request *req, void (*stopped)(struct rt_export_r
ASSERT_DIE(req->hook);
struct rt_export_hook *hook = req->hook;
- /* Cancel the feeder event */
- ev_postpone(&hook->event);
-
- /* Stop feeding from the exporter */
- CALL(hook->table->class->stop, hook);
-
- /* Reset the event as the stopped event */
- hook->event.hook = hook->table->class->done;
+ /* Set the stopped callback */
hook->stopped = stopped;
+ /* Run the stop code */
+ if (hook->table->class->stop)
+ hook->table->class->stop(hook);
+ else
+ rt_stop_export_common(hook);
+}
+
+void
+rt_stop_export_common(struct rt_export_hook *hook)
+{
/* Update export state */
rt_set_export_state(hook, TES_STOP);
+ /* Reset the event as the stopped event */
+ hook->event.hook = hook->table->class->done;
+
/* Run the stopped event */
rt_send_export_event(hook);
}
@@ -2230,6 +2315,7 @@ rt_refresh_begin(struct rt_import_request *req)
e->rte.stale_cycle = 0;
}
FIB_WALK_END;
+ tab->rr_counter -= (hook->stale_set - hook->stale_pruned - 1);
hook->stale_set = 1;
hook->stale_valid = 0;
hook->stale_pruned = 0;
@@ -2240,6 +2326,7 @@ rt_refresh_begin(struct rt_import_request *req)
/* Let's reserve the stale_cycle zero value for always-invalid routes */
hook->stale_set = 1;
hook->stale_valid = 0;
+ tab->rr_counter++;
}
if (req->trace_routes & D_STATES)
@@ -2391,22 +2478,18 @@ rt_schedule_nhu(struct rtable_private *tab)
if (tab->nhu_corked)
{
if (!(tab->nhu_corked & NHU_SCHEDULED))
- {
tab->nhu_corked |= NHU_SCHEDULED;
- rt_lock_table(tab);
- }
}
else if (!(tab->nhu_state & NHU_SCHEDULED))
{
rt_trace(tab, D_EVENTS, "Scheduling NHU");
- rt_lock_table(tab);
/* state change:
* NHU_CLEAN -> NHU_SCHEDULED
* NHU_RUNNING -> NHU_DIRTY
*/
if ((tab->nhu_state |= NHU_SCHEDULED) == NHU_SCHEDULED)
- ev_schedule(tab->nhu_event);
+ birdloop_flag(tab->loop, RTF_NHU);
}
}
@@ -2414,42 +2497,51 @@ void
rt_schedule_prune(struct rtable_private *tab)
{
if (tab->prune_state == 0)
- ev_schedule(tab->rt_event);
+ birdloop_flag(tab->loop, RTF_CLEANUP);
/* state change 0->1, 2->3 */
tab->prune_state |= 1;
}
static void
-rt_export_used(struct rt_table_exporter *e)
+rt_export_used(struct rt_table_exporter *e, const char *who, const char *why)
{
struct rtable_private *tab = SKIP_BACK(struct rtable_private, exporter, e);
ASSERT_DIE(RT_IS_LOCKED(tab));
- rt_trace(tab, D_EVENTS, "Export cleanup requested");
+ rt_trace(tab, D_EVENTS, "Export cleanup requested by %s %s", who, why);
if (tab->export_used)
return;
tab->export_used = 1;
- ev_schedule(tab->rt_event);
+ birdloop_flag(tab->loop, RTF_CLEANUP);
}
static void
-rt_event(void *ptr)
+rt_flag_handler(struct birdloop_flag_handler *fh, u32 flags)
{
- RT_LOCKED((rtable *) ptr, tab)
+ RT_LOCKED(RT_PUB(SKIP_BACK(struct rtable_private, fh, fh)), tab)
{
+ ASSERT_DIE(birdloop_inside(tab->loop));
+ rt_lock_table(tab);
- rt_lock_table(tab);
+ if (flags & RTF_NHU)
+ rt_next_hop_update(tab);
- if (tab->export_used)
- rt_export_cleanup(tab);
+ if (flags & RTF_EXPORT)
+ rt_kick_export_settle(tab);
- if (tab->prune_state)
- rt_prune_table(tab);
+ if (flags & RTF_CLEANUP)
+ {
+ if (tab->export_used)
+ rt_export_cleanup(tab);
+
+ if (tab->prune_state)
+ rt_prune_table(tab);
+ }
- rt_unlock_table(tab);
+ rt_unlock_table(tab);
}
}
@@ -2471,7 +2563,7 @@ rt_kick_prune_timer(struct rtable_private *tab)
/* Randomize GC period to +/- 50% */
btime gc_period = tab->config->gc_period;
gc_period = (gc_period / 2) + (random_u32() % (uint) gc_period);
- tm_start(tab->prune_timer, gc_period);
+ tm_start_in(tab->prune_timer, gc_period, tab->loop);
}
@@ -2516,6 +2608,14 @@ rt_flowspec_dump_req(struct rt_export_request *req)
debug(" Flowspec link for table %s (%p)\n", ln->dst->name, req);
}
+static void
+rt_flowspec_log_state_change(struct rt_export_request *req, u8 state)
+{
+ struct rt_flowspec_link *ln = SKIP_BACK(struct rt_flowspec_link, req, req);
+ rt_trace(ln->dst, D_STATES, "Flowspec link from %s export state changed to %s",
+ ln->src->name, rt_export_state_name(state));
+}
+
static struct rt_flowspec_link *
rt_flowspec_find_link(struct rtable_private *src, rtable *dst)
{
@@ -2523,6 +2623,7 @@ rt_flowspec_find_link(struct rtable_private *src, rtable *dst)
WALK_LIST2(hook, n, src->exporter.e.hooks, h.n)
switch (atomic_load_explicit(&hook->h.export_state, memory_order_acquire))
{
+ case TES_HUNGRY:
case TES_FEEDING:
case TES_READY:
if (hook->h.req->export_one == rt_flowspec_export_one)
@@ -2559,6 +2660,7 @@ rt_flowspec_link(rtable *src_pub, rtable *dst_pub)
.list = &global_work_list,
.trace_routes = src->config->debug,
.dump_req = rt_flowspec_dump_req,
+ .log_state_change = rt_flowspec_log_state_change,
.export_one = rt_flowspec_export_one,
};
@@ -2670,6 +2772,8 @@ uint rtable_max_id = 0;
rtable *
rt_setup(pool *pp, struct rtable_config *cf)
{
+ ASSERT_DIE(birdloop_inside(&main_birdloop));
+
pool *p = rp_newf(pp, "Routing table %s", cf->name);
struct rtable_private *t = ralloc(p, &rt_class);
@@ -2701,18 +2805,19 @@ rt_setup(pool *pp, struct rtable_config *cf)
hmap_init(&t->id_map, p, 1024);
hmap_set(&t->id_map, 0);
- t->rt_event = ev_new_init(p, rt_event, t);
- t->nhu_event = ev_new_init(p, rt_next_hop_update, t);
+ t->fh = (struct birdloop_flag_handler) { .hook = rt_flag_handler, };
+ t->nhu_uncork_event = ev_new_init(p, rt_nhu_uncork, t);
t->prune_timer = tm_new_init(p, rt_prune_timer, t, 0, 0);
t->last_rt_change = t->gc_time = current_time();
+ t->export_settle = SETTLE_INIT(&cf->export_settle, rt_announce_exports, NULL);
+
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,
};
@@ -2730,6 +2835,12 @@ rt_setup(pool *pp, struct rtable_config *cf)
t->flowspec_trie->ipv4 = (t->addr_type == NET_FLOW4);
}
+ /* Start the service thread */
+ t->loop = birdloop_new(p, DOMAIN_ORDER(service), mb_sprintf(p, "Routing tahle %s", t->name));
+ birdloop_enter(t->loop);
+ birdloop_flag_set_handler(t->loop, &t->fh);
+ birdloop_leave(t->loop);
+
return RT_PUB(t);
}
@@ -2818,7 +2929,7 @@ again:
if (limit <= 0)
{
FIB_ITERATE_PUT(fit);
- ev_schedule(tab->rt_event);
+ birdloop_flag(tab->loop, RTF_CLEANUP);
return;
}
@@ -2852,15 +2963,15 @@ 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);
+ rt_kick_export_settle(tab);
#ifdef DEBUGGING
fib_check(&tab->fib);
#endif
/* state change 2->0, 3->1 */
- tab->prune_state &= 1;
+ if (tab->prune_state &= 1)
+ birdloop_flag(tab->loop, RTF_CLEANUP);
if (tab->trie_new)
{
@@ -2902,9 +3013,11 @@ again:
ih->flush_seq = tab->exporter.next_seq;
rt_set_import_state(ih, TIS_WAITING);
flushed_channels++;
+ tab->rr_counter--;
}
else if (ih->stale_pruning != ih->stale_pruned)
{
+ tab->rr_counter -= (ih->stale_pruned - ih->stale_pruning);
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);
@@ -2932,6 +3045,7 @@ rt_export_cleanup(struct rtable_private *tab)
switch (atomic_load_explicit(&eh->h.export_state, memory_order_acquire))
{
case TES_DOWN:
+ case TES_HUNGRY:
continue;
case TES_READY:
@@ -3075,11 +3189,10 @@ done:;
rt_kick_prune_timer(tab);
if (tab->export_used)
- ev_schedule(tab->rt_event);
+ birdloop_flag(tab->loop, RTF_CLEANUP);
-
- if (EMPTY_LIST(tab->exporter.pending) && tm_active(tab->exporter.export_timer))
- tm_stop(tab->exporter.export_timer);
+ if (EMPTY_LIST(tab->exporter.pending))
+ settle_cancel(&tab->export_settle);
}
static void
@@ -3681,35 +3794,44 @@ rt_next_hop_update_net(struct rtable_private *tab, net *n)
}
static void
-rt_next_hop_update(void *_tab)
+rt_nhu_uncork(void *_tab)
{
RT_LOCKED((rtable *) _tab, tab)
{
-
- /* If called from an uncork hook, reset the state */
- if (tab->nhu_corked)
- {
+ ASSERT_DIE(tab->nhu_corked);
ASSERT_DIE(tab->nhu_state == 0);
+
+ /* Reset the state */
tab->nhu_state = tab->nhu_corked;
tab->nhu_corked = 0;
rt_trace(tab, D_STATES, "Next hop updater uncorked");
+
+ birdloop_flag(tab->loop, RTF_NHU);
}
+}
+
+static void
+rt_next_hop_update(struct rtable_private *tab)
+{
+ ASSERT_DIE(birdloop_inside(tab->loop));
+
+ if (tab->nhu_corked)
+ return;
if (!tab->nhu_state)
- bug("Called NHU event for no reason in table %s", tab->name);
+ return;
/* Check corkedness */
- if (rt_cork_check(tab->nhu_event))
+ if (rt_cork_check(tab->nhu_uncork_event))
{
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);
+ && !EMPTY_LIST(tab->exporter.pending))
+ rt_kick_export_settle(tab);
tab->nhu_corked = tab->nhu_state;
tab->nhu_state = 0;
- RT_RETURN(tab);
+ return;
}
struct fib_iterator *fit = &tab->nhu_fit;
@@ -3731,8 +3853,8 @@ rt_next_hop_update(void *_tab)
if (max_feed <= 0)
{
FIB_ITERATE_PUT(fit);
- ev_schedule(tab->nhu_event);
- RT_RETURN(tab);
+ birdloop_flag(tab->loop, RTF_NHU);
+ return;
}
lp_state lps;
lp_save(tmp_linpool, &lps);
@@ -3743,20 +3865,14 @@ rt_next_hop_update(void *_tab)
/* Finished NHU, cleanup */
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);
+ rt_kick_export_settle(tab);
/* State change:
* NHU_DIRTY -> NHU_SCHEDULED
* NHU_RUNNING -> NHU_CLEAN
*/
if ((tab->nhu_state &= NHU_SCHEDULED) == NHU_SCHEDULED)
- ev_schedule(tab->nhu_event);
-
- rt_unlock_table(tab);
-
- }
+ birdloop_flag(tab->loop, RTF_NHU);
}
void
@@ -3801,6 +3917,14 @@ rt_new_table(struct symbol *s, uint addr_type)
c->gc_period = (uint) -1; /* set in rt_postconfig() */
c->cork_threshold.low = 128;
c->cork_threshold.high = 512;
+ c->export_settle = (struct settle_config) {
+ .min = 1 MS,
+ .max = 100 MS,
+ };
+ c->export_rr_settle = (struct settle_config) {
+ .min = 100 MS,
+ .max = 3 S,
+ };
c->debug = new_config->table_debug;
add_tail(&new_config->tables, &c->n);
@@ -3840,13 +3964,22 @@ rt_unlock_table_priv(struct rtable_private *r, const char *file, uint line)
{
rt_trace(r, D_STATES, "Unlocked at %s:%d", file, line);
if (!--r->use_count && r->deleted)
- /* Schedule the delete event to finish this up */
- ev_send(&global_event_list, ev_new_init(r->rp, rt_delete, r));
+ /* Stop the service thread to finish this up */
+ ev_send(&global_event_list, ev_new_init(r->rp, rt_shutdown, r));
+}
+
+static void
+rt_shutdown(void *tab_)
+{
+ struct rtable_private *r = tab_;
+ birdloop_stop(r->loop, rt_delete, r);
}
static void
rt_delete(void *tab_)
{
+ birdloop_enter(&main_birdloop);
+
/* We assume that nobody holds the table reference now as use_count is zero.
* Anyway the last holder may still hold the lock. Therefore we lock and
* unlock it the last time to be sure that nobody is there. */
@@ -3857,6 +3990,8 @@ rt_delete(void *tab_)
rfree(tab->rp);
config_del_obstacle(conf);
+
+ birdloop_leave(&main_birdloop);
}
@@ -3970,7 +4105,11 @@ rt_commit(struct config *new, struct config *old)
rt_lock_table(tab);
if (tab->hostcache)
+ {
rt_stop_export(&tab->hostcache->req, NULL);
+ if (ev_get_list(&tab->hostcache->update) == &rt_cork.queue)
+ ev_postpone(&tab->hostcache->update);
+ }
rt_unlock_table(tab);
@@ -4091,9 +4230,6 @@ rt_feed_by_fib(void *data)
{
if ((c->h.req->addr_mode == TE_ADDR_NONE) || net_in_netX(n->n.addr, c->h.req->addr))
{
- if (atomic_load_explicit(&c->h.export_state, memory_order_acquire) != TES_FEEDING)
- return;
-
if (!rt_prepare_feed(c, n, &block))
{
FIB_ITERATE_PUT(fit);
@@ -4133,9 +4269,6 @@ rt_feed_by_trie(void *data)
if (!n)
continue;
- if (atomic_load_explicit(&c->h.export_state, memory_order_acquire) != TES_FEEDING)
- RT_RETURN(tab);
-
if (!rt_prepare_feed(c, n, &block))
{
RT_UNLOCK(tab);
@@ -4336,16 +4469,28 @@ hc_notify_dump_req(struct rt_export_request *req)
}
static void
+hc_notify_log_state_change(struct rt_export_request *req, u8 state)
+{
+ struct hostcache *hc = SKIP_BACK(struct hostcache, req, req);
+ rt_trace((rtable *) hc->update.data, D_STATES, "HCU Export state changed to %s", rt_export_state_name(state));
+}
+
+static void
hc_notify_export_one(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *first)
{
struct hostcache *hc = SKIP_BACK(struct hostcache, req, req);
/* No interest in this update, mark seen only */
- if (ev_active(&hc->update) || !trie_match_net(hc->trie, net))
- {
- rpe_mark_seen_all(req->hook, first, NULL);
+ int interested = 1;
+ RT_LOCKED((rtable *) hc->update.data, tab)
+ if (ev_active(&hc->update) || !trie_match_net(hc->trie, net))
+ {
+ rpe_mark_seen_all(req->hook, first, NULL);
+ interested = 0;
+ }
+
+ if (!interested)
return;
- }
/* This net may affect some hostentries, check the actual change */
rte *o = RTE_VALID_OR_NULL(first->old_best);
@@ -4359,7 +4504,10 @@ hc_notify_export_one(struct rt_export_request *req, const net_addr *net, struct
/* Yes, something has actually changed. Do the hostcache update. */
if (o != RTE_VALID_OR_NULL(new_best))
- ev_schedule_work(&hc->update);
+ RT_LOCKED((rtable *) hc->update.data, tab)
+ if ((atomic_load_explicit(&req->hook->export_state, memory_order_acquire) == TES_READY)
+ && !ev_active(&hc->update))
+ ev_send_loop(tab->loop, &hc->update);
}
@@ -4386,6 +4534,7 @@ rt_init_hostcache(struct rtable_private *tab)
.list = &global_work_list,
.trace_routes = tab->config->debug,
.dump_req = hc_notify_dump_req,
+ .log_state_change = hc_notify_log_state_change,
.export_one = hc_notify_export_one,
};
@@ -4522,6 +4671,10 @@ rt_update_hostcache(void *data)
struct hostcache *hc = tab->hostcache;
+ /* Shutdown shortcut */
+ if (!hc->req.hook)
+ RT_RETURN(tab);
+
if (rt_cork_check(&hc->update))
{
rt_trace(tab, D_STATES, "Hostcache update corked");
diff --git a/nest/rt.h b/nest/rt.h
index 3a8489e8..6ee2ce9b 100644
--- a/nest/rt.h
+++ b/nest/rt.h
@@ -19,6 +19,8 @@
#include "lib/route.h"
#include "lib/event.h"
#include "lib/rcu.h"
+#include "lib/io-loop.h"
+#include "lib/settle.h"
#include <stdatomic.h>
@@ -61,8 +63,10 @@ struct rtable_config {
byte sorted; /* Routes of network are sorted according to rte_better() */
byte trie_used; /* Rtable has attached trie */
byte debug; /* Whether to log */
- btime export_settle_time; /* Delay before exports are announced */
struct rt_cork_threshold cork_threshold; /* Cork threshold values */
+ struct settle_config export_settle; /* Export announcement settler */
+ struct settle_config export_rr_settle;/* Export announcement settler config valid when any
+ route refresh is running */
};
struct rt_export_hook;
@@ -85,7 +89,6 @@ struct rt_exporter {
struct rt_table_exporter {
struct rt_exporter e;
list pending; /* List of packed struct rt_pending_export */
- struct timer *export_timer;
struct rt_pending_export *first; /* First export to announce */
u64 next_seq; /* The next export will have this ID */
@@ -104,6 +107,7 @@ DEFINE_DOMAIN(rtable);
uint id; /* Integer table ID for fast lookup */ \
DOMAIN(rtable) lock; /* Lock to take to access the private parts */ \
struct rtable_config *config; /* Configuration of this table */ \
+ struct birdloop *loop; /* Service thread */ \
/* The complete rtable structure */
struct rtable_private {
@@ -127,12 +131,16 @@ struct rtable_private {
* delete as soon as use_count becomes 0 and remove
* obstacle from this routing table.
*/
- struct event *rt_event; /* Routing table event */
- struct event *nhu_event; /* Specific event for next hop update */
+ struct event *nhu_uncork_event; /* Helper event to schedule NHU on uncork */
+ struct settle export_settle; /* Export batching settle timer */
struct timer *prune_timer; /* Timer for periodic pruning / GC */
+ struct birdloop_flag_handler fh; /* Handler for simple events */
btime last_rt_change; /* Last time when route changed */
btime gc_time; /* Time of last GC */
uint gc_counter; /* Number of operations since last GC */
+ uint rr_counter; /* Number of currently running route refreshes,
+ in fact sum of (stale_set - stale_pruned) over all importers
+ + one for each TIS_FLUSHING importer */
byte prune_state; /* Table prune state, 1 -> scheduled, 2-> running */
byte prune_trie; /* Prune prefix trie during next table prune */
byte nhu_state; /* Next Hop Update state */
@@ -171,6 +179,11 @@ typedef union rtable {
#define RT_PRIV_SAME(tpriv, tpub) (&(tpub)->priv == (tpriv))
+/* Flags for birdloop_flag() */
+#define RTF_CLEANUP 1
+#define RTF_NHU 2
+#define RTF_EXPORT 4
+
extern struct rt_cork {
_Atomic uint active;
event_list queue;
@@ -187,7 +200,7 @@ static inline void rt_cork_release(void)
if (atomic_fetch_sub_explicit(&rt_cork.active, 1, memory_order_acq_rel) == 1)
{
synchronize_rcu();
- ev_schedule_work(&rt_cork.run);
+ ev_send(&global_work_list, &rt_cork.run);
}
}
@@ -356,6 +369,7 @@ struct rt_table_export_hook {
#define TIS_MAX 6
#define TES_DOWN 0
+#define TES_HUNGRY 1
#define TES_FEEDING 2
#define TES_READY 3
#define TES_STOP 4
@@ -417,6 +431,7 @@ int rpe_get_seen(struct rt_export_hook *hook, struct rt_pending_export *rpe);
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_stop_export_common(struct rt_export_hook *hook);
void rt_export_stopped(struct rt_export_hook *hook);
void rt_exporter_init(struct rt_exporter *re);