From e7d749a6e8b003e57fd9a8a7b740f5845c0bea3c Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Tue, 27 Aug 2024 17:50:30 +0200 Subject: [PATCH] Global runtime splitout to BIRD specific and lib things --- conf/conf.c | 54 +++++++++----------------------------- conf/conf.h | 62 +++++++++++++++----------------------------- lib/Makefile | 2 +- lib/runtime.c | 32 +++++++++++++++++++++++ lib/runtime.h | 35 +++++++++++++++++++++++++ nest/cli.c | 2 +- nest/cmds.c | 2 +- nest/config.Y | 18 ++++++------- nest/iface.c | 2 +- nest/proto.c | 19 +++++++++----- nest/protocol.h | 2 +- proto/bfd/bfd.c | 2 +- proto/bgp/packets.c | 2 +- proto/mrt/mrt.c | 5 +++- sysdep/unix/config.Y | 8 +++--- sysdep/unix/io.c | 4 +-- sysdep/unix/main.c | 6 ++--- 17 files changed, 141 insertions(+), 116 deletions(-) create mode 100644 lib/runtime.c create mode 100644 lib/runtime.h diff --git a/conf/conf.c b/conf/conf.c index cfe484cbc..2002fe69f 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); - -#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) + union bird_global_runtime *ng = &new->runtime; + SKIP_BACK_DECLARE(union bird_global_runtime, og, generic, + atomic_load_explicit(&global_runtime, memory_order_relaxed)); + + 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 03ef4ef82..db261e56e 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" #include "lib/tlists.h" @@ -34,33 +35,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 */ @@ -78,26 +76,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 5ed759e9d..63efd083b 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 000000000..cf40c124f --- /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 000000000..455f89a80 --- /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 b33ffd437..6cfb25275 100644 --- a/nest/cli.c +++ b/nest/cli.c @@ -250,7 +250,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 a42112bcc..594d0675c 100644 --- a/nest/cmds.c +++ b/nest/cmds.c @@ -23,7 +23,7 @@ void cmd_show_status(void) { 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 = this_cli->tf ?: &gr->tf_base; byte tim[TM_DATETIME_BUFFER_SIZE]; diff --git a/nest/config.Y b/nest/config.Y index 30ecc819b..9ed9c124f 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -206,7 +206,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; } ; @@ -226,11 +226,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) */ @@ -447,7 +447,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; } ; @@ -460,10 +460,10 @@ 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: @@ -722,7 +722,7 @@ r_args: init_list(&($$->tables)); $$->filter = FILTER_ACCEPT; $$->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 4782b3efa..0e8b4df74 100644 --- a/nest/iface.c +++ b/nest/iface.c @@ -165,7 +165,7 @@ if_dump_all(struct dump_request *dreq) IFACE_WALK(i) if_dump_locked(dreq, i); rcu_read_lock(); - RDUMP("Router ID: %08x\n", atomic_load_explicit(&global_runtime, memory_order_relaxed)->router_id); + RDUMP("Router ID: %08x\n", BIRD_GLOBAL_RUNTIME->router_id); rcu_read_unlock(); } diff --git a/nest/proto.c b/nest/proto.c index caf99829b..7908a019e 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -1771,7 +1771,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); @@ -2008,7 +2008,7 @@ graceful_restart_init(void) _graceful_recovery_context.grc_state = GRS_ACTIVE; _graceful_recovery_context.wait_timer = (timer) { .hook = graceful_recovery_timeout }; - u32 gr_wait = atomic_load_explicit(&global_runtime, memory_order_relaxed)->gr_wait; + u32 gr_wait = BIRD_GLOBAL_RUNTIME->gr_wait; tm_start(&_graceful_recovery_context.wait_timer, gr_wait S); callback_init(&_graceful_recovery_context.obstacles_cleared, graceful_recovery_done, &main_birdloop); @@ -2029,7 +2029,7 @@ graceful_restart_show_status(void) obstacle_target_count(&_graceful_recovery_context.obstacles)); cli_msg(-24, " Wait timer is %t/%u", tm_remains(&_graceful_recovery_context.wait_timer), - atomic_load_explicit(&global_runtime, memory_order_relaxed)->gr_wait); + BIRD_GLOBAL_RUNTIME->gr_wait); } /** @@ -2668,11 +2668,16 @@ proto_cmd_show(struct proto *p, uintptr_t verbose, int cnt) if (p->proto->get_status) p->proto->get_status(p, buf); - rcu_read_lock(); - struct timeformat *tf = this_cli->tf ?: &atomic_load_explicit(&global_runtime, memory_order_acquire)->tf_proto; - rcu_read_unlock(); + struct timeformat *tf = this_cli->tf; + if (this_cli->tf) + tm_format_time(tbuf, this_cli->tf, p->last_state_change); + else + { + rcu_read_lock(); + tm_format_time(tbuf, &BIRD_GLOBAL_RUNTIME->tf_proto, p->last_state_change); + rcu_read_unlock(); + } - tm_format_time(tbuf, tf, p->last_state_change); cli_msg(-1002, "%-10s %-10s %-10s %-6s %-12s %s", p->name, p->proto->name, diff --git a/nest/protocol.h b/nest/protocol.h index ec561b263..3fba4d942 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -309,7 +309,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 4997f803a..c85dda303 100644 --- a/proto/bfd/bfd.c +++ b/proto/bfd/bfd.c @@ -1251,7 +1251,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, this_cli->tf ?: &gr->tf_proto, s->last_state_change); rcu_read_unlock(); diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index a40ca91b4..3d8a04a3e 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/proto/mrt/mrt.c b/proto/mrt/mrt.c index 015a1e15b..af624b3dd 100644 --- a/proto/mrt/mrt.c +++ b/proto/mrt/mrt.c @@ -327,7 +327,10 @@ static void mrt_peer_table_dump(struct mrt_table_dump_state *s) { mrt_init_message(&s->buf, MRT_TABLE_DUMP_V2, MRT_PEER_INDEX_TABLE); - mrt_peer_table_header(s, OBSREF_GET(config)->router_id, s->table_open->name); + + rcu_read_lock(); + mrt_peer_table_header(s, BIRD_GLOBAL_RUNTIME->router_id, s->table_open->name); + rcu_read_unlock(); /* 0 is fake peer for non-BGP routes */ mrt_peer_table_entry(s, 0, 0, IPA_NONE); diff --git a/sysdep/unix/config.Y b/sysdep/unix/config.Y index 42d78c6f6..303769153 100644 --- a/sysdep/unix/config.Y +++ b/sysdep/unix/config.Y @@ -154,10 +154,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 45999c210..f9aee4737 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -613,7 +613,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); @@ -633,7 +633,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 4c38cf0f2..8a94b74d5 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -211,8 +211,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); @@ -533,7 +533,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) -- 2.47.2