mirror of
https://github.com/systemd/systemd.git
synced 2024-10-28 11:55:44 +03:00
sd-dhcp6-client: Add DHCPv6 client Solicitation timeout handling
Add the core of DHCPv6 client message retransmission and upper bound timer and message count handling according to RFC 3315 Secions 7.1.2 and 14. Omit the DHCPv6 initial delay; for now it is assumed that systemd-networkd will provide decent startup randomization that will desynchronize the clients. When reinitializing the client, clear all timers.
This commit is contained in:
parent
813e3a6ffc
commit
d1b0afe365
@ -41,6 +41,10 @@ enum {
|
||||
DHCP6_PORT_CLIENT = 546,
|
||||
};
|
||||
|
||||
#define DHCP6_SOL_MAX_DELAY 1 * USEC_PER_SEC
|
||||
#define DHCP6_SOL_TIMEOUT 1 * USEC_PER_SEC
|
||||
#define DHCP6_SOL_MAX_RT 120 * USEC_PER_SEC
|
||||
|
||||
enum {
|
||||
DHCP6_DUID_LLT = 1,
|
||||
DHCP6_DUID_EN = 2,
|
||||
@ -51,6 +55,7 @@ enum {
|
||||
enum DHCP6State {
|
||||
DHCP6_STATE_STOPPED = 0,
|
||||
DHCP6_STATE_RS = 1,
|
||||
DHCP6_STATE_SOLICITATION = 2,
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -46,6 +46,10 @@ struct sd_dhcp6_client {
|
||||
int index;
|
||||
struct ether_addr mac_addr;
|
||||
DHCP6IA ia_na;
|
||||
usec_t retransmit_time;
|
||||
uint8_t retransmit_count;
|
||||
sd_event_source *timeout_resend;
|
||||
sd_event_source *timeout_resend_expire;
|
||||
sd_dhcp6_client_cb_t cb;
|
||||
void *userdata;
|
||||
|
||||
@ -109,6 +113,12 @@ static int client_initialize(sd_dhcp6_client *client)
|
||||
client->ia_na.timeout_t2 =
|
||||
sd_event_source_unref(client->ia_na.timeout_t2);
|
||||
|
||||
client->retransmit_time = 0;
|
||||
client->retransmit_count = 0;
|
||||
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
|
||||
client->timeout_resend_expire =
|
||||
sd_event_source_unref(client->timeout_resend_expire);
|
||||
|
||||
client->state = DHCP6_STATE_STOPPED;
|
||||
|
||||
return 0;
|
||||
@ -124,6 +134,118 @@ static sd_dhcp6_client *client_stop(sd_dhcp6_client *client, int error) {
|
||||
return client;
|
||||
}
|
||||
|
||||
static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec,
|
||||
void *userdata) {
|
||||
sd_dhcp6_client *client = userdata;
|
||||
|
||||
assert(s);
|
||||
assert(client);
|
||||
assert(client->event);
|
||||
|
||||
client_stop(client, DHCP6_EVENT_RESEND_EXPIRE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static usec_t client_timeout_compute_random(usec_t val) {
|
||||
return val - val / 10 +
|
||||
(random_u32() % (2 * USEC_PER_SEC)) * val / 10 / USEC_PER_SEC;
|
||||
}
|
||||
|
||||
static int client_timeout_resend(sd_event_source *s, uint64_t usec,
|
||||
void *userdata) {
|
||||
int r = 0;
|
||||
sd_dhcp6_client *client = userdata;
|
||||
usec_t time_now, init_retransmit_time, max_retransmit_time;
|
||||
usec_t max_retransmit_duration;
|
||||
uint8_t max_retransmit_count;
|
||||
char time_string[FORMAT_TIMESPAN_MAX];
|
||||
|
||||
assert(s);
|
||||
assert(client);
|
||||
assert(client->event);
|
||||
|
||||
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
|
||||
|
||||
switch (client->state) {
|
||||
case DHCP6_STATE_SOLICITATION:
|
||||
init_retransmit_time = DHCP6_SOL_TIMEOUT;
|
||||
max_retransmit_time = DHCP6_SOL_MAX_RT;
|
||||
max_retransmit_count = 0;
|
||||
max_retransmit_duration = 0;
|
||||
|
||||
break;
|
||||
|
||||
case DHCP6_STATE_STOPPED:
|
||||
case DHCP6_STATE_RS:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (max_retransmit_count &&
|
||||
client->retransmit_count >= max_retransmit_count) {
|
||||
client_stop(client, DHCP6_EVENT_RETRANS_MAX);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
if (!client->retransmit_time) {
|
||||
client->retransmit_time =
|
||||
client_timeout_compute_random(init_retransmit_time);
|
||||
} else {
|
||||
if (max_retransmit_time &&
|
||||
client->retransmit_time > max_retransmit_time / 2)
|
||||
client->retransmit_time = client_timeout_compute_random(max_retransmit_time);
|
||||
else
|
||||
client->retransmit_time += client_timeout_compute_random(client->retransmit_time);
|
||||
}
|
||||
|
||||
log_dhcp6_client(client, "Next retransmission in %s",
|
||||
format_timespan(time_string, FORMAT_TIMESPAN_MAX,
|
||||
client->retransmit_time, 0));
|
||||
|
||||
r = sd_event_add_time(client->event, &client->timeout_resend,
|
||||
CLOCK_MONOTONIC,
|
||||
time_now + client->retransmit_time,
|
||||
10 * USEC_PER_MSEC, client_timeout_resend,
|
||||
client);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_event_source_set_priority(client->timeout_resend,
|
||||
client->event_priority);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
if (max_retransmit_duration && !client->timeout_resend_expire) {
|
||||
|
||||
log_dhcp6_client(client, "Max retransmission duration %"PRIu64" secs",
|
||||
max_retransmit_duration / USEC_PER_SEC);
|
||||
|
||||
r = sd_event_add_time(client->event,
|
||||
&client->timeout_resend_expire,
|
||||
CLOCK_MONOTONIC,
|
||||
time_now + max_retransmit_duration,
|
||||
USEC_PER_SEC,
|
||||
client_timeout_resend_expire, client);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_event_source_set_priority(client->timeout_resend_expire,
|
||||
client->event_priority);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
if (r < 0)
|
||||
client_stop(client, r);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int client_ensure_iaid(sd_dhcp6_client *client) {
|
||||
const char *name = NULL;
|
||||
uint64_t id;
|
||||
@ -180,6 +302,19 @@ static int client_start(sd_dhcp6_client *client)
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
client->state = DHCP6_STATE_SOLICITATION;
|
||||
|
||||
r = sd_event_add_time(client->event, &client->timeout_resend,
|
||||
CLOCK_MONOTONIC, 0, 0, client_timeout_resend,
|
||||
client);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_event_source_set_priority(client->timeout_resend,
|
||||
client->event_priority);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,8 @@
|
||||
|
||||
enum {
|
||||
DHCP6_EVENT_STOP = 0,
|
||||
DHCP6_EVENT_RESEND_EXPIRE = 10,
|
||||
DHCP6_EVENT_RETRANS_MAX = 11,
|
||||
};
|
||||
|
||||
typedef struct sd_dhcp6_client sd_dhcp6_client;
|
||||
|
Loading…
Reference in New Issue
Block a user