]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: also check SR-IOV PF port and other VF ports before configuring 23340/head
authorYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 28 Jul 2022 06:11:46 +0000 (15:11 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 5 Aug 2022 12:49:27 +0000 (21:49 +0900)
When a PF port becomes down (this can happens e.g. the PF port is joining
a bond interface), some drivers make its VF ports also become down, and
may cause failures in configuring VF ports.

Similary, when a VF port become down, some drivers make its PF port and
other VF ports down.

Let's configure SR-IOV ports (both PF and VFs) after all link-layer
settings of all ports being applied.

Fixes #23315.

src/network/netdev/netdev.c
src/network/networkd-link.c
src/network/networkd-setlink.c
src/network/networkd-sriov.c
src/network/networkd-sriov.h

index 7882cbc3645539dd9172d51b08147e14b8d2aa67..e9fadfddde8e8fa81e020c9a6dc0f23fe2434bf4 100644 (file)
@@ -31,6 +31,7 @@
 #include "networkd-manager.h"
 #include "networkd-queue.h"
 #include "networkd-setlink.h"
+#include "networkd-sriov.h"
 #include "nlmon.h"
 #include "path-lookup.h"
 #include "siphash24.h"
@@ -604,12 +605,15 @@ static int stacked_netdev_create(NetDev *netdev, Link *link, Request *req) {
         return 0;
 }
 
-static bool link_is_ready_to_create_stacked_netdev(Link *link) {
+static bool link_is_ready_to_create_stacked_netdev_one(Link *link, bool allow_unmanaged) {
         assert(link);
 
-        if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
+        if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED, LINK_STATE_UNMANAGED))
                 return false;
 
+        if (!link->network)
+                return allow_unmanaged;
+
         if (link->set_link_messages > 0)
                 return false;
 
@@ -621,6 +625,11 @@ static bool link_is_ready_to_create_stacked_netdev(Link *link) {
         return true;
 }
 
+static bool link_is_ready_to_create_stacked_netdev(Link *link) {
+        return check_ready_for_all_sr_iov_ports(link, /* allow_unmanaged = */ false,
+                                                link_is_ready_to_create_stacked_netdev_one);
+}
+
 static int netdev_is_ready_to_create(NetDev *netdev, Link *link) {
         assert(netdev);
 
index dc897085d28ef9c3130e7a2557d68e919906b821..20eb43eb0949c35a83b46828f7d68d16d192d80b 100644 (file)
@@ -92,7 +92,7 @@ bool link_ipv6_enabled(Link *link) {
         return false;
 }
 
-bool link_is_ready_to_configure(Link *link, bool allow_unmanaged) {
+static bool link_is_ready_to_configure_one(Link *link, bool allow_unmanaged) {
         assert(link);
 
         if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED, LINK_STATE_UNMANAGED))
@@ -118,6 +118,10 @@ bool link_is_ready_to_configure(Link *link, bool allow_unmanaged) {
         return true;
 }
 
+bool link_is_ready_to_configure(Link *link, bool allow_unmanaged) {
+        return check_ready_for_all_sr_iov_ports(link, allow_unmanaged, link_is_ready_to_configure_one);
+}
+
 void link_ntp_settings_clear(Link *link) {
         link->ntp = strv_free(link->ntp);
 }
index 29e1192a83606d81ada7cbbaaff333f6b2c6eb78..4c0d3d23c3dae4f6a4c294d2c48637848cf0c825 100644 (file)
@@ -14,6 +14,7 @@
 #include "networkd-manager.h"
 #include "networkd-queue.h"
 #include "networkd-setlink.h"
+#include "networkd-sriov.h"
 #include "networkd-wiphy.h"
 
 static int get_link_default_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
@@ -1007,15 +1008,28 @@ static int link_up_or_down(Link *link, bool up, Request *req) {
         return request_call_netlink_async(link->manager->rtnl, m, req);
 }
 
-static bool link_is_ready_to_activate(Link *link, bool up) {
+static bool link_is_ready_to_activate_one(Link *link, bool allow_unmanaged) {
         assert(link);
 
-        if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
+        if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED, LINK_STATE_UNMANAGED))
                 return false;
 
+        if (!link->network)
+                return allow_unmanaged;
+
         if (link->set_link_messages > 0)
                 return false;
 
+        return true;
+}
+
+ static bool link_is_ready_to_activate(Link *link, bool up) {
+        assert(link);
+
+        if (!check_ready_for_all_sr_iov_ports(link, /* allow_unmanaged = */ false,
+                                              link_is_ready_to_activate_one))
+                return false;
+
         if (up && link_rfkilled(link) > 0)
                 return false;
 
index 5a4d3b5014eb43ccb0b1ea54235bda6d5e446d61..3d44c8fc82c9bd7787da6ef5c01897adb05b3667 100644 (file)
@@ -319,3 +319,49 @@ void link_clear_sr_iov_ifindices(Link *link) {
                         virt_link->sr_iov_phys_port_ifindex = 0;
         }
 }
+
+bool check_ready_for_all_sr_iov_ports(
+                Link *link,
+                bool allow_unmanaged, /* for the main target */
+                bool (check_one)(Link *link, bool allow_unmanaged)) {
+
+        Link *phys_link;
+        void *v;
+
+        assert(link);
+        assert(link->manager);
+        assert(check_one);
+
+        /* Some drivers make VF ports become down when their PF port becomes down, and may fail to configure
+         * VF ports. Also, when a VF port becomes up/down, its PF port and other VF ports may become down.
+         * See issue #23315. */
+
+        /* First, check the main target. */
+        if (!check_one(link, allow_unmanaged))
+                return false;
+
+        /* If this is a VF port, then also check the PF port. */
+        if (link->sr_iov_phys_port_ifindex > 0) {
+                if (link_get_by_index(link->manager, link->sr_iov_phys_port_ifindex, &phys_link) < 0 ||
+                    !check_one(phys_link, /* allow_unmanaged = */ true))
+                        return false;
+        } else
+                phys_link = link;
+
+        /* Also check all VF ports. */
+        SET_FOREACH(v, phys_link->sr_iov_virt_port_ifindices) {
+                int ifindex = PTR_TO_INT(v);
+                Link *virt_link;
+
+                if (ifindex == link->ifindex)
+                        continue; /* The main target link is a VF port, and its state is already checked. */
+
+                if (link_get_by_index(link->manager, ifindex, &virt_link) < 0)
+                        return false;
+
+                if (!check_one(virt_link, /* allow_unmanaged = */ true))
+                        return false;
+        }
+
+        return true;
+}
index 988b086c79bb2904832047b564eca1aeebe782af..0d4276e099359756aaa81636fe6df80162a41ba7 100644 (file)
@@ -10,3 +10,8 @@ int link_request_sr_iov_vfs(Link *link);
 
 int link_set_sr_iov_ifindices(Link *link);
 void link_clear_sr_iov_ifindices(Link *link);
+
+bool check_ready_for_all_sr_iov_ports(
+                Link *link,
+                bool allow_unmanaged, /* for the main target */
+                bool (check_one)(Link *link, bool allow_unmanaged));