]> 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:03:43 +0000 (21:03 +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 03ef4ef823e2b0c5f8b6b3f3fbe1923bdca3f800..734b28cd7c2648ac614a99d60cbe1c9ba9fdaa2d 100644 (file)
@@ -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. */
index 3554c0a02e700cb7e69691e0e793485311767266..eb556b9789ead0cbb6a1e8e3d3183a5d11a124ed 100644 (file)
@@ -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,
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 65f19c4a96c573f208c61acd7381a359ba9ef5e1..1e4fa93c20d8c8ec4523e886e67bd7fb7700c039 100644 (file)
@@ -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 */
index 330cd822b3f1c15da0548b6739475d9ad36d17ff..75b8d8e53f370e7eabdaf0b9f9edee575c31d462 100644 (file)
@@ -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;
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 e10be62252f235cafcbd60b4817858badad6ab68..de9e6d671725795831a70bfe15607bbfe3e41188 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 ce8436156c149b173969925fe520fd14a339e22b..b92d31eb72ae51d9da8da0e87a4409d0641b1210 100644 (file)
@@ -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;