From f3bd46c657d9ffd4c34624fbbff23d21d5848ca4 Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Mon, 14 Dec 2020 15:50:11 -0500 Subject: [PATCH 1/7] sd-dhcp-client: don't log timeouts if already expired --- src/libsystemd-network/sd-dhcp-client.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index f47a542483..face7d7dd6 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -1712,13 +1712,13 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { if (r < 0) return r; - log_dhcp_client(client, "lease expires in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC)); - /* don't arm earlier timeouts if this has already expired */ if (lifetime_timeout <= time_now) return 0; + log_dhcp_client(client, "lease expires in %s", + format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC)); + /* arm T2 timeout */ r = event_reset_time(client->event, &client->timeout_t2, clock_boottime_or_monotonic(), @@ -1728,13 +1728,13 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { if (r < 0) return r; - log_dhcp_client(client, "T2 expires in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC)); - /* don't arm earlier timeout if this has already expired */ if (t2_timeout <= time_now) return 0; + log_dhcp_client(client, "T2 expires in %s", + format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC)); + /* arm T1 timeout */ r = event_reset_time(client->event, &client->timeout_t1, clock_boottime_or_monotonic(), @@ -1744,8 +1744,9 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { if (r < 0) return r; - log_dhcp_client(client, "T1 expires in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC)); + if (t1_timeout > time_now) + log_dhcp_client(client, "T1 expires in %s", + format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC)); return 0; } From 0c3c59783b127ec9a1c4860c6509d133cccffe10 Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Tue, 8 Dec 2020 14:37:59 -0500 Subject: [PATCH 2/7] sd-dhcp-client: track dhcp4 t1, t2, expire times Add fields to dhcp4 client to track t1, t2, and lease expiry times --- src/libsystemd-network/sd-dhcp-client.c | 54 ++++++++++++------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index face7d7dd6..60e4a93328 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -98,6 +98,9 @@ struct sd_dhcp_client { uint32_t fallback_lease_lifetime; uint32_t xid; usec_t start_time; + usec_t t1_time; + usec_t t2_time; + usec_t expire_time; uint64_t attempt; uint64_t max_attempts; OrderedHashmap *extra_options; @@ -1634,9 +1637,6 @@ static uint64_t client_compute_timeout(sd_dhcp_client *client, uint32_t lifetime static int client_set_lease_timeouts(sd_dhcp_client *client) { usec_t time_now; - uint64_t lifetime_timeout; - uint64_t t2_timeout; - uint64_t t1_timeout; char time_string[FORMAT_TIMESPAN_MAX]; int r; @@ -1660,93 +1660,93 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { assert(client->request_sent <= time_now); /* convert the various timeouts from relative (secs) to absolute (usecs) */ - lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1); + client->expire_time = client_compute_timeout(client, client->lease->lifetime, 1); if (client->lease->t1 > 0 && client->lease->t2 > 0) { /* both T1 and T2 are given */ if (client->lease->t1 < client->lease->t2 && client->lease->t2 < client->lease->lifetime) { /* they are both valid */ - t2_timeout = client_compute_timeout(client, client->lease->t2, 1); - t1_timeout = client_compute_timeout(client, client->lease->t1, 1); + client->t2_time = client_compute_timeout(client, client->lease->t2, 1); + client->t1_time = client_compute_timeout(client, client->lease->t1, 1); } else { /* discard both */ - t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); + client->t2_time = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); client->lease->t2 = (client->lease->lifetime * 7) / 8; - t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); + client->t1_time = client_compute_timeout(client, client->lease->lifetime, 0.5); client->lease->t1 = client->lease->lifetime / 2; } } else if (client->lease->t2 > 0 && client->lease->t2 < client->lease->lifetime) { /* only T2 is given, and it is valid */ - t2_timeout = client_compute_timeout(client, client->lease->t2, 1); - t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); + client->t2_time = client_compute_timeout(client, client->lease->t2, 1); + client->t1_time = client_compute_timeout(client, client->lease->lifetime, 0.5); client->lease->t1 = client->lease->lifetime / 2; - if (t2_timeout <= t1_timeout) { + if (client->t2_time <= client->t1_time) { /* the computed T1 would be invalid, so discard T2 */ - t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); + client->t2_time = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); client->lease->t2 = (client->lease->lifetime * 7) / 8; } } else if (client->lease->t1 > 0 && client->lease->t1 < client->lease->lifetime) { /* only T1 is given, and it is valid */ - t1_timeout = client_compute_timeout(client, client->lease->t1, 1); - t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); + client->t1_time = client_compute_timeout(client, client->lease->t1, 1); + client->t2_time = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); client->lease->t2 = (client->lease->lifetime * 7) / 8; - if (t2_timeout <= t1_timeout) { + if (client->t2_time <= client->t1_time) { /* the computed T2 would be invalid, so discard T1 */ - t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); + client->t2_time = client_compute_timeout(client, client->lease->lifetime, 0.5); client->lease->t2 = client->lease->lifetime / 2; } } else { /* fall back to the default timeouts */ - t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); + client->t1_time = client_compute_timeout(client, client->lease->lifetime, 0.5); client->lease->t1 = client->lease->lifetime / 2; - t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); + client->t2_time = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); client->lease->t2 = (client->lease->lifetime * 7) / 8; } /* arm lifetime timeout */ r = event_reset_time(client->event, &client->timeout_expire, clock_boottime_or_monotonic(), - lifetime_timeout, 10 * USEC_PER_MSEC, + client->expire_time, 10 * USEC_PER_MSEC, client_timeout_expire, client, client->event_priority, "dhcp4-lifetime", true); if (r < 0) return r; /* don't arm earlier timeouts if this has already expired */ - if (lifetime_timeout <= time_now) + if (client->expire_time <= time_now) return 0; log_dhcp_client(client, "lease expires in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC)); + format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->expire_time - time_now, USEC_PER_SEC)); /* arm T2 timeout */ r = event_reset_time(client->event, &client->timeout_t2, clock_boottime_or_monotonic(), - t2_timeout, 10 * USEC_PER_MSEC, + client->t2_time, 10 * USEC_PER_MSEC, client_timeout_t2, client, client->event_priority, "dhcp4-t2-timeout", true); if (r < 0) return r; /* don't arm earlier timeout if this has already expired */ - if (t2_timeout <= time_now) + if (client->t2_time <= time_now) return 0; log_dhcp_client(client, "T2 expires in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC)); + format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->t2_time - time_now, USEC_PER_SEC)); /* arm T1 timeout */ r = event_reset_time(client->event, &client->timeout_t1, clock_boottime_or_monotonic(), - t1_timeout, 10 * USEC_PER_MSEC, + client->t1_time, 10 * USEC_PER_MSEC, client_timeout_t1, client, client->event_priority, "dhcp4-t1-timer", true); if (r < 0) return r; - if (t1_timeout > time_now) + if (client->t1_time > time_now) log_dhcp_client(client, "T1 expires in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC)); + format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->t1_time - time_now, USEC_PER_SEC)); return 0; } From 3d75a443ee819c4b2df8bfd8caee5c3ebc76fae3 Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Tue, 8 Dec 2020 15:33:29 -0500 Subject: [PATCH 3/7] sd-dhcp-client: add RFC2131 retransmission details RFC2131, providing the details for dhcpv4, has specific retransmission intervals that it outlines. This adds functions to compute the timeouts as the RFC describes. --- src/libsystemd-network/sd-dhcp-client.c | 32 +++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 60e4a93328..0ffc543132 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -29,6 +29,7 @@ #include "sort-util.h" #include "string-util.h" #include "strv.h" +#include "time-util.h" #include "utf8.h" #include "web-util.h" @@ -730,6 +731,37 @@ static void client_stop(sd_dhcp_client *client, int error) { client_initialize(client); } +/* RFC2131 section 4.1: + * retransmission delays should include -1 to +1 sec of random 'fuzz'. */ +#define RFC2131_RANDOM_FUZZ \ + ((int64_t)(random_u64() % (2 * USEC_PER_SEC)) - (int64_t)USEC_PER_SEC) + +/* RFC2131 section 4.1: + * for retransmission delays, timeout should start at 4s then double + * each attempt with max of 64s, with -1 to +1 sec of random 'fuzz' added. + * This assumes the first call will be using attempt 1. */ +static usec_t client_compute_request_timeout(usec_t now, uint64_t attempt) { + usec_t timeout = (UINT64_C(1) << MIN(attempt + 1, UINT64_C(6))) * USEC_PER_SEC; + + return usec_sub_signed(usec_add(now, timeout), RFC2131_RANDOM_FUZZ); +} + +/* RFC2131 section 4.4.5: + * T1 defaults to (0.5 * duration_of_lease). + * T2 defaults to (0.875 * duration_of_lease). */ +#define T1_DEFAULT(lifetime) ((lifetime) / 2) +#define T2_DEFAULT(lifetime) (((lifetime) * 7) / 8) + +/* RFC2131 section 4.4.5: + * the client SHOULD wait one-half of the remaining time until T2 (in RENEWING state) + * and one-half of the remaining lease time (in REBINDING state), down to a minimum + * of 60 seconds. + * Note that while the default T1/T2 initial times do have random 'fuzz' applied, + * the RFC sec 4.4.5 does not mention adding any fuzz to retries. */ +static usec_t client_compute_reacquisition_timeout(usec_t now, usec_t expire) { + return MAX(usec_sub_unsigned(expire, now) / 2, 60 * USEC_PER_SEC); +} + static int cmp_uint8(const uint8_t *a, const uint8_t *b) { return CMP(*a, *b); } From b0d7d8063cb61bb204523f02fd45fb671a1f4d43 Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Tue, 8 Dec 2020 15:36:19 -0500 Subject: [PATCH 4/7] sd-dhcp-client: simplify dhcp4 t1/t2 parsing The parsing of the dhcpv4 lease lifetime, as well as the t1/t2 times, is simplified by this commit. This differs from previous behavior; previously, the lease lifetime and t1/t2 values were modified by random 'fuzz' by subtracting 3, then adding a random number between 0 and (slightly over) 2 seconds. The resulting values were therefore always between 1-3 seconds shorter than the value provided by the server (or the default, in case of t1/t2). Now, as described in RFC2131, the random 'fuzz' is between -1 and +1 seconds, meaning the actual t1 and t2 value will be up to 1 second earlier or later than the server-provided (or default) t1/t2 value. This also differs in handling the lease lifetime, as described above it previously was adjusted by the random 'fuzz', but the RFC does not state that the lease expiration time should be adjusted, so now the code uses exactly the lease lifetime as provided by the server with no adjustment. --- src/libsystemd-network/sd-dhcp-client.c | 82 ++++++++----------------- 1 file changed, 25 insertions(+), 57 deletions(-) diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 0ffc543132..8c6affac81 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -1653,20 +1653,6 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t le return r; } -static uint64_t client_compute_timeout(sd_dhcp_client *client, uint32_t lifetime, double factor) { - assert(client); - assert(client->request_sent); - assert(lifetime > 0); - - if (lifetime > 3) - lifetime -= 3; - else - lifetime = 0; - - return client->request_sent + (lifetime * USEC_PER_SEC * factor) + - + (random_u32() & 0x1fffff); -} - static int client_set_lease_timeouts(sd_dhcp_client *client) { usec_t time_now; char time_string[FORMAT_TIMESPAN_MAX]; @@ -1691,49 +1677,31 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { return r; assert(client->request_sent <= time_now); - /* convert the various timeouts from relative (secs) to absolute (usecs) */ - client->expire_time = client_compute_timeout(client, client->lease->lifetime, 1); - if (client->lease->t1 > 0 && client->lease->t2 > 0) { - /* both T1 and T2 are given */ - if (client->lease->t1 < client->lease->t2 && - client->lease->t2 < client->lease->lifetime) { - /* they are both valid */ - client->t2_time = client_compute_timeout(client, client->lease->t2, 1); - client->t1_time = client_compute_timeout(client, client->lease->t1, 1); - } else { - /* discard both */ - client->t2_time = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); - client->lease->t2 = (client->lease->lifetime * 7) / 8; - client->t1_time = client_compute_timeout(client, client->lease->lifetime, 0.5); - client->lease->t1 = client->lease->lifetime / 2; - } - } else if (client->lease->t2 > 0 && client->lease->t2 < client->lease->lifetime) { - /* only T2 is given, and it is valid */ - client->t2_time = client_compute_timeout(client, client->lease->t2, 1); - client->t1_time = client_compute_timeout(client, client->lease->lifetime, 0.5); - client->lease->t1 = client->lease->lifetime / 2; - if (client->t2_time <= client->t1_time) { - /* the computed T1 would be invalid, so discard T2 */ - client->t2_time = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); - client->lease->t2 = (client->lease->lifetime * 7) / 8; - } - } else if (client->lease->t1 > 0 && client->lease->t1 < client->lease->lifetime) { - /* only T1 is given, and it is valid */ - client->t1_time = client_compute_timeout(client, client->lease->t1, 1); - client->t2_time = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); - client->lease->t2 = (client->lease->lifetime * 7) / 8; - if (client->t2_time <= client->t1_time) { - /* the computed T2 would be invalid, so discard T1 */ - client->t2_time = client_compute_timeout(client, client->lease->lifetime, 0.5); - client->lease->t2 = client->lease->lifetime / 2; - } - } else { - /* fall back to the default timeouts */ - client->t1_time = client_compute_timeout(client, client->lease->lifetime, 0.5); - client->lease->t1 = client->lease->lifetime / 2; - client->t2_time = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); - client->lease->t2 = (client->lease->lifetime * 7) / 8; - } + /* verify that 0 < t2 < lifetime */ + if (client->lease->t2 == 0 || client->lease->t2 >= client->lease->lifetime) + client->lease->t2 = T2_DEFAULT(client->lease->lifetime); + /* verify that 0 < t1 < lifetime */ + if (client->lease->t1 == 0 || client->lease->t1 >= client->lease->t2) + client->lease->t1 = T1_DEFAULT(client->lease->lifetime); + /* now, if t1 >= t2, t1 *must* be T1_DEFAULT, since the previous check + * could not evalate to false if t1 >= t2; so setting t2 to T2_DEFAULT + * guarantees t1 < t2. */ + if (client->lease->t1 >= client->lease->t2) + client->lease->t2 = T2_DEFAULT(client->lease->lifetime); + + client->expire_time = client->request_sent + client->lease->lifetime * USEC_PER_SEC; + client->t1_time = client->request_sent + client->lease->t1 * USEC_PER_SEC; + client->t2_time = client->request_sent + client->lease->t2 * USEC_PER_SEC; + + /* RFC2131 section 4.4.5: + * Times T1 and T2 SHOULD be chosen with some random "fuzz". + * Since the RFC doesn't specify here the exact 'fuzz' to use, + * we use the range from section 4.1: -1 to +1 sec. */ + client->t1_time = usec_sub_signed(client->t1_time, RFC2131_RANDOM_FUZZ); + client->t2_time = usec_sub_signed(client->t2_time, RFC2131_RANDOM_FUZZ); + + /* after fuzzing, ensure t2 is still >= t1 */ + client->t2_time = MAX(client->t1_time, client->t2_time); /* arm lifetime timeout */ r = event_reset_time(client->event, &client->timeout_expire, From c24288d21ee94856f5c60473191d41c77b71da91 Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Tue, 8 Dec 2020 15:40:10 -0500 Subject: [PATCH 5/7] sd-dhcp-client: correct dhcpv4 renew/rebind retransmit timeouts Use the request timeout algorithm specified in RFC2131 section 4.4.5 for handling timed out RENEW and REBIND requests. This changes behavior, as previously only 2 RENEW and 2 REBIND requests were sent, no matter how long the lease lifetime. Now, requests are send according to the RFC, which results in starting with a timeout of 1/2 the t1 or t2 period, and halving the timeout for each retry down to a minimum of 60 seconds. Fixes: #17909 --- src/libsystemd-network/sd-dhcp-client.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 8c6affac81..4a693ba706 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -1227,7 +1227,6 @@ static int client_timeout_resend( DHCP_CLIENT_DONT_DESTROY(client); usec_t next_timeout; uint64_t time_now; - uint32_t time_left; int r; assert(s); @@ -1241,19 +1240,11 @@ static int client_timeout_resend( switch (client->state) { case DHCP_STATE_RENEWING: - time_left = (client->lease->t2 - client->lease->t1) / 2; - if (time_left < 60) - time_left = 60; - - next_timeout = time_now + time_left * USEC_PER_SEC; + next_timeout = client_compute_reacquisition_timeout(time_now, client->t2_time); break; case DHCP_STATE_REBINDING: - time_left = (client->lease->lifetime - client->lease->t2) / 2; - if (time_left < 60) - time_left = 60; - - next_timeout = time_now + time_left * USEC_PER_SEC; + next_timeout = client_compute_reacquisition_timeout(time_now, client->expire_time); break; case DHCP_STATE_REBOOTING: @@ -1279,6 +1270,7 @@ static int client_timeout_resend( client->attempt++; next_timeout = time_now + ((UINT64_C(1) << MIN(client->attempt, (uint64_t) 6)) - 1) * USEC_PER_SEC; + next_timeout += (random_u32() & 0x1fffff); break; case DHCP_STATE_STOPPED: @@ -1286,8 +1278,6 @@ static int client_timeout_resend( goto error; } - next_timeout += (random_u32() & 0x1fffff); - r = event_reset_time(client->event, &client->timeout_resend, clock_boottime_or_monotonic(), next_timeout, 10 * USEC_PER_MSEC, From f3808b872f78b3224ecd0517f96f18a353bfba79 Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Wed, 9 Dec 2020 14:32:06 -0500 Subject: [PATCH 6/7] sd-dhcp-client: correct retransmission timeout to match RFC This changes the retransmission timeout algorithm for requests other than RENEW and REBIND. Previously, the retransmission timeout started at 2 seconds, then doubling each retransmission up to a max of 64 seconds. This is changed to match what RFC2131 section 4.1 describes, which skips the initial 2 second timeout and starts with a 4 second timeout instead. Note that -1 to +1 seconds of random 'fuzz' is added to each timeout, in previous and current behavior. This change is therefore slightly slower than the previous behavior in attempting retransmissions when no server response is received, since the first transmission times out in 4 seconds instead of 2. Since TRANSIENT_FAILURE_ATTEMPTS is set to 3, the previous length of time before a transient failure was reported back to systemd-networkd was 2 + 4 + 8 = 14 seconds, plus, on average, 3 seconds of random 'fuzz' for a transient failure timeout between 11 and 17 seconds. Now, since the first timeout starts at 4, the transient failure will be reported at 4 + 8 + 16 = 28 seconds, again plus 3 random seconds for a transient failure timeout between 25 and 31 seconds. Additionally, if MaxAttempts= is set, it will take slightly longer to reach than with previous behavior. --- src/libsystemd-network/sd-dhcp-client.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 4a693ba706..c3b51c0d0f 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -1269,8 +1269,7 @@ static int client_timeout_resend( goto error; client->attempt++; - next_timeout = time_now + ((UINT64_C(1) << MIN(client->attempt, (uint64_t) 6)) - 1) * USEC_PER_SEC; - next_timeout += (random_u32() & 0x1fffff); + next_timeout = client_compute_request_timeout(time_now, client->attempt); break; case DHCP_STATE_STOPPED: From b226c15cfb993dc6e00ae6180bb287fc4dd93acd Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Wed, 9 Dec 2020 15:24:09 -0500 Subject: [PATCH 7/7] test-network: increase wait_online timeout to handle longer dhcpv4 transient timeout Previous commits changed the dhcpv4 retransmission algorithm to be slightly slower, changing the amount of time it takes to notify systemd-networkd that the dhcpv4 configuration has (transiently) failed from around 14 second up to 28 seconds. Since the test_dhcp_client_with_ipv4ll_without_dhcp_server test configures an interface to use dhcpv4 without any operating dhcpv4 server running, it must increase the amount of time it waits for the test interface to reach degraded state. --- test/test-network/systemd-networkd-tests.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 0a33ce7779..454e6ce66b 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -4104,7 +4104,9 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-with-ipv4ll.network') start_networkd() - self.wait_online(['veth99:degraded', 'veth-peer:routable']) + # we need to increase timeout above default, as this will need to wait for + # systemd-networkd to get the dhcpv4 transient failure event + self.wait_online(['veth99:degraded', 'veth-peer:routable'], timeout='60s') output = check_output('ip address show dev veth99') print(output)