diff options
Diffstat (limited to '')
-rw-r--r-- | net/bird3/files/patch-08-kernel-feed-only-once | 274 |
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 + |