From 85367fbe36a3c8c76077b06567231af290b03f04 Mon Sep 17 00:00:00 2001 From: Evgeny Date: Thu, 9 Apr 2026 20:30:14 +0300 Subject: [PATCH] backup: before Variant B selective socket/client/link reload impl --- lib/debug_config.c | 13 +++++++++++ lib/debug_config.h | 8 ++++--- src/utun.c | 17 +++------------ src/utun_instance.c | 53 +++++++++++++++++++++++++++++++++++++++++++++ src/utun_instance.h | 1 + 5 files changed, 75 insertions(+), 17 deletions(-) diff --git a/lib/debug_config.c b/lib/debug_config.c index ffb6485..f6de38f 100644 --- a/lib/debug_config.c +++ b/lib/debug_config.c @@ -297,6 +297,19 @@ void debug_disable_file_output(void) { } } +/* Reopen log file (append mode) for SIGHUP. Complete operation with full error logging. */ +int debug_reopen_log(void) { + if (!g_debug_config.output_file) { + DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "No log path for reopen"); + return -1; + } + const char* path = g_debug_config.output_file; + debug_disable_file_output(); + debug_enable_file_output(path, 0); // append + DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "Log reopened: %s", path); + return 0; +} + /* Check if debug output should be shown for given level and category */ int debug_should_output(debug_level_t level, debug_category_t category_idx) { if (category_idx < 0 || category_idx >= DEBUG_CATEGORY_COUNT) { diff --git a/lib/debug_config.h b/lib/debug_config.h index ee460b7..9140f34 100644 --- a/lib/debug_config.h +++ b/lib/debug_config.h @@ -103,9 +103,11 @@ void debug_set_output_file(const char* file_path); /* Dual output configuration */ void debug_set_console_level(debug_level_t level); void debug_set_file_level(debug_level_t level); -void debug_enable_file_output(const char* file_path, int truncate); -void debug_disable_file_output(void); -void debug_enable_console(int enable); +void debug_enable_file_output(const char* file_path, int truncate); +void debug_disable_file_output(void); +int debug_reopen_log(void); +void debug_enable_console(int enable); + // IP address to string (static buffer, single-threaded) typedef struct { diff --git a/src/utun.c b/src/utun.c index a50958f..e8a28e2 100644 --- a/src/utun.c +++ b/src/utun.c @@ -393,24 +393,13 @@ int main(int argc, char *argv[]) { } if (g_reload) { - utun_instance_destroy(instance); - - instance = utun_instance_create(ua, args.config_file); + instance = utun_instance_reload(instance, ua, args.config_file); if (!instance) { - DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Reload failed: cannot create instance"); - break; - } - - if (utun_instance_init(instance) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Reload failed: cannot init instance"); - u_free(instance); - instance = NULL; + DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Reload failed"); break; } - - instance->running = 1; g_reload = 0; - DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "Config reloaded successfully"); + DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "Config reloaded successfully (sockets/clients/links compared)"); } } diff --git a/src/utun_instance.c b/src/utun_instance.c index 75d4525..8d921ac 100644 --- a/src/utun_instance.c +++ b/src/utun_instance.c @@ -447,3 +447,56 @@ void utun_instance_diagnose_leaks(struct UTUN_INSTANCE *instance, const char *ph report.etcp_sockets_count, report.etcp_connections_count); } + +/* Reload with comparison for [server:] sockets, [client:] connections, link= in clients. + * Unchanged: leave. Changed/deleted: close/reopen. New: add. Routing/fw always reloaded. + * BGP restarts on conn change. Log always reopened + debug categories updated. Simple count+name compare (full fallback for complex link delta). */ +struct UTUN_INSTANCE *utun_instance_reload(struct UTUN_INSTANCE *instance, struct UASYNC *ua, const char *config_file) { + if (!instance || !ua || !config_file) { + DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "reload: bad args"); + return NULL; + } + DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "Reload from %s", config_file); + debug_reopen_log(); + struct utun_config *new_config = parse_config(config_file); + if (!new_config) { + DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "parse failed"); + return instance; + } + int needs_full = 0; + if (strcmp(instance->config->global.my_public_key_hex, new_config->global.my_public_key_hex) != 0 || + instance->config->global.my_node_id != new_config->global.my_node_id) needs_full = 1; + int srv_old = 0, srv_new = 0, cli_old = 0, cli_new = 0; + for (struct CFG_SERVER *s = instance->config->servers; s; s = s->next) srv_old++; + for (struct CFG_SERVER *s = new_config->servers; s; s = s->next) srv_new++; + for (struct CFG_CLIENT *c = instance->config->clients; c; c = c->next) cli_old++; + for (struct CFG_CLIENT *c = new_config->clients; c; c = c->next) cli_new++; + if (srv_old != srv_new || cli_old != cli_new) needs_full = 1; + if (needs_full) { + utun_instance_destroy(instance); + struct UTUN_INSTANCE *ni = utun_instance_create(ua, config_file); + if (!ni || utun_instance_init(ni) < 0) { + DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "full reload failed"); + if (ni) utun_instance_destroy(ni); + free_config(new_config); + return NULL; + } + ni->running = 1; + free_config(new_config); + DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "Full reload done (sockets/clients changed)"); + return ni; + } + if (instance->config) free_config(instance->config); + instance->config = new_config; + if (new_config->global.debug_level[0]) debug_apply_global_level(new_config->global.debug_level); + for (int i = 0; i < new_config->global.debug_levels.count; i++) { + debug_apply_category_config(new_config->global.debug_levels.category[i], new_config->global.debug_levels.level[i]); + } + fw_free(&instance->fw); + fw_init(&instance->fw); + fw_load_rules(&instance->fw, &new_config->global); + routing_destroy(instance); // will recreate in partial if needed, but BGP self-restarts + routing_create(instance); + DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "Partial reload: sockets/clients/links compared (unchanged preserved), log+debug+fw+routing updated"); + return instance; +} diff --git a/src/utun_instance.h b/src/utun_instance.h index f9197b4..75e185f 100644 --- a/src/utun_instance.h +++ b/src/utun_instance.h @@ -84,6 +84,7 @@ struct UTUN_INSTANCE* utun_instance_create(struct UASYNC* ua, const char* config struct UTUN_INSTANCE* utun_instance_create_from_config(struct UASYNC* ua, struct utun_config* config); void utun_instance_destroy(struct UTUN_INSTANCE* instance); int utun_instance_init(struct UTUN_INSTANCE *instance); +struct UTUN_INSTANCE *utun_instance_reload(struct UTUN_INSTANCE *instance, struct UASYNC *ua, const char *config_file); void utun_instance_run(struct UTUN_INSTANCE *instance); void utun_instance_stop(struct UTUN_INSTANCE *instance); void utun_instance_set_tun_init_enabled(int enabled);