mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-04-25 07:20:38 +02:00
n-dhcp4: support init-reboot state
Currently the client always starts from the INIT state (i.e. sending a
discover message). If a requested-ip was specified by the caller, it
is added as an option in the discover.
It was reported that some DHCP servers don't respond to discover
messages with the requested-ip option set [1][2].
The RFC allows to skip the discover by entering the INIT-REBOOT state
and starting directly with a broadcast request message containing the
requested IP address. Implement that.
[1] https://bugzilla.redhat.com/show_bug.cgi?id=1781856
[2] https://gitlab.freedesktop.org/NetworkManager/NetworkManager/issues/310
(cherry picked from commit af03b77980)
This commit is contained in:
parent
0a428153f8
commit
965219a4cd
3 changed files with 80 additions and 7 deletions
|
|
@ -319,7 +319,6 @@ void n_dhcp4_c_connection_get_timeout(NDhcp4CConnection *connection,
|
|||
switch (connection->request->userdata.type) {
|
||||
case N_DHCP4_C_MESSAGE_DISCOVER:
|
||||
case N_DHCP4_C_MESSAGE_SELECT:
|
||||
case N_DHCP4_C_MESSAGE_REBOOT:
|
||||
case N_DHCP4_C_MESSAGE_INFORM:
|
||||
/*
|
||||
* Resend with an exponential backoff and a one second random
|
||||
|
|
@ -338,6 +337,7 @@ void n_dhcp4_c_connection_get_timeout(NDhcp4CConnection *connection,
|
|||
break;
|
||||
case N_DHCP4_C_MESSAGE_REBIND:
|
||||
case N_DHCP4_C_MESSAGE_RENEW:
|
||||
case N_DHCP4_C_MESSAGE_REBOOT:
|
||||
/*
|
||||
* Resend every sixty seconds with a one second random slack.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -170,8 +170,6 @@ _c_public_ void n_dhcp4_client_probe_config_set_inform_only(NDhcp4ClientProbeCon
|
|||
* INIT-REBOOT path, as described by the DHCP specification. In most cases, you
|
||||
* do not want this.
|
||||
*
|
||||
* XXX: This is currently not implemented, and setting the property has no effect.
|
||||
*
|
||||
* Background: The INIT-REBOOT path allows a DHCP client to skip
|
||||
* server-discovery when rebooting/resuming their machine. The DHCP
|
||||
* client simply re-requests the lease it had acquired before. This
|
||||
|
|
@ -438,11 +436,17 @@ int n_dhcp4_client_probe_new(NDhcp4ClientProbe **probep,
|
|||
if (r)
|
||||
return r;
|
||||
|
||||
if (probe->config->init_reboot && probe->config->requested_ip.s_addr != INADDR_ANY)
|
||||
probe->state = N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT;
|
||||
else
|
||||
probe->state = N_DHCP4_CLIENT_PROBE_STATE_INIT;
|
||||
|
||||
if (active) {
|
||||
/*
|
||||
* Defer the sending of DISCOVER by a random amount (by default up to 9 seconds).
|
||||
*/
|
||||
probe->ns_deferred = ns_now + (n_dhcp4_client_probe_config_get_random(probe->config) % (probe->config->ms_start_delay * 1000000ULL));
|
||||
if (probe->state == N_DHCP4_CLIENT_PROBE_STATE_INIT)
|
||||
probe->ns_deferred = ns_now + (n_dhcp4_client_probe_config_get_random(probe->config) % (probe->config->ms_start_delay * 1000000ULL));
|
||||
probe->client->current_probe = probe;
|
||||
} else {
|
||||
r = n_dhcp4_client_probe_raise(probe,
|
||||
|
|
@ -575,6 +579,14 @@ void n_dhcp4_client_probe_get_timeout(NDhcp4ClientProbe *probe, uint64_t *timeou
|
|||
n_dhcp4_c_connection_get_timeout(&probe->connection, &timeout);
|
||||
|
||||
switch (probe->state) {
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
|
||||
/* send DHCP request immediately */
|
||||
timeout = 1;
|
||||
break;
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
|
||||
if (probe->ns_reinit && (!timeout || probe->ns_reinit < timeout))
|
||||
timeout = probe->ns_reinit;
|
||||
break;
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_INIT:
|
||||
if (probe->ns_deferred && (!timeout || probe->ns_deferred < timeout))
|
||||
timeout = probe->ns_deferred;
|
||||
|
|
@ -626,6 +638,52 @@ static int n_dhcp4_client_probe_outgoing_append_options(NDhcp4ClientProbe *probe
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int n_dhcp4_client_probe_transition_reboot(NDhcp4ClientProbe *probe, uint64_t ns_now) {
|
||||
_c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *request = NULL;
|
||||
int r;
|
||||
|
||||
switch (probe->state) {
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
|
||||
r = n_dhcp4_c_connection_listen(&probe->connection);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = n_dhcp4_c_connection_reboot_new(&probe->connection, &request, &probe->config->requested_ip);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = n_dhcp4_client_probe_outgoing_append_options(probe, request);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = n_dhcp4_c_connection_start_request(&probe->connection, request, ns_now);
|
||||
if (r)
|
||||
return r;
|
||||
else
|
||||
request = NULL; /* consumed */
|
||||
|
||||
probe->state = N_DHCP4_CLIENT_PROBE_STATE_REBOOTING;
|
||||
probe->ns_reinit = ns_now + 2000000000ULL;
|
||||
|
||||
break;
|
||||
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_INIT:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int n_dhcp4_client_probe_transition_deferred(NDhcp4ClientProbe *probe, uint64_t ns_now) {
|
||||
_c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *request = NULL;
|
||||
int r;
|
||||
|
|
@ -635,12 +693,14 @@ static int n_dhcp4_client_probe_transition_deferred(NDhcp4ClientProbe *probe, ui
|
|||
r = n_dhcp4_c_connection_listen(&probe->connection);
|
||||
if (r)
|
||||
return r;
|
||||
/* fall-through */
|
||||
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
|
||||
r = n_dhcp4_c_connection_discover_new(&probe->connection, &request);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (probe->config->requested_ip.s_addr != INADDR_ANY) {
|
||||
if (!probe->config->init_reboot && probe->config->requested_ip.s_addr != INADDR_ANY) {
|
||||
r = n_dhcp4_outgoing_append_requested_ip(request, probe->config->requested_ip);
|
||||
if (r)
|
||||
return r;
|
||||
|
|
@ -663,7 +723,6 @@ static int n_dhcp4_client_probe_transition_deferred(NDhcp4ClientProbe *probe, ui
|
|||
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
|
||||
|
|
@ -876,6 +935,7 @@ static int n_dhcp4_client_probe_transition_ack(NDhcp4ClientProbe *probe, NDhcp4I
|
|||
break;
|
||||
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
|
||||
|
||||
r = n_dhcp4_client_probe_raise(probe,
|
||||
&node,
|
||||
|
|
@ -900,7 +960,6 @@ static int n_dhcp4_client_probe_transition_ack(NDhcp4ClientProbe *probe, NDhcp4I
|
|||
case N_DHCP4_CLIENT_PROBE_STATE_INIT:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
|
||||
|
|
@ -1079,6 +1138,19 @@ int n_dhcp4_client_probe_dispatch_timer(NDhcp4ClientProbe *probe, uint64_t ns_no
|
|||
int r;
|
||||
|
||||
switch (probe->state) {
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
|
||||
r = n_dhcp4_client_probe_transition_reboot(probe, ns_now);
|
||||
if (r)
|
||||
return r;
|
||||
break;
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
|
||||
if (ns_now >= probe->ns_reinit) {
|
||||
r = n_dhcp4_client_probe_transition_deferred(probe, ns_now);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
break;
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_INIT:
|
||||
if (ns_now >= probe->ns_deferred) {
|
||||
r = n_dhcp4_client_probe_transition_deferred(probe, ns_now);
|
||||
|
|
|
|||
|
|
@ -351,6 +351,7 @@ struct NDhcp4ClientProbe {
|
|||
|
||||
unsigned int state; /* current probe state */
|
||||
uint64_t ns_deferred; /* timeout for deferred action */
|
||||
uint64_t ns_reinit;
|
||||
NDhcp4ClientLease *current_lease; /* current lease */
|
||||
|
||||
NDhcp4CConnection connection; /* client connection wrapper */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue