sd-dhcp6-lease: unify lease lifetime calculation
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "dhcp6-internal.h"
|
||||
#include "macro.h"
|
||||
#include "time-util.h"
|
||||
|
||||
struct sd_dhcp6_lease {
|
||||
unsigned n_ref;
|
||||
@@ -22,6 +23,9 @@ struct sd_dhcp6_lease {
|
||||
uint8_t preference;
|
||||
bool rapid_commit;
|
||||
triple_timestamp timestamp;
|
||||
usec_t lifetime_t1;
|
||||
usec_t lifetime_t2;
|
||||
usec_t max_retransmit_duration;
|
||||
struct in6_addr server_address;
|
||||
|
||||
DHCP6IA *ia_na;
|
||||
@@ -41,12 +45,14 @@ struct sd_dhcp6_lease {
|
||||
char *fqdn;
|
||||
};
|
||||
|
||||
int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire);
|
||||
|
||||
void dhcp6_ia_clear_addresses(DHCP6IA *ia);
|
||||
DHCP6IA *dhcp6_ia_free(DHCP6IA *ia);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(DHCP6IA*, dhcp6_ia_free);
|
||||
|
||||
void dhcp6_lease_set_lifetime(sd_dhcp6_lease *lease);
|
||||
int dhcp6_lease_get_lifetime(sd_dhcp6_lease *lease, usec_t *ret_t1, usec_t *ret_t2);
|
||||
int dhcp6_lease_get_max_retransmit_duration(sd_dhcp6_lease *lease, usec_t *ret);
|
||||
|
||||
int dhcp6_lease_set_clientid(sd_dhcp6_lease *lease, const uint8_t *id, size_t len);
|
||||
int dhcp6_lease_get_clientid(sd_dhcp6_lease *lease, uint8_t **ret_id, size_t *ret_len);
|
||||
int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id, size_t len);
|
||||
|
||||
@@ -696,7 +696,7 @@ int dhcp6_option_parse_ia(
|
||||
DHCP6IA **ret) {
|
||||
|
||||
_cleanup_(dhcp6_ia_freep) DHCP6IA *ia = NULL;
|
||||
uint32_t lt_t1, lt_t2, lt_min = UINT32_MAX;
|
||||
uint32_t lt_t1, lt_t2;
|
||||
size_t header_len;
|
||||
int r;
|
||||
|
||||
@@ -772,22 +772,16 @@ int dhcp6_option_parse_ia(
|
||||
r = dhcp6_option_parse_ia_address(client, ia, subdata, subdata_len);
|
||||
if (r == -ENOMEM)
|
||||
return r;
|
||||
if (r < 0)
|
||||
/* Ignore non-critical errors in the sub-option. */
|
||||
continue;
|
||||
|
||||
lt_min = MIN(lt_min, be32toh(ia->addresses->iaaddr.lifetime_valid));
|
||||
/* Ignore non-critical errors in the sub-option. */
|
||||
break;
|
||||
}
|
||||
case SD_DHCP6_OPTION_IA_PD_PREFIX: {
|
||||
r = dhcp6_option_parse_ia_pdprefix(client, ia, subdata, subdata_len);
|
||||
if (r == -ENOMEM)
|
||||
return r;
|
||||
if (r < 0)
|
||||
/* Ignore non-critical errors in the sub-option. */
|
||||
continue;
|
||||
|
||||
lt_min = MIN(lt_min, be32toh(ia->addresses->iapdprefix.lifetime_valid));
|
||||
/* Ignore non-critical errors in the sub-option. */
|
||||
break;
|
||||
}
|
||||
case SD_DHCP6_OPTION_STATUS_CODE: {
|
||||
@@ -815,22 +809,6 @@ int dhcp6_option_parse_ia(
|
||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(ENODATA),
|
||||
"Received an IA option without valid IA addresses or PD prefixes, ignoring.");
|
||||
|
||||
if (lt_t2 == 0 && IN_SET(option_code, SD_DHCP6_OPTION_IA_NA, SD_DHCP6_OPTION_IA_PD)) {
|
||||
|
||||
/* addresses or prefixes with zero valid lifetime are already ignored. */
|
||||
assert(lt_min != UINT32_MAX);
|
||||
|
||||
lt_t1 = lt_min / 2;
|
||||
lt_t2 = lt_min / 10 * 8;
|
||||
|
||||
ia->header.lifetime_t1 = htobe32(lt_t1);
|
||||
ia->header.lifetime_t1 = htobe32(lt_t2);
|
||||
|
||||
log_dhcp6_client(client, "Received an IA option with both T1 and T2 equal to zero. "
|
||||
"Adjusting them based on the minimum valid lifetime of IA addresses or PD prefixes: "
|
||||
"T1=%"PRIu32"sec, T2=%"PRIu32"sec", lt_t1, lt_t2);
|
||||
}
|
||||
|
||||
*ret = TAKE_PTR(ia);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -981,14 +981,11 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
|
||||
max_retransmit_time = DHCP6_REB_MAX_RT;
|
||||
|
||||
if (event_source_is_enabled(client->timeout_resend_expire) <= 0) {
|
||||
uint32_t expire = 0;
|
||||
|
||||
r = dhcp6_lease_ia_rebind_expire(client->lease->ia_na, &expire);
|
||||
r = dhcp6_lease_get_max_retransmit_duration(client->lease, &max_retransmit_duration);
|
||||
if (r < 0) {
|
||||
client_stop(client, r);
|
||||
return 0;
|
||||
}
|
||||
max_retransmit_duration = expire * USEC_PER_SEC;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1090,7 +1087,6 @@ int client_parse_message(
|
||||
size_t len,
|
||||
sd_dhcp6_lease *lease) {
|
||||
|
||||
uint32_t lt_t1 = UINT32_MAX, lt_t2 = UINT32_MAX;
|
||||
usec_t irt = IRT_DEFAULT;
|
||||
int r;
|
||||
|
||||
@@ -1178,10 +1174,6 @@ int client_parse_message(
|
||||
|
||||
dhcp6_ia_free(lease->ia_na);
|
||||
lease->ia_na = TAKE_PTR(ia);
|
||||
|
||||
lt_t1 = MIN(lt_t1, be32toh(lease->ia_na->header.lifetime_t1));
|
||||
lt_t2 = MIN(lt_t2, be32toh(lease->ia_na->header.lifetime_t2));
|
||||
|
||||
break;
|
||||
}
|
||||
case SD_DHCP6_OPTION_IA_PD: {
|
||||
@@ -1205,10 +1197,6 @@ int client_parse_message(
|
||||
|
||||
dhcp6_ia_free(lease->ia_pd);
|
||||
lease->ia_pd = TAKE_PTR(ia);
|
||||
|
||||
lt_t1 = MIN(lt_t1, be32toh(lease->ia_pd->header.lifetime_t1));
|
||||
lt_t2 = MIN(lt_t2, be32toh(lease->ia_pd->header.lifetime_t2));
|
||||
|
||||
break;
|
||||
}
|
||||
case SD_DHCP6_OPTION_RAPID_COMMIT:
|
||||
@@ -1282,15 +1270,7 @@ int client_parse_message(
|
||||
if (!lease->ia_na && !lease->ia_pd)
|
||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "No IA_PD prefix or IA_NA address received. Ignoring.");
|
||||
|
||||
if (lease->ia_na) {
|
||||
lease->ia_na->header.lifetime_t1 = htobe32(lt_t1);
|
||||
lease->ia_na->header.lifetime_t2 = htobe32(lt_t2);
|
||||
}
|
||||
|
||||
if (lease->ia_pd) {
|
||||
lease->ia_pd->header.lifetime_t1 = htobe32(lt_t1);
|
||||
lease->ia_pd->header.lifetime_t2 = htobe32(lt_t2);
|
||||
}
|
||||
dhcp6_lease_set_lifetime(lease);
|
||||
}
|
||||
|
||||
client->information_refresh_time_usec = MAX(irt, IRT_MINIMUM);
|
||||
@@ -1551,32 +1531,9 @@ static int client_receive_message(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int client_get_lifetime(sd_dhcp6_client *client, uint32_t *lifetime_t1,
|
||||
uint32_t *lifetime_t2) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(client->lease, -EINVAL);
|
||||
|
||||
if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_NA) && client->lease->ia_na) {
|
||||
*lifetime_t1 = be32toh(client->lease->ia_na->header.lifetime_t1);
|
||||
*lifetime_t2 = be32toh(client->lease->ia_na->header.lifetime_t2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_PD) && client->lease->ia_pd) {
|
||||
*lifetime_t1 = be32toh(client->lease->ia_pd->header.lifetime_t1);
|
||||
*lifetime_t2 = be32toh(client->lease->ia_pd->header.lifetime_t2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOMSG;
|
||||
}
|
||||
|
||||
static int client_start(sd_dhcp6_client *client, DHCP6State state) {
|
||||
usec_t timeout, time_now, lifetime_t1, lifetime_t2;
|
||||
int r;
|
||||
usec_t timeout, time_now;
|
||||
uint32_t lifetime_t1, lifetime_t2;
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(client->event, -EINVAL);
|
||||
@@ -1635,18 +1592,18 @@ static int client_start(sd_dhcp6_client *client, DHCP6State state) {
|
||||
|
||||
case DHCP6_STATE_BOUND:
|
||||
|
||||
r = client_get_lifetime(client, &lifetime_t1, &lifetime_t2);
|
||||
assert(client->lease);
|
||||
|
||||
r = dhcp6_lease_get_lifetime(client->lease, &lifetime_t1, &lifetime_t2);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
if (lifetime_t1 == 0xffffffff || lifetime_t2 == 0xffffffff) {
|
||||
log_dhcp6_client(client, "Infinite T1 0x%08x or T2 0x%08x",
|
||||
lifetime_t1, lifetime_t2);
|
||||
|
||||
if (lifetime_t1 == USEC_INFINITY || lifetime_t2 == USEC_INFINITY) {
|
||||
log_dhcp6_client(client, "Infinite T1 or T2");
|
||||
return 0;
|
||||
}
|
||||
|
||||
timeout = client_timeout_compute_random(lifetime_t1 * USEC_PER_SEC);
|
||||
timeout = client_timeout_compute_random(lifetime_t1);
|
||||
|
||||
log_dhcp6_client(client, "T1 expires in %s", FORMAT_TIMESPAN(timeout, USEC_PER_SEC));
|
||||
|
||||
@@ -1658,7 +1615,7 @@ static int client_start(sd_dhcp6_client *client, DHCP6State state) {
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
timeout = client_timeout_compute_random(lifetime_t2 * USEC_PER_SEC);
|
||||
timeout = client_timeout_compute_random(lifetime_t2);
|
||||
|
||||
log_dhcp6_client(client, "T2 expires in %s", FORMAT_TIMESPAN(timeout, USEC_PER_SEC));
|
||||
|
||||
|
||||
@@ -24,6 +24,67 @@ int sd_dhcp6_lease_get_timestamp(sd_dhcp6_lease *lease, clockid_t clock, uint64_
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dhcp6_lease_set_lifetime(sd_dhcp6_lease *lease) {
|
||||
uint32_t t1 = UINT32_MAX, t2 = UINT32_MAX, min_valid_lt = UINT32_MAX;
|
||||
DHCP6Address *a;
|
||||
|
||||
assert(lease);
|
||||
assert(lease->ia_na || lease->ia_pd);
|
||||
|
||||
if (lease->ia_na) {
|
||||
t1 = MIN(t1, be32toh(lease->ia_na->header.lifetime_t1));
|
||||
t2 = MIN(t2, be32toh(lease->ia_na->header.lifetime_t2));
|
||||
|
||||
LIST_FOREACH(addresses, a, lease->ia_na->addresses)
|
||||
min_valid_lt = MIN(min_valid_lt, be32toh(a->iaaddr.lifetime_valid));
|
||||
}
|
||||
|
||||
if (lease->ia_pd) {
|
||||
t1 = MIN(t1, be32toh(lease->ia_pd->header.lifetime_t1));
|
||||
t2 = MIN(t2, be32toh(lease->ia_pd->header.lifetime_t2));
|
||||
|
||||
LIST_FOREACH(addresses, a, lease->ia_pd->addresses)
|
||||
min_valid_lt = MIN(min_valid_lt, be32toh(a->iapdprefix.lifetime_valid));
|
||||
}
|
||||
|
||||
if (t2 == 0 || t2 > min_valid_lt) {
|
||||
/* If T2 is zero or longer than the minimum valid lifetime of the addresses or prefixes,
|
||||
* then adjust lifetime with it. */
|
||||
t1 = min_valid_lt / 2;
|
||||
t2 = min_valid_lt / 10 * 8;
|
||||
}
|
||||
|
||||
assert(t2 <= min_valid_lt);
|
||||
lease->max_retransmit_duration = (min_valid_lt - t2) * USEC_PER_SEC;
|
||||
|
||||
lease->lifetime_t1 = t1 == UINT32_MAX ? USEC_INFINITY : t1 * USEC_PER_SEC;
|
||||
lease->lifetime_t2 = t2 == UINT32_MAX ? USEC_INFINITY : t2 * USEC_PER_SEC;
|
||||
}
|
||||
|
||||
int dhcp6_lease_get_lifetime(sd_dhcp6_lease *lease, usec_t *ret_t1, usec_t *ret_t2) {
|
||||
assert(lease);
|
||||
|
||||
if (!lease->ia_na && !lease->ia_pd)
|
||||
return -ENODATA;
|
||||
|
||||
if (ret_t1)
|
||||
*ret_t1 = lease->lifetime_t1;
|
||||
if (ret_t2)
|
||||
*ret_t2 = lease->lifetime_t2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_lease_get_max_retransmit_duration(sd_dhcp6_lease *lease, usec_t *ret) {
|
||||
assert(lease);
|
||||
|
||||
if (!lease->ia_na && !lease->ia_pd)
|
||||
return -ENODATA;
|
||||
|
||||
if (ret)
|
||||
*ret = lease->max_retransmit_duration;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_lease_get_server_address(sd_dhcp6_lease *lease, struct in6_addr *ret) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
@@ -32,28 +93,6 @@ int sd_dhcp6_lease_get_server_address(sd_dhcp6_lease *lease, struct in6_addr *re
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire) {
|
||||
DHCP6Address *addr;
|
||||
uint32_t valid = 0, t;
|
||||
|
||||
assert(ia);
|
||||
assert(expire);
|
||||
|
||||
LIST_FOREACH(addresses, addr, ia->addresses) {
|
||||
t = be32toh(addr->iaaddr.lifetime_valid);
|
||||
if (valid < t)
|
||||
valid = t;
|
||||
}
|
||||
|
||||
t = be32toh(ia->header.lifetime_t2);
|
||||
if (t > valid)
|
||||
return -EINVAL;
|
||||
|
||||
*expire = valid - t;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dhcp6_ia_clear_addresses(DHCP6IA *ia) {
|
||||
DHCP6Address *a, *n;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user