diff --git a/conf/conf.c b/conf/conf.c index 9f259691..e80e0ac6 100644 --- a/conf/conf.c +++ b/conf/conf.c @@ -113,9 +113,9 @@ config_alloc(const char *name) c->pool = p; c->mem = l; c->file_name = ndup; - 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; + c->runtime.tf_route = c->runtime.tf_proto = TM_ISO_SHORT_MS; + c->runtime.tf_base = c->runtime.tf_log = TM_ISO_LONG_MS; + c->runtime.gr_wait = DEFAULT_GR_WAIT; callback_init(&c->obstacles_cleared, config_obstacles_cleared, &main_birdloop); obstacle_target_init(&c->obstacles, &c->obstacles_cleared, p, "Config"); @@ -229,42 +229,15 @@ config_free_old(void) old_config = NULL; } -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) { /* 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); + union bird_global_runtime *ng = &new->runtime; + SKIP_BACK_DECLARE(union bird_global_runtime, og, generic, + atomic_load_explicit(&global_runtime, memory_order_relaxed)); -#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) + if (!ng->router_id && old) { /* The startup router ID must be determined after start of device protocol, * thus if old == NULL then we do nothing */ @@ -280,10 +253,7 @@ global_commit(struct config *new, struct config *old) } } - 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(); + switch_runtime(&ng->generic); } static int @@ -306,11 +276,11 @@ config_do_commit(config_ref *cr, int type) OBSREF_CLEAR(config); OBSREF_SET(config, OBSREF_GET(*cr)); - if (!c->hostname) + if (!c->runtime.hostname) { - c->hostname = get_hostname(c->mem); + c->runtime.hostname = get_hostname(c->mem); - if (!c->hostname) + if (!c->runtime.hostname) log(L_WARN "Cannot determine hostname"); } diff --git a/conf/conf.h b/conf/conf.h index 9a06ad4d..60c89267 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -13,6 +13,7 @@ #include "lib/ip.h" #include "lib/hash.h" #include "lib/resource.h" +#include "lib/runtime.h" #include "lib/obstacle.h" #include "lib/timer.h" @@ -32,33 +33,30 @@ struct config { struct symbol *def_tables[NET_MAX]; /* Default routing tables for each network */ struct iface_patt *router_id_from; /* Configured list of router ID iface patterns */ - u32 router_id; /* Our Router ID */ u32 proto_default_debug; /* Default protocol debug mask */ u32 proto_default_mrtdump; /* Default protocol mrtdump mask */ u32 channel_default_debug; /* Default channel debug mask */ u32 table_default_debug; /* Default table debug mask */ u32 show_route_debug; /* Exports to CLI debug mask */ u16 filter_vstk, filter_estk; /* Filter stack depth */ - 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) */ - const char *hostname; /* Hostname */ - int cli_debug; /* Tracing of CLI connections and commands */ - enum latency_debug_flags { - DL_PING = 1, - DL_WAKEUP = 2, - DL_SCHEDULING = 4, - DL_ALLOCATOR = 8, - DL_SOCKETS = 0x10, - DL_EVENTS = 0x20, - DL_TIMERS = 0x40, - } latency_debug; /* I/O loops log information about task scheduling */ - 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) */ + union bird_global_runtime { + struct global_runtime generic; + struct { + GLOBAL_RUNTIME_CONTENTS; + + struct timeformat tf_route; /* Time format for 'show route' */ + struct timeformat tf_proto; /* Time format for 'show protocol' */ + + u32 gr_wait; /* Graceful restart wait timeout (sec) */ + + u32 router_id; /* Our Router ID */ + + int cli_debug; /* Tracing of CLI connections and commands */ + u32 watchdog_timeout; /* Watchdog timeout (in seconds, 0 = disabled) */ + }; + } runtime; + char *err_msg; /* Parser error message */ int err_lino; /* Line containing error */ int err_chno; /* Character where the parser stopped */ @@ -76,26 +74,8 @@ struct config { int gr_down; /* This is a pseudo-config for graceful restart */ }; -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; +/* BIRD's global runtime accessor */ +#define BIRD_GLOBAL_RUNTIME SKIP_BACK(union bird_global_runtime, generic, atomic_load_explicit(&global_runtime, memory_order_relaxed)) /* Please don't use these variables in protocols. Use proto_config->global instead. */ typedef OBSREF(struct config) config_ref; diff --git a/lib/Makefile b/lib/Makefile index 1a2cc928..9d977e67 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,4 +1,4 @@ -src := a-path.c a-set.c bitmap.c bitops.c blake2s.c blake2b.c checksum.c defer.c event.c flowspec.c idm.c ip.c lists.c lockfree.c mac.c md5.c mempool.c net.c netindex.c patmatch.c printf.c rcu.c resource.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c +src := a-path.c a-set.c bitmap.c bitops.c blake2s.c blake2b.c checksum.c defer.c event.c flowspec.c idm.c ip.c lists.c lockfree.c mac.c md5.c mempool.c net.c netindex.c patmatch.c printf.c rcu.c resource.c runtime.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c obj := $(src-o-files) $(all-daemon) diff --git a/lib/runtime.c b/lib/runtime.c new file mode 100644 index 00000000..cf40c124 --- /dev/null +++ b/lib/runtime.c @@ -0,0 +1,32 @@ +/* + * BIRD Internet Routing Daemon -- Global runtime context + * + * (c) 2024 Maria Matejka + * (c) 2024 CZ.NIC, z.s.p.o. + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#include "lib/runtime.h" + +struct global_runtime global_runtime_initial = { + .tf_log = { + .fmt1 = "%F %T.%3f", + }, + .tf_base = { + .fmt1 = "%F %T.%3f", + }, +}; + +struct global_runtime * _Atomic global_runtime = &global_runtime_initial; + +void +switch_runtime(struct global_runtime *new) +{ + new->load_time = current_time(); + atomic_store_explicit(&global_runtime, new, memory_order_release); + + /* We have to wait until every reader surely doesn't read the old values */ + synchronize_rcu(); +} + diff --git a/lib/runtime.h b/lib/runtime.h new file mode 100644 index 00000000..455f89a8 --- /dev/null +++ b/lib/runtime.h @@ -0,0 +1,35 @@ +/* + * BIRD Internet Routing Daemon -- Global runtime context + * + * (c) 2024 Maria Matejka + * (c) 2024 CZ.NIC, z.s.p.o. + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#include "lib/timer.h" + +/* I/O loops log information about task scheduling */ +enum latency_debug_flags { + DL_PING = 1, + DL_WAKEUP = 2, + DL_SCHEDULING = 4, + DL_ALLOCATOR = 8, + DL_SOCKETS = 0x10, + DL_EVENTS = 0x20, + DL_TIMERS = 0x40, +}; + +#define GLOBAL_RUNTIME_CONTENTS \ + struct timeformat tf_log; /* Time format for the logfile */ \ + struct timeformat tf_base; /* Time format for other purposes */ \ + btime load_time; /* When we reconfigured last time */ \ + enum latency_debug_flags latency_debug; /* What to log about IO loop */ \ + u32 latency_limit; /* Events with longer duration are logged (us) */ \ + u32 watchdog_warning; /* I/O loop watchdog limit for warning (us) */ \ + const char *hostname; /* Hostname */ \ + +struct global_runtime { GLOBAL_RUNTIME_CONTENTS }; +extern struct global_runtime * _Atomic global_runtime; + +void switch_runtime(struct global_runtime *); diff --git a/nest/cli.c b/nest/cli.c index 24535e3f..3d7d4d5e 100644 --- a/nest/cli.c +++ b/nest/cli.c @@ -221,7 +221,7 @@ cli_command(struct cli *c) struct config f; int res; - if (OBSREF_GET(config)->cli_debug > 1) + if (BIRD_GLOBAL_RUNTIME->cli_debug > 1) log(L_TRACE "CLI: %s", c->rx_buf); bzero(&f, sizeof(f)); f.mem = c->parser_pool; diff --git a/nest/cmds.c b/nest/cmds.c index b55d2c23..7b1181a6 100644 --- a/nest/cmds.c +++ b/nest/cmds.c @@ -25,7 +25,7 @@ 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); + union bird_global_runtime *gr = BIRD_GLOBAL_RUNTIME; struct timeformat *tf = &gr->tf_base; cli_msg(-1000, "BIRD " BIRD_VERSION); diff --git a/nest/config.Y b/nest/config.Y index a0a10daf..7449fb64 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -202,7 +202,7 @@ CF_GRAMMAR conf: rtrid ; rtrid: - ROUTER ID idval ';' { new_config->router_id = $3; } + ROUTER ID idval ';' { new_config->runtime.router_id = $3; } | ROUTER ID FROM iface_patt ';' { new_config->router_id_from = this_ipatt; } ; @@ -222,11 +222,11 @@ idval: conf: hostname_override ; -hostname_override: HOSTNAME text ';' { new_config->hostname = $2; } ; +hostname_override: HOSTNAME text ';' { new_config->runtime.hostname = $2; } ; conf: gr_opts ; -gr_opts: GRACEFUL RESTART WAIT expr ';' { new_config->gr_wait = $4; } ; +gr_opts: GRACEFUL RESTART WAIT expr ';' { new_config->runtime.gr_wait = $4; } ; /* Network types (for tables, channels) */ @@ -443,7 +443,7 @@ debug_default: DEBUG PROTOCOLS debug_mask { new_config->proto_default_debug = $3; } | DEBUG CHANNELS debug_mask { new_config->channel_default_debug = $3; } | DEBUG TABLES debug_mask { new_config->table_default_debug = $3; } - | DEBUG COMMANDS expr { new_config->cli_debug = $3; } + | DEBUG COMMANDS expr { new_config->runtime.cli_debug = $3; } | DEBUG SHOW ROUTE debug_mask { new_config->show_route_debug = $4; } ; @@ -452,10 +452,10 @@ debug_default: conf: timeformat_base ; timeformat_which: - ROUTE { $$ = &new_config->tf_route; } - | PROTOCOL { $$ = &new_config->tf_proto; } - | BASE { $$ = &new_config->tf_base; } - | LOG { $$ = &new_config->tf_log; } + ROUTE { $$ = &new_config->runtime.tf_route; } + | PROTOCOL { $$ = &new_config->runtime.tf_proto; } + | BASE { $$ = &new_config->runtime.tf_base; } + | LOG { $$ = &new_config->runtime.tf_log; } ; timeformat_spec: @@ -736,7 +736,7 @@ r_args: $$->filter = FILTER_ACCEPT; OBSREF_SET($$->running_on_config, this_cli->main_config); $$->cli = this_cli; - $$->tf_route = this_cli->main_config->tf_route; + $$->tf_route = this_cli->main_config->runtime.tf_route; } | r_args net_any { $$ = $1; diff --git a/nest/iface.c b/nest/iface.c index 1059ae06..27ac4123 100644 --- a/nest/iface.c +++ b/nest/iface.c @@ -165,7 +165,7 @@ if_dump_all(void) IFACE_WALK(i) if_dump(i); rcu_read_lock(); - debug("Router ID: %08x\n", atomic_load_explicit(&global_runtime, memory_order_relaxed)->router_id); + debug("Router ID: %08x\n", BIRD_GLOBAL_RUNTIME->router_id); rcu_read_unlock(); } diff --git a/nest/proto.c b/nest/proto.c index 2bb0766e..6b0cb755 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -1671,7 +1671,7 @@ protos_do_commit(struct config *new, struct config *old, int type) global_commit() because it is postponed after start of device protocol */ if ((phase == PROTOCOL_STARTUP_NECESSARY) && !old) { - struct global_runtime *gr = atomic_load_explicit(&global_runtime, memory_order_relaxed); + union bird_global_runtime *gr = BIRD_GLOBAL_RUNTIME; if (!gr->router_id) { gr->router_id = if_choose_router_id(new->router_id_from, 0); @@ -1830,7 +1830,7 @@ graceful_restart_init(void) graceful_restart_state = GRS_ACTIVE; gr_wait_timer = tm_new_init(proto_pool, graceful_restart_done, NULL, 0, 0); - u32 gr_wait = atomic_load_explicit(&global_runtime, memory_order_relaxed)->gr_wait; + u32 gr_wait = BIRD_GLOBAL_RUNTIME->gr_wait; tm_start(gr_wait_timer, gr_wait S); } @@ -1884,7 +1884,7 @@ 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), - atomic_load_explicit(&global_runtime, memory_order_relaxed)->gr_wait); + BIRD_GLOBAL_RUNTIME->gr_wait); } /** @@ -2472,7 +2472,7 @@ proto_cmd_show(struct proto *p, uintptr_t verbose, int cnt) p->proto->get_status(p, buf); rcu_read_lock(); - tm_format_time(tbuf, &atomic_load_explicit(&global_runtime, memory_order_acquire)->tf_proto, p->last_state_change); + tm_format_time(tbuf, &BIRD_GLOBAL_RUNTIME->tf_proto, p->last_state_change); rcu_read_unlock(); cli_msg(-1002, "%-10s %-10s %-10s %-6s %-12s %s", p->name, diff --git a/nest/protocol.h b/nest/protocol.h index bbb76a8a..3e9eacf4 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -303,7 +303,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 ?: atomic_load_explicit(&global_runtime, memory_order_relaxed)->router_id; + return pc->router_id ?: BIRD_GLOBAL_RUNTIME->router_id; } diff --git a/proto/bfd/bfd.c b/proto/bfd/bfd.c index e6bf3f39..f0c56832 100644 --- a/proto/bfd/bfd.c +++ b/proto/bfd/bfd.c @@ -1239,7 +1239,7 @@ bfd_show_session(struct bfd_session *s, int details) byte tbuf[TM_DATETIME_BUFFER_SIZE]; rcu_read_lock(); - struct global_runtime *gr = atomic_load_explicit(&global_runtime, memory_order_relaxed); + union bird_global_runtime *gr = BIRD_GLOBAL_RUNTIME; tm_format_time(tbuf, &gr->tf_proto, s->last_state_change); rcu_read_unlock(); diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 10ee4bc0..c9cfbf22 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -284,7 +284,7 @@ bgp_prepare_capabilities(struct bgp_conn *conn) caps->llgr_aware = 1; rcu_read_lock(); - struct global_runtime *gr = atomic_load_explicit(&global_runtime, memory_order_relaxed); + union bird_global_runtime *gr = BIRD_GLOBAL_RUNTIME; if (p->cf->enable_hostname && gr->hostname) { size_t length = strlen(gr->hostname); diff --git a/sysdep/unix/config.Y b/sysdep/unix/config.Y index 46365c85..60541e44 100644 --- a/sysdep/unix/config.Y +++ b/sysdep/unix/config.Y @@ -132,10 +132,10 @@ conf: THREADS expr { conf: debug_unix ; debug_unix: - DEBUG LATENCY latency_debug_mask { new_config->latency_debug = $3; } - | DEBUG LATENCY LIMIT expr_us { new_config->latency_limit = $4; } - | WATCHDOG WARNING expr_us { new_config->watchdog_warning = $3; } - | WATCHDOG TIMEOUT expr_us { new_config->watchdog_timeout = ($3 + 999999) TO_S; } + DEBUG LATENCY latency_debug_mask { new_config->runtime.latency_debug = $3; } + | DEBUG LATENCY LIMIT expr_us { new_config->runtime.latency_limit = $4; } + | WATCHDOG WARNING expr_us { new_config->runtime.watchdog_warning = $3; } + | WATCHDOG TIMEOUT expr_us { new_config->runtime.watchdog_timeout = ($3 + 999999) TO_S; } ; latency_debug_mask: diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index b09039dc..e8d37848 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -464,7 +464,7 @@ watchdog_start(void) loop_time = last_io_time; event_log_num = 0; - struct global_runtime *gr = atomic_load_explicit(&global_runtime, memory_order_relaxed); + union bird_global_runtime *gr = BIRD_GLOBAL_RUNTIME; if (gr->watchdog_timeout) { alarm(gr->watchdog_timeout); @@ -484,7 +484,7 @@ watchdog_stop(void) } btime duration = last_io_time - loop_time; - struct global_runtime *gr = atomic_load_explicit(&global_runtime, memory_order_relaxed); + union bird_global_runtime *gr = BIRD_GLOBAL_RUNTIME; 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); diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c index 0f97f422..4b809d87 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -191,8 +191,8 @@ sysdep_preconfig(struct config *c) { init_list(&c->logfiles); - c->latency_limit = UNIX_DEFAULT_LATENCY_LIMIT; - c->watchdog_warning = UNIX_DEFAULT_WATCHDOG_WARNING; + c->runtime.latency_limit = UNIX_DEFAULT_LATENCY_LIMIT; + c->runtime.watchdog_warning = UNIX_DEFAULT_WATCHDOG_WARNING; #ifdef PATH_IPROUTE_DIR read_iproute_table(c, PATH_IPROUTE_DIR "/rt_protos", "ipp_", 255); @@ -489,7 +489,7 @@ cli_rx(sock *s, uint size UNUSED) return 0; } -#define GLOBAL_CLI_DEBUG (atomic_load_explicit(&global_runtime, memory_order_relaxed)->cli_debug) +#define GLOBAL_CLI_DEBUG (BIRD_GLOBAL_RUNTIME->cli_debug) static void cli_err(sock *s, int err)