A single PCI device may have multiple netdevs associated with it. Each of those netdevs will have a different phys_port_id entry in sysfs. This patch modifies virPCIGetNetName() to allow selecting one of the potential many netdevs in two different ways: 1) by setting the "idx" argument, the caller can select the 1st (0), 2nd (1), etc. netdev from the PCI device's net subdirectory. 2) If the physPortID arg is set (to a null-terminated string) then virPCIGetNetName() returns the netdev that has that phys_port_id in the sysfs file of the same name in the netdev's directory. --- Change from V1 - in V1 I had only added the physPortID arg. In V2 I also added the idx arg to allow choosing port 1 or 2 regardless of physPortID (because in some situations you can't know the physPortID). src/util/virhostdev.c | 2 +- src/util/virnetdev.c | 9 ++++--- src/util/virpci.c | 66 ++++++++++++++++++++++++++++++++++++++++++--------- src/util/virpci.h | 5 +++- 4 files changed, 66 insertions(+), 16 deletions(-) diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c index 579563c3f..580f0fac0 100644 --- a/src/util/virhostdev.c +++ b/src/util/virhostdev.c @@ -326,7 +326,7 @@ virHostdevNetDevice(virDomainHostdevDefPtr hostdev, char **linkdev, * type='hostdev'>, and it is only those devices that should * end up calling this function. */ - if (virPCIGetNetName(sysfs_path, linkdev) < 0) + if (virPCIGetNetName(sysfs_path, 0, NULL, linkdev) < 0) goto cleanup; if (!linkdev) { diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index a2664de78..b6ef00e2e 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -1262,8 +1262,10 @@ virNetDevGetVirtualFunctions(const char *pfname, goto cleanup; } - if (virPCIGetNetName(pci_sysfs_device_link, &((*vfname)[i])) < 0) + if (virPCIGetNetName(pci_sysfs_device_link, 0, + NULL, &((*vfname)[i])) < 0) { goto cleanup; + } if (!(*vfname)[i]) VIR_INFO("VF does not have an interface name"); @@ -1362,7 +1364,8 @@ virNetDevGetPhysicalFunction(const char *ifname, char **pfname) if (virNetDevSysfsDeviceFile(&physfn_sysfs_path, ifname, "physfn") < 0) return ret; - if (virPCIGetNetName(physfn_sysfs_path, pfname) < 0) + if (virPCIGetNetName(physfn_sysfs_path, 0, + NULL, pfname) < 0) goto cleanup; if (!*pfname) { @@ -1422,7 +1425,7 @@ virNetDevPFGetVF(const char *pfname, int vf, char **vfname) * isn't bound to a netdev driver, it won't have a netdev name, * and vfname will be NULL). */ - ret = virPCIGetNetName(virtfnSysfsPath, vfname); + ret = virPCIGetNetName(virtfnSysfsPath, 0, NULL, vfname); cleanup: VIR_FREE(virtfnName); diff --git a/src/util/virpci.c b/src/util/virpci.c index 110d9741c..62a36b380 100644 --- a/src/util/virpci.c +++ b/src/util/virpci.c @@ -24,6 +24,7 @@ #include <config.h> #include "virpci.h" +#include "virnetdev.h" #include <dirent.h> #include <fcntl.h> @@ -2853,16 +2854,30 @@ virPCIDeviceAddressGetSysfsFile(virPCIDeviceAddressPtr addr, return 0; } -/* - * Returns the network device name of a pci device +/** + * virPCIGetNetName: + * @device_link_sysfs_path: sysfs path to the PCI device + * @idx: used to choose which netdev when there are several + * (ignored if physPortID is set) + * @physPortID: match this string in the netdev's phys_port_id + * (or NULL to ignore and use idx instead) + * @netname: used to return the name of the netdev + * (set to NULL (but returns success) if there is no netdev) + * + * Returns 0 on success, -1 on error (error has been logged) */ int -virPCIGetNetName(const char *device_link_sysfs_path, char **netname) +virPCIGetNetName(const char *device_link_sysfs_path, + size_t idx, + char *physPortID, + char **netname) { char *pcidev_sysfs_net_path = NULL; int ret = -1; DIR *dir = NULL; struct dirent *entry = NULL; + char *thisPhysPortID = NULL; + size_t i = 0; if (virBuildPath(&pcidev_sysfs_net_path, device_link_sysfs_path, "net") == -1) { @@ -2873,21 +2888,48 @@ virPCIGetNetName(const char *device_link_sysfs_path, char **netname) if (virDirOpenQuiet(&dir, pcidev_sysfs_net_path) < 0) { /* this *isn't* an error - caller needs to check for netname == NULL */ ret = 0; - goto out; + goto cleanup; } while (virDirRead(dir, &entry, pcidev_sysfs_net_path) > 0) { - /* Assume a single directory entry */ - if (VIR_STRDUP(*netname, entry->d_name) > 0) - ret = 0; + /* if the caller sent a physPortID, compare it to the + * physportID of this netdev. If not, look for entry[idx]. + */ + if (physPortID) { + if (virNetDevGetPhysPortID(entry->d_name, &thisPhysPortID) < 0) + goto cleanup; + + /* if this one doesn't match, keep looking */ + if (STRNEQ_NULLABLE(physPortID, thisPhysPortID)) { + VIR_FREE(thisPhysPortID); + continue; + } + } else { + if (i++ < idx) + continue; + } + + if (VIR_STRDUP(*netname, entry->d_name) < 0) + goto cleanup; + + ret = 0; break; } + if (ret < 0) { + if (physPortID) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not find network device with " + "phys_port_id '%s' under PCI device at %s"), + physPortID, device_link_sysfs_path); + } else { + ret = 0; /* no netdev at the given index is *not* an error */ + } + } + cleanup: VIR_DIR_CLOSE(dir); - - out: VIR_FREE(pcidev_sysfs_net_path); - + VIR_FREE(thisPhysPortID); return ret; } @@ -2915,7 +2957,7 @@ virPCIGetVirtualFunctionInfo(const char *vf_sysfs_device_path, goto cleanup; } - if (virPCIGetNetName(pf_sysfs_device_path, pfname) < 0) + if (virPCIGetNetName(pf_sysfs_device_path, 0, NULL, pfname) < 0) goto cleanup; if (!*pfname) { @@ -2992,6 +3034,8 @@ virPCIDeviceAddressGetSysfsFile(virPCIDeviceAddressPtr dev ATTRIBUTE_UNUSED, int virPCIGetNetName(const char *device_link_sysfs_path ATTRIBUTE_UNUSED, + size_t idx ATTRIBUTE_UNUSED, + char *physPortID ATTRIBUTE_UNUSED, char **netname ATTRIBUTE_UNUSED) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); diff --git a/src/util/virpci.h b/src/util/virpci.h index 82d4ddc61..adf336706 100644 --- a/src/util/virpci.h +++ b/src/util/virpci.h @@ -207,7 +207,10 @@ int virPCIGetVirtualFunctionIndex(const char *pf_sysfs_device_link, int virPCIDeviceAddressGetSysfsFile(virPCIDeviceAddressPtr addr, char **pci_sysfs_device_link); -int virPCIGetNetName(const char *device_link_sysfs_path, char **netname); +int virPCIGetNetName(const char *device_link_sysfs_path, + size_t idx, + char *physPortID, + char **netname); int virPCIGetSysfsFile(char *virPCIDeviceName, char **pci_sysfs_device_link) -- 2.13.3 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list