summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShawn Routhier <sar@isc.org>2013-11-14 12:55:10 -0800
committerShawn Routhier <sar@isc.org>2013-11-14 12:55:10 -0800
commit0895c955d16a957107771e442397c6260d92cbc2 (patch)
treebeb3d593cb202f75f92bad953fb1eaef1a875671
parentf88446f16b9b3be36492f78b0f66a4166e459896 (diff)
downloadisc-dhcp-0895c955d16a957107771e442397c6260d92cbc2.tar.gz
[master] Fix up the gentle shutdown code to handle failover
This patch modifies the gentle failover patch to be cleaner and to handle failover peers better.
-rw-r--r--RELNOTES2
-rw-r--r--client/dhclient.c15
-rw-r--r--common/dispatch.c30
-rw-r--r--dhcpctl/omshell.c4
-rw-r--r--includes/omapip/isclib.h1
-rw-r--r--omapip/isclib.c21
-rw-r--r--relay/dhcrelay.c5
-rw-r--r--server/dhcpd.c34
8 files changed, 84 insertions, 28 deletions
diff --git a/RELNOTES b/RELNOTES
index 18ffd448..1eff1dcf 100644
--- 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.
diff --git a/client/dhclient.c b/client/dhclient.c
index f131e393..97b86a6f 100644
--- a/client/dhclient.c
+++ b/client/dhclient.c
@@ -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) {
diff --git a/common/dispatch.c b/common/dispatch.c
index 976d37e2..c75a003b 100644
--- a/common/dispatch.c
+++ b/common/dispatch.c
@@ -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
diff --git a/dhcpctl/omshell.c b/dhcpctl/omshell.c
index 22506eec..07411b82 100644
--- a/dhcpctl/omshell.c
+++ b/dhcpctl/omshell.c
@@ -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);
}
diff --git a/includes/omapip/isclib.h b/includes/omapip/isclib.h
index 7fd30fea..fc45ef3d 100644
--- a/includes/omapip/isclib.h
+++ b/includes/omapip/isclib.h
@@ -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 */
diff --git a/omapip/isclib.c b/omapip/isclib.c
index 5dcb12c0..afab262c 100644
--- a/omapip/isclib.c
+++ b/omapip/isclib.c
@@ -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);
}
}
diff --git a/relay/dhcrelay.c b/relay/dhcrelay.c
index a218dece..b2d7bd90 100644
--- a/relay/dhcrelay.c
+++ b/relay/dhcrelay.c
@@ -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);
}
diff --git a/server/dhcpd.c b/server/dhcpd.c
index 457b3cc0..bfd84e00 100644
--- a/server/dhcpd.c
+++ b/server/dhcpd.c
@@ -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;
}