]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Shutdown: Do not export routes
authorMaria Matejka <mq@ucw.cz>
Fri, 23 May 2025 18:40:22 +0000 (20:40 +0200)
committerMaria Matejka <mq@ucw.cz>
Sun, 25 May 2025 19:01:49 +0000 (21:01 +0200)
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.

conf/conf.c
conf/conf.h
nest/proto.c
proto/aggregator/aggregator.c
proto/babel/babel.c
proto/bgp/attrs.c
proto/l3vpn/l3vpn.c
proto/ospf/ospf.c
proto/ospf/topology.c
proto/pipe/pipe.c
proto/rip/rip.c

index 73e0ae0505460ee0cf462e005143511fa41ec2a4..aa54db60ed330adec7bedd7e8c9afd93bf594e9d 100644 (file)
@@ -259,7 +259,8 @@ global_commit(struct config *new, struct config *old)
       watchdog_warning,
       watchdog_timeout,
       gr_wait,
-      hostname
+      hostname,
+      shutdown
       );
 #undef COPY
 
index c67c74c8c8f3f726cf91d9bf68e9568b1b8c536a..d5019398dda3fc21ef5fd88bcab1b0e0b41ddaeb 100644 (file)
@@ -99,8 +99,12 @@ struct global_runtime {
   u32 watchdog_timeout;                        /* Watchdog timeout (in seconds, 0 = disabled) */
 
   struct thread_group *default_thread_group;   /* Default thread group if not specified otherwise */
+
+  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. */
index 7cb1e855b9a3520c06d8bdb9dd1ddc8dc47cebd6..51b1a82ddba5c06b6ae3db9da8d974c1d40f7743 100644 (file)
@@ -1880,7 +1880,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);
 }
 
@@ -1938,7 +1938,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,
index 70dd1dac638a2f18232a2f9019f82060a3faf8c3..dbb52feaeab2b94cdc5491a5dca89806d625e786 100644 (file)
@@ -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)
index e249938addcb55c559b4ed31c2aae20d01f1d00b..9ed0ce629188f2634ea234c769d30535276c4fa1 100644 (file)
@@ -2431,6 +2431,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;
 
@@ -2463,6 +2466,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 */
index d5162bbd0059943db0aa66524c145aa9786583be..5843183e65c6bf608d3019547d332e928ca64a3c 100644 (file)
@@ -2229,6 +2229,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;
@@ -2440,6 +2444,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;
index 2fd8bdcdd6806afcd5cf837823fbc92fc4021deb..cb043e971ab93f53b56d2c8b2d65b4c94e854600 100644 (file)
@@ -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)
index bde7d8051804ac6aa58592761c92b65aeea27fbe..9719403358d662d36b3e3e5e610a53e01d74ac5b 100644 (file)
@@ -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);
 
index 402afcd57a1fe9381864840392b55626cfd99afe..3fc85cebbce82c4dd075296f1c5807cf45bad48a 100644 (file)
@@ -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
index 4e9f8d8eb8801b832a30b8bbe48679f74ceeffd8..0420ca14010d9a84ae695470f3c3a086fe6e7987 100644 (file)
@@ -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;
index 27c9408bc7b6519378184bd3aacd780038222c4b..a4ce3c9d7f2bd2f5c12fa1ed762f057ead38110e 100644 (file)
@@ -349,6 +349,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;