summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Markwalder <tmark@isc.org>2016-02-16 13:07:02 -0500
committerThomas Markwalder <tmark@isc.org>2016-02-16 13:07:02 -0500
commitdce576b86004110d98c6c89c7a9c4f4b410601f9 (patch)
tree3f0fedce5b38aa1c65c398a03fb4ed9dd63be11f
parent6e7e6637ac8d94a0f230a3dd37e1a83f7ea2847b (diff)
downloadisc-dhcp-dce576b86004110d98c6c89c7a9c4f4b410601f9.tar.gz
[master] Add global DHCPv6 option, dhcpv6-set-tee-times to calculate T1/T2
Merges in rt25687
-rw-r--r--RELNOTES7
-rw-r--r--includes/dhcpd.h1
-rw-r--r--server/dhcpd.conf.541
-rw-r--r--server/dhcpv6.c233
-rw-r--r--server/stables.c3
5 files changed, 179 insertions, 106 deletions
diff --git a/RELNOTES b/RELNOTES
index d8c9cfba..7e43510c 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -213,11 +213,16 @@ by Eric Young (eay@cryptsoft.com).
[ISC-Bugs #39262]
- Add support for RFC 3527 to dhcrelay. A new, dhcrelay command line argument,
- "-l <interface>" enables the addition of a RFC 3527 compliant link selection
+ "-u <interface>" enables the addition of a RFC 3527 compliant link selection
suboption to the agent option added for clients directly connected to the
relay.
[ISC-Bugs #34875]
+- Add a new global DHCPv6 option, dhcpv6-set-tee-times, which when enabled
+ instructs the server to calculate T1 and T2 as recommended in RFC 3315,
+ Section 22.4.
+ [ISC-Bugs #25687]
+
Changes since 4.3.3b1
- None
diff --git a/includes/dhcpd.h b/includes/dhcpd.h
index cef87858..bdd00c6d 100644
--- a/includes/dhcpd.h
+++ b/includes/dhcpd.h
@@ -790,6 +790,7 @@ struct lease_state {
#define SV_ECHO_CLIENT_ID 85
#define SV_SERVER_ID_CHECK 86
#define SV_PREFIX_LEN_MODE 87
+#define SV_DHCPV6_SET_TEE_TIMES 88
#if !defined (DEFAULT_PING_TIMEOUT)
# define DEFAULT_PING_TIMEOUT 1
diff --git a/server/dhcpd.conf.5 b/server/dhcpd.conf.5
index 806efd52..ebc99120 100644
--- a/server/dhcpd.conf.5
+++ b/server/dhcpd.conf.5
@@ -1,6 +1,6 @@
.\" dhcpd.conf.5
.\"
-.\" Copyright (c) 2004-2015 by Internet Systems Consortium, Inc. ("ISC")
+.\" Copyright (c) 2004-2016 by Internet Systems Consortium, Inc. ("ISC")
.\" Copyright (c) 1996-2003 by Internet Software Consortium
.\"
.\" Permission to use, copy, modify, and distribute this software for any
@@ -2822,8 +2822,7 @@ longer useable. A preferred lifetime is an advisory condition to help
applications move off of the address and onto currently valid addresses
(should there still be any open TCP sockets or similar).
.PP
-The preferred lifetime defaults to the renew+rebind timers, or 3/4 the
-default lease time if none were specified.
+The preferred lifetime defaults to 5/8 the default lease time.
.RE
.PP
The
@@ -3025,6 +3024,42 @@ be the name that will be provided to the client.
.RE
.PP
The
+.I dhcpv6-set-tee-times
+statement
+.RS 0.25i
+.PP
+.B dhcpv6-set-tee-times\fR \fIflag\fR\fB;\fR
+.PP
+The \fIdhcpv6-set-tee-times\fR statement enables setting T1 and T2 to the
+values recommended in RFC 3315 (Section 22.4). When setting T1 and T2, the
+server will use dhcp-renewal-time and dhcp-rebinding-time, respectively.
+A value of zero tells the client it may choose its own value.
+
+When those options are not defined then values will be set to zero unless the
+global \fIdhcpv6-set-tee-times\R is enabled. When this option is enabled the
+times are calculated as recommended by RFC 3315, Section 22.4:
+
+ T1 will be set to 0.5 times the shortest preferred lifetime
+ in the reply. If the "shortest" preferred lifetime is
+ 0xFFFFFFFF, T1 will set to 0xFFFFFFFF.
+
+ T2 will be set to 0.8 times the shortest preferred lifetime
+ in the reply. If the "shortest" preferred lifetime is
+ 0xFFFFFFFF, T2 will set to 0xFFFFFFFF.
+
+Keep in mind that given sufficiently small lease lifetimes, the above
+calculations will result in the two values being equal. For example, a 9 second
+lease lifetime would yield T1 = T2 = 4 seconds, which would cause clients to
+issue rebinds only. In such a case it would likely be better to explicitly
+define the values.
+
+Note that dhcpv6-set-tee-times is intended to be transitional and will likely
+be removed in a future release. Once removed the behavior will be to use
+the configured values when present or calculate them per the RFC. If you want
+zeros, define them as zeros.
+.RE
+.PP
+The
.I site-option-space
statement
.RS 0.25i
diff --git a/server/dhcpv6.c b/server/dhcpv6.c
index f307c9b8..f6bf15c9 100644
--- a/server/dhcpv6.c
+++ b/server/dhcpv6.c
@@ -70,7 +70,7 @@ struct reply_state {
* "t1", "t2", preferred, and valid lifetimes records for calculating
* t1 and t2 (min/max).
*/
- u_int32_t renew, rebind, prefer, valid;
+ u_int32_t renew, rebind, min_prefer, min_valid;
/* Client-requested valid and preferred lifetimes. */
u_int32_t client_valid, client_prefer;
@@ -164,6 +164,9 @@ static isc_result_t shared_network_from_requested_addr (struct shared_network
static isc_result_t get_first_ia_addr_val (struct packet* packet, int addr_type,
struct iaddr* iaddr);
+static void
+set_reply_tee_times(struct reply_state* reply, unsigned ia_cursor);
+
/*
* Schedule lease timeouts for all of the iasubopts in the reply.
* This is currently used to schedule timeouts for soft leases.
@@ -1816,7 +1819,7 @@ lease_to_client(struct data_string *reply_ret,
data_string_forget(&reply.client_id, MDL);
if (packet_oro.buffer != NULL)
data_string_forget(&packet_oro, MDL);
- reply.renew = reply.rebind = reply.prefer = reply.valid = 0;
+ reply.renew = reply.rebind = reply.min_prefer = reply.min_valid = 0;
reply.cursor = 0;
}
@@ -1952,7 +1955,7 @@ reply_process_ia_na(struct reply_state *reply, struct option_cache *ia) {
* A not included IA ("cleanup" below) could give a Renew/Rebind.
*/
oc = lookup_option(&dhcpv6_universe, packet_ia, D6O_IAADDR);
- reply->valid = reply->prefer = 0xffffffff;
+ reply->min_valid = reply->min_prefer = 0xffffffff;
reply->client_valid = reply->client_prefer = 0;
for (; oc != NULL ; oc = oc->next) {
status = reply_process_addr(reply, oc);
@@ -2063,50 +2066,8 @@ reply_process_ia_na(struct reply_state *reply, struct option_cache *ia) {
putUShort(reply->buf.data + ia_cursor + 2,
reply->cursor - (ia_cursor + 4));
- /*
- * T1/T2 time selection is kind of weird. We actually use DHCP
- * (v4) scoped options as handy existing places where these might
- * be configured by an administrator. A value of zero tells the
- * client it may choose its own renewal time.
- */
- reply->renew = 0;
- oc = lookup_option(&dhcp_universe, reply->opt_state,
- DHO_DHCP_RENEWAL_TIME);
- if (oc != NULL) {
- if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
- reply->packet->options,
- reply->opt_state, &global_scope,
- oc, MDL) ||
- (data.len != 4)) {
- log_error("Invalid renewal time.");
- } else {
- reply->renew = getULong(data.data);
- }
-
- if (data.data != NULL)
- data_string_forget(&data, MDL);
- }
- putULong(reply->buf.data + ia_cursor + 8, reply->renew);
-
- /* Now T2. */
- reply->rebind = 0;
- oc = lookup_option(&dhcp_universe, reply->opt_state,
- DHO_DHCP_REBINDING_TIME);
- if (oc != NULL) {
- if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
- reply->packet->options,
- reply->opt_state, &global_scope,
- oc, MDL) ||
- (data.len != 4)) {
- log_error("Invalid rebinding time.");
- } else {
- reply->rebind = getULong(data.data);
- }
-
- if (data.data != NULL)
- data_string_forget(&data, MDL);
- }
- putULong(reply->buf.data + ia_cursor + 12, reply->rebind);
+ /* Calculate T1/T2 and stuff them in the reply */
+ set_reply_tee_times(reply, ia_cursor);
/*
* yes, goto's aren't the best but we also want to avoid extra
@@ -2722,7 +2683,7 @@ reply_process_ia_ta(struct reply_state *reply, struct option_cache *ia) {
* Deal with an IAADDR for lifetimes.
* For all or none, process IAADDRs as hints.
*/
- reply->valid = reply->prefer = 0xffffffff;
+ reply->min_valid = reply->min_prefer = 0xffffffff;
reply->client_valid = reply->client_prefer = 0;
oc = lookup_option(&dhcpv6_universe, packet_ia, D6O_IAADDR);
for (; oc != NULL; oc = oc->next) {
@@ -3477,11 +3438,11 @@ reply_process_is_addressed(struct reply_state *reply,
}
/* Note lowest values for later calculation of renew/rebind times. */
- if (reply->prefer > reply->send_prefer)
- reply->prefer = reply->send_prefer;
+ if (reply->min_prefer > reply->send_prefer)
+ reply->min_prefer = reply->send_prefer;
- if (reply->valid > reply->send_valid)
- reply->valid = reply->send_valid;
+ if (reply->min_valid > reply->send_valid)
+ reply->min_valid = reply->send_valid;
#if 0
/*
@@ -3796,7 +3757,7 @@ reply_process_ia_pd(struct reply_state *reply, struct option_cache *ia) {
* For each prefix in this IA_PD, decide what to do about it.
*/
oc = lookup_option(&dhcpv6_universe, packet_ia, D6O_IAPREFIX);
- reply->valid = reply->prefer = 0xffffffff;
+ reply->min_valid = reply->min_prefer = 0xffffffff;
reply->client_valid = reply->client_prefer = 0;
reply->preflen = -1;
for (; oc != NULL ; oc = oc->next) {
@@ -3885,50 +3846,8 @@ reply_process_ia_pd(struct reply_state *reply, struct option_cache *ia) {
putUShort(reply->buf.data + ia_cursor + 2,
reply->cursor - (ia_cursor + 4));
- /*
- * T1/T2 time selection is kind of weird. We actually use DHCP
- * (v4) scoped options as handy existing places where these might
- * be configured by an administrator. A value of zero tells the
- * client it may choose its own renewal time.
- */
- reply->renew = 0;
- oc = lookup_option(&dhcp_universe, reply->opt_state,
- DHO_DHCP_RENEWAL_TIME);
- if (oc != NULL) {
- if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
- reply->packet->options,
- reply->opt_state, &global_scope,
- oc, MDL) ||
- (data.len != 4)) {
- log_error("Invalid renewal time.");
- } else {
- reply->renew = getULong(data.data);
- }
-
- if (data.data != NULL)
- data_string_forget(&data, MDL);
- }
- putULong(reply->buf.data + ia_cursor + 8, reply->renew);
-
- /* Now T2. */
- reply->rebind = 0;
- oc = lookup_option(&dhcp_universe, reply->opt_state,
- DHO_DHCP_REBINDING_TIME);
- if (oc != NULL) {
- if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
- reply->packet->options,
- reply->opt_state, &global_scope,
- oc, MDL) ||
- (data.len != 4)) {
- log_error("Invalid rebinding time.");
- } else {
- reply->rebind = getULong(data.data);
- }
-
- if (data.data != NULL)
- data_string_forget(&data, MDL);
- }
- putULong(reply->buf.data + ia_cursor + 12, reply->rebind);
+ /* Calculate T1/T2 and stuff them in the reply */
+ set_reply_tee_times(reply, ia_cursor);
/*
* yes, goto's aren't the best but we also want to avoid extra
@@ -4765,11 +4684,11 @@ reply_process_is_prefixed(struct reply_state *reply,
}
/* Note lowest values for later calculation of renew/rebind times. */
- if (reply->prefer > reply->send_prefer)
- reply->prefer = reply->send_prefer;
+ if (reply->min_prefer > reply->send_prefer)
+ reply->min_prefer = reply->send_prefer;
- if (reply->valid > reply->send_valid)
- reply->valid = reply->send_valid;
+ if (reply->min_valid > reply->send_valid)
+ reply->min_valid = reply->send_valid;
/* Perform dynamic prefix related update work. */
if (reply->lease != NULL) {
@@ -7178,4 +7097,116 @@ get_first_ia_addr_val (struct packet* packet, int addr_type,
return (status);
}
+/*
+* \brief Calculates the reply T1/T2 times and stuffs them in outbound buffer
+*
+* T1/T2 time selection is kind of weird. We actually use DHCP * (v4) scoped
+* options, dhcp-renewal-time and dhcp-rebinding-time, as handy existing places
+* where these can be configured by an administrator. A value of zero tells the
+* client it may choose its own value.
+*
+* When those options are not defined, the values will be set to zero unless
+* the global option, dhcpv6-set-tee-times is enabled. When this option is
+* enabled the values are calculated as recommended by RFC 3315, Section 22.4:
+*
+* T1 will be set to 0.5 times the shortest preferred lifetime
+* in the IA_XX option. If the "shortest" preferred lifetime is
+* 0xFFFFFFFF, T1 will set to 0xFFFFFFFF.
+*
+* T2 will be set to 0.8 times the shortest preferred lifetime
+* in the IA_XX option. If the "shortest" preferred lifetime is
+* 0xFFFFFFFF, T2 will set to 0xFFFFFFFF.
+*
+* Note that dhcpv6-set-tee-times is intended to be transitional and will
+* likely be removed in 4.4.0, leaving the behavior as getting the values
+* either from the configured parameters (if you want zeros, define them as
+* zeros) or by calculating them per the RFC.
+*
+* \param reply - pointer to the reply_state structure
+* \param ia_cursor - offset of the beginning of the IA_XX option within the
+* reply's outbound data buffer
+*/
+static void
+set_reply_tee_times(struct reply_state* reply, unsigned ia_cursor)
+{
+ struct option_cache *oc;
+ int set_tee_times;
+
+ /* Found out if calculated values are enabled. */
+ oc = lookup_option(&server_universe, reply->opt_state,
+ SV_DHCPV6_SET_TEE_TIMES);
+ set_tee_times = (oc &&
+ evaluate_boolean_option_cache(NULL, reply->packet,
+ NULL, NULL,
+ reply->packet->options,
+ reply->opt_state,
+ &global_scope, oc, MDL));
+
+ oc = lookup_option(&dhcp_universe, reply->opt_state,
+ DHO_DHCP_RENEWAL_TIME);
+ if (oc != NULL) {
+ /* dhcp-renewal-time is defined, use it */
+ struct data_string data;
+ memset(&data, 0x00, sizeof(data));
+
+ if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
+ reply->packet->options,
+ reply->opt_state, &global_scope,
+ oc, MDL) ||
+ (data.len != 4)) {
+ log_error("Invalid renewal time.");
+ reply->renew = 0;
+ } else {
+ reply->renew = getULong(data.data);
+ }
+
+ if (data.data != NULL)
+ data_string_forget(&data, MDL);
+ } else if (set_tee_times) {
+ /* Setting them is enabled so T1 is either infinite or
+ * 0.5 * the shortest preferred lifetime in the IA_XX */
+ reply->renew = (reply->min_prefer == 0xFFFFFFFF ? 0xFFFFFFFF
+ : reply->min_prefer / 2);
+ } else {
+ /* Default is to let the client choose */
+ reply->renew = 0;
+ }
+
+ putULong(reply->buf.data + ia_cursor + 8, reply->renew);
+
+ /* Now T2. */
+ oc = lookup_option(&dhcp_universe, reply->opt_state,
+ DHO_DHCP_REBINDING_TIME);
+ if (oc != NULL) {
+ /* dhcp-rebinding-time is defined, use it */
+ struct data_string data;
+ memset(&data, 0x00, sizeof(data));
+
+ if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
+ reply->packet->options,
+ reply->opt_state, &global_scope,
+ oc, MDL) ||
+ (data.len != 4)) {
+ log_error("Invalid rebinding time.");
+ reply->rebind = 0;
+ } else {
+ reply->rebind = getULong(data.data);
+ }
+
+ if (data.data != NULL)
+ data_string_forget(&data, MDL);
+ } else if (set_tee_times) {
+ /* Setting them is enabled so T2 is either infinite or
+ * 0.8 * the shortest preferred lifetime in the reply */
+ reply->rebind = (reply->min_prefer == 0xFFFFFFFF ? 0xFFFFFFFF
+ : (reply->min_prefer / 5) * 4);
+ } else {
+ /* Default is to let the client choose */
+ reply->rebind = 0;
+ }
+
+ putULong(reply->buf.data + ia_cursor + 12, reply->rebind);
+}
+
+
#endif /* DHCPv6 */
diff --git a/server/stables.c b/server/stables.c
index 963503e7..d375bad6 100644
--- a/server/stables.c
+++ b/server/stables.c
@@ -3,7 +3,7 @@
Tables of information only used by server... */
/*
- * Copyright (c) 2004-2011,2013-2015 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2004-2011,2013-2016 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1995-2003 by Internet Software Consortium
*
* Permission to use, copy, modify, and distribute this software for any
@@ -275,6 +275,7 @@ static struct option server_options[] = {
{ "echo-client-id", "f", &server_universe, SV_ECHO_CLIENT_ID, 1 },
{ "server-id-check", "f", &server_universe, SV_SERVER_ID_CHECK, 1 },
{ "prefix-length-mode", "Nprefix_length_modes.", &server_universe, SV_PREFIX_LEN_MODE, 1 },
+ { "dhcpv6-set-tee-times", "f", &server_universe, SV_DHCPV6_SET_TEE_TIMES, 1 },
{ NULL, NULL, NULL, 0, 0 }
};