summaryrefslogtreecommitdiff
path: root/net/bird3/files/patch-08-kernel-feed-only-once
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--net/bird3/files/patch-08-kernel-feed-only-once274
1 files changed, 274 insertions, 0 deletions
diff --git a/net/bird3/files/patch-08-kernel-feed-only-once b/net/bird3/files/patch-08-kernel-feed-only-once
new file mode 100644
index 000000000000..33a98cbc4795
--- /dev/null
+++ b/net/bird3/files/patch-08-kernel-feed-only-once
@@ -0,0 +1,274 @@
+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
+