Merge pull request #23340 from yuwata/network-check-sr-iov-pf-state

network: check SR-IOV PF state
This commit is contained in:
Yu Watanabe
2022-08-06 03:18:30 +09:00
committed by GitHub
19 changed files with 417 additions and 79 deletions
+2
View File
@@ -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;
+23
View File
@@ -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;
+2 -2
View File
@@ -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)
+1 -1
View File
@@ -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) {
+28 -12
View 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,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);
+1 -7
View File
@@ -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))
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -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));
+18 -9
View File
@@ -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. */
+3
View File
@@ -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;
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -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))
+2 -1
View File
@@ -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;
+29 -7
View 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) {
@@ -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;
+262
View File
@@ -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;
}
+8
View File
@@ -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));
+23 -24
View File
@@ -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;
}
+2
View File
@@ -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);
+9 -12
View File
@@ -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 (chase_symlinks(virtfn_link_file, NULL, 0, &virtfn_pci_syspath, NULL) < 0)
if (sd_device_new_child(&virtfn_pcidev, physfn_pcidev, de->d_name) < 0)
continue;
if (streq(syspath, virtfn_pci_syspath)) {
if (sd_device_get_syspath(virtfn_pcidev, &s) < 0)
continue;
if (streq(s, syspath)) {
char *suffix;
suffix = strjoin("v", n);