network: register already enslaved interfaces when their master appears (#43557)

When networkd starts or restarts, links are enumerated in ifindex
order. A slave enumerated before its master cannot register itself in
link_append_to_master(), as the master Link object does not exist yet.
The master then wrongly believes it has no slaves until the next
RTM_NEWLINK message for the slave arrives.

The stale slaves set affects operational state propagation
(degraded-carrier detection) and any code that inspects the slaves of
a master.
For instance, on restart, when networkd thinks that the master has no
slaves yet, we try to set the bond fail-over policy, which the kernel
then refuses because in reality the bond does have slaves.

To fix the issue, this updates the list of slaves after enumeration.

Co-authored-by: Yu Watanabe <watanabe.yu+github@gmail.com>
This commit is contained in:
Ramses
2026-09-01 18:28:43 +09:00
committed by GitHub
co-authored by Yu Watanabe
parent f396adf4e9
commit 3da5c65d87
6 changed files with 47 additions and 2 deletions
+1 -1
View File
@@ -1035,7 +1035,7 @@ static void link_free_bound_by_list(Link *link) {
link_dirty(link);
}
static int link_append_to_master(Link *link) {
int link_append_to_master(Link *link) {
Link *master;
int r;
+1
View File
@@ -222,6 +222,7 @@ int link_get_master(Link *link, Link **ret);
int link_getlink_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg);
int link_call_getlink(Link *link, link_netlink_message_handler_t callback);
int link_handle_bound_to_list(Link *link);
int link_append_to_master(Link *link);
void link_enter_failed(Link *link);
void link_set_state(Link *link, LinkState state);
+12 -1
View File
@@ -939,7 +939,18 @@ static int manager_enumerate_links(Manager *m) {
if (r < 0)
return r;
return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_link);
r = manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_link);
if (r < 0)
return r;
/* Slave interfaces enumerated before the master could not register themselves, as the master Link
* object did not exist yet at that time. Register them now, so that the slaves set correctly
* reflects the kernel state. */
Link *link;
HASHMAP_FOREACH(link, m->links_by_index)
RET_GATHER(r, link_append_to_master(link));
return r;
}
static int manager_enumerate_qdisc(Manager *m) {