ubus: add reload command
authorFelix Fietkau <nbd@nbd.name>
Thu, 1 Sep 2022 18:38:50 +0000 (20:38 +0200)
committerFelix Fietkau <nbd@nbd.name>
Thu, 1 Sep 2022 18:38:52 +0000 (20:38 +0200)
This will reload all explicitly configured files (network json, peer lists)
without causing unnecessary network disruption

Signed-off-by: Felix Fietkau <nbd@nbd.name>
host.c
host.h
network.c
network.h
ubus.c

diff --git a/host.c b/host.c
index 71fc8408ef3cfaa1a2064190f4e4e253fd390a52..9fea39c08a10b2a2b0e7744035e02cb0af1280c0 100644 (file)
--- 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 75fc9490ed534a75c9b1e3b170637254d1f9ee47..040c292f42fa7f086ce24b0cab64efea2609c8d3 100644 (file)
--- 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);
index 48b0716c04ca3156ed9564cff2945f034ee3fbba..cb3e94b5e03e91931c497524fc3cad98d95fa279 100644 (file)
--- 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)) {
index 38bb8e26f4c05c5af75d147f294d117b31883baf..344c5d23e61679dc8bc760a29b63f390b9eb6206 100644 (file)
--- 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 323fe44cfa6aba9b79c66f888c196ac9de60fe4c..df45a546adc68d5c804bc11bd3510fd0128ba466 100644 (file)
--- 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),
 };