From: Maria Matejka Date: Fri, 23 May 2025 18:40:22 +0000 (+0200) Subject: Shutdown: Do not export routes X-Git-Tag: v3.0.4~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=82244ea23752c1be90311a0ce935ab6be74e2242;p=thirdparty%2Fbird.git Shutdown: Do not export routes When shutting down, the tables start flushing routes before all protocols are even officially aware of the shutdown. This fix allows for a fast check whether the shutdown is already running or not, and if so, all exports are ignored instead of processing them. One notable exception is the kernel protocol which needs to process all the exports normally to actually withdraw the routes. This is a hotfix for #251 and #252. Proper fix will require protocol state machine refactoring. --- diff --git a/conf/conf.c b/conf/conf.c index 73e0ae050..aa54db60e 100644 --- a/conf/conf.c +++ b/conf/conf.c @@ -259,7 +259,8 @@ global_commit(struct config *new, struct config *old) watchdog_warning, watchdog_timeout, gr_wait, - hostname + hostname, + shutdown ); #undef COPY diff --git a/conf/conf.h b/conf/conf.h index 03ef4ef82..734b28cd7 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -95,8 +95,12 @@ struct global_runtime { u32 latency_limit; /* Events with longer duration are logged (us) */ u32 watchdog_warning; /* I/O loop watchdog limit for warning (us) */ u32 watchdog_timeout; /* Watchdog timeout (in seconds, 0 = disabled) */ + + int shutdown; /* Shutdown in progress */ }; +#define SHUTTING_DOWN atomic_load_explicit(&global_runtime, memory_order_acquire)->shutdown + extern struct global_runtime * _Atomic global_runtime; /* Please don't use these variables in protocols. Use proto_config->global instead. */ diff --git a/nest/proto.c b/nest/proto.c index 3554c0a02..eb556b978 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -1872,7 +1872,7 @@ protos_do_commit(struct config *new, struct config *old, int type) protos_commit_request.phase--; /* If something is pending, the next round will be called asynchronously from proto_rethink_goal(). */ - if (!proto_rethink_goal_pending) + if (new->shutdown || !proto_rethink_goal_pending) protos_do_commit(new, old, type); } @@ -1930,7 +1930,7 @@ proto_rethink_goal(struct proto *p) proto_start(p); done: - if (goal_pending && !--proto_rethink_goal_pending) + if (goal_pending && !--proto_rethink_goal_pending && protos_commit_request.new) protos_do_commit( protos_commit_request.new, protos_commit_request.old, diff --git a/proto/aggregator/aggregator.c b/proto/aggregator/aggregator.c index 70dd1dac6..dbb52feae 100644 --- a/proto/aggregator/aggregator.c +++ b/proto/aggregator/aggregator.c @@ -210,6 +210,10 @@ HASH_DEFINE_REHASH_FN(AGGR_BUCK, struct aggregator_bucket); static void aggregator_rt_notify(struct proto *P, struct channel *src_ch, const net_addr *net, rte *new, const rte *old) { + /* Ignore everything on shutdown */ + if (SHUTTING_DOWN) + return; + SKIP_BACK_DECLARE(struct aggregator_proto, p, p, P); ASSERT_DIE(src_ch == p->src); struct aggregator_bucket *new_bucket = NULL, *old_bucket = NULL; @@ -316,6 +320,10 @@ aggregator_rt_notify(struct proto *P, struct channel *src_ch, const net_addr *ne static int aggregator_preexport(struct channel *C, struct rte *new) { + /* Reject everything on shutdown */ + if (SHUTTING_DOWN) + return -1; + SKIP_BACK_DECLARE(struct aggregator_proto, p, p, C->proto); /* Reject our own routes */ if (new->sender == p->dst->in_req.hook) diff --git a/proto/babel/babel.c b/proto/babel/babel.c index 65f19c4a9..1e4fa93c2 100644 --- a/proto/babel/babel.c +++ b/proto/babel/babel.c @@ -2423,6 +2423,9 @@ babel_kick_timer(struct babel_proto *p) static int babel_preexport(struct channel *C, struct rte *new) { + if (SHUTTING_DOWN) + return -1; + if (new->src->owner != &C->proto->sources) return 0; @@ -2455,6 +2458,10 @@ babel_rt_notify(struct proto *P, struct channel *c UNUSED, const net_addr *net, struct babel_proto *p = (void *) P; struct babel_entry *e; + /* Ignore everything on shutdown */ + if (SHUTTING_DOWN) + return; + if (new) { /* Update */ diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 330cd822b..75b8d8e53 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -2210,6 +2210,10 @@ bgp_preexport(struct channel *C, rte *e) struct bgp_proto *src = bgp_rte_proto(e); struct bgp_channel *c = (struct bgp_channel *) C; + /* Reject everything on shutdown */ + if (SHUTTING_DOWN) + return -1; + /* Ignore non-BGP channels */ if (C->class != &channel_bgp) return -1; @@ -2421,6 +2425,10 @@ bgp_rt_notify(struct proto *P, struct channel *C, const net_addr *n, rte *new, c struct bgp_bucket *buck; struct rte_src *path; + /* Reject everything on shutdown */ + if (SHUTTING_DOWN) + return; + /* Ignore non-BGP channels */ if (C->class != &channel_bgp) return; diff --git a/proto/l3vpn/l3vpn.c b/proto/l3vpn/l3vpn.c index 2fd8bdcdd..cb043e971 100644 --- a/proto/l3vpn/l3vpn.c +++ b/proto/l3vpn/l3vpn.c @@ -150,6 +150,9 @@ l3vpn_prepare_export_targets(struct l3vpn_proto *p) static void l3vpn_rt_notify(struct proto *P, struct channel *c0, const net_addr *n0, rte *new, const rte *old UNUSED) { + if (SHUTTING_DOWN) + return; + struct l3vpn_proto *p = (void *) P; struct rte_src *src = NULL; struct channel *dst = NULL; @@ -249,6 +252,10 @@ l3vpn_rt_notify(struct proto *P, struct channel *c0, const net_addr *n0, rte *ne static int l3vpn_preexport(struct channel *C, rte *e) { + /* Reject everything on shutdown */ + if (SHUTTING_DOWN) + return -1; + struct l3vpn_proto *p = (void *) C->proto; if (&C->in_req == e->sender->req) diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index e10be6225..de9e6d671 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -489,6 +489,10 @@ ospf_disp(timer * timer) static int ospf_preexport(struct channel *C, rte *e) { + /* Reject everything on shutdown */ + if (SHUTTING_DOWN) + return -1; + struct ospf_proto *p = (struct ospf_proto *) C->proto; struct ospf_area *oa = ospf_main_area(p); diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index 402afcd57..3fc85cebb 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -1282,6 +1282,10 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *n, rt struct ospf_area *oa = NULL; /* non-NULL for NSSA-LSA */ ort *nf; + /* Reject everything on shutdown */ + if (SHUTTING_DOWN) + return; + /* * There are several posibilities: * 1) router in regular area - originate external LSA with global scope diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c index 4e9f8d8eb..0420ca140 100644 --- a/proto/pipe/pipe.c +++ b/proto/pipe/pipe.c @@ -49,6 +49,10 @@ pipe_rt_notify(struct proto *P, struct channel *src_ch, const net_addr *n, rte * struct pipe_proto *p = (void *) P; struct channel *dst = (src_ch == p->pri) ? p->sec : p->pri; + /* Reject everything on shutdown */ + if (SHUTTING_DOWN) + return; + if (!new && !old) return; @@ -70,6 +74,10 @@ pipe_preexport(struct channel *C, rte *e) { struct pipe_proto *p = (void *) C->proto; + /* Reject everything on shutdown */ + if (SHUTTING_DOWN) + return -1; + /* Avoid direct loopbacks */ if (e->sender == C->in_req.hook) return -1; diff --git a/proto/rip/rip.c b/proto/rip/rip.c index ce8436156..b92d31eb7 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -348,6 +348,9 @@ static void rip_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *net, struct rte *new, const struct rte *old UNUSED) { + if (SHUTTING_DOWN) + return; + struct rip_proto *p = (struct rip_proto *) P; struct rip_entry *en; int old_metric;