From f44b20b7b6c6b0a089a3ec2392ac85e4772e0357 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 27 May 2025 23:17:40 +0900 Subject: [PATCH 1/4] network/link: ENODATA from reading IFLA_MASTER when an interface has no master When an interface leaved from the master interface, then reading IFLA_MASTER attribute causes ENODATA. When the interface was previously enslaved to another interface, we need to remove reference to the interface from the previous master interface. This is especially important when ``` ip link set dev eth0 nomaster ``` is called. Fixes a bug introduced by 0d411b7f8f5407e9ce84dcb4ede0b029ade7fede (v249). Fixes #37629. --- src/network/networkd-link.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 96739b0d0a..ccaaba25d3 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2205,8 +2205,8 @@ static int link_update_master(Link *link, sd_netlink_message *message) { r = sd_netlink_message_read_u32(message, IFLA_MASTER, (uint32_t*) &master_ifindex); if (r == -ENODATA) - return 0; - if (r < 0) + master_ifindex = 0; /* no master interface */ + else if (r < 0) return log_link_debug_errno(link, r, "rtnl: failed to read master ifindex: %m"); if (master_ifindex == link->ifindex) From 7dde00ca57cf20a5d71e580d0bc6173f454095e5 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 28 May 2025 02:09:52 +0900 Subject: [PATCH 2/4] network/link: update state file when master ifindex is changed If master ifindex is non-zero, then the carrier state and operational state of the interface may be the enslaved state. As the operational state is saved in link state file, and read by wait-online, we need to update the state file when the master ifindex is changed. --- src/network/networkd-link.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index ccaaba25d3..65fd8b43e3 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2223,6 +2223,9 @@ static int link_update_master(Link *link, sd_netlink_message *message) { link_drop_from_master(link); link->master_ifindex = master_ifindex; + + /* Updating master ifindex may cause operational state change, e.g. carrier <-> enslaved */ + link_dirty(link); } r = link_append_to_master(link); From b1bed07d84d76f3ab2f11a42fefce2685dbbe685 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 27 May 2025 23:31:48 +0900 Subject: [PATCH 3/4] test-network: add test case for issue #37629 --- test/test-network/systemd-networkd-tests.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 894d43c0c1..541280a3d7 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -5775,6 +5775,21 @@ class NetworkdBondTests(unittest.TestCase, Utilities): print(output) self.assertRegex(output, 'master bond199') + # Test case for #37629 + for _ in range(3): + # When a slave leaved from its master bonding interface, the kernel brings down the slave. + check_output('ip link set dummy98 nomaster') + self.wait_online('dummy98:off') + + # Bring up the interface to check if networkd recognizes the interface has no master now. + check_output('ip link set dummy98 up') + self.wait_online('dummy98:carrier') + + # We need to first bring down the interface to make it join a bonding interface. + check_output('ip link set dummy98 down') + check_output('ip link set dummy98 master bond199') + self.wait_online('dummy98:enslaved') + def test_bond_active_slave(self): copy_network_unit('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev') start_networkd() From ff6f0a58c5437789a6144e3afb8ed838b113d87f Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 27 May 2025 23:42:33 +0900 Subject: [PATCH 4/4] test-network: replace unnecessary assertRegex() with assertIn() This fixes the following warning: ``` /tmp/systemd/test/test-network/systemd-networkd-tests.py:5107: SyntaxWarning: invalid escape sequence '\.' self.assertRegex(output, 'inet 10\.234\.77\.111/32.*dummy98') ``` Follow-up for 6479204e567cd55e1bfc5894131fba80ea68a780. --- test/test-network/systemd-networkd-tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 541280a3d7..3f8c6b1b65 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -5104,11 +5104,11 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): output = check_output('ip -4 addr show dev dummy98') print(output) - self.assertRegex(output, 'inet 10\.234\.77\.111/32.*dummy98') + self.assertIn('inet 10.234.77.111/32', output) output = check_output('ip -6 addr show dev dummy98') print(output) - self.assertRegex(output, 'inet6 2222:3333::4444/64 scope global') + self.assertIn('inet6 2222:3333::4444/64 scope global', output) def check_nexthop(self, manage_foreign_nexthops, first): self.wait_online('veth99:routable', 'veth-peer:routable', 'dummy98:routable')