]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
wait-online: exit with success when all interfaces are ready or unmanaged
authorYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 22 Dec 2022 00:40:37 +0000 (09:40 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 22 Dec 2022 00:40:46 +0000 (09:40 +0900)
Previously, when neither '--any' nor '--interface' options specified,
at least one of the interfaces must be in configured state.
This patch makes wait-online exit with success even if all interfaces
are in unmanaged state.

This may break backward compatibility in a rare situation. But in most
cases, this typically not change anything, as at least one interface
is managed by networkd.service when it is enabled.

This is mostly for making wait-online gracefully handle the case that
networkd.service and wait-online.service are enabled by mistake. In such
situation, all interfaces are typically not managed.

Fixes #25813.

src/network/wait-online/manager.c

index 43ac10704b7df030bab24b9c747a1cde17c48caa..f481149d81288c6aa3121e6d5dec2e57aff7006c 100644 (file)
@@ -61,9 +61,11 @@ static int manager_link_is_online(Manager *m, Link *l, LinkOperationalStateRange
         assert(l);
 
         /* This returns the following:
-         * -EAGAIN: not processed by udev or networkd
-         *       0: operstate is not enough
-         *       1: online */
+         * -EAGAIN       : not processed by udev
+         * -EBUSY        : being processed by networkd
+         * -EADDRNOTAVAIL: requested conditions (operstate and/or addresses) are not satisfied
+         * false         : unmanaged
+         * true          : online */
 
         if (!l->state || streq(l->state, "pending"))
                 /* If no state string exists, networkd (and possibly also udevd) has not detected the
@@ -79,13 +81,13 @@ static int manager_link_is_online(Manager *m, Link *l, LinkOperationalStateRange
                 /* If the link is in unmanaged state, then ignore the interface unless the interface is
                  * specified in '--interface/-i' option. */
                 if (!link_in_command_line_interfaces(l, m)) {
-                        log_link_debug(l, "link is not managed by networkd (yet?).");
-                        return 0;
+                        log_link_debug(l, "link is not managed by networkd.");
+                        return false;
                 }
 
         } else if (!streq(l->state, "configured"))
                 /* If the link is in non-configured state, return negative value here. */
-                return log_link_debug_errno(l, SYNTHETIC_ERRNO(EAGAIN),
+                return log_link_debug_errno(l, SYNTHETIC_ERRNO(EBUSY),
                                             "link is being processed by networkd: setup state is %s.",
                                             l->state);
 
@@ -97,84 +99,75 @@ static int manager_link_is_online(Manager *m, Link *l, LinkOperationalStateRange
                 s.max = m->required_operstate.max >= 0 ? m->required_operstate.max
                                                        : l->required_operstate.max;
 
-        if (l->operational_state < s.min || l->operational_state > s.max) {
-                log_link_debug(l, "Operational state '%s' is not in range ['%s':'%s']",
-                               link_operstate_to_string(l->operational_state),
-                               link_operstate_to_string(s.min), link_operstate_to_string(s.max));
-                return 0;
-        }
+        if (l->operational_state < s.min || l->operational_state > s.max)
+                return log_link_debug_errno(l, SYNTHETIC_ERRNO(EADDRNOTAVAIL),
+                                            "Operational state '%s' is not in range ['%s':'%s']",
+                                            link_operstate_to_string(l->operational_state),
+                                            link_operstate_to_string(s.min), link_operstate_to_string(s.max));
 
         required_family = m->required_family > 0 ? m->required_family : l->required_family;
         needs_ipv4 = required_family & ADDRESS_FAMILY_IPV4;
         needs_ipv6 = required_family & ADDRESS_FAMILY_IPV6;
 
         if (s.min < LINK_OPERSTATE_ROUTABLE) {
-                if (needs_ipv4 && l->ipv4_address_state < LINK_ADDRESS_STATE_DEGRADED) {
-                        log_link_debug(l, "No routable or link-local IPv4 address is configured.");
-                        return 0;
-                }
+                if (needs_ipv4 && l->ipv4_address_state < LINK_ADDRESS_STATE_DEGRADED)
+                        return log_link_debug_errno(l, SYNTHETIC_ERRNO(EADDRNOTAVAIL),
+                                                    "No routable or link-local IPv4 address is configured.");
 
-                if (needs_ipv6 && l->ipv6_address_state < LINK_ADDRESS_STATE_DEGRADED) {
-                        log_link_debug(l, "No routable or link-local IPv6 address is configured.");
-                        return 0;
-                }
+                if (needs_ipv6 && l->ipv6_address_state < LINK_ADDRESS_STATE_DEGRADED)
+                        return log_link_debug_errno(l, SYNTHETIC_ERRNO(EADDRNOTAVAIL),
+                                                    "No routable or link-local IPv6 address is configured.");
         } else {
-                if (needs_ipv4 && l->ipv4_address_state < LINK_ADDRESS_STATE_ROUTABLE) {
-                        log_link_debug(l, "No routable IPv4 address is configured.");
-                        return 0;
-                }
+                if (needs_ipv4 && l->ipv4_address_state < LINK_ADDRESS_STATE_ROUTABLE)
+                        return log_link_debug_errno(l, SYNTHETIC_ERRNO(EADDRNOTAVAIL),
+                                                    "No routable IPv4 address is configured.");
 
-                if (needs_ipv6 && l->ipv6_address_state < LINK_ADDRESS_STATE_ROUTABLE) {
-                        log_link_debug(l, "No routable IPv6 address is configured.");
-                        return 0;
-                }
+                if (needs_ipv6 && l->ipv6_address_state < LINK_ADDRESS_STATE_ROUTABLE)
+                        return log_link_debug_errno(l, SYNTHETIC_ERRNO(EADDRNOTAVAIL),
+                                                    "No routable IPv6 address is configured.");
         }
 
         log_link_debug(l, "link is configured by networkd and online.");
-        return 1;
+        return true;
 }
 
 bool manager_configured(Manager *m) {
-        bool one_ready = false;
-        const char *ifname;
         Link *l;
         int r;
 
         if (!hashmap_isempty(m->command_line_interfaces_by_name)) {
                 LinkOperationalStateRange *range;
+                const char *ifname;
 
                 /* wait for all the links given on the command line to appear */
                 HASHMAP_FOREACH_KEY(range, ifname, m->command_line_interfaces_by_name) {
 
                         l = hashmap_get(m->links_by_name, ifname);
-                        if (!l && range->min == LINK_OPERSTATE_MISSING) {
-                                one_ready = true;
-                                continue;
-                        }
-
                         if (!l) {
-                                log_debug("still waiting for %s", ifname);
-                                if (!m->any)
-                                        return false;
+                                if (range->min == LINK_OPERSTATE_MISSING) {
+                                        if (m->any)
+                                                return true;
+                                } else {
+                                        log_debug("still waiting for %s", ifname);
+                                        if (!m->any)
+                                                return false;
+                                }
                                 continue;
                         }
 
-                        if (manager_link_is_online(m, l, *range) <= 0) {
-                                if (!m->any)
-                                        return false;
-                                continue;
-                        }
-
-                        one_ready = true;
+                        r = manager_link_is_online(m, l, *range);
+                        if (r <= 0 && !m->any)
+                                return false;
+                        if (r > 0 && m->any)
+                                return true;
                 }
 
-                /* all interfaces given by the command line are online, or
-                 * one of the specified interfaces is online. */
-                return one_ready;
+                /* With '--any'   : no interface is ready
+                 * Without '--any': all interfaces are ready */
+                return !m->any;
         }
 
-        /* wait for all links networkd manages to be in admin state 'configured'
-         * and at least one link to gain a carrier */
+        /* wait for all links networkd manages */
         HASHMAP_FOREACH(l, m->links_by_index) {
                 if (manager_ignore_link(m, l)) {
                         log_link_debug(l, "link is ignored");
@@ -184,15 +177,15 @@ bool manager_configured(Manager *m) {
                 r = manager_link_is_online(m, l,
                                            (LinkOperationalStateRange) { _LINK_OPERSTATE_INVALID,
                                                                          _LINK_OPERSTATE_INVALID });
-                if (r < 0 && !m->any)
+                if (r < 0 && !m->any) /* Unlike the above loop, unmanaged interfaces are ignored here. */
                         return false;
-                if (r > 0)
-                        /* we wait for at least one link to be ready,
-                         * regardless of who manages it */
-                        one_ready = true;
+                if (r > 0 && m->any)
+                        return true;
         }
 
-        return one_ready;
+        /* With '--any'   : no interface is ready
+         * Without '--any': all interfaces are ready or unmanaged */
+        return !m->any;
 }
 
 static int manager_process_link(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {