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;
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:
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
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 */
#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)
{
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();
cli_msg(13, "Reconfiguration in progress");
else
cli_msg(13, "Daemon is up and running");
+
+ rcu_read_unlock();
}
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
/* 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 */
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);
}
/**
* 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;
}
graceful_restart_locks = 0;
+
+ rfree(t);
}
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);
}
/**
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,
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;
}
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)
{
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)
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)
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)
/* 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;
{
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));
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;
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
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");
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;
}
}
}
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);
}
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
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;
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));
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));
}
{
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;