]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Global runtime values separated from config
authorMaria Matejka <mq@ucw.cz>
Thu, 13 Jun 2024 14:30:51 +0000 (16:30 +0200)
committerMaria Matejka <mq@ucw.cz>
Fri, 14 Jun 2024 21:16:07 +0000 (23:16 +0200)
14 files changed:
conf/conf.c
conf/conf.h
lib/io-loop.h
nest/cmds.c
nest/iface.c
nest/proto.c
nest/protocol.h
proto/bfd/bfd.c
proto/bgp/packets.c
sysdep/unix/domain.c
sysdep/unix/io-loop.c
sysdep/unix/io.c
sysdep/unix/log.c
sysdep/unix/main.c

index 981db7091bf6ad3410b619095824862ff2fd481b..0db7ae477741af8a8e6fd0e8d5e10ba43d69cdd0 100644 (file)
@@ -105,7 +105,6 @@ config_alloc(const char *name)
   c->pool = p;
   c->mem = l;
   c->file_name = ndup;
-  c->load_time = current_time();
   c->tf_route = c->tf_proto = TM_ISO_SHORT_MS;
   c->tf_base = c->tf_log = TM_ISO_LONG_MS;
   c->gr_wait = DEFAULT_GR_WAIT;
@@ -150,11 +149,6 @@ config_parse(struct config *c)
   if (EMPTY_LIST(c->protos))
     cf_error("No protocol is specified in the config file");
 
-  /*
-  if (!c->router_id)
-    cf_error("Router ID must be configured manually");
-  */
-
   done = 1;
 
 cleanup:
@@ -244,25 +238,61 @@ config_del_obstacle(struct config *c)
     ev_send_loop(&main_birdloop, &c->done_event);
 }
 
+struct global_runtime global_runtime_internal[2] = {{
+  .tf_log = {
+    .fmt1 = "%F %T.%3f",
+  },
+}};
+struct global_runtime * _Atomic global_runtime = &global_runtime_internal[0];
+
 static void
 global_commit(struct config *new, struct config *old)
 {
-  if (!old)
-    return;
+  /* Updating the global runtime. */
+  struct global_runtime *og = atomic_load_explicit(&global_runtime, memory_order_relaxed);
+  struct global_runtime *ng = &global_runtime_internal[og == &global_runtime_internal[0]];
+  ASSERT_DIE(ng != og);
+
+#define COPY(x)        ng->x = new->x;
+  MACRO_FOREACH(COPY,
+      tf_route,
+      tf_proto,
+      tf_log,
+      tf_base,
+      cli_debug,
+      latency_debug,
+      latency_limit,
+      watchdog_warning,
+      watchdog_timeout,
+      gr_wait,
+      hostname
+      );
+#undef COPY
+
+  ng->load_time = current_time();
+
+  if (new->router_id)
+    ng->router_id = new->router_id;
+  else if (old)
+  {
+    /* The startup router ID must be determined after start of device protocol,
+     * thus if old == NULL then we do nothing */
+    ng->router_id = og->router_id;
 
-  if (!new->router_id)
+    if (new->router_id_from)
     {
-      new->router_id = old->router_id;
-
-      if (new->router_id_from)
-       {
-         u32 id = if_choose_router_id(new->router_id_from, old->router_id);
-         if (!id)
-           log(L_WARN "Cannot determine router ID, using old one");
-         else
-           new->router_id = id;
-       }
+      u32 id = if_choose_router_id(new->router_id_from, og->router_id);
+      if (!id)
+       log(L_WARN "Cannot determine router ID, using old one");
+      else
+       ng->router_id = id;
     }
+  }
+
+  atomic_store_explicit(&global_runtime, ng, memory_order_release);
+
+  /* We have to wait until every reader surely doesn't read the old values */
+  synchronize_rcu();
 }
 
 static int
index a4ce225f40175025f4fede19ecde5fa440d2dcf2..1ce5468cbc82198910a08b451d98c1980e90e78d 100644 (file)
@@ -72,9 +72,29 @@ struct config {
   event done_event;                    /* Called when obstacle_count reaches zero */
   int shutdown;                                /* This is a pseudo-config for daemon shutdown */
   int gr_down;                         /* This is a pseudo-config for graceful restart */
-  btime load_time;                     /* When we've got this configuration */
 };
 
+struct global_runtime {
+  struct timeformat tf_route;          /* Time format for 'show route' */
+  struct timeformat tf_proto;          /* Time format for 'show protocol' */
+  struct timeformat tf_log;            /* Time format for the logfile */
+  struct timeformat tf_base;           /* Time format for other purposes */
+
+  u32 gr_wait;                         /* Graceful restart wait timeout (sec) */
+
+  u32 router_id;                       /* Our Router ID */
+  const char *hostname;                        /* Hostname */
+
+  btime load_time;                     /* When we reconfigured last time */
+  int cli_debug;                       /* Tracing of CLI connections and commands */
+  enum latency_debug_flags latency_debug;
+  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) */
+};
+
+extern struct global_runtime * _Atomic global_runtime;
+
 /* Please don't use these variables in protocols. Use proto_config->global instead. */
 extern struct config *config;          /* Currently active configuration */
 extern _Thread_local struct config *new_config;        /* Configuration being parsed */
index 5cad30333d5f6ee8d1b8bfa0355d4c8173893d9c..03fe25292ed4fc828bc46e6a236a0c29f8fa206f 100644 (file)
@@ -25,7 +25,7 @@ _Bool task_before_halftime(void);
 
 #define MAYBE_DEFER_TASK(target, event, fmt, args...) do { \
   if (!task_still_in_limit()) { \
-    if (config && (config->latency_debug & DL_SCHEDULING)) \
+    if (atomic_load_explicit(&global_runtime, memory_order_relaxed)->latency_debug & DL_SCHEDULING) \
       log(L_TRACE "Deferring " fmt, ##args); \
     return ev_send(target, event); \
   } } while (0)
index 6f8796350461f3992d73710b55c93e91b1b2703e..b3729a5b7f1baa4a477b2729f810a7f736fee03d 100644 (file)
@@ -24,14 +24,18 @@ cmd_show_status(void)
 {
   byte tim[TM_DATETIME_BUFFER_SIZE];
 
+  rcu_read_lock();
+  struct global_runtime *gr = atomic_load_explicit(&global_runtime, memory_order_acquire);
+  struct timeformat *tf = &gr->tf_base;
+
   cli_msg(-1000, "BIRD " BIRD_VERSION);
-  tm_format_time(tim, &config->tf_base, current_time());
-  cli_msg(-1011, "Router ID is %R", config->router_id);
-  cli_msg(-1011, "Hostname is %s", config->hostname);
+  tm_format_time(tim, tf, current_time());
+  cli_msg(-1011, "Router ID is %R", gr->router_id);
+  cli_msg(-1011, "Hostname is %s", gr->hostname);
   cli_msg(-1011, "Current server time is %s", tim);
-  tm_format_time(tim, &config->tf_base, boot_time);
+  tm_format_time(tim, tf, boot_time);
   cli_msg(-1011, "Last reboot on %s", tim);
-  tm_format_time(tim, &config->tf_base, config->load_time);
+  tm_format_time(tim, tf, gr->load_time);
   cli_msg(-1011, "Last reconfiguration on %s", tim);
 
   graceful_restart_show_status();
@@ -42,6 +46,8 @@ cmd_show_status(void)
     cli_msg(13, "Reconfiguration in progress");
   else
     cli_msg(13, "Daemon is up and running");
+
+  rcu_read_unlock();
 }
 
 void
index 1e6374790cd55e217e6a0301a12d231bf13bfa88..1059ae06d6accb57b2e15bcd77d287d7d4c2e979 100644 (file)
@@ -164,7 +164,9 @@ if_dump_all(void)
   debug("Known network interfaces:\n");
   IFACE_WALK(i)
     if_dump(i);
-  debug("Router ID: %08x\n", config->router_id);
+  rcu_read_lock();
+  debug("Router ID: %08x\n", atomic_load_explicit(&global_runtime, memory_order_relaxed)->router_id);
+  rcu_read_unlock();
 }
 
 void
index 696e098c168893873ce2d8f34467de60b594c3bf..e6613d24e84979584bc8560c0acd27170e5767e3 100644 (file)
@@ -1624,11 +1624,15 @@ protos_do_commit(struct config *new, struct config *old, int type)
 
   /* Determine router ID for the first time - it has to be here and not in
      global_commit() because it is postponed after start of device protocol */
-  if (!config->router_id)
+  if ((phase == PROTOCOL_STARTUP_NECESSARY) && !old)
   {
-    config->router_id = if_choose_router_id(config->router_id_from, 0);
-    if (!config->router_id)
-      die("Cannot determine router ID, please configure it manually");
+    struct global_runtime *gr = atomic_load_explicit(&global_runtime, memory_order_relaxed);
+    if (!gr->router_id)
+    {
+      gr->router_id = if_choose_router_id(new->router_id_from, 0);
+      if (!gr->router_id)
+       die("Cannot determine router ID, please configure it manually");
+    }
   }
 
   /* Commit next round of protocols */
@@ -1781,7 +1785,8 @@ graceful_restart_init(void)
 
   graceful_restart_state = GRS_ACTIVE;
   gr_wait_timer = tm_new_init(proto_pool, graceful_restart_done, NULL, 0, 0);
-  tm_start(gr_wait_timer, config->gr_wait S);
+  u32 gr_wait = atomic_load_explicit(&global_runtime, memory_order_relaxed)->gr_wait;
+  tm_start(gr_wait_timer, gr_wait S);
 }
 
 /**
@@ -1795,7 +1800,7 @@ graceful_restart_init(void)
  * restart wait timer fires (but there are still some locks).
  */
 static void
-graceful_restart_done(timer *t UNUSED)
+graceful_restart_done(timer *t)
 {
   log(L_INFO "Graceful restart done");
   graceful_restart_state = GRS_DONE;
@@ -1821,6 +1826,8 @@ graceful_restart_done(timer *t UNUSED)
   }
 
   graceful_restart_locks = 0;
+
+  rfree(t);
 }
 
 void
@@ -1831,7 +1838,8 @@ graceful_restart_show_status(void)
 
   cli_msg(-24, "Graceful restart recovery in progress");
   cli_msg(-24, "  Waiting for %d channels to recover", graceful_restart_locks);
-  cli_msg(-24, "  Wait timer is %t/%u", tm_remains(gr_wait_timer), config->gr_wait);
+  cli_msg(-24, "  Wait timer is %t/%u", tm_remains(gr_wait_timer),
+      atomic_load_explicit(&global_runtime, memory_order_relaxed)->gr_wait);
 }
 
 /**
@@ -2422,7 +2430,10 @@ proto_cmd_show(struct proto *p, uintptr_t verbose, int cnt)
   buf[0] = 0;
   if (p->proto->get_status)
     p->proto->get_status(p, buf);
-  tm_format_time(tbuf, &config->tf_proto, p->last_state_change);
+
+  rcu_read_lock();
+  tm_format_time(tbuf, &atomic_load_explicit(&global_runtime, memory_order_acquire)->tf_proto, p->last_state_change);
+  rcu_read_unlock();
   cli_msg(-1002, "%-10s %-10s %-10s %-6s %-12s  %s",
          p->name,
          p->proto->name,
index 9d2e629287767a6cd306d40963d1d7a1f3665a03..a4279c5a0240ed102e6c14b0a6a454e4ce9d668f 100644 (file)
@@ -302,7 +302,7 @@ static inline struct domain_generic *proto_domain(struct proto *p)
 static inline u32
 proto_get_router_id(struct proto_config *pc)
 {
-  return pc->router_id ? pc->router_id : pc->global->router_id;
+  return pc->router_id ?: atomic_load_explicit(&global_runtime, memory_order_relaxed)->router_id;
 }
 
 
index de3e58b29e53be5213d32cee274bb25c6bb543bc..e6bf3f39096944c70f43b3f27cc4e48d14277d2c 100644 (file)
@@ -1237,7 +1237,11 @@ bfd_show_session(struct bfd_session *s, int details)
 
   byte dbuf[BFD_DIAG_BUFFER_SIZE];
   byte tbuf[TM_DATETIME_BUFFER_SIZE];
-  tm_format_time(tbuf, &config->tf_proto, s->last_state_change);
+
+  rcu_read_lock();
+  struct global_runtime *gr = atomic_load_explicit(&global_runtime, memory_order_relaxed);
+  tm_format_time(tbuf, &gr->tf_proto, s->last_state_change);
+  rcu_read_unlock();
 
   if (!details)
   {
index 7e937aed51e8637e52bb1e85b2a8384afaa4f463..1602911818aa6a5c75d3fba4174d6f9aff10e736 100644 (file)
@@ -283,13 +283,16 @@ bgp_prepare_capabilities(struct bgp_conn *conn)
   if (p->cf->llgr_mode)
     caps->llgr_aware = 1;
 
-  if (p->cf->enable_hostname && config->hostname)
+  rcu_read_lock();
+  struct global_runtime *gr = atomic_load_explicit(&global_runtime, memory_order_relaxed);
+  if (p->cf->enable_hostname && gr->hostname)
   {
-    size_t length = strlen(config->hostname);
+    size_t length = strlen(gr->hostname);
     char *hostname = mb_allocz(p->p.pool, length+1);
-    memcpy(hostname, config->hostname, length+1);
+    memcpy(hostname, gr->hostname, length+1);
     caps->hostname = hostname;
   }
+  rcu_read_unlock();
 
   /* Allocate and fill per-AF fields */
   BGP_WALK_CHANNELS(p, c)
index 2d2c0ff4c623d9fd897b288449fac75154ebb898..2817455fdf1b5cec0592050ed156b7207710af4b 100644 (file)
@@ -123,7 +123,8 @@ void do_lock(struct domain_generic *dg, struct domain_generic **lsp)
   btime lock_begin = current_time();
   pthread_mutex_lock(&dg->mutex);
   btime duration = current_time() - lock_begin;
-  if (config && (duration > config->watchdog_warning))
+  btime wdw = atomic_load_explicit(&global_runtime, memory_order_relaxed)->watchdog_warning;
+  if (wdw && (duration > wdw))
     log(L_WARN "Locking of %s took %d ms", dg->name, (int) (duration TO_MS));
 
   if (dg->prev || dg->locked_by)
index ec8aa72961cf1e7ffcca526727c9d44ffd2e233f..49e9f2db14a8af09934e0799e8463292f67110b9 100644 (file)
@@ -152,9 +152,10 @@ static _Thread_local struct birdloop *birdloop_wakeup_masked;
 static _Thread_local uint birdloop_wakeup_masked_count;
 
 #define LOOP_NAME(loop)                        domain_name((loop)->time.domain)
+#define LATENCY_DEBUG(flags)           (atomic_load_explicit(&global_runtime, memory_order_relaxed)->latency_debug & (flags))
 
-#define LOOP_TRACE(loop, flags, fmt, args...)  do { if (config && (config->latency_debug & (flags))) log(L_TRACE "%s (%p): " fmt, LOOP_NAME(loop), (loop), ##args); } while (0)
-#define THREAD_TRACE(flags, ...)               do { if (config && (config->latency_debug & (flags))) log(L_TRACE "Thread: " __VA_ARGS__); } while (0)
+#define LOOP_TRACE(loop, flags, fmt, args...)  do { if (LATENCY_DEBUG(flags)) log(L_TRACE "%s (%p): " fmt, LOOP_NAME(loop), (loop), ##args); } while (0)
+#define THREAD_TRACE(flags, ...)               do { if (LATENCY_DEBUG(flags)) log(L_TRACE "Thread: " __VA_ARGS__); } while (0)
 
 #define LOOP_WARN(loop, fmt, args...)  log(L_WARN "%s (%p): " fmt, LOOP_NAME(loop), (loop), ##args)
 
@@ -1506,7 +1507,8 @@ birdloop_run(void *_loop)
   /* Now we can actually do some work */
   u64 dif = account_to(&loop->working);
 
-  if (dif > this_thread->max_loop_time_ns + config->latency_limit TO_NS)
+  struct global_runtime *gr = atomic_load_explicit(&global_runtime, memory_order_relaxed);
+  if (dif > this_thread->max_loop_time_ns + gr->latency_limit TO_NS)
     LOOP_WARN(loop, "locked %lu us after its scheduled end time", dif NS TO_US);
 
   uint repeat, loop_runs = 0;
index ab2379aa5d829d623d3c0f0ba4226304e76c53fd..7e974ec10274a94d04b46a7e48696d44a5d3c441 100644 (file)
@@ -2247,7 +2247,8 @@ io_update_time(void)
   {
     event_open->duration = last_io_time - event_open->timestamp;
 
-    if (event_open->duration > config->latency_limit)
+    struct global_runtime *gr = atomic_load_explicit(&global_runtime, memory_order_relaxed);
+    if (event_open->duration > gr->latency_limit)
       log(L_WARN "Event 0x%p 0x%p took %u.%03u ms",
          event_open->hook, event_open->data, (uint) (event_open->duration TO_MS), (uint) (event_open->duration % 1000));
 
@@ -2267,7 +2268,8 @@ io_update_time(void)
 void
 io_log_event(void *hook, void *data, uint flag)
 {
-  if (config->latency_debug & flag)
+  struct global_runtime *gr = atomic_load_explicit(&global_runtime, memory_order_relaxed);
+  if (gr->latency_debug & flag)
     io_update_time();
 
   struct event_log_entry *en = event_log + event_log_pos;
@@ -2281,7 +2283,7 @@ io_log_event(void *hook, void *data, uint flag)
   event_log_pos++;
   event_log_pos %= EVENT_LOG_LENGTH;
 
-  event_open = (config->latency_debug & flag) ? en : NULL;
+  event_open = (gr->latency_debug & flag) ? en : NULL;
 }
 
 static inline void
@@ -2310,7 +2312,8 @@ void
 watchdog_sigalrm(int sig UNUSED)
 {
   /* Update last_io_time and duration, but skip latency check */
-  config->latency_limit = 0xffffffff;
+  struct global_runtime *gr = atomic_load_explicit(&global_runtime, memory_order_relaxed);
+  gr->latency_limit = 0xffffffff;
   io_update_time();
 
   debug_safe("Watchdog timer timed out\n");
@@ -2335,9 +2338,10 @@ watchdog_start(void)
   loop_time = last_io_time;
   event_log_num = 0;
 
-  if (config->watchdog_timeout)
+  struct global_runtime *gr = atomic_load_explicit(&global_runtime, memory_order_relaxed);
+  if (gr->watchdog_timeout)
   {
-    alarm(config->watchdog_timeout);
+    alarm(gr->watchdog_timeout);
     watchdog_active = 1;
   }
 }
@@ -2354,7 +2358,8 @@ watchdog_stop(void)
   }
 
   btime duration = last_io_time - loop_time;
-  if (duration > config->watchdog_warning)
+  struct global_runtime *gr = atomic_load_explicit(&global_runtime, memory_order_relaxed);
+  if (duration > gr->watchdog_warning)
     log(L_WARN "I/O loop cycle took %u.%03u ms for %d events",
        (uint) (duration TO_MS), (uint) (duration % 1000), event_log_num);
 }
index 6046364d59fe1c5e6746bee622244bd38bf9628d..98642e9c3d7d9285aea92cebdb813557c205bf48 100644 (file)
@@ -284,8 +284,10 @@ log_prepare(log_buffer *buf, int class)
   buf->pos[LBP_TIMESTAMP] = buf->buf.pos;
   if (BIT32_TEST(&lf, LBP_TIMESTAMP))
   {
-    const char *fmt = config ? config->tf_log.fmt1 : "%F %T.%3f";
+    rcu_read_lock();
+    const char *fmt = atomic_load_explicit(&global_runtime, memory_order_acquire)->tf_log.fmt1;
     int t = tm_format_real_time(buf->buf.pos, buf->buf.end - buf->buf.pos, fmt, current_real_time());
+    rcu_read_unlock();
     if (t)
       buf->buf.pos += t;
     else
@@ -307,8 +309,10 @@ log_prepare(log_buffer *buf, int class)
     else
       buffer_puts(&buf->buf, "<time format error>");
 
-    const char *hostname = (config && config->hostname) ? config->hostname : "<none>";
+    rcu_read_lock();
+    const char *hostname = atomic_load_explicit(&global_runtime, memory_order_acquire)->hostname ?: "<none>";
     buffer_print(&buf->buf, " %s %s: ", hostname, bird_name);
+    rcu_read_unlock();
   }
 
   buf->pos[LBP_THREAD_ID] = buf->buf.pos;
index f17996751c3bf0233bcc3d0645ebaf2c3c5d9885..4dece4037033ac7e6eec9baee472cb7d38de28f2 100644 (file)
@@ -487,10 +487,12 @@ cli_rx(sock *s, uint size UNUSED)
   return 0;
 }
 
+#define GLOBAL_CLI_DEBUG (atomic_load_explicit(&global_runtime, memory_order_relaxed)->cli_debug)
+
 static void
 cli_err(sock *s, int err)
 {
-  if (config->cli_debug)
+  if (GLOBAL_CLI_DEBUG)
     {
       if (err)
        log(L_INFO "CLI connection dropped: %s", strerror(err));
@@ -505,7 +507,7 @@ static void
 cli_connect_err(sock *s UNUSED, int err)
 {
   ASSERT_DIE(err);
-  if (config->cli_debug)
+  if (GLOBAL_CLI_DEBUG)
     log(L_INFO "Failed to accept CLI connection: %s", strerror(err));
 }
 
@@ -514,7 +516,7 @@ cli_connect(sock *s, uint size UNUSED)
 {
   cli *c;
 
-  if (config->cli_debug)
+  if (GLOBAL_CLI_DEBUG)
     log(L_INFO "CLI connect");
   s->rx_hook = cli_rx;
   s->tx_hook = cli_tx;