Blob Blame History Raw
From f382f3e59823e2d94df9c88b0d5c0f736bb71a31 Mon Sep 17 00:00:00 2001
Message-Id: <f382f3e59823e2d94df9c88b0d5c0f736bb71a31@dist-git>
From: Laine Stump <laine@laine.org>
Date: Mon, 14 Aug 2017 21:28:16 -0400
Subject: [PATCH] util: new function virNetDevGetPhysPortID()

On Linux each network device *can* (but not necessarily *does*) have
an attribute called phys_port_id which can be read from the file of
that name in the netdev's sysfs directory. The examples I've seen have
been a many-digit hexadecimal number (as an ASCII string).

This value can be useful when a single PCI device is associated with
multiple netdevs (e.g a dual port Mellanox SR-IOV NIC - this card has
a single PCI Physical Function (PF), and that PF has two netdevs
associated with it (the "net" subdirectory of the PF in sysfs has two
links rather than the usual single link to a netdev directory). Each
of the PF netdevs has a different phys_port_id. The Virtual Functions
(VF) are similar - the PF (a PCI device) has "n" VFs (also each of
these is a PCI device), each VF has two netdevs, and each of the VF
netdevs points back to the VF PCI device (with the "device" entry in
its sysfs directory) as well as having a phys_port_id matching the PF
netdev it is associated with.

virNetDevGetPhysPortID() simply attempts to read the phys_port_id for
the given netdev and return it to the caller. If this particular
netdev driver doesn't support phys_port_id, it returns NULL (*not* a
NULL-terminated string, but a NULL pointer) but still counts it as a
success.

Resolves: https://bugzilla.redhat.com/1460082

(cherry picked from commit 48f33bb5df476df3c534978f0119e537f5fbb4ca)

Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
---
 src/libvirt_private.syms |  1 +
 src/util/virnetdev.c     | 51 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/util/virnetdev.h     |  5 +++++
 3 files changed, 57 insertions(+)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 04c9ff6120..add87a4dc9 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2061,6 +2061,7 @@ virNetDevGetMTU;
 virNetDevGetName;
 virNetDevGetOnline;
 virNetDevGetPhysicalFunction;
+virNetDevGetPhysPortID;
 virNetDevGetPromiscuous;
 virNetDevGetRcvAllMulti;
 virNetDevGetRcvMulti;
diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c
index 2beb39bb60..2fced369b3 100644
--- a/src/util/virnetdev.c
+++ b/src/util/virnetdev.c
@@ -1169,6 +1169,46 @@ virNetDevGetPCIDevice(const char *devName)
 }
 
 
+/**
+ * virNetDevGetPhysPortID:
+ *
+ * @ifname: name of a netdev
+ *
+ * @physPortID: pointer to char* that will receive @ifname's
+ *              phys_port_id from sysfs (null terminated
+ *              string). Could be NULL if @ifname's net driver doesn't
+ *              support phys_port_id (most netdev drivers
+ *              don't). Caller is responsible for freeing the string
+ *              when finished.
+ *
+ * Returns 0 on success or -1 on failure.
+ */
+int
+virNetDevGetPhysPortID(const char *ifname,
+                       char **physPortID)
+{
+    int ret = -1;
+    char *physPortIDFile = NULL;
+
+    *physPortID = NULL;
+
+    if (virNetDevSysfsFile(&physPortIDFile, ifname, "phys_port_id") < 0)
+        goto cleanup;
+
+    /* a failure to read just means the driver doesn't support
+     * phys_port_id, so set success now and ignore the return from
+     * virFileReadAllQuiet().
+     */
+    ret = 0;
+
+    ignore_value(virFileReadAllQuiet(physPortIDFile, 1024, physPortID));
+
+ cleanup:
+    VIR_FREE(physPortIDFile);
+    return ret;
+}
+
+
 /**
  * virNetDevGetVirtualFunctions:
  *
@@ -1432,6 +1472,17 @@ virNetDevGetVirtualFunctionInfo(const char *vfname, char **pfname,
 }
 
 #else /* !__linux__ */
+int
+virNetDevGetPhysPortID(const char *ifname ATTRIBUTE_UNUSED,
+                       char **physPortID)
+{
+    /* this actually should never be called, and is just here to
+     * satisfy the linker.
+     */
+    *physPortID = NULL;
+    return 0;
+}
+
 int
 virNetDevGetVirtualFunctions(const char *pfname ATTRIBUTE_UNUSED,
                              char ***vfname ATTRIBUTE_UNUSED,
diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h
index c2c09af636..5fb9c6d169 100644
--- a/src/util/virnetdev.h
+++ b/src/util/virnetdev.h
@@ -226,6 +226,11 @@ int virNetDevGetPhysicalFunction(const char *ifname, char **pfname)
 int virNetDevPFGetVF(const char *pfname, int vf, char **vfname)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
 
+int virNetDevGetPhysPortID(const char *ifname,
+                           char **physPortID)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
+    ATTRIBUTE_RETURN_CHECK;
+
 int virNetDevGetVirtualFunctions(const char *pfname,
                                  char ***vfname,
                                  virPCIDeviceAddressPtr **virt_fns,
-- 
2.14.1