]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
[master] Fix up the gentle shutdown code to handle failover
authorShawn Routhier <sar@isc.org>
Thu, 14 Nov 2013 20:55:10 +0000 (12:55 -0800)
committerShawn Routhier <sar@isc.org>
Thu, 14 Nov 2013 20:55:10 +0000 (12:55 -0800)
This patch modifies the gentle failover patch to
be cleaner and to handle failover peers better.

RELNOTES
client/dhclient.c
common/dispatch.c
dhcpctl/omshell.c
includes/omapip/isclib.h
omapip/isclib.c
relay/dhcrelay.c
server/dhcpd.c

index 18ffd448b6ed9fdbdd3588d568db42c00183ff9f..1eff1dcfec9bd5edac5b8fd7362e0117df670985 100644 (file)
--- a/RELNOTES
+++ b/RELNOTES
@@ -151,7 +151,7 @@ work on other platforms. Please report any problems and suggested fixes to
   [ISC-Bugs #34784]
 
 - Added support for gentle shutdown after signal is received.
-  [ISC-BUGS #32692]
+  [ISC-Bugs #32692] [ISC-Bugs 34945]
 
 - Enhance the DHCPv6 server logging to include the addresses that are assigned
   to the clients.
index f131e39302041b53a60e0e3e553ebc6acabafa61..97b86a6f93c34caef7b34f31858f5874efa9e726 100644 (file)
@@ -708,6 +708,7 @@ main(int argc, char **argv) {
        /* Start dispatching packets and timeouts... */
        dispatch();
 
+       /* In fact dispatch() never returns. */
        return 0;
 }
 
@@ -3944,6 +3945,20 @@ isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
        struct client_state *client;
        struct timeval tv;
 
+       if (newstate == server_shutdown) {
+               /* Re-entry */
+               if (shutdown_signal == SIGUSR1)
+                       return ISC_R_SUCCESS;
+               /* Log shutdown on signal. */
+               if ((shutdown_signal == SIGINT) ||
+                   (shutdown_signal == SIGTERM)) {
+                       log_info("Received signal %d, initiating shutdown.",
+                                shutdown_signal);
+               }
+               /* Mark it was called. */
+               shutdown_signal = SIGUSR1;
+       }
+
        /* Do the right thing for each interface. */
        for (ip = interfaces; ip; ip = ip -> next) {
            for (client = ip -> client; client; client = client -> next) {
index 976d37e2b302874575fa622268663a0a254750a5..c75a003b2879d762812960a5e7ae55e799d96a8e 100644 (file)
@@ -110,17 +110,29 @@ dispatch(void)
 {
        isc_result_t status;
 
-       status = isc_app_ctxrun(dhcp_gbl_ctx.actx);
+       do {
+               status = isc_app_ctxrun(dhcp_gbl_ctx.actx);
 
-        /*
-         * isc_app_ctxrun can be stopped by receiving a signal. It will
-         * return ISC_R_SUCCESS in that case. That is a normal behavior.
-         */
+               /*
+                * isc_app_ctxrun can be stopped by receiving a
+                * signal. It will return ISC_R_RELOAD in that
+                * case. That is a normal behavior.
+                */
 
-       if (status != ISC_R_SUCCESS) {
-               log_fatal ("Dispatch routine failed: %s -- exiting",
-                          isc_result_totext (status));
-       }
+               if (status == ISC_R_RELOAD) {
+                       /*
+                        * dhcp_set_control_state() will do the job.
+                        * Note its first argument is ignored.
+                        */
+                       status = dhcp_set_control_state(server_shutdown,
+                                                       server_shutdown);
+                       if (status == ISC_R_SUCCESS)
+                               status = ISC_R_RELOAD;
+               }
+       } while (status == ISC_R_RELOAD);
+
+       log_fatal ("Dispatch routine failed: %s -- exiting",
+                  isc_result_totext (status));
 }
 
 void
index 22506eec9cd941d75f2b8f31b3eafa190fe4d9aa..07411b8285cf55923e2e38ebb668d4b6bc213a7a 100644 (file)
@@ -738,5 +738,7 @@ main(int argc, char **argv) {
 isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
                                     control_object_state_t newstate)
 {
-       return ISC_R_SUCCESS;
+       if (newstate != server_shutdown)
+               return ISC_R_SUCCESS;
+       exit (0);
 }
index 7fd30feab280c359662381c4c72612389b3e89b5..fc45ef3d8c0c178a7fcf31a0f30f9576b1b23a7c 100644 (file)
@@ -120,5 +120,6 @@ isc_result_t dhcp_context_create(void);
 void isclib_cleanup(void);
 
 void dhcp_signal_handler(int signal);
+extern int shutdown_signal;
 
 #endif /* ISCLIB_H */
index 5dcb12c096c129fa662fd8a993440c91c102ffc9..afab262ca42bf6542c5c9febea52158484d3488a 100644 (file)
@@ -31,6 +31,7 @@
 #include <signal.h>
 
 dhcp_context_t dhcp_gbl_ctx;
+int shutdown_signal = 0;
 
 void
 isclib_cleanup(void)
@@ -225,13 +226,17 @@ isclib_make_dst_key(char          *inname,
  */
 void dhcp_signal_handler(int signal) {
        isc_appctx_t *ctx = dhcp_gbl_ctx.actx;
-       if (ctx && ctx->methods && ctx->methods->ctxshutdown) {
-               /*
-                * Let's not use standard log facilities here. They may not be
-                * signal safe, e.g. we could get the signal in the middle of
-                * another log call
-                */
-               printf("Received signal %d, initiating shutdown.\n", signal);
-               ctx->methods->ctxshutdown(ctx);
+       int prev = shutdown_signal;
+
+       if (prev != 0) {
+               /* Already in shutdown. */
+               return;
+       }
+       /* Possible race but does it matter? */
+       shutdown_signal = signal;
+
+       /* Use reload (aka suspend) for easier dispatch() reenter. */
+       if (ctx && ctx->methods && ctx->methods->ctxsuspend) {
+               (void) isc_app_ctxsuspend(ctx);
        }
 }
index a218decee16e8dfca561faff5ad771b1f63d0349..b2d7bd90ce42162cc9ecb493d4398cc80cc01d1a 100644 (file)
@@ -585,6 +585,7 @@ main(int argc, char **argv) {
        /* Start dispatching packets and timeouts... */
        dispatch();
 
+       /* In fact dispatch() never returns. */
        return (0);
 }
 
@@ -1686,5 +1687,7 @@ parse_allow_deny(struct option_cache **oc, struct parse *p, int i) {
 isc_result_t
 dhcp_set_control_state(control_object_state_t oldstate,
                       control_object_state_t newstate) {
-       return ISC_R_SUCCESS;
+       if (newstate != server_shutdown)
+               return ISC_R_SUCCESS;
+       exit(0);
 }
index 457b3cc099e0a4fa9a48559264694a05b6dc5767..bfd84e004b3b204543688b50f71d0d1ac3d17d54 100644 (file)
@@ -790,13 +790,10 @@ main(int argc, char **argv) {
 
        /*
         * Receive packets and dispatch them...
-        * dispatch() will return only when we are shutting down.
+        * dispatch() will never return.
         */
        dispatch ();
 
-       log_info("Shutting down.");
-       dhcp_set_control_state(server_shutdown/*ignored*/, server_shutdown);
-
        /* Let's return status code */
        return 0;
 }
@@ -1358,11 +1355,32 @@ static isc_result_t dhcp_io_shutdown_countdown (void *vlp)
 isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
                                     control_object_state_t newstate)
 {
-       if (newstate == server_shutdown) {
-               shutdown_time = cur_time;
-               shutdown_state = shutdown_listeners;
+       struct timeval tv;
+
+       if (newstate != server_shutdown)
+               return DHCP_R_INVALIDARG;
+       /* Re-entry. */
+       if (shutdown_signal == SIGUSR1)
+               return ISC_R_SUCCESS;
+       shutdown_time = cur_time;
+       shutdown_state = shutdown_listeners;
+       /* Called by user. */
+       if (shutdown_signal == 0) {
+               shutdown_signal = SIGUSR1;
                dhcp_io_shutdown_countdown (0);
                return ISC_R_SUCCESS;
        }
-       return DHCP_R_INVALIDARG;
+       /* Called on signal. */
+       log_info("Received signal %d, initiating shutdown.", shutdown_signal);
+       shutdown_signal = SIGUSR1;
+       
+       /*
+        * Prompt the shutdown event onto the timer queue
+        * and return to the dispatch loop.
+        */
+       tv.tv_sec = cur_tv.tv_sec;
+       tv.tv_usec = cur_tv.tv_usec + 1;
+       add_timeout(&tv,
+                   (void (*)(void *))dhcp_io_shutdown_countdown, 0, 0, 0);
+       return ISC_R_SUCCESS;
 }