diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 96739b0d0a..65fd8b43e3 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) @@ -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); diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 894d43c0c1..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') @@ -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()