From: Yu Watanabe Date: Thu, 28 Jul 2022 06:11:46 +0000 (+0900) Subject: network: also check SR-IOV PF port and other VF ports before configuring X-Git-Tag: v252-rc1~505^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F23340%2Fhead;p=thirdparty%2Fsystemd.git network: also check SR-IOV PF port and other VF ports before configuring 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. --- diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c index 7882cbc3645..e9fadfddde8 100644 --- a/src/network/netdev/netdev.c +++ b/src/network/netdev/netdev.c @@ -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); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index dc897085d28..20eb43eb094 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -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); } diff --git a/src/network/networkd-setlink.c b/src/network/networkd-setlink.c index 29e1192a836..4c0d3d23c3d 100644 --- a/src/network/networkd-setlink.c +++ b/src/network/networkd-setlink.c @@ -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; diff --git a/src/network/networkd-sriov.c b/src/network/networkd-sriov.c index 5a4d3b5014e..3d44c8fc82c 100644 --- a/src/network/networkd-sriov.c +++ b/src/network/networkd-sriov.c @@ -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; +} diff --git a/src/network/networkd-sriov.h b/src/network/networkd-sriov.h index 988b086c79b..0d4276e0993 100644 --- a/src/network/networkd-sriov.h +++ b/src/network/networkd-sriov.h @@ -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));