From: David Hankins Date: Wed, 17 Jun 2009 22:08:42 +0000 (+0000) Subject: - A new failover configuration parameter has been introduced for those X-Git-Tag: v4_2_0a1~66 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=9e3eb22ab78a2645f9d4107447b91549f0cac1ea;p=thirdparty%2Fdhcp.git - A new failover configuration parameter has been introduced for those environments where DHCP servers can be reasonably guaranteed to be "down" when the failover TCP socket is severed, "auto-partner-down". This parameter is not generally safe, and by default is disabled, so please carefully review the documentation of this parameter in the dhcpd.conf(5) manpage before determining to use it yourself. [ISC-Bugs #19600] --- diff --git a/RELNOTES b/RELNOTES index 312169eba..c9b6b6c6b 100644 --- a/RELNOTES +++ b/RELNOTES @@ -51,6 +51,13 @@ work on other platforms. Please report any problems and suggested fixes to - Added client -D option to specify DUID type to send. +- A new failover configuration parameter has been introduced for those + environments where DHCP servers can be reasonably guaranteed to be + "down" when the failover TCP socket is severed, "auto-partner-down". + This parameter is not generally safe, and by default is disabled, so + please carefully review the documentation of this parameter in the + dhcpd.conf(5) manpage before determining to use it yourself. + Changes since 4.1.0 (bug fixes) - Remove infinite loop in token_print_indent_concat(). diff --git a/common/conflex.c b/common/conflex.c index e74264172..d17b3040a 100644 --- a/common/conflex.c +++ b/common/conflex.c @@ -706,50 +706,70 @@ intern(char *atom, enum dhcp_token dfv) { break; case 'a': - if (!strncasecmp (atom + 1, "uth", 3)) { - if (!strncasecmp (atom + 3, "uthenticat", 10)) { - if (!strcasecmp (atom + 13, "ed")) - return AUTHENTICATED; - if (!strcasecmp (atom + 13, "ion")) - return AUTHENTICATION; + if (!strcasecmp(atom + 1, "bandoned")) + return TOKEN_ABANDONED; + if (!strcasecmp(atom + 1, "ctive")) + return TOKEN_ACTIVE; + if (!strncasecmp(atom + 1, "dd", 2)) { + if (atom[3] == '\0') + return TOKEN_ADD; + else if (!strcasecmp(atom + 3, "ress")) + return ADDRESS; + break; + } + if (!strcasecmp(atom + 1, "fter")) + return AFTER; + if (isascii(atom[1]) && (tolower(atom[1]) == 'l')) { + if (!strcasecmp(atom + 2, "gorithm")) + return ALGORITHM; + if (!strcasecmp(atom + 2, "ias")) + return ALIAS; + if (isascii(atom[2]) && (tolower(atom[2]) == 'l')) { + if (atom[3] == '\0') + return ALL; + else if (!strcasecmp(atom + 3, "ow")) + return ALLOW; break; } - if (!strcasecmp (atom + 1, "uthoritative")) - return AUTHORITATIVE; + if (!strcasecmp(atom + 2, "so")) + return TOKEN_ALSO; break; } - if (!strcasecmp (atom + 1, "nd")) - return AND; - if (!strcasecmp(atom + 1, "nycast-mac")) - return ANYCAST_MAC; - if (!strcasecmp (atom + 1, "ppend")) + if (isascii(atom[1]) && (tolower(atom[1]) == 'n')) { + if (!strcasecmp(atom + 2, "d")) + return AND; + if (!strcasecmp(atom + 2, "ycast-mac")) + return ANYCAST_MAC; + break; + } + if (!strcasecmp(atom + 1, "ppend")) return APPEND; - if (!strcasecmp (atom + 1, "llow")) - return ALLOW; - if (!strcasecmp (atom + 1, "lias")) - return ALIAS; - if (!strcasecmp (atom + 1, "lgorithm")) - return ALGORITHM; - if (!strcasecmp (atom + 1, "lso")) - return TOKEN_ALSO; - if (!strcasecmp (atom + 1, "bandoned")) - return TOKEN_ABANDONED; - if (!strcasecmp (atom + 1, "dd")) - return TOKEN_ADD; - if (!strcasecmp (atom + 1, "ll")) - return ALL; - if (!strcasecmp (atom + 1, "t")) - return AT; - if (!strcasecmp (atom + 1, "rray")) + if (!strcasecmp(atom + 1, "rray")) return ARRAY; - if (!strcasecmp (atom + 1, "ddress")) - return ADDRESS; - if (!strcasecmp (atom + 1, "ctive")) - return TOKEN_ACTIVE; - if (!strcasecmp (atom + 1, "tsfp")) - return ATSFP; - if (!strcasecmp (atom + 1, "fter")) - return AFTER; + if (isascii(atom[1]) && (tolower(atom[1]) == 't')) { + if (atom[2] == '\0') + return AT; + if (!strcasecmp(atom + 2, "sfp")) + return ATSFP; + break; + } + if (!strncasecmp(atom + 1, "ut", 2)) { + if (isascii(atom[3] && (tolower(atom[3]) == 'h'))) { + if (!strncasecmp(atom + 4, "enticat", 7)) { + if (!strcasecmp(atom + 11, "ed")) + return AUTHENTICATED; + if (!strcasecmp(atom + 11, "ion")) + return AUTHENTICATION; + break; + } + if (!strcasecmp(atom + 4, "oritative")) + return AUTHORITATIVE; + break; + } + if (!strcasecmp(atom + 3, "o-partner-down")) + return AUTO_PARTNER_DOWN; + break; + } break; case 'b': if (!strcasecmp (atom + 1, "ackup")) diff --git a/includes/dhcpd.h b/includes/dhcpd.h index b0c4969d6..d76103991 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -3150,6 +3150,7 @@ void dhcp_failover_reconnect (void *); void dhcp_failover_startup_timeout (void *); void dhcp_failover_link_startup_timeout (void *); void dhcp_failover_listener_restart (void *); +void dhcp_failover_auto_partner_down(void *vs); isc_result_t dhcp_failover_state_get_value PROTO ((omapi_object_t *, omapi_object_t *, omapi_data_string_t *, diff --git a/includes/dhctoken.h b/includes/dhctoken.h index 3cb397ac3..01ed13037 100644 --- a/includes/dhctoken.h +++ b/includes/dhctoken.h @@ -354,7 +354,8 @@ enum dhcp_token { PREFIX6 = 657, FIXED_PREFIX6 = 658, ANYCAST_MAC = 659, - CONFLICT_DONE = 660 + CONFLICT_DONE = 660, + AUTO_PARTNER_DOWN = 661 }; #define is_identifier(x) ((x) >= FIRST_TOKEN && \ diff --git a/includes/failover.h b/includes/failover.h index ed3dc961f..f80beb7d9 100644 --- a/includes/failover.h +++ b/includes/failover.h @@ -352,6 +352,8 @@ typedef struct _dhcp_failover_state { u_int32_t max_balance, min_balance; TIME last_balance, sched_balance; + u_int32_t auto_partner_down; + enum service_state service_state; const char *nrr; /* Printable reason why we're in the not_responding service state (empty diff --git a/server/confpars.c b/server/confpars.c index 63dc465db..2ccd89721 100644 --- a/server/confpars.c +++ b/server/confpars.c @@ -1012,6 +1012,10 @@ void parse_failover_peer (cfile, group, type) tp = &peer->min_balance; goto parse_idle; + case AUTO_PARTNER_DOWN: + tp = &peer->auto_partner_down; + goto parse_idle; + case MAX_RESPONSE_DELAY: tp = &cp -> max_response_delay; parse_idle: diff --git a/server/dhcpd.conf.5 b/server/dhcpd.conf.5 index e5eec88e4..45e390d62 100644 --- a/server/dhcpd.conf.5 +++ b/server/dhcpd.conf.5 @@ -28,7 +28,7 @@ .\" see ``http://www.vix.com''. To learn more about Nominum, Inc., see .\" ``http://www.nominum.com''. .\" -.\" $Id: dhcpd.conf.5,v 1.103 2009/03/30 18:28:55 jreed Exp $ +.\" $Id: dhcpd.conf.5,v 1.104 2009/06/17 22:08:42 dhankins Exp $ .\" .TH dhcpd.conf 5 .SH NAME @@ -741,6 +741,34 @@ failover peer will take over its client load automatically as the clients retry. .RE .PP +The +.I auto-partner-down +statement +.RS 0.25i +.PP +.B auto-partner-down \fIseconds\fR\fB;\fR +.PP +This statement instructs the server to initiate a timed delay upon entering +the communications-interrupted state (any situation of being out-of-contact +with the remote failover peer). At the conclusion of the timer, the server +will automatically enter the partner-down state. This permits the server +to allocate leases from the partner's free lease pool after an STOS+MCLT +timer expires, which can be dangerous if the partner is in fact operating +at the time (the two servers will give conflicting bindings). +.PP +Think very carefully before enabling this feature. The partner-down and +communications-interrupted states are intentionally segregated because +there do exist situations where a failover server can fail to communicate +with its peer, but still has the ability to receive and reply to requests +from DHCP clients. In general, this feature should only be used in those +deployments where the failover servers are directly connected to one +another, such as by a dedicated hardwired link ("a heartbeat cable"). +.PP +A zero value disables the auto-partner-down feature (also the default), and +any positive value indicates the time in seconds to wait before automatically +entering partner-down. +.RE +.PP The Failover pool balance statements. .RS 0.25i .PP diff --git a/server/failover.c b/server/failover.c index 773f1e7a0..795f896a6 100644 --- a/server/failover.c +++ b/server/failover.c @@ -1797,6 +1797,12 @@ isc_result_t dhcp_failover_set_state (dhcp_failover_state_t *state, if (new_state != startup && saved_state == startup) cancel_timeout (dhcp_failover_startup_timeout, state); + /* + * If the state changes for any reason, cancel 'delayed auto state + * changes' (currently there is just the one). + */ + cancel_timeout(dhcp_failover_auto_partner_down, state); + /* Set our service state. */ dhcp_failover_set_service_state (state); @@ -1805,6 +1811,29 @@ isc_result_t dhcp_failover_set_state (dhcp_failover_state_t *state, dhcp_failover_send_state (state); switch (new_state) { + case communications_interrupted: + /* + * There is an optional feature to automatically enter partner + * down after a timer expires, upon entering comms-interrupted. + * This feature is generally not safe except in specific + * circumstances. + * + * A zero value (also the default) disables it. + */ + if (state->auto_partner_down == 0) + break; + +#if defined (DEBUG_FAILOVER_TIMING) + log_info("add_timeout +%ul dhcp_failover_auto_partner_down", + (unsigned long)state->auto_partner_down); +#endif + tv.tv_sec = cur_time + state->auto_partner_down; + tv.tv_usec = 0; + add_timeout(&tv, dhcp_failover_auto_partner_down, state, + (tvref_t)omapi_object_reference, + (tvunref_t)omapi_object_dereference); + break; + case normal: /* Upon entering normal state, the server is expected to retransmit * all pending binding updates. This is a good opportunity to @@ -1820,12 +1849,12 @@ isc_result_t dhcp_failover_set_state (dhcp_failover_state_t *state, } break; - + case potential_conflict: if (state -> i_am == primary) dhcp_failover_send_update_request (state); break; - + case startup: #if defined (DEBUG_FAILOVER_TIMING) log_info ("add_timeout +15 %s", @@ -3066,6 +3095,18 @@ void dhcp_failover_listener_restart (void *vs) } } +void +dhcp_failover_auto_partner_down(void *vs) +{ + dhcp_failover_state_t *state = vs; + +#if defined (DEBUG_FAILOVER_TIMING) + log_info("dhcp_failover_auto_partner_down"); +#endif + + dhcp_failover_set_state(state, partner_down); +} + isc_result_t dhcp_failover_state_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name,