0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-22 09:41: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->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);
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)
{
new->router_id = old->router_id;
/* 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)
{
u32 id = if_choose_router_id(new->router_id_from, old->router_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
new->router_id = id;
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

View 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 */

View 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)

View 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

View 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

View File

@ -1624,12 +1624,16 @@ 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)
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 */
if (new->shutdown && !new->gr_down)
@ -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,

View 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;
}

View 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)
{

View 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)

View 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)

View 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;

View 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);
}

View 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;

View 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;