From d7fb9e5b065bf9eecb5bcbcf741b5f89695c5dcc Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 1 Sep 2022 20:38:50 +0200 Subject: [PATCH] ubus: add reload command This will reload all explicitly configured files (network json, peer lists) without causing unnecessary network disruption Signed-off-by: Felix Fietkau --- host.c | 49 +++++++++++++++++++++++++++++++++++++++---------- host.h | 1 + network.c | 23 +++++++++++++++++++++++ network.h | 2 ++ ubus.c | 14 ++++++++++++++ 5 files changed, 79 insertions(+), 10 deletions(-) diff --git a/host.c b/host.c index 71fc840..9fea39c 100644 --- a/host.c +++ b/host.c @@ -246,8 +246,9 @@ network_hosts_load_dynamic_file(struct network *net, const char *file) } static void -network_hosts_load_dynamic(struct network *net) +network_hosts_load_dynamic_peers(struct network *net) { + struct network_dynamic_peer *dyn; struct blob_attr *cur; int rem; @@ -258,6 +259,41 @@ network_hosts_load_dynamic(struct network *net) network_hosts_load_dynamic_file(net, blobmsg_get_string(cur)); blob_buf_free(&b); + + list_for_each_entry(dyn, &net->dynamic_peers, list) + vlist_add(&net->peers, &dyn->peer.node, &dyn->peer.key); +} + +static void +network_host_free_dynamic_peers(struct list_head *list) +{ + struct network_dynamic_peer *dyn, *dyn_tmp; + + list_for_each_entry_safe(dyn, dyn_tmp, list, list) { + list_del(&dyn->list); + free(dyn); + } +} + +void network_hosts_reload_dynamic_peers(struct network *net) +{ + struct network_peer *peer; + LIST_HEAD(old_entries); + + if (!net->config.peer_data) + return; + + list_splice_init(&net->dynamic_peers, &old_entries); + + vlist_for_each_element(&net->peers, peer, node) + if (peer->dynamic) + peer->node.version = net->peers.version - 1; + + network_hosts_load_dynamic_peers(net); + + vlist_flush(&net->peers); + + network_host_free_dynamic_peers(&old_entries); } void network_hosts_update_start(struct network *net) @@ -280,7 +316,6 @@ static void __network_hosts_update_done(struct network *net, bool free_net) { struct network_host *local, *host, *tmp; - struct network_dynamic_peer *dyn, *dyn_tmp; LIST_HEAD(old_dynamic); const char *local_name; @@ -307,18 +342,12 @@ __network_hosts_update_done(struct network *net, bool free_net) vlist_add(&net->peers, &host->peer.node, host->peer.key); } - network_hosts_load_dynamic(net); - - list_for_each_entry(dyn, &net->dynamic_peers, list) - vlist_add(&net->peers, &dyn->peer.node, &dyn->peer.key); + network_hosts_load_dynamic_peers(net); out: vlist_flush(&net->peers); - list_for_each_entry_safe(dyn, dyn_tmp, &old_dynamic, list) { - list_del(&dyn->list); - free(dyn); - } + network_host_free_dynamic_peers(&old_dynamic); list_for_each_entry_safe(host, tmp, &old_hosts, node.list) { list_del(&host->node.list); diff --git a/host.h b/host.h index 75fc949..040c292 100644 --- a/host.h +++ b/host.h @@ -106,6 +106,7 @@ network_host_uses_peer_route(struct network_host *host, struct network *net, void network_hosts_update_start(struct network *net); void network_hosts_update_done(struct network *net); void network_hosts_add(struct network *net, struct blob_attr *hosts); +void network_hosts_reload_dynamic_peers(struct network *net); void network_hosts_init(struct network *net); void network_hosts_free(struct network *net); diff --git a/network.c b/network.c index 48b0716..cb3e94b 100644 --- a/network.c +++ b/network.c @@ -100,7 +100,9 @@ static void network_load_config_data(struct network *net, struct blob_attr *data static int network_load_data(struct network *net, struct blob_attr *data) { struct blob_attr *tb[__NETDATA_ATTR_MAX]; + siphash_key_t key = {}; + net->net_config.hash = siphash(data, blob_raw_len(data), &key); blobmsg_parse(netdata_policy, __NETDATA_ATTR_MAX, tb, blobmsg_data(data), blobmsg_len(data)); @@ -424,6 +426,27 @@ static void network_reload(struct uloop_timeout *t) network_pex_open(net); } +void network_soft_reload(struct network *net) +{ + siphash_key_t key = {}; + uint64_t hash; + + if (net->config.type == NETWORK_TYPE_FILE) { + blob_buf_init(&b, 0); + + if (!blobmsg_add_json_from_file(&b, net->config.file)) + return; + + hash = siphash(b.head, blob_raw_len(b.head), &key); + if (hash != net->net_config.hash) { + uloop_timeout_set(&net->reload_timer, 1); + return; + } + } + + network_hosts_reload_dynamic_peers(net); +} + static int network_setup(struct network *net) { if (wg_init_network(net)) { diff --git a/network.h b/network.h index 38bb8e2..344c5d2 100644 --- a/network.h +++ b/network.h @@ -42,6 +42,7 @@ struct network { } config; struct { + uint64_t hash; union network_addr addr; struct network_host *local_host; unsigned int keepalive; @@ -99,6 +100,7 @@ static inline const char *network_name(struct network *net) void network_fill_host_addr(union network_addr *addr, uint8_t *key); int network_save_dynamic(struct network *net); +void network_soft_reload(struct network *net); void network_free_all(void); int unetd_network_add(const char *name, struct blob_attr *config); diff --git a/ubus.c b/ubus.c index 323fe44..df45a54 100644 --- a/ubus.c +++ b/ubus.c @@ -250,6 +250,19 @@ ubus_network_connect(struct ubus_context *ctx, struct ubus_object *obj, return 0; } +static int +ubus_reload(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct network *net; + + avl_for_each_element(&networks, net, node) + network_soft_reload(net); + + return 0; +} + static const struct ubus_method unetd_methods[] = { UBUS_METHOD("network_add", ubus_network_add, network_policy), @@ -258,6 +271,7 @@ static const struct ubus_method unetd_methods[] = { UBUS_METHOD_MASK("network_get", ubus_network_get, network_policy, (1 << NETWORK_ATTR_NAME)), UBUS_METHOD("network_connect", ubus_network_connect, connect_policy), + UBUS_METHOD_NOARG("reload", ubus_reload), UBUS_METHOD("service_get", ubus_service_get, service_policy), }; -- 2.30.2