mirror of
https://git.freebsd.org/ports.git
synced 2025-04-28 01:26:39 -04:00
274 lines
8 KiB
Text
274 lines
8 KiB
Text
From 0fa80d7c79428e5370740a2eba5605b65131ebd6 Mon Sep 17 00:00:00 2001
|
|
From: Maria Matejka <mq@ucw.cz>
|
|
Date: Mon, 23 Dec 2024 11:58:05 +0100
|
|
Subject: [PATCH] Kernel: feed only once during startup
|
|
|
|
There was an inefficiency in the initial scan state machine,
|
|
causing routes to be fed several times instead of just once.
|
|
Now the export startup is postponed until first krt_scan()
|
|
finishes and we actually can do the pruning with full information.
|
|
---
|
|
nest/proto.c | 4 ++-
|
|
nest/protocol.h | 2 ++
|
|
sysdep/unix/krt.c | 69 ++++++++++++++++++++++++++++-------------------
|
|
sysdep/unix/krt.h | 5 ++--
|
|
4 files changed, 48 insertions(+), 32 deletions(-)
|
|
|
|
diff --git a/nest/proto.c b/nest/proto.c
|
|
index 678697d69..6fa74e9f1 100644
|
|
--- nest/proto.c
|
|
+++ nest/proto.c
|
|
@@ -676,9 +676,11 @@ void channel_notify_basic(void *);
|
|
void channel_notify_accepted(void *);
|
|
void channel_notify_merged(void *);
|
|
|
|
-static void
|
|
+void
|
|
channel_start_export(struct channel *c)
|
|
{
|
|
+ ASSERT_DIE(birdloop_inside(c->proto->loop));
|
|
+
|
|
if (rt_export_get_state(&c->out_req) != TES_DOWN)
|
|
bug("%s.%s: Attempted to start channel's already started export", c->proto->name, c->name);
|
|
|
|
diff --git a/nest/protocol.h b/nest/protocol.h
|
|
index cf7ecb898..2bfa1628a 100644
|
|
--- nest/protocol.h
|
|
+++ nest/protocol.h
|
|
@@ -747,6 +747,8 @@ int proto_configure_channel(struct proto *p, struct channel **c, struct channel_
|
|
|
|
void channel_set_state(struct channel *c, uint state);
|
|
|
|
+void channel_start_export(struct channel *c);
|
|
+
|
|
void channel_add_obstacle(struct channel *c);
|
|
void channel_del_obstacle(struct channel *c);
|
|
|
|
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
|
|
index 34882b88f..1658dd6fe 100644
|
|
--- sysdep/unix/krt.c
|
|
+++ sysdep/unix/krt.c
|
|
@@ -342,6 +342,8 @@ krt_learn_async(struct krt_proto *p, rte *e, int new)
|
|
/* Hook defined in nest/rt-table.c ... to be refactored away later */
|
|
rte *krt_export_net(struct channel *c, const net_addr *a, linpool *lp);
|
|
|
|
+static void krt_rt_notify(struct proto *P, struct channel *ch, const net_addr *net, rte *new, const rte *old);
|
|
+
|
|
static int
|
|
krt_same_dest(rte *k, rte *e)
|
|
{
|
|
@@ -361,6 +363,11 @@ krt_same_dest(rte *k, rte *e)
|
|
void
|
|
krt_got_route(struct krt_proto *p, rte *e, s8 src)
|
|
{
|
|
+ /* If we happen to get an asynchronous route notification
|
|
+ * before initialization, we wait for the scan. */
|
|
+ if (p->sync_state == KPS_INIT)
|
|
+ return;
|
|
+
|
|
rte *new = NULL;
|
|
e->pflags = 0;
|
|
|
|
@@ -391,10 +398,6 @@ krt_got_route(struct krt_proto *p, rte *e, s8 src)
|
|
|
|
/* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */
|
|
|
|
- /* We wait for the initial feed to have correct installed state */
|
|
- if (!p->ready)
|
|
- goto ignore;
|
|
-
|
|
/* Get the exported version */
|
|
new = krt_export_net(p->p.main_channel, e->net, krt_filter_lp);
|
|
|
|
@@ -423,10 +426,6 @@ aseen:
|
|
krt_trace_in(p, e, "already seen");
|
|
goto done;
|
|
|
|
-ignore:
|
|
- krt_trace_in(p, e, "ignored");
|
|
- goto done;
|
|
-
|
|
update:
|
|
krt_trace_in(p, new, "updating");
|
|
krt_replace_rte(p, e->net, new, e);
|
|
@@ -447,12 +446,21 @@ krt_init_scan(struct krt_proto *p)
|
|
{
|
|
switch (p->sync_state)
|
|
{
|
|
+ case KPS_INIT:
|
|
+ /* Allow exports now */
|
|
+ p->p.rt_notify = krt_rt_notify;
|
|
+ channel_start_export(p->p.main_channel);
|
|
+ rt_refresh_begin(&p->p.main_channel->in_req);
|
|
+ p->sync_state = KPS_FIRST_SCAN;
|
|
+ return 1;
|
|
+
|
|
case KPS_IDLE:
|
|
rt_refresh_begin(&p->p.main_channel->in_req);
|
|
bmap_reset(&p->seen_map, 1024);
|
|
p->sync_state = KPS_SCANNING;
|
|
return 1;
|
|
|
|
+ case KPS_FIRST_SCAN:
|
|
case KPS_SCANNING:
|
|
bug("Kernel scan double-init");
|
|
|
|
@@ -470,14 +478,17 @@ krt_prune(struct krt_proto *p)
|
|
{
|
|
switch (p->sync_state)
|
|
{
|
|
+ case KPS_INIT:
|
|
case KPS_IDLE:
|
|
bug("Kernel scan prune without scan");
|
|
|
|
case KPS_SCANNING:
|
|
+ channel_request_full_refeed(p->p.main_channel);
|
|
+ /* fall through */
|
|
+ case KPS_FIRST_SCAN:
|
|
p->sync_state = KPS_PRUNING;
|
|
KRT_TRACE(p, D_EVENTS, "Pruning table %s", p->p.main_channel->table->name);
|
|
rt_refresh_end(&p->p.main_channel->in_req);
|
|
- channel_request_full_refeed(p->p.main_channel);
|
|
break;
|
|
|
|
case KPS_PRUNING:
|
|
@@ -549,7 +560,7 @@ krt_scan_all(timer *t UNUSED)
|
|
krt_do_scan(NULL);
|
|
|
|
WALK_LIST2(p, n, krt_proto_list, krt_node)
|
|
- if (p->sync_state == KPS_SCANNING)
|
|
+ if ((p->sync_state == KPS_SCANNING) || (p->sync_state == KPS_FIRST_SCAN))
|
|
krt_prune(p);
|
|
}
|
|
|
|
@@ -644,6 +655,9 @@ krt_scan_timer_kick(struct krt_proto *p)
|
|
static int
|
|
krt_preexport(struct channel *C, rte *e)
|
|
{
|
|
+ /* The export should not start before proper sync */
|
|
+ ASSERT_DIE(SKIP_BACK(struct krt_proto, p, C->proto)->sync_state != KPS_INIT);
|
|
+
|
|
if (e->src->owner == &C->proto->sources)
|
|
#ifdef CONFIG_SINGLE_ROUTE
|
|
return 1;
|
|
@@ -659,15 +673,6 @@ krt_preexport(struct channel *C, rte *e)
|
|
return -1;
|
|
}
|
|
|
|
- /* Before first scan we don't touch the routes */
|
|
- if (!SKIP_BACK(struct krt_proto, p, C->proto)->ready)
|
|
- {
|
|
- if (C->debug & D_ROUTES)
|
|
- log(L_TRACE "%s.%s not ready yet to accept route for %N",
|
|
- C->proto->name, C->name, e->net);
|
|
- return -1;
|
|
- }
|
|
-
|
|
return 0;
|
|
}
|
|
|
|
@@ -685,18 +690,24 @@ krt_rt_notify(struct proto *P, struct channel *ch, const net_addr *net,
|
|
|
|
switch (p->sync_state)
|
|
{
|
|
+ case KPS_INIT:
|
|
+ bug("Routes in init state should have been rejected by preexport.");
|
|
+
|
|
case KPS_IDLE:
|
|
case KPS_PRUNING:
|
|
if (new && bmap_test(&p->seen_map, new->id))
|
|
+ {
|
|
if (ch->debug & D_ROUTES)
|
|
{
|
|
/* Already installed and seen in the kernel dump */
|
|
log(L_TRACE "%s.%s: %N already in kernel",
|
|
P->name, ch->name, net);
|
|
- return;
|
|
}
|
|
+ return;
|
|
+ }
|
|
|
|
/* fall through */
|
|
+ case KPS_FIRST_SCAN:
|
|
case KPS_SCANNING:
|
|
/* Actually replace the route */
|
|
krt_replace_rte(p, net, new, old);
|
|
@@ -732,7 +743,6 @@ krt_reload_routes(struct channel *C, struct rt_feeding_request *rfr)
|
|
|
|
if (KRT_CF->learn)
|
|
{
|
|
- p->reload = 1;
|
|
krt_scan_timer_kick(p);
|
|
}
|
|
|
|
@@ -749,15 +759,18 @@ krt_export_fed(struct channel *C)
|
|
{
|
|
struct krt_proto *p = (void *) C->proto;
|
|
|
|
- p->ready = 1;
|
|
- p->initialized = 1;
|
|
-
|
|
switch (p->sync_state)
|
|
{
|
|
+ case KPS_INIT:
|
|
+ bug("KRT export started before scan");
|
|
+
|
|
case KPS_IDLE:
|
|
krt_scan_timer_kick(p);
|
|
break;
|
|
|
|
+ case KPS_FIRST_SCAN:
|
|
+ bug("KRT export done before first scan");
|
|
+
|
|
case KPS_SCANNING:
|
|
break;
|
|
|
|
@@ -831,7 +844,8 @@ krt_init(struct proto_config *CF)
|
|
p->p.main_channel = proto_add_channel(&p->p, proto_cf_main_channel(CF));
|
|
|
|
p->p.preexport = krt_preexport;
|
|
- p->p.rt_notify = krt_rt_notify;
|
|
+ /* Not setting rt_notify here to not start exports, must wait for the first scan
|
|
+ * and then we can start exports manually */
|
|
p->p.iface_sub.if_notify = krt_if_notify;
|
|
p->p.reload_routes = krt_reload_routes;
|
|
p->p.export_fed = krt_export_fed;
|
|
@@ -887,7 +901,7 @@ krt_shutdown(struct proto *P)
|
|
return PS_FLUSH;
|
|
|
|
/* FIXME we should flush routes even when persist during reconfiguration */
|
|
- if (p->initialized && !KRT_CF->persist && (P->down_code != PDC_CMD_GR_DOWN))
|
|
+ if ((p->sync_state != KPS_INIT) && !KRT_CF->persist && (P->down_code != PDC_CMD_GR_DOWN))
|
|
{
|
|
struct rt_export_feeder req = (struct rt_export_feeder)
|
|
{
|
|
@@ -922,8 +936,7 @@ krt_shutdown(struct proto *P)
|
|
static void
|
|
krt_cleanup(struct krt_proto *p)
|
|
{
|
|
- p->ready = 0;
|
|
- p->initialized = 0;
|
|
+ p->sync_state = KPS_INIT;
|
|
|
|
krt_sys_shutdown(p);
|
|
rem_node(&p->krt_node);
|
|
diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h
|
|
index 394e74010..14be715f8 100644
|
|
--- sysdep/unix/krt.h
|
|
+++ sysdep/unix/krt.h
|
|
@@ -59,10 +59,9 @@ struct krt_proto {
|
|
struct bmap seen_map; /* Routes seen during last periodic scan */
|
|
node krt_node; /* Node in krt_proto_list */
|
|
byte af; /* Kernel address family (AF_*) */
|
|
- byte ready; /* Initial feed has been finished */
|
|
- byte initialized; /* First scan has been finished */
|
|
- byte reload; /* Next scan is doing reload */
|
|
PACKED enum krt_prune_state {
|
|
+ KPS_INIT,
|
|
+ KPS_FIRST_SCAN,
|
|
KPS_IDLE,
|
|
KPS_SCANNING,
|
|
KPS_PRUNING,
|
|
--
|
|
GitLab
|
|
|