From 67957b1464ee433f205d8bbba90602a720bd2e05 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 12 Mar 2026 16:15:47 +0900 Subject: [PATCH 1/4] test-network: drop duplicated definition of networkd_pid() --- test/test-network/systemd-networkd-tests.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 1f3a99a040..835f31656e 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -987,7 +987,7 @@ def networkd_invocation_id(): return check_output('systemctl show --value -p InvocationID systemd-networkd.service') def networkd_pid(): - return check_output('systemctl show --value -p MainPID systemd-networkd.service') + return int(check_output('systemctl show --value -p MainPID systemd-networkd.service')) def read_networkd_log(invocation_id=None, since=None): if not invocation_id: @@ -1051,9 +1051,6 @@ def restart_networkd(show_logs=True): pid = networkd_pid() print(f'Restarted systemd-networkd.service: PID={pid}, Invocation ID={invocation_id}') -def networkd_pid(): - return int(check_output('systemctl show --value -p MainPID systemd-networkd.service')) - def networkctl(*args): # Do not call networkctl if networkd is in failed state. # Otherwise, networkd may be restarted and we may get wrong results. From bd061abd87987e8233aa8fa91d209d42637df8f8 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 12 Mar 2026 16:48:29 +0900 Subject: [PATCH 2/4] test-network: improve reliability of test case of DHCPRELEASE message --- test/test-network/systemd-networkd-tests.py | 81 ++++++++++++++------- 1 file changed, 54 insertions(+), 27 deletions(-) diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 835f31656e..b1754cd80d 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -7992,6 +7992,44 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): self.teardown_nftset('addr4', 'network4', 'ifindex') + def _test_dhcp_client_send_release_one(self) -> bool: + start_dnsmasq( + namespace='ns-server', + interface='server', + ipv4_range='192.0.2.100,192.0.2.109', + ipv4_router='192.0.2.1', + ) + + start_networkd() + self.wait_online('client:routable') + + print('## ip -4 address show dev client scope global') + output = check_output('ip -4 address show dev client scope global') + print(output) + self.assertRegex(output, r'192.0.2.10[0-9]/24') + + print('## ip -4 route show dev client') + output = check_output('ip -4 route show dev client') + print(output) + self.assertRegex(output, r'default via 192.0.2.1 proto dhcp src 192.0.2.10[0-9]') + self.assertRegex(output, r'192.0.2.0/24 proto kernel scope link src 192.0.2.10[0-9]') + self.assertRegex(output, r'192.0.2.1 proto dhcp scope link src 192.0.2.10[0-9]') + + networkctl('down', 'client') + + success = False + for _ in range(20): + time.sleep(0.5) + output = read_dnsmasq_log_file() + if 'DHCPRELEASE' in output: + success = True + break + + print('## dnsmasq log') + print(output) + + return success + def test_dhcp_client_send_release(self): check_output('ip netns add ns-bridge') check_output('ip netns exec ns-bridge ip link add bridge99 type bridge') @@ -8013,40 +8051,29 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): check_output('ip netns exec ns-server ip link set server up') check_output('ip netns exec ns-server ip address add 192.0.2.1/24 dev server') - start_dnsmasq( - namespace='ns-server', - interface='server', - ipv4_range='192.0.2.100,192.0.2.109', - ipv4_router='192.0.2.1', - ) - copy_network_unit('25-dhcp-client-simple.network') - start_networkd() - self.wait_online('client:routable') - print('## ip -4 address show dev client scope global') - output = check_output('ip -4 address show dev client scope global') - print(output) - self.assertRegex(output, r'192.0.2.10[0-9]/24') + ''' + Sending DHCPRELEASE is best-effort. Even if send() succeeds, the packet may be dropped later in the + networking stack (e.g. due to unresolved neighbor state or interface teardown). Userspace cannot + reliably determine whether the packet was eventually transmitted or dropped. - print('## ip -4 route show dev client') - output = check_output('ip -4 route show dev client') - print(output) - self.assertRegex(output, r'default via 192.0.2.1 proto dhcp src 192.0.2.10[0-9]') - self.assertRegex(output, r'192.0.2.0/24 proto kernel scope link src 192.0.2.10[0-9]') - self.assertRegex(output, r'192.0.2.1 proto dhcp scope link src 192.0.2.10[0-9]') + Hence, the test below may be flaky. In most cases, neighbor resolution completes quickly enough and + the packet is transmitted before the interface is brought down. Running the test multiple times + should make it sufficiently reliable. + ''' - networkctl('down', 'client') + first = True + for _ in range(5): + if not first: + stop_dnsmasq() + stop_networkd(show_logs=False) - print('## dnsmasq log') - for _ in range(20): - time.sleep(0.5) - output = read_dnsmasq_log_file() - if 'DHCPRELEASE' in output: - print(output) + first = False + + if self._test_dhcp_client_send_release_one(): break else: - print(output) self.fail('Timed out waiting for DHCPRELEASE in dnsmasq log') def test_dhcp_client_ipv4_dbus_status(self): From 8e764acf1ea39bd9fa93a061b9e5156e07a79274 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 12 Mar 2026 17:38:37 +0900 Subject: [PATCH 3/4] test-network: also check if DHCPRELEASE is sent on stopping networkd --- test/test-network/systemd-networkd-tests.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index b1754cd80d..8aee898aab 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -7992,7 +7992,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): self.teardown_nftset('addr4', 'network4', 'ifindex') - def _test_dhcp_client_send_release_one(self) -> bool: + def _test_dhcp_client_send_release_one(self, stop=True) -> bool: start_dnsmasq( namespace='ns-server', interface='server', @@ -8015,7 +8015,10 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): self.assertRegex(output, r'192.0.2.0/24 proto kernel scope link src 192.0.2.10[0-9]') self.assertRegex(output, r'192.0.2.1 proto dhcp scope link src 192.0.2.10[0-9]') - networkctl('down', 'client') + if stop: + stop_networkd() + else: + networkctl('down', 'client') success = False for _ in range(20): @@ -8074,7 +8077,16 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): if self._test_dhcp_client_send_release_one(): break else: - self.fail('Timed out waiting for DHCPRELEASE in dnsmasq log') + self.fail('Timed out waiting for DHCPRELEASE in dnsmasq log (on stopping networkd)') + + for _ in range(5): + stop_dnsmasq() + stop_networkd(show_logs=False) + + if self._test_dhcp_client_send_release_one(stop=False): + break + else: + self.fail('Timed out waiting for DHCPRELEASE in dnsmasq log (on bringing down interface)') def test_dhcp_client_ipv4_dbus_status(self): copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-ipv4-only.network') From e799263ff4160565953ac6b52be3706d91133bd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 13 Mar 2026 12:02:07 +0100 Subject: [PATCH 4/4] test-network: handle the case where dnsmasq is slow to start better MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit > read_dnsmasq_log_file() will raise FileNotFoundError if dnsmasq hasn’t created the > log file yet (or if the file was just removed by stop_dnsmasq() before the restart). > This would error the test instead of retrying. Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- test/test-network/systemd-networkd-tests.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 8aee898aab..bab725bd23 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -8023,7 +8023,10 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): success = False for _ in range(20): time.sleep(0.5) - output = read_dnsmasq_log_file() + try: + output = read_dnsmasq_log_file() + except FileNotFoundError: + output = "" if 'DHCPRELEASE' in output: success = True break