summaryrefslogtreecommitdiff
path: root/nest/rt-table.c
diff options
context:
space:
mode:
authorMaria Matejka <mq@ucw.cz>2022-08-31 14:01:59 +0200
committerMaria Matejka <mq@ucw.cz>2022-09-01 18:46:40 +0200
commitecdb1ec6eabbf0c47c410e9bb8551ab5d039a650 (patch)
treee1330a5e3b41789eb8e02801b4adead00fc89a59 /nest/rt-table.c
parent7450eea071941c683da158d6dfe8365288eed5b8 (diff)
Hostcache update notification converted to an export hook
Instead of synchronous notifications, we use the asynchronous export framework to notify also hostcache updates. This allows us to do the hostcache update and the subsequent next hop update notification without locking collisions.
Diffstat (limited to 'nest/rt-table.c')
-rw-r--r--nest/rt-table.c120
1 files changed, 73 insertions, 47 deletions
diff --git a/nest/rt-table.c b/nest/rt-table.c
index d4e0d63c..e23e766e 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -43,10 +43,10 @@
* all prefixes that may influence resolving of tracked next hops.
*
* When a best route changes in the src table, the hostcache is notified using
- * rt_notify_hostcache(), which immediately checks using the trie whether the
+ * an auxiliary export request, which checks using the trie whether the
* change is relevant and if it is, then it schedules asynchronous hostcache
* recomputation. The recomputation is done by rt_update_hostcache() (called
- * from rt_event() of src table), it walks through all hostentries and resolves
+ * as an event of src table), it walks through all hostentries and resolves
* them (by rt_update_hostentry()). It also updates the trie. If a change in
* hostentry resolution was found, then it schedules asynchronous nexthop
* recomputation of associated dst table. That is done by rt_next_hop_update()
@@ -130,8 +130,7 @@ struct rt_export_block {
};
static void rt_free_hostcache(rtable *tab);
-static void rt_notify_hostcache(rtable *tab, net *net);
-static void rt_update_hostcache(rtable *tab);
+static void rt_update_hostcache(void *tab);
static void rt_next_hop_update(rtable *tab);
static inline void rt_next_hop_resolve_rte(rte *r);
static inline void rt_flowspec_resolve_rte(rte *r, struct channel *c);
@@ -1280,9 +1279,6 @@ rte_announce(rtable *tab, net *net, struct rte_storage *new, struct rte_storage
if (old_best_valid)
old_best->rte.sender->stats.pref--;
- if (tab->hostcache)
- rt_notify_hostcache(tab, net);
-
if (!EMPTY_LIST(tab->flowspec_links))
rt_flowspec_notify(tab, net);
}
@@ -2238,8 +2234,8 @@ void
rt_dump_hooks(rtable *tab)
{
debug("Dump of hooks in routing table <%s>%s\n", tab->name, tab->deleted ? " (deleted)" : "");
- debug(" nhu_state=%u hcu_scheduled=%u use_count=%d rt_count=%u\n",
- tab->nhu_state, tab->hcu_scheduled, tab->use_count, tab->rt_count);
+ debug(" nhu_state=%u use_count=%d rt_count=%u\n",
+ tab->nhu_state, tab->use_count, tab->rt_count);
debug(" last_rt_change=%t gc_time=%t gc_counter=%d prune_state=%u\n",
tab->last_rt_change, tab->gc_time, tab->gc_counter, tab->prune_state);
@@ -2280,16 +2276,6 @@ rt_dump_hooks_all(void)
}
static inline void
-rt_schedule_hcu(rtable *tab)
-{
- if (tab->hcu_scheduled)
- return;
-
- tab->hcu_scheduled = 1;
- ev_schedule(tab->rt_event);
-}
-
-static inline void
rt_schedule_nhu(rtable *tab)
{
if (tab->nhu_state == NHU_CLEAN)
@@ -2336,25 +2322,15 @@ rt_event(void *ptr)
if (tab->export_used)
rt_export_cleanup(tab);
- if (
- tab->hcu_corked ||
- tab->nhu_corked ||
- (tab->hcu_scheduled || tab->nhu_state) && rt_cork_check(tab->uncork_event)
- )
+ if (tab->nhu_corked || tab->nhu_state && rt_cork_check(tab->uncork_event))
{
- if (!tab->hcu_corked && !tab->nhu_corked)
+ if (!tab->nhu_corked)
rt_trace(tab, D_STATES, "Next hop updater corked");
- tab->hcu_corked |= tab->hcu_scheduled;
- tab->hcu_scheduled = 0;
-
tab->nhu_corked |= tab->nhu_state;
tab->nhu_state = 0;
}
- if (tab->hcu_scheduled)
- rt_update_hostcache(tab);
-
if (tab->nhu_state)
rt_next_hop_update(tab);
@@ -2369,9 +2345,6 @@ rt_uncork_event(void *ptr)
{
rtable *tab = ptr;
- tab->hcu_scheduled |= tab->hcu_corked;
- tab->hcu_corked = 0;
-
tab->nhu_state |= tab->nhu_corked;
tab->nhu_corked = 0;
@@ -3719,6 +3692,9 @@ rt_reconfigure(rtable *tab, struct rtable_config *new, struct rtable_config *old
tab->name = new->name;
tab->config = new;
+ if (tab->hostcache)
+ tab->hostcache->req.trace_routes = new->debug;
+
tab->cork_threshold = new->cork_threshold;
if (new->cork_threshold.high != old->cork_threshold.high)
@@ -3771,6 +3747,10 @@ rt_commit(struct config *new, struct config *old)
tab->deleted = old;
config_add_obstacle(old);
rt_lock_table(tab);
+
+ if (tab->hostcache)
+ rt_stop_export(&tab->hostcache->req, NULL);
+
rt_unlock_table(tab);
}
}
@@ -4056,6 +4036,41 @@ hc_delete_hostentry(struct hostcache *hc, pool *p, struct hostentry *he)
}
static void
+hc_notify_dump_req(struct rt_export_request *req)
+{
+ debug(" Table %s (%p)\n", req->name, req);
+}
+
+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);
+ return;
+ }
+
+ /* This net may affect some hostentries, check the actual change */
+ rte *o = RTE_VALID_OR_NULL(first->old_best);
+ struct rte_storage *new_best = first->new_best;
+
+ RPE_WALK(first, rpe, NULL)
+ {
+ rpe_mark_seen(req->hook, rpe);
+ new_best = rpe->new_best;
+ }
+
+ /* Yes, something has actually changed. Do the hostcache update.
+ * We don't need any more updates until then. */
+ if (o != RTE_VALID_OR_NULL(new_best))
+ ev_schedule_work(&hc->update);
+}
+
+
+static void
rt_init_hostcache(rtable *tab)
{
struct hostcache *hc = mb_allocz(tab->rp, sizeof(struct hostcache));
@@ -4068,6 +4083,21 @@ rt_init_hostcache(rtable *tab)
hc->lp = lp_new(tab->rp);
hc->trie = f_new_trie(hc->lp, 0);
+ hc->update = (event) {
+ .hook = rt_update_hostcache,
+ .data = tab,
+ };
+
+ hc->req = (struct rt_export_request) {
+ .name = mb_sprintf(tab->rp, "%s.hcu.notifier", tab->name),
+ .list = &global_work_list,
+ .trace_routes = tab->config->debug,
+ .dump_req = hc_notify_dump_req,
+ .export_one = hc_notify_export_one,
+ };
+
+ rt_request_export(&tab->exporter, &hc->req);
+
tab->hostcache = hc;
}
@@ -4094,16 +4124,6 @@ rt_free_hostcache(rtable *tab)
*/
}
-static void
-rt_notify_hostcache(rtable *tab, net *net)
-{
- if (tab->hcu_scheduled)
- return;
-
- if (trie_match_net(tab->hostcache->trie, net->n.addr))
- rt_schedule_hcu(tab);
-}
-
static int
if_local_addr(ip_addr a, struct iface *i)
{
@@ -4200,9 +4220,17 @@ done:
}
static void
-rt_update_hostcache(rtable *tab)
+rt_update_hostcache(void *data)
{
+ rtable *tab = data;
struct hostcache *hc = tab->hostcache;
+
+ if (rt_cork_check(&hc->update))
+ {
+ rt_trace(tab, D_STATES, "Hostcache update corked");
+ return;
+ }
+
struct hostentry *he;
node *n, *x;
@@ -4222,8 +4250,6 @@ rt_update_hostcache(rtable *tab)
if (rt_update_hostentry(tab, he))
rt_schedule_nhu(he->tab);
}
-
- tab->hcu_scheduled = 0;
}
static struct hostentry *