]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- fast-reload, reload the config and swap trees for forwards and stub hints.
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Tue, 9 Jan 2024 11:06:00 +0000 (12:06 +0100)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Tue, 9 Jan 2024 11:06:00 +0000 (12:06 +0100)
daemon/remote.c
iterator/iter_fwd.c
iterator/iter_fwd.h
iterator/iter_hints.c
iterator/iter_hints.h

index 28c2ceccd0ff3488854caf77d04b49c31ff10ef4..ead1067f2cb2fe235a09511ed148e3e8268222d1 100644 (file)
@@ -3709,6 +3709,9 @@ struct fast_reload_construct {
        struct iter_forwards* fwds;
        /** construct for stubs */
        struct iter_hints* hints;
+       /** storage for the old configuration elements. The outer struct
+        * is allocated with malloc here, the items are from config. */
+       struct config_file* oldcfg;
 };
 
 /** fast reload thread, read config */
@@ -3754,6 +3757,13 @@ fr_construct_clear(struct fast_reload_construct* ct)
                return;
        forwards_delete(ct->fwds);
        hints_delete(ct->hints);
+       /* Delete the log identity here so that the global value is not
+        * reset by config_delete. */
+       if(ct->oldcfg->log_identity) {
+               free(ct->oldcfg->log_identity);
+               ct->oldcfg->log_identity = NULL;
+       }
+       config_delete(ct->oldcfg);
 }
 
 /** fast reload thread, construct from config the new items */
@@ -3779,6 +3789,11 @@ fr_construct_from_config(struct fast_reload_thread* fr,
        if(fr_poll_for_quit(fr))
                return 1;
 
+       if(!(ct->oldcfg = (struct config_file*)calloc(1,
+               sizeof(*ct->oldcfg)))) {
+               fr_construct_clear(ct);
+               return 0;
+       }
        return 1;
 }
 
@@ -3816,6 +3831,62 @@ fr_finish_time(struct fast_reload_thread* fr, struct timeval* time_start,
        return 1;
 }
 
+/** fast reload thread, reload config with putting the new config items
+ * in place and swapping out the old items. */
+static int
+fr_reload_config(struct fast_reload_thread* fr, struct config_file* newcfg,
+       struct fast_reload_construct* ct)
+{
+       struct daemon* daemon = fr->worker->daemon;
+       struct module_env* env = daemon->env;
+
+       /* Grab big locks to satisfy lock conditions. */
+       lock_rw_wrlock(&ct->fwds->lock);
+       lock_rw_wrlock(&ct->hints->lock);
+       lock_rw_wrlock(&env->fwds->lock);
+       lock_rw_wrlock(&env->hints->lock);
+
+       /* Store old config elements. */
+       *ct->oldcfg = *env->cfg;
+       /* Insert new config elements. */
+       *env->cfg = *newcfg;
+       if(env->cfg->log_identity || ct->oldcfg->log_identity) {
+               /* pick up new log_identity string to use for log output. */
+               log_ident_set_or_default(env->cfg->log_identity);
+       }
+       /* the newcfg elements are in env->cfg, so should not be freed here. */
+       memset(newcfg, 0, sizeof(*newcfg));
+
+       /* Quickly swap the tree roots themselves with the already allocated
+        * elements. This is a quick swap operation on the pointer.
+        * The other threads are stopped and locks are held, so that a
+        * consistent view of the configuration, before, and after, exists
+        * towards the state machine for query resolution. */
+       forwards_swap_tree(env->fwds, ct->fwds);
+       hints_swap_tree(env->hints, ct->hints);
+
+       /* Set globals with new config. */
+       config_apply(env->cfg);
+
+       lock_rw_unlock(&env->fwds->lock);
+       lock_rw_unlock(&env->hints->lock);
+       lock_rw_unlock(&ct->fwds->lock);
+       lock_rw_unlock(&ct->hints->lock);
+
+       return 1;
+}
+
+/** fast reload thread, reload ipc communication to stop and start threads. */
+static int
+fr_reload_ipc(struct fast_reload_thread* fr, struct config_file* newcfg,
+       struct fast_reload_construct* ct)
+{
+       if(!fr_reload_config(fr, newcfg, ct)) {
+               return 0;
+       }
+       return 1;
+}
+
 /** fast reload thread, load config */
 static int
 fr_load_config(struct fast_reload_thread* fr, struct timeval* time_read,
@@ -3854,6 +3925,14 @@ fr_load_config(struct fast_reload_thread* fr, struct timeval* time_read,
        }
 
        /* Reload server. */
+       if(!fr_reload_ipc(fr, newcfg, &ct)) {
+               config_delete(newcfg);
+               fr_construct_clear(&ct);
+               if(!fr_output_printf(fr, "error: reload failed\n"))
+                       return 0;
+               fr_send_notification(fr, fast_reload_notification_printout);
+               return 0;
+       }
        if(gettimeofday(time_reload, NULL) < 0)
                log_err("gettimeofday: %s", strerror(errno));
 
index cf418b0720fce0bae4760e8a322cc2a8917e4ad8..e2697bab4fdb8ff1a9e75a46d05191afbc3e416d 100644 (file)
@@ -539,3 +539,11 @@ forwards_delete_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm)
        fwd_zone_free(z);
        fwd_init_parents(fwd);
 }
+
+void
+forwards_swap_tree(struct iter_forwards* fwd, struct iter_forwards* data)
+{
+       rbtree_type* oldtree = fwd->tree;
+       fwd->tree = data->tree;
+       data->tree = oldtree;
+}
index c1160b8533097f1e274c53293b56f117b413c270..e51165edee5fc3c5e1f4068cbd27529aaf0e94fb 100644 (file)
@@ -207,4 +207,13 @@ int forwards_add_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm);
 void forwards_delete_stub_hole(struct iter_forwards* fwd, uint16_t c,
        uint8_t* nm);
 
+/**
+ * Swap internal tree with preallocated entries. Caller should manage
+ * the locks.
+ * @param fwd: the forward data structure.
+ * @param data: the data structure used to take elements from. This contains
+ *     the old elements on return.
+ */
+void forwards_swap_tree(struct iter_forwards* fwd, struct iter_forwards* data);
+
 #endif /* ITERATOR_ITER_FWD_H */
index a56aa8e409264da94fc280fa767433d1413332aa..ce2741eaf9676705572ec535873d6317ed60f60c 100644 (file)
@@ -575,3 +575,11 @@ hints_delete_stub(struct iter_hints* hints, uint16_t c, uint8_t* nm)
        hints_stub_free(z);
        name_tree_init_parents(&hints->tree);
 }
+
+void
+hints_swap_tree(struct iter_hints* hints, struct iter_hints* data)
+{
+       rbnode_type* oldroot = hints->tree.root;
+       hints->tree.root = data->tree.root;
+       data->tree.root = oldroot;
+}
index f201d8c11c4aaca170b0d255f25b429a85faf719..6f6b6dc68b77e0cbfb4e2a0667be6983a0e51616 100644 (file)
@@ -168,4 +168,13 @@ int hints_add_stub(struct iter_hints* hints, uint16_t c, struct delegpt* dp,
  */
 void hints_delete_stub(struct iter_hints* hints, uint16_t c, uint8_t* nm);
 
+/**
+ * Swap internal tree with preallocated entries. Caller should manage
+ * the locks.
+ * @param hints: the hints data structure.
+ * @param data: the data structure used to take elements from. This contains
+ *     the old elements on return.
+ */
+void hints_swap_tree(struct iter_hints* hints, struct iter_hints* data);
+
 #endif /* ITERATOR_ITER_HINTS_H */