summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2022-08-05 20:18:30 +0200
committerGitHub <noreply@github.com>2022-08-05 20:18:30 +0200
commit1ab7e2b58719ffa36054483c826b9f5e53206e54 (patch)
tree02e3c2e416d6911e4da42d70c04202fd44c75531 /src
parentMerge pull request #23508 from yuwata/core-device (diff)
parentnetwork: also check SR-IOV PF port and other VF ports before configuring (diff)
downloadsystemd-1ab7e2b58719ffa36054483c826b9f5e53206e54.tar.xz
systemd-1ab7e2b58719ffa36054483c826b9f5e53206e54.zip
Merge pull request #23340 from yuwata/network-check-sr-iov-pf-state
network: check SR-IOV PF state
Diffstat (limited to 'src')
-rw-r--r--src/libsystemd/libsystemd.sym2
-rw-r--r--src/libsystemd/sd-device/sd-device.c23
-rw-r--r--src/network/netdev/l2tp-tunnel.c4
-rw-r--r--src/network/netdev/netdev-util.c2
-rw-r--r--src/network/netdev/netdev.c40
-rw-r--r--src/network/networkd-dhcp-server.c8
-rw-r--r--src/network/networkd-dhcp4.c2
-rw-r--r--src/network/networkd-dhcp6.c2
-rw-r--r--src/network/networkd-link.c27
-rw-r--r--src/network/networkd-link.h3
-rw-r--r--src/network/networkd-ndisc.c2
-rw-r--r--src/network/networkd-radv.c2
-rw-r--r--src/network/networkd-route.c3
-rw-r--r--src/network/networkd-setlink.c36
-rw-r--r--src/network/networkd-sriov.c262
-rw-r--r--src/network/networkd-sriov.h8
-rw-r--r--src/network/networkd-wiphy.c47
-rw-r--r--src/systemd/sd-device.h2
-rw-r--r--src/udev/udev-builtin-net_id.c19
19 files changed, 416 insertions, 78 deletions
diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym
index fb6e6f6431..5c5446e987 100644
--- a/src/libsystemd/libsystemd.sym
+++ b/src/libsystemd/libsystemd.sym
@@ -784,6 +784,8 @@ global:
sd_bus_message_read_strv_extend;
sd_bus_error_setfv;
+ sd_device_new_child;
+
sd_id128_string_equal;
sd_hwdb_new_from_path;
diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c
index 3e31beb1f2..1050234afe 100644
--- a/src/libsystemd/sd-device/sd-device.c
+++ b/src/libsystemd/sd-device/sd-device.c
@@ -861,6 +861,29 @@ _public_ int sd_device_get_syspath(sd_device *device, const char **ret) {
return 0;
}
+_public_ int sd_device_new_child(sd_device **ret, sd_device *device, const char *suffix) {
+ _cleanup_free_ char *path = NULL;
+ const char *s;
+ int r;
+
+ assert_return(ret, -EINVAL);
+ assert_return(device, -EINVAL);
+ assert_return(suffix, -EINVAL);
+
+ if (!path_is_normalized(suffix))
+ return -EINVAL;
+
+ r = sd_device_get_syspath(device, &s);
+ if (r < 0)
+ return r;
+
+ path = path_join(s, suffix);
+ if (!path)
+ return -ENOMEM;
+
+ return sd_device_new_from_syspath(ret, path);
+}
+
static int device_new_from_child(sd_device **ret, sd_device *child) {
_cleanup_free_ char *path = NULL;
const char *syspath;
diff --git a/src/network/netdev/l2tp-tunnel.c b/src/network/netdev/l2tp-tunnel.c
index c38b9dc312..7e7d167928 100644
--- a/src/network/netdev/l2tp-tunnel.c
+++ b/src/network/netdev/l2tp-tunnel.c
@@ -292,7 +292,7 @@ static int l2tp_get_local_address(NetDev *netdev, union in_addr_union *ret) {
if (r < 0)
return r;
- if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
+ if (!link_is_ready_to_configure(link, /* allow_unmanaged = */ false))
return -EBUSY;
}
@@ -346,7 +346,7 @@ static int l2tp_get_local_address(NetDev *netdev, union in_addr_union *ret) {
return link_get_l2tp_local_address(link, t, ret);
HASHMAP_FOREACH(link, netdev->manager->links_by_index) {
- if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
+ if (!link_is_ready_to_configure(link, /* allow_unmanaged = */ false))
continue;
if (link_get_l2tp_local_address(link, t, ret) >= 0)
diff --git a/src/network/netdev/netdev-util.c b/src/network/netdev/netdev-util.c
index 06028855a8..23506246ce 100644
--- a/src/network/netdev/netdev-util.c
+++ b/src/network/netdev/netdev-util.c
@@ -51,7 +51,7 @@ int link_get_local_address(
assert_not_reached();
}
- if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
+ if (!link_is_ready_to_configure(link, /* allow_unmanaged = */ false))
return -EBUSY;
SET_FOREACH(a, link->addresses) {
diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c
index f015168692..e9fadfddde 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,24 +605,39 @@ static int stacked_netdev_create(NetDev *netdev, Link *link, Request *req) {
return 0;
}
+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, LINK_STATE_UNMANAGED))
+ return false;
+
+ if (!link->network)
+ return allow_unmanaged;
+
+ if (link->set_link_messages > 0)
+ return false;
+
+ /* If stacked netdevs are created before the underlying interface being activated, then
+ * the activation policy for the netdevs are ignored. See issue #22593. */
+ if (!link->activated)
+ return false;
+
+ 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);
if (netdev->state != NETDEV_STATE_LOADING)
return false;
- if (link) {
- if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
- return false;
-
- if (link->set_link_messages > 0)
- return false;
-
- /* If stacked netdevs are created before the underlying interface being activated, then
- * the activation policy for the netdevs are ignored. See issue #22593. */
- if (!link->activated)
- return false;
- }
+ if (link && !link_is_ready_to_create_stacked_netdev(link))
+ return false;
if (NETDEV_VTABLE(netdev)->is_ready_to_create)
return NETDEV_VTABLE(netdev)->is_ready_to_create(netdev, link);
diff --git a/src/network/networkd-dhcp-server.c b/src/network/networkd-dhcp-server.c
index 5861ecb922..076779dc0e 100644
--- a/src/network/networkd-dhcp-server.c
+++ b/src/network/networkd-dhcp-server.c
@@ -539,13 +539,7 @@ static bool dhcp_server_is_ready_to_configure(Link *link) {
assert(link);
- if (!link->network)
- return false;
-
- if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
- return false;
-
- if (link->set_flags_messages > 0)
+ if (!link_is_ready_to_configure(link, /* allow_unmanaged = */ false))
return false;
if (!link_has_carrier(link))
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index c6cbadc08b..3795fb32f3 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -1557,7 +1557,7 @@ static int dhcp4_process_request(Request *req, Link *link, void *userdata) {
assert(link);
- if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
+ if (!link_is_ready_to_configure(link, /* allow_unmanaged = */ false))
return 0;
r = dhcp4_configure_duid(link);
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index 7f9f4e12b9..4293eb6242 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -741,7 +741,7 @@ static int dhcp6_process_request(Request *req, Link *link, void *userdata) {
assert(link);
- if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
+ if (!link_is_ready_to_configure(link, /* allow_unmanaged = */ false))
return 0;
r = dhcp_configure_duid(link, link_get_dhcp6_duid(link));
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 76e0690aef..20eb43eb09 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -92,19 +92,15 @@ 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 (!link->network) {
- if (!allow_unmanaged)
- return false;
-
- return link_has_carrier(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->network->configure_without_carrier) {
if (link->set_flags_messages > 0)
return false;
@@ -122,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);
}
@@ -183,6 +183,7 @@ static Link *link_free(Link *link) {
link_free_engines(link);
+ set_free(link->sr_iov_virt_port_ifindices);
free(link->ifname);
strv_free(link->alternative_names);
free(link->kind);
@@ -894,6 +895,8 @@ static Link *link_drop(Link *link) {
link_free_bound_to_list(link);
link_free_bound_by_list(link);
+ link_clear_sr_iov_ifindices(link);
+
link_drop_from_master(link);
if (link->state_file)
@@ -1393,6 +1396,8 @@ static int link_initialized_handler(sd_netlink *rtnl, sd_netlink_message *m, Lin
}
static int link_initialized(Link *link, sd_device *device) {
+ int r;
+
assert(link);
assert(device);
@@ -1400,6 +1405,10 @@ static int link_initialized(Link *link, sd_device *device) {
* or sysattrs) may be outdated. */
device_unref_and_replace(link->dev, device);
+ r = link_set_sr_iov_ifindices(link);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Failed to manage SR-IOV PF and VF ports, ignoring: %m");
+
/* Do not ignore unamanaged state case here. If an interface is renamed after being once
* configured, and the corresponding .network file has Name= in [Match] section, then the
* interface may be already in unmanaged state. See #20657. */
diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
index 807fb44709..362f439940 100644
--- a/src/network/networkd-link.h
+++ b/src/network/networkd-link.h
@@ -52,6 +52,9 @@ typedef struct Link {
int ifindex;
int master_ifindex;
int dsa_master_ifindex;
+ int sr_iov_phys_port_ifindex;
+ Set *sr_iov_virt_port_ifindices;
+
char *ifname;
char **alternative_names;
char *kind;
diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c
index dfbb7043bf..579282136f 100644
--- a/src/network/networkd-ndisc.c
+++ b/src/network/networkd-ndisc.c
@@ -1099,7 +1099,7 @@ static int ndisc_process_request(Request *req, Link *link, void *userdata) {
assert(link);
- if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
+ if (!link_is_ready_to_configure(link, /* allow_unmanaged = */ false))
return 0;
r = ndisc_configure(link);
diff --git a/src/network/networkd-radv.c b/src/network/networkd-radv.c
index c59ae82694..a0ce162532 100644
--- a/src/network/networkd-radv.c
+++ b/src/network/networkd-radv.c
@@ -549,7 +549,7 @@ static int radv_is_ready_to_configure(Link *link) {
assert(link);
assert(link->network);
- if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
+ if (!link_is_ready_to_configure(link, /* allow_unmanaged = */ false))
return false;
if (in6_addr_is_null(&link->ipv6ll_address))
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c
index 921b031b29..71e578d898 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -1298,7 +1298,8 @@ static int route_is_ready_to_configure(const Route *route, Link *link) {
if (r < 0)
return false;
if (r > 0) {
- if (!link_is_ready_to_configure(l, true))
+ if (!link_is_ready_to_configure(l, /* allow_unmanaged = */ true) ||
+ !link_has_carrier(l))
return false;
m->ifindex = l->ifindex;
diff --git a/src/network/networkd-setlink.c b/src/network/networkd-setlink.c
index e2b5acc086..4c0d3d23c3 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) {
@@ -797,20 +798,28 @@ int link_request_to_set_master(Link *link) {
assert(link->network);
if (link->network->keep_master) {
+ /* When KeepMaster=yes, BatmanAdvanced=, Bond=, Bridge=, and VRF= are ignored. */
link->master_set = true;
return 0;
- }
-
- link->master_set = false;
- if (link->network->batadv || link->network->bond || link->network->bridge || link->network->vrf)
+ } else if (link->network->batadv || link->network->bond || link->network->bridge || link->network->vrf) {
+ link->master_set = false;
return link_request_set_link(link, REQUEST_TYPE_SET_LINK_MASTER,
link_set_master_handler,
NULL);
- else
+
+ } else if (link->master_ifindex != 0) {
+ /* Unset master only when it is set. */
+ link->master_set = false;
return link_request_set_link(link, REQUEST_TYPE_SET_LINK_MASTER,
link_unset_master_handler,
NULL);
+
+ } else {
+ /* Nothing we need to do. */
+ link->master_set = true;
+ return 0;
+ }
}
int link_request_to_set_mtu(Link *link, uint32_t mtu) {
@@ -999,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 09980b4256..3d44c8fc82 100644
--- a/src/network/networkd-sriov.c
+++ b/src/network/networkd-sriov.c
@@ -1,6 +1,9 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later
* Copyright © 2020 VMware, Inc. */
+#include "device-enumerator-private.h"
+#include "dirent-util.h"
+#include "fd-util.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-queue.h"
@@ -103,3 +106,262 @@ int link_request_sr_iov_vfs(Link *link) {
return 0;
}
+
+static int find_ifindex_from_pci_dev_port(sd_device *pci_dev, const char *dev_port) {
+ _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+ sd_device *dev;
+ int ifindex, r;
+
+ assert(pci_dev);
+ assert(dev_port);
+
+ r = sd_device_enumerator_new(&e);
+ if (r < 0)
+ return r;
+
+ r = sd_device_enumerator_allow_uninitialized(e);
+ if (r < 0)
+ return r;
+
+ r = sd_device_enumerator_add_match_parent(e, pci_dev);
+ if (r < 0)
+ return r;
+
+ r = sd_device_enumerator_add_match_subsystem(e, "net", true);
+ if (r < 0)
+ return r;
+
+ r = sd_device_enumerator_add_match_sysattr(e, "dev_port", dev_port, true);
+ if (r < 0)
+ return r;
+
+ dev = sd_device_enumerator_get_device_first(e);
+ if (!dev)
+ return -ENODEV; /* no device found */
+
+ if (sd_device_enumerator_get_device_next(e))
+ return -ENXIO; /* multiple devices found */
+
+ r = sd_device_get_ifindex(dev, &ifindex);
+ if (r < 0)
+ return r;
+
+ assert(ifindex > 0);
+ return ifindex;
+}
+
+static int manager_update_sr_iov_ifindices(Manager *manager, int phys_port_ifindex, int virt_port_ifindex) {
+ Link *phys_link = NULL, *virt_link = NULL;
+ int r;
+
+ assert(manager);
+ assert(phys_port_ifindex > 0);
+ assert(virt_port_ifindex > 0);
+
+ /* This sets ifindices only whenn both interfaces are already managed by us. */
+
+ r = link_get_by_index(manager, phys_port_ifindex, &phys_link);
+ if (r < 0)
+ return r;
+
+ r = link_get_by_index(manager, virt_port_ifindex, &virt_link);
+ if (r < 0)
+ return r;
+
+ /* update VF ifindex in PF */
+ r = set_ensure_put(&phys_link->sr_iov_virt_port_ifindices, NULL, INT_TO_PTR(virt_port_ifindex));
+ if (r < 0)
+ return r;
+
+ log_link_debug(phys_link,
+ "Found SR-IOV VF port %s(%i).",
+ virt_link ? virt_link->ifname : "n/a", virt_port_ifindex);
+
+ /* update PF ifindex in VF */
+ if (virt_link->sr_iov_phys_port_ifindex > 0 && virt_link->sr_iov_phys_port_ifindex != phys_port_ifindex) {
+ Link *old_phys_link;
+
+ if (link_get_by_index(manager, virt_link->sr_iov_phys_port_ifindex, &old_phys_link) >= 0)
+ set_remove(old_phys_link->sr_iov_virt_port_ifindices, INT_TO_PTR(virt_port_ifindex));
+ }
+
+ virt_link->sr_iov_phys_port_ifindex = phys_port_ifindex;
+
+ log_link_debug(virt_link,
+ "Found SR-IOV PF port %s(%i).",
+ phys_link ? phys_link->ifname : "n/a", phys_port_ifindex);
+
+ return 0;
+}
+
+static int link_set_sr_iov_phys_port(Link *link) {
+ _cleanup_(sd_device_unrefp) sd_device *pci_physfn_dev = NULL;
+ const char *dev_port;
+ sd_device *pci_dev;
+ int r;
+
+ assert(link);
+ assert(link->manager);
+
+ if (link->sr_iov_phys_port_ifindex > 0)
+ return 0;
+
+ if (!link->dev)
+ return -ENODEV;
+
+ r = sd_device_get_sysattr_value(link->dev, "dev_port", &dev_port);
+ if (r < 0)
+ return r;
+
+ r = sd_device_get_parent_with_subsystem_devtype(link->dev, "pci", NULL, &pci_dev);
+ if (r < 0)
+ return r;
+
+ r = sd_device_new_child(&pci_physfn_dev, pci_dev, "physfn");
+ if (r < 0)
+ return r;
+
+ r = find_ifindex_from_pci_dev_port(pci_physfn_dev, dev_port);
+ if (r < 0)
+ return r;
+
+ return manager_update_sr_iov_ifindices(link->manager, r, link->ifindex);
+}
+
+static int link_set_sr_iov_virt_ports(Link *link) {
+ const char *dev_port, *pci_syspath;
+ _cleanup_closedir_ DIR *dir = NULL;
+ sd_device *pci_dev;
+ int r;
+
+ assert(link);
+ assert(link->manager);
+
+ set_clear(link->sr_iov_virt_port_ifindices);
+
+ if (!link->dev)
+ return -ENODEV;
+
+ r = sd_device_get_sysattr_value(link->dev, "dev_port", &dev_port);
+ if (r < 0)
+ return r;
+
+ r = sd_device_get_parent_with_subsystem_devtype(link->dev, "pci", NULL, &pci_dev);
+ if (r < 0)
+ return r;
+
+ r = sd_device_get_syspath(pci_dev, &pci_syspath);
+ if (r < 0)
+ return r;
+
+ dir = opendir(pci_syspath);
+ if (!dir)
+ return -errno;
+
+ FOREACH_DIRENT_ALL(de, dir, break) {
+ _cleanup_(sd_device_unrefp) sd_device *pci_virtfn_dev = NULL;
+
+ if (de->d_type != DT_LNK)
+ continue;
+
+ /* Accept name prefixed with "virtfn", but refuse "virtfn" itself. */
+ if (isempty(startswith(de->d_name, "virtfn")))
+ continue;
+
+ if (sd_device_new_child(&pci_virtfn_dev, pci_dev, de->d_name) < 0)
+ continue;
+
+ if (find_ifindex_from_pci_dev_port(pci_virtfn_dev, dev_port) < 0)
+ continue;
+
+ if (manager_update_sr_iov_ifindices(link->manager, link->ifindex, r) < 0)
+ continue;
+ }
+
+ return 0;
+}
+
+int link_set_sr_iov_ifindices(Link *link) {
+ int r;
+
+ assert(link);
+
+ r = link_set_sr_iov_phys_port(link);
+ if (r < 0 && !ERRNO_IS_DEVICE_ABSENT(r))
+ return r;
+
+ r = link_set_sr_iov_virt_ports(link);
+ if (r < 0 && !ERRNO_IS_DEVICE_ABSENT(r))
+ return r;
+
+ return 0;
+}
+
+void link_clear_sr_iov_ifindices(Link *link) {
+ void *v;
+
+ assert(link);
+ assert(link->manager);
+
+ if (link->sr_iov_phys_port_ifindex > 0) {
+ Link *phys_link;
+
+ if (link_get_by_index(link->manager, link->sr_iov_phys_port_ifindex, &phys_link) >= 0)
+ set_remove(phys_link->sr_iov_virt_port_ifindices, INT_TO_PTR(link->ifindex));
+
+ link->sr_iov_phys_port_ifindex = 0;
+ }
+
+ while ((v = set_steal_first(link->sr_iov_virt_port_ifindices))) {
+ Link *virt_link;
+
+ if (link_get_by_index(link->manager, PTR_TO_INT(v), &virt_link) >= 0)
+ 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 539fa06099..0d4276e099 100644
--- a/src/network/networkd-sriov.h
+++ b/src/network/networkd-sriov.h
@@ -7,3 +7,11 @@
typedef struct Link Link;
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));
diff --git a/src/network/networkd-wiphy.c b/src/network/networkd-wiphy.c
index 38d1ceeba1..63874cdf98 100644
--- a/src/network/networkd-wiphy.c
+++ b/src/network/networkd-wiphy.c
@@ -116,7 +116,7 @@ static int link_get_wiphy(Link *link, Wiphy **ret) {
return -EOPNOTSUPP;
if (!link->dev)
- return -EOPNOTSUPP;
+ return -ENODEV;
r = sd_device_get_devtype(link->dev, &s);
if (r < 0)
@@ -125,12 +125,7 @@ static int link_get_wiphy(Link *link, Wiphy **ret) {
if (!streq_ptr(s, "wlan"))
return -EOPNOTSUPP;
- r = sd_device_get_syspath(link->dev, &s);
- if (r < 0)
- return r;
-
- s = strjoina(s, "/phy80211");
- r = sd_device_new_from_syspath(&phy, s);
+ r = sd_device_new_child(&phy, link->dev, "phy80211");
if (r < 0)
return r;
@@ -219,10 +214,11 @@ int link_rfkilled(Link *link) {
assert(link);
r = link_get_wiphy(link, &w);
- if (IN_SET(r, -EOPNOTSUPP, -ENODEV))
- return false; /* Typically, non-wifi interface or running in container */
- if (r < 0)
+ if (r < 0) {
+ if (ERRNO_IS_NOT_SUPPORTED(r) || ERRNO_IS_DEVICE_ABSENT(r))
+ return false; /* Typically, non-wifi interface or running in container */
return log_link_debug_errno(link, r, "Could not get phy: %m");
+ }
return wiphy_rfkilled(w);
}
@@ -272,11 +268,8 @@ static int wiphy_update_device(Wiphy *w) {
w->dev = sd_device_unref(w->dev);
r = sd_device_new_from_subsystem_sysname(&dev, "ieee80211", w->name);
- if (r < 0) {
- /* The corresponding syspath may not exist yet, and may appear later. */
- log_wiphy_debug_errno(w, r, "Failed to get wiphy device, ignoring: %m");
- return 0;
- }
+ if (r < 0)
+ return r;
if (DEBUG_LOGGING) {
const char *s = NULL;
@@ -321,14 +314,12 @@ static int wiphy_update_rfkill(Wiphy *w) {
return r;
rfkill = sd_device_enumerator_get_device_first(e);
- if (!rfkill) {
+ if (!rfkill)
/* rfkill device may not detected by the kernel yet, and may appear later. */
- log_wiphy_debug_errno(w, SYNTHETIC_ERRNO(ENODEV), "No rfkill device found, ignoring.");
- return 0;
- }
+ return -ENODEV;
if (sd_device_enumerator_get_device_next(e))
- return log_wiphy_debug_errno(w, SYNTHETIC_ERRNO(EEXIST), "Multiple rfkill devices found.");
+ return -ENXIO; /* multiple devices found */
w->rfkill = sd_device_ref(rfkill);
@@ -348,12 +339,20 @@ static int wiphy_update(Wiphy *w) {
assert(w);
r = wiphy_update_device(w);
- if (r < 0)
- return log_wiphy_debug_errno(w, r, "Failed to update wiphy device: %m");
+ if (r < 0) {
+ if (ERRNO_IS_DEVICE_ABSENT(r))
+ log_wiphy_debug_errno(w, r, "Failed to update wiphy device, ignoring: %m");
+ else
+ return log_wiphy_warning_errno(w, r, "Failed to update wiphy device: %m");
+ }
r = wiphy_update_rfkill(w);
- if (r < 0)
- return log_wiphy_debug_errno(w, r, "Failed to update rfkill device: %m");
+ if (r < 0) {
+ if (ERRNO_IS_DEVICE_ABSENT(r))
+ log_wiphy_debug_errno(w, r, "Failed to update rfkill device, ignoring: %m");
+ else
+ return log_wiphy_warning_errno(w, r, "Failed to update rfkill device: %m");
+ }
return 0;
}
diff --git a/src/systemd/sd-device.h b/src/systemd/sd-device.h
index 19dd4d9eef..0b2f8f8b42 100644
--- a/src/systemd/sd-device.h
+++ b/src/systemd/sd-device.h
@@ -67,6 +67,8 @@ int sd_device_new_from_path(sd_device **ret, const char *path);
int sd_device_new_from_ifname(sd_device **ret, const char *ifname);
int sd_device_new_from_ifindex(sd_device **ret, int ifindex);
+int sd_device_new_child(sd_device **ret, sd_device *device, const char *suffix);
+
int sd_device_get_parent(sd_device *child, sd_device **ret);
int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *subsystem, const char *devtype, sd_device **ret);
diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
index 59db7641b5..45387b2bdb 100644
--- a/src/udev/udev-builtin-net_id.c
+++ b/src/udev/udev-builtin-net_id.c
@@ -23,7 +23,6 @@
#include <linux/pci_regs.h>
#include "alloc-util.h"
-#include "chase-symlinks.h"
#include "device-util.h"
#include "dirent-util.h"
#include "fd-util.h"
@@ -109,8 +108,7 @@ static int get_virtfn_info(sd_device *pcidev, sd_device **ret_physfn_pcidev, cha
return r;
/* Get physical function's pci device. */
- physfn_syspath = strjoina(syspath, "/physfn");
- r = sd_device_new_from_syspath(&physfn_pcidev, physfn_syspath);
+ r = sd_device_new_child(&physfn_pcidev, pcidev, "physfn");
if (r < 0)
return r;
@@ -124,21 +122,20 @@ static int get_virtfn_info(sd_device *pcidev, sd_device **ret_physfn_pcidev, cha
return -errno;
FOREACH_DIRENT_ALL(de, dir, break) {
- _cleanup_free_ char *virtfn_link_file = NULL, *virtfn_pci_syspath = NULL;
- const char *n;
+ _cleanup_(sd_device_unrefp) sd_device *virtfn_pcidev = NULL;
+ const char *n, *s;
n = startswith(de->d_name, "virtfn");
- if (!n)
+ if (isempty(n))
continue;
- virtfn_link_file = path_join(physfn_syspath, de->d_name);
- if (!virtfn_link_file)
- return -ENOMEM;
+ if (sd_device_new_child(&virtfn_pcidev, physfn_pcidev, de->d_name) < 0)
+ continue;
- if (chase_symlinks(virtfn_link_file, NULL, 0, &virtfn_pci_syspath, NULL) < 0)
+ if (sd_device_get_syspath(virtfn_pcidev, &s) < 0)
continue;
- if (streq(syspath, virtfn_pci_syspath)) {
+ if (streq(s, syspath)) {
char *suffix;
suffix = strjoin("v", n);