diff options
author | Thomas Markwalder <tmark@isc.org> | 2016-02-16 13:34:24 -0500 |
---|---|---|
committer | Thomas Markwalder <tmark@isc.org> | 2016-02-16 13:34:24 -0500 |
commit | 5aa1d83711f23be61ae9f64f409e66f7dd0c2924 (patch) | |
tree | 8c11c15382db8fbbcd9c97154f92d2785da95042 /server | |
parent | 25db5f89854a685b1f2cc64a165026de296cee2c (diff) | |
download | isc-dhcp-5aa1d83711f23be61ae9f64f409e66f7dd0c2924.tar.gz |
[v4_1_esv] Add global DHCPv6 option, dhcpv6-set-tee-times to calculate T1/T2
Merges in rt25687
Diffstat (limited to 'server')
-rw-r--r-- | server/dhcpd.conf.5 | 41 | ||||
-rw-r--r-- | server/dhcpv6.c | 233 | ||||
-rw-r--r-- | server/stables.c | 1 |
3 files changed, 171 insertions, 104 deletions
diff --git a/server/dhcpd.conf.5 b/server/dhcpd.conf.5 index 1598c065..63990a7d 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 @@ -2689,8 +2689,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 @@ -2780,6 +2779,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 7dd7e963..8312f054 100644 --- a/server/dhcpv6.c +++ b/server/dhcpv6.c @@ -68,7 +68,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; @@ -156,6 +156,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. @@ -1561,7 +1564,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; } @@ -1697,7 +1700,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); @@ -1808,50 +1811,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 @@ -2428,7 +2389,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) { @@ -3039,11 +3000,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 /* @@ -3349,7 +3310,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) { @@ -3438,50 +3399,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 @@ -4120,11 +4039,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) { @@ -6528,4 +6447,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 67f0ffb3..91fbb169 100644 --- a/server/stables.c +++ b/server/stables.c @@ -238,6 +238,7 @@ static struct option server_options[] = { { "delayed-ack", "S", &server_universe, 58, 1 }, { "max-ack-delay", "L", &server_universe, 59, 1 }, #endif + { "dhcpv6-set-tee-times", "f", &server_universe, SV_DHCPV6_SET_TEE_TIMES, 1 }, { NULL, NULL, NULL, 0, 0 } }; |