summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaria Matejka <mq@ucw.cz>2022-09-09 13:52:37 +0200
committerMaria Matejka <mq@ucw.cz>2022-09-18 16:33:51 +0200
commitc49ee6e1a673fc1dc396857dbf8a73fa5d9d6b74 (patch)
tree33491b506b756017922c7f1ac3cdf3c6af14c771
parentb80823fe828a0687d4baae3c34c737d46fbf439c (diff)
Routing tables have their own service loops.
-rw-r--r--lib/locking.h1
-rw-r--r--nest/rt-table.c80
-rw-r--r--nest/rt.h4
3 files changed, 61 insertions, 24 deletions
diff --git a/lib/locking.h b/lib/locking.h
index 1df30063..498afdc8 100644
--- a/lib/locking.h
+++ b/lib/locking.h
@@ -15,6 +15,7 @@ struct domain_generic;
struct lock_order {
struct domain_generic *the_bird;
struct domain_generic *proto;
+ struct domain_generic *service;
struct domain_generic *rtable;
struct domain_generic *attrs;
struct domain_generic *resource;
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 08d67331..f596e808 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -131,6 +131,7 @@ 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_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,6 +143,7 @@ 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 *);
@@ -1437,7 +1439,7 @@ rt_kick_announce_exports(void *_tab)
{
RT_LOCKED((rtable *) _tab, tab)
if (!tm_active(tab->export_timer))
- tm_start(tab->export_timer, tab->config->export_settle_time);
+ tm_start_in(tab->export_timer, tab->config->export_settle_time, tab->loop);
}
static void
@@ -1463,7 +1465,7 @@ rt_import_announce_exports(void *_hook)
}
rt_trace(tab, D_EVENTS, "Announcing exports after imports from %s", hook->req->name);
- ev_schedule(tab->export_event);
+ ev_send_loop(tab->loop, tab->export_event);
}
}
@@ -2412,7 +2414,7 @@ rt_schedule_nhu(struct rtable_private *tab)
* NHU_RUNNING -> NHU_DIRTY
*/
if ((tab->nhu_state |= NHU_SCHEDULED) == NHU_SCHEDULED)
- ev_schedule(tab->nhu_event);
+ ev_send_loop(tab->loop, tab->nhu_event);
}
}
@@ -2420,7 +2422,7 @@ void
rt_schedule_prune(struct rtable_private *tab)
{
if (tab->prune_state == 0)
- ev_schedule(tab->rt_event);
+ ev_send_loop(tab->loop, tab->rt_event);
/* state change 0->1, 2->3 */
tab->prune_state |= 1;
@@ -2438,7 +2440,7 @@ rt_export_used(struct rt_table_exporter *e)
return;
tab->export_used = 1;
- ev_schedule(tab->rt_event);
+ ev_send_loop(tab->loop, tab->rt_event);
}
static void
@@ -2447,6 +2449,7 @@ rt_event(void *ptr)
RT_LOCKED((rtable *) ptr, tab)
{
+ ASSERT_DIE(birdloop_inside(tab->loop));
rt_lock_table(tab);
if (tab->export_used)
@@ -2477,7 +2480,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);
}
@@ -2676,6 +2679,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);
@@ -2709,6 +2714,7 @@ rt_setup(pool *pp, struct rtable_config *cf)
t->rt_event = ev_new_init(p, rt_event, t);
t->nhu_event = ev_new_init(p, rt_next_hop_update, t);
+ t->nhu_uncork_event = ev_new_init(p, rt_nhu_uncork, t);
t->export_event = ev_new_init(p, rt_kick_announce_exports, t);
t->export_timer = tm_new_init(p, rt_announce_exports, t, 0, 0);
t->prune_timer = tm_new_init(p, rt_prune_timer, t, 0, 0);
@@ -2737,6 +2743,9 @@ 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));
+
return RT_PUB(t);
}
@@ -2825,7 +2834,7 @@ again:
if (limit <= 0)
{
FIB_ITERATE_PUT(fit);
- ev_schedule(tab->rt_event);
+ ev_send_loop(tab->loop, tab->rt_event);
return;
}
@@ -2860,7 +2869,7 @@ again:
rt_trace(tab, D_EVENTS, "Prune done, scheduling export timer");
if (!tm_active(tab->export_timer))
- tm_start(tab->export_timer, tab->config->export_settle_time);
+ tm_start_in(tab->export_timer, tab->config->export_settle_time, tab->loop);
#ifdef DEBUGGING
fib_check(&tab->fib);
@@ -3082,7 +3091,7 @@ done:;
rt_kick_prune_timer(tab);
if (tab->export_used)
- ev_schedule(tab->rt_event);
+ ev_send_loop(tab->loop, tab->rt_event);
if (EMPTY_LIST(tab->exporter.pending) && tm_active(tab->export_timer))
@@ -3688,31 +3697,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");
+
+ ev_send_loop(tab->loop, tab->nhu_event);
}
+}
+
+static void
+rt_next_hop_update(void *_tab)
+{
+ RT_LOCKED((rtable *) _tab, 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->export_timer))
- tm_start(tab->export_timer, tab->config->export_settle_time);
+ tm_start_in(tab->export_timer, tab->config->export_settle_time, tab->loop);
tab->nhu_corked = tab->nhu_state;
tab->nhu_state = 0;
@@ -3738,7 +3760,7 @@ rt_next_hop_update(void *_tab)
if (max_feed <= 0)
{
FIB_ITERATE_PUT(fit);
- ev_schedule(tab->nhu_event);
+ ev_send_loop(tab->loop, tab->nhu_event);
RT_RETURN(tab);
}
lp_state lps;
@@ -3752,14 +3774,14 @@ rt_next_hop_update(void *_tab)
rt_trace(tab, D_EVENTS, "NHU done, scheduling export timer");
if (!tm_active(tab->export_timer))
- tm_start(tab->export_timer, tab->config->export_settle_time);
+ tm_start_in(tab->export_timer, tab->config->export_settle_time, tab->loop);
/* State change:
* NHU_DIRTY -> NHU_SCHEDULED
* NHU_RUNNING -> NHU_CLEAN
*/
if ((tab->nhu_state &= NHU_SCHEDULED) == NHU_SCHEDULED)
- ev_schedule(tab->nhu_event);
+ ev_send_loop(tab->loop, tab->nhu_event);
rt_unlock_table(tab);
@@ -3847,13 +3869,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. */
@@ -3864,6 +3895,8 @@ rt_delete(void *tab_)
rfree(tab->rp);
config_del_obstacle(conf);
+
+ birdloop_leave(&main_birdloop);
}
@@ -4366,7 +4399,8 @@ 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)
+ ev_send_loop(tab->loop, &hc->update);
}
diff --git a/nest/rt.h b/nest/rt.h
index 23231c0b..cd3745d6 100644
--- a/nest/rt.h
+++ b/nest/rt.h
@@ -111,6 +111,7 @@ struct rtable_private {
/* Here the private items not to be accessed without locking */
pool *rp; /* Resource pool to allocate everything from, including itself */
+ struct birdloop *loop; /* Service thread */
struct slab *rte_slab; /* Slab to allocate route objects */
struct fib fib;
struct f_trie *trie; /* Trie of prefixes defined in fib */
@@ -128,6 +129,7 @@ struct rtable_private {
*/
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 event *export_event; /* Event for export batching */
struct timer *export_timer; /* Timer for export batching */
struct timer *prune_timer; /* Timer for periodic pruning / GC */
@@ -188,7 +190,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);
}
}