]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: recreate stacked netdevs when underlying device is re-added
authorYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 12 Aug 2021 05:31:27 +0000 (14:31 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 12 Aug 2021 06:03:47 +0000 (15:03 +0900)
Closes #20430.

src/network/netdev/netdev.c

index 9b4291be0a5f46947703551bb940b14acd2aca8b..426be8c7fc7aae67da374666752a2cbad01f327f 100644 (file)
@@ -203,6 +203,18 @@ static bool netdev_is_stacked_and_independent(NetDev *netdev) {
         }
 }
 
+static bool netdev_is_stacked(NetDev *netdev) {
+        assert(netdev);
+
+        if (!IN_SET(netdev_get_create_type(netdev), NETDEV_CREATE_STACKED, NETDEV_CREATE_AFTER_CONFIGURED))
+                return false;
+
+        if (netdev_is_stacked_and_independent(netdev))
+                return false;
+
+        return true;
+}
+
 static void netdev_detach_from_manager(NetDev *netdev) {
         if (netdev->ifname && netdev->manager)
                 hashmap_remove(netdev->manager->netdevs, netdev->ifname);
@@ -238,8 +250,18 @@ static NetDev *netdev_free(NetDev *netdev) {
 DEFINE_TRIVIAL_REF_UNREF_FUNC(NetDev, netdev, netdev_free);
 
 void netdev_drop(NetDev *netdev) {
-        if (!netdev || netdev->state == NETDEV_STATE_LINGER)
+        if (!netdev)
+                return;
+
+        if (netdev_is_stacked(netdev)) {
+                /* The netdev may be removed due to the underlying device removal, and the device may
+                 * be re-added later. */
+                netdev->state = NETDEV_STATE_LOADING;
+                netdev->ifindex = 0;
+
+                log_netdev_debug(netdev, "netdev removed");
                 return;
+        }
 
         netdev->state = NETDEV_STATE_LINGER;
 
@@ -668,21 +690,18 @@ static int link_create_stacked_netdev_after_configured_handler(sd_netlink *rtnl,
 }
 
 int link_request_stacked_netdev(Link *link, NetDev *netdev) {
-        NetDevCreateType create_type;
         int r;
 
         assert(link);
         assert(netdev);
 
-        create_type = netdev_get_create_type(netdev);
-        if (!IN_SET(create_type, NETDEV_CREATE_STACKED, NETDEV_CREATE_AFTER_CONFIGURED))
+        if (!netdev_is_stacked(netdev))
                 return -EINVAL;
 
-        if (netdev->state != NETDEV_STATE_LOADING || netdev->ifindex > 0)
-                /* Already created (or removed?) */
-                return 0;
+        if (!IN_SET(netdev->state, NETDEV_STATE_LOADING, NETDEV_STATE_FAILED) || netdev->ifindex > 0)
+                return 0; /* Already created. */
 
-        if (create_type == NETDEV_CREATE_STACKED) {
+        if (netdev_get_create_type(netdev) == NETDEV_CREATE_STACKED) {
                 link->stacked_netdevs_created = false;
                 r = link_queue_request(link, REQUEST_TYPE_STACKED_NETDEV, netdev, false,
                                        &link->create_stacked_netdev_messages,