]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: reconfigure link after coming back from sleep
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 12 Jun 2021 03:01:42 +0000 (12:01 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 10 Aug 2021 05:43:34 +0000 (14:43 +0900)
Previously, link was reconfigured with `link_carrier_reset()`, but it
just re-request to configure static addresses, routes, etc, and restart
engines (e.g. DHCP client).
However, after coming back from sleep, several link information may be
changed, especially the wifi access point may be different. So, we may
need to reconfigure the interface.

src/network/networkd-link.c
src/network/networkd-link.h
src/network/networkd-manager.c

index 17fb932f81ac1d33fb4378fdfd32092306a063a6..2cf84b0f1397bae1bd065979b8a983479eb6d9fb 100644 (file)
@@ -1284,44 +1284,107 @@ static int link_reconfigure_impl(Link *link, bool force) {
         return 1;
 }
 
-static int link_reconfigure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, bool force) {
+static int link_reconfigure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, bool force, bool update_wifi) {
+        bool link_was_lower_up;
         int r;
 
+        assert(link);
+
+        link_was_lower_up = link->flags & IFF_LOWER_UP;
+
         r = link_getlink_handler_internal(rtnl, m, link, "Failed to update link state");
         if (r <= 0)
                 return r;
 
+        if (update_wifi && link_was_lower_up && link->flags & IFF_LOWER_UP) {
+                /* If the interface's L1 was not up, then wifi_get_info() is already called in
+                 * link_update_flags(). So, it is not necessary to re-call here. */
+                r = wifi_get_info(link);
+                if (r < 0) {
+                        link_enter_failed(link);
+                        return 0;
+                }
+        }
+
         r = link_reconfigure_impl(link, force);
-        if (r < 0)
+        if (r < 0) {
                 link_enter_failed(link);
+                return 0;
+        }
 
-        return 0;
+        return r;
 }
 
 static int link_reconfigure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
-        return link_reconfigure_handler_internal(rtnl, m, link, false);
+        return link_reconfigure_handler_internal(rtnl, m, link, /* force = */ false, /* update_wifi = */ false);
 }
 
 static int link_force_reconfigure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
-        return link_reconfigure_handler_internal(rtnl, m, link, true);
+        return link_reconfigure_handler_internal(rtnl, m, link, /* force = */ true, /* update_wifi = */ false);
 }
 
-int link_reconfigure(Link *link, bool force) {
+static int link_reconfigure_after_sleep_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
+        assert(link);
+
+        r = link_reconfigure_handler_internal(rtnl, m, link, /* force = */ false, /* update_wifi = */ true);
+        if (r != 0)
+                return r;
+
+        /* r == 0 means an error occurs, the link is unmanaged, or the matching network file is unchanged. */
+        if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
+                return 0;
+
+        /* re-request static configs, and restart engines. */
+        r = link_stop_engines(link, false);
+        if (r < 0) {
+                link_enter_failed(link);
+                return 0;
+        }
+
+        r = link_acquire_dynamic_conf(link);
+        if (r < 0) {
+                link_enter_failed(link);
+                return 0;
+        }
+
+        r = link_request_static_configs(link);
+        if (r < 0) {
+                link_enter_failed(link);
+                return 0;
+        }
+
+        return 0;
+}
+
+static int link_reconfigure_internal(Link *link, link_netlink_message_handler_t callback) {
+        int r;
+
+        assert(link);
+        assert(callback);
+
         /* When link in pending or initialized state, then link_configure() will be called. To prevent
          * the function from being called multiple times simultaneously, refuse to reconfigure the
          * interface in these cases. */
         if (IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_INITIALIZED, LINK_STATE_LINGER))
                 return 0; /* 0 means no-op. */
 
-        r = link_call_getlink(link, force ? link_force_reconfigure_handler : link_reconfigure_handler);
+        r = link_call_getlink(link, callback);
         if (r < 0)
                 return r;
 
         return 1; /* 1 means the interface will be reconfigured. */
 }
 
+int link_reconfigure(Link *link, bool force) {
+        return link_reconfigure_internal(link, force ? link_force_reconfigure_handler : link_reconfigure_handler);
+}
+
+int link_reconfigure_after_sleep(Link *link) {
+        return link_reconfigure_internal(link, link_reconfigure_after_sleep_handler);
+}
+
 static int link_initialized_and_synced(Link *link) {
         Network *network;
         int r;
@@ -1570,26 +1633,6 @@ static int link_carrier_lost(Link *link) {
         return 0;
 }
 
-int link_carrier_reset(Link *link) {
-        int r;
-
-        assert(link);
-
-        if (!link_has_carrier(link))
-                return 0;
-
-        r = link_carrier_lost(link);
-        if (r < 0)
-                return r;
-
-        r = link_carrier_gained(link);
-        if (r < 0)
-                return r;
-
-        log_link_info(link, "Reset carrier");
-        return 0;
-}
-
 static int link_admin_state_up(Link *link) {
         int r;
 
index 4077ccaf09c5b99ba32b702834052873d826a128..79400dee2e9c1b22d30435bca75536ee2c82fc5a 100644 (file)
@@ -232,7 +232,6 @@ void link_check_ready(Link *link);
 
 void link_update_operstate(Link *link, bool also_update_bond_master);
 
-int link_carrier_reset(Link *link);
 bool link_has_carrier(Link *link);
 
 bool link_ipv6_enabled(Link *link);
@@ -247,6 +246,7 @@ const char* link_state_to_string(LinkState s) _const_;
 LinkState link_state_from_string(const char *s) _pure_;
 
 int link_reconfigure(Link *link, bool force);
+int link_reconfigure_after_sleep(Link *link);
 
 int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, void *userdata);
 int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
index 374d27bef34cd2654ce025a5a087eca1658cdf41..82aecf1c76b25cd097f7445a6fee4f036503049b 100644 (file)
@@ -59,9 +59,9 @@ static int manager_reset_all(Manager *m) {
         assert(m);
 
         HASHMAP_FOREACH(link, m->links_by_index) {
-                r = link_carrier_reset(link);
+                r = link_reconfigure_after_sleep(link);
                 if (r < 0) {
-                        log_link_warning_errno(link, r, "Could not reset carrier: %m");
+                        log_link_warning_errno(link, r, "Failed to reconfigure interface: %m");
                         link_enter_failed(link);
                 }
         }