0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2025-01-18 06:51:54 +00:00

Global runtime values separated from config

This commit is contained in:
Maria Matejka 2024-06-13 16:30:51 +02:00
parent 73ad0e2dcb
commit 61dcbb1d83
14 changed files with 146 additions and 56 deletions

View File

@ -105,7 +105,6 @@ config_alloc(const char *name)
c->pool = p; c->pool = p;
c->mem = l; c->mem = l;
c->file_name = ndup; c->file_name = ndup;
c->load_time = current_time();
c->tf_route = c->tf_proto = TM_ISO_SHORT_MS; c->tf_route = c->tf_proto = TM_ISO_SHORT_MS;
c->tf_base = c->tf_log = TM_ISO_LONG_MS; c->tf_base = c->tf_log = TM_ISO_LONG_MS;
c->gr_wait = DEFAULT_GR_WAIT; c->gr_wait = DEFAULT_GR_WAIT;
@ -150,11 +149,6 @@ config_parse(struct config *c)
if (EMPTY_LIST(c->protos)) if (EMPTY_LIST(c->protos))
cf_error("No protocol is specified in the config file"); cf_error("No protocol is specified in the config file");
/*
if (!c->router_id)
cf_error("Router ID must be configured manually");
*/
done = 1; done = 1;
cleanup: cleanup:
@ -244,25 +238,61 @@ config_del_obstacle(struct config *c)
ev_send_loop(&main_birdloop, &c->done_event); 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 static void
global_commit(struct config *new, struct config *old) global_commit(struct config *new, struct config *old)
{ {
if (!old) /* Updating the global runtime. */
return; 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);
if (!new->router_id) #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_from)
{ {
new->router_id = old->router_id; u32 id = if_choose_router_id(new->router_id_from, og->router_id);
if (!id)
if (new->router_id_from) log(L_WARN "Cannot determine router ID, using old one");
{ else
u32 id = if_choose_router_id(new->router_id_from, old->router_id); ng->router_id = id;
if (!id)
log(L_WARN "Cannot determine router ID, using old one");
else
new->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 static int

View File

@ -72,9 +72,29 @@ struct config {
event done_event; /* Called when obstacle_count reaches zero */ event done_event; /* Called when obstacle_count reaches zero */
int shutdown; /* This is a pseudo-config for daemon shutdown */ int shutdown; /* This is a pseudo-config for daemon shutdown */
int gr_down; /* This is a pseudo-config for graceful restart */ 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. */ /* Please don't use these variables in protocols. Use proto_config->global instead. */
extern struct config *config; /* Currently active configuration */ extern struct config *config; /* Currently active configuration */
extern _Thread_local struct config *new_config; /* Configuration being parsed */ extern _Thread_local struct config *new_config; /* Configuration being parsed */

View File

@ -25,7 +25,7 @@ _Bool task_before_halftime(void);
#define MAYBE_DEFER_TASK(target, event, fmt, args...) do { \ #define MAYBE_DEFER_TASK(target, event, fmt, args...) do { \
if (!task_still_in_limit()) { \ 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); \ log(L_TRACE "Deferring " fmt, ##args); \
return ev_send(target, event); \ return ev_send(target, event); \
} } while (0) } } while (0)

View File

@ -24,14 +24,18 @@ cmd_show_status(void)
{ {
byte tim[TM_DATETIME_BUFFER_SIZE]; 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); cli_msg(-1000, "BIRD " BIRD_VERSION);
tm_format_time(tim, &config->tf_base, current_time()); tm_format_time(tim, tf, current_time());
cli_msg(-1011, "Router ID is %R", config->router_id); cli_msg(-1011, "Router ID is %R", gr->router_id);
cli_msg(-1011, "Hostname is %s", config->hostname); cli_msg(-1011, "Hostname is %s", gr->hostname);
cli_msg(-1011, "Current server time is %s", tim); 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); 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); cli_msg(-1011, "Last reconfiguration on %s", tim);
graceful_restart_show_status(); graceful_restart_show_status();
@ -42,6 +46,8 @@ cmd_show_status(void)
cli_msg(13, "Reconfiguration in progress"); cli_msg(13, "Reconfiguration in progress");
else else
cli_msg(13, "Daemon is up and running"); cli_msg(13, "Daemon is up and running");
rcu_read_unlock();
} }
void void

View File

@ -164,7 +164,9 @@ if_dump_all(void)
debug("Known network interfaces:\n"); debug("Known network interfaces:\n");
IFACE_WALK(i) IFACE_WALK(i)
if_dump(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 void

View 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 /* 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 */ 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); struct global_runtime *gr = atomic_load_explicit(&global_runtime, memory_order_relaxed);
if (!config->router_id) if (!gr->router_id)
die("Cannot determine router ID, please configure it manually"); {
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 */ /* Commit next round of protocols */
@ -1781,7 +1785,8 @@ graceful_restart_init(void)
graceful_restart_state = GRS_ACTIVE; graceful_restart_state = GRS_ACTIVE;
gr_wait_timer = tm_new_init(proto_pool, graceful_restart_done, NULL, 0, 0); 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). * restart wait timer fires (but there are still some locks).
*/ */
static void static void
graceful_restart_done(timer *t UNUSED) graceful_restart_done(timer *t)
{ {
log(L_INFO "Graceful restart done"); log(L_INFO "Graceful restart done");
graceful_restart_state = GRS_DONE; graceful_restart_state = GRS_DONE;
@ -1821,6 +1826,8 @@ graceful_restart_done(timer *t UNUSED)
} }
graceful_restart_locks = 0; graceful_restart_locks = 0;
rfree(t);
} }
void void
@ -1831,7 +1838,8 @@ graceful_restart_show_status(void)
cli_msg(-24, "Graceful restart recovery in progress"); cli_msg(-24, "Graceful restart recovery in progress");
cli_msg(-24, " Waiting for %d channels to recover", graceful_restart_locks); 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; buf[0] = 0;
if (p->proto->get_status) if (p->proto->get_status)
p->proto->get_status(p, buf); 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", cli_msg(-1002, "%-10s %-10s %-10s %-6s %-12s %s",
p->name, p->name,
p->proto->name, p->proto->name,

View File

@ -302,7 +302,7 @@ static inline struct domain_generic *proto_domain(struct proto *p)
static inline u32 static inline u32
proto_get_router_id(struct proto_config *pc) 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;
} }

View File

@ -1237,7 +1237,11 @@ bfd_show_session(struct bfd_session *s, int details)
byte dbuf[BFD_DIAG_BUFFER_SIZE]; byte dbuf[BFD_DIAG_BUFFER_SIZE];
byte tbuf[TM_DATETIME_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 (!details)
{ {

View File

@ -283,13 +283,16 @@ bgp_prepare_capabilities(struct bgp_conn *conn)
if (p->cf->llgr_mode) if (p->cf->llgr_mode)
caps->llgr_aware = 1; 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); char *hostname = mb_allocz(p->p.pool, length+1);
memcpy(hostname, config->hostname, length+1); memcpy(hostname, gr->hostname, length+1);
caps->hostname = hostname; caps->hostname = hostname;
} }
rcu_read_unlock();
/* Allocate and fill per-AF fields */ /* Allocate and fill per-AF fields */
BGP_WALK_CHANNELS(p, c) BGP_WALK_CHANNELS(p, c)

View File

@ -123,7 +123,8 @@ void do_lock(struct domain_generic *dg, struct domain_generic **lsp)
btime lock_begin = current_time(); btime lock_begin = current_time();
pthread_mutex_lock(&dg->mutex); pthread_mutex_lock(&dg->mutex);
btime duration = current_time() - lock_begin; 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)); log(L_WARN "Locking of %s took %d ms", dg->name, (int) (duration TO_MS));
if (dg->prev || dg->locked_by) if (dg->prev || dg->locked_by)

View File

@ -152,9 +152,10 @@ static _Thread_local struct birdloop *birdloop_wakeup_masked;
static _Thread_local uint birdloop_wakeup_masked_count; static _Thread_local uint birdloop_wakeup_masked_count;
#define LOOP_NAME(loop) domain_name((loop)->time.domain) #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 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 (config && (config->latency_debug & (flags))) log(L_TRACE "Thread: " __VA_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) #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 */ /* Now we can actually do some work */
u64 dif = account_to(&loop->working); 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); LOOP_WARN(loop, "locked %lu us after its scheduled end time", dif NS TO_US);
uint repeat, loop_runs = 0; uint repeat, loop_runs = 0;

View File

@ -2247,7 +2247,8 @@ io_update_time(void)
{ {
event_open->duration = last_io_time - event_open->timestamp; 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", 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)); 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 void
io_log_event(void *hook, void *data, uint flag) 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(); io_update_time();
struct event_log_entry *en = event_log + event_log_pos; 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_pos %= EVENT_LOG_LENGTH; 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 static inline void
@ -2310,7 +2312,8 @@ void
watchdog_sigalrm(int sig UNUSED) watchdog_sigalrm(int sig UNUSED)
{ {
/* Update last_io_time and duration, but skip latency check */ /* 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(); io_update_time();
debug_safe("Watchdog timer timed out\n"); debug_safe("Watchdog timer timed out\n");
@ -2335,9 +2338,10 @@ watchdog_start(void)
loop_time = last_io_time; loop_time = last_io_time;
event_log_num = 0; 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; watchdog_active = 1;
} }
} }
@ -2354,7 +2358,8 @@ watchdog_stop(void)
} }
btime duration = last_io_time - loop_time; 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", log(L_WARN "I/O loop cycle took %u.%03u ms for %d events",
(uint) (duration TO_MS), (uint) (duration % 1000), event_log_num); (uint) (duration TO_MS), (uint) (duration % 1000), event_log_num);
} }

View File

@ -284,8 +284,10 @@ log_prepare(log_buffer *buf, int class)
buf->pos[LBP_TIMESTAMP] = buf->buf.pos; buf->pos[LBP_TIMESTAMP] = buf->buf.pos;
if (BIT32_TEST(&lf, LBP_TIMESTAMP)) 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()); int t = tm_format_real_time(buf->buf.pos, buf->buf.end - buf->buf.pos, fmt, current_real_time());
rcu_read_unlock();
if (t) if (t)
buf->buf.pos += t; buf->buf.pos += t;
else else
@ -307,8 +309,10 @@ log_prepare(log_buffer *buf, int class)
else else
buffer_puts(&buf->buf, "<time format error>"); 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); buffer_print(&buf->buf, " %s %s: ", hostname, bird_name);
rcu_read_unlock();
} }
buf->pos[LBP_THREAD_ID] = buf->buf.pos; buf->pos[LBP_THREAD_ID] = buf->buf.pos;

View File

@ -487,10 +487,12 @@ cli_rx(sock *s, uint size UNUSED)
return 0; return 0;
} }
#define GLOBAL_CLI_DEBUG (atomic_load_explicit(&global_runtime, memory_order_relaxed)->cli_debug)
static void static void
cli_err(sock *s, int err) cli_err(sock *s, int err)
{ {
if (config->cli_debug) if (GLOBAL_CLI_DEBUG)
{ {
if (err) if (err)
log(L_INFO "CLI connection dropped: %s", strerror(err)); log(L_INFO "CLI connection dropped: %s", strerror(err));
@ -505,7 +507,7 @@ static void
cli_connect_err(sock *s UNUSED, int err) cli_connect_err(sock *s UNUSED, int err)
{ {
ASSERT_DIE(err); ASSERT_DIE(err);
if (config->cli_debug) if (GLOBAL_CLI_DEBUG)
log(L_INFO "Failed to accept CLI connection: %s", strerror(err)); log(L_INFO "Failed to accept CLI connection: %s", strerror(err));
} }
@ -514,7 +516,7 @@ cli_connect(sock *s, uint size UNUSED)
{ {
cli *c; cli *c;
if (config->cli_debug) if (GLOBAL_CLI_DEBUG)
log(L_INFO "CLI connect"); log(L_INFO "CLI connect");
s->rx_hook = cli_rx; s->rx_hook = cli_rx;
s->tx_hook = cli_tx; s->tx_hook = cli_tx;