|
|
5c27b6 |
From 1a69b4e4b8f0eed78951464a8916356961203687 Mon Sep 17 00:00:00 2001
|
|
|
5c27b6 |
Message-Id: <1a69b4e4b8f0eed78951464a8916356961203687@dist-git>
|
|
|
5c27b6 |
From: Laine Stump <laine@laine.org>
|
|
|
5c27b6 |
Date: Thu, 13 Apr 2017 14:29:29 -0400
|
|
|
5c27b6 |
Subject: [PATCH] util: new functions virNetDev(Save|Read|Set)NetConfig()
|
|
|
5c27b6 |
|
|
|
5c27b6 |
These three functions are destined to replace
|
|
|
5c27b6 |
virNetDev(Replace|Restore)NetConfig() and
|
|
|
5c27b6 |
virNetDev(Replace|Restore)MacAddress(), which both do the save and set
|
|
|
5c27b6 |
together as a single step. We need to separate the save, read, and set
|
|
|
5c27b6 |
steps because there will be situations where we need to do something
|
|
|
5c27b6 |
else in between (in particular, we will need to rebind a VF's driver
|
|
|
5c27b6 |
after save but before set).
|
|
|
5c27b6 |
|
|
|
5c27b6 |
This patch creates the new functions, but doesn't call them - that
|
|
|
5c27b6 |
will come in a subsequent patch. Note that the new functions to
|
|
|
5c27b6 |
read/write the file that stores the original network config now uses
|
|
|
5c27b6 |
JSON rather than plaintext (it still recognizes the old format as well
|
|
|
5c27b6 |
though, so it won't get confused during an upgrade).
|
|
|
5c27b6 |
|
|
|
5c27b6 |
Resolves: https://bugzilla.redhat.com/1442040 (RHEL 7.3.z)
|
|
|
5c27b6 |
Resolves: https://bugzilla.redhat.com/1415609 (RHEL 7.4)
|
|
|
5c27b6 |
|
|
|
5c27b6 |
(cherry picked from commit 26694daf0997290e4a02fd10b1c2e24678ca8653)
|
|
|
5c27b6 |
---
|
|
|
5c27b6 |
src/libvirt_private.syms | 3 +
|
|
|
5c27b6 |
src/util/virnetdev.c | 590 ++++++++++++++++++++++++++++++++++++++++++++++-
|
|
|
5c27b6 |
src/util/virnetdev.h | 22 ++
|
|
|
5c27b6 |
3 files changed, 613 insertions(+), 2 deletions(-)
|
|
|
5c27b6 |
|
|
|
5c27b6 |
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
|
|
|
5c27b6 |
index f91703f2e..9b0bc0100 100644
|
|
|
5c27b6 |
--- a/src/libvirt_private.syms
|
|
|
5c27b6 |
+++ b/src/libvirt_private.syms
|
|
|
5c27b6 |
@@ -1900,6 +1900,7 @@ virNetDevIfStateTypeFromString;
|
|
|
5c27b6 |
virNetDevIfStateTypeToString;
|
|
|
5c27b6 |
virNetDevIsVirtualFunction;
|
|
|
5c27b6 |
virNetDevPFGetVF;
|
|
|
5c27b6 |
+virNetDevReadNetConfig;
|
|
|
5c27b6 |
virNetDevReplaceMacAddress;
|
|
|
5c27b6 |
virNetDevReplaceNetConfig;
|
|
|
5c27b6 |
virNetDevRestoreMacAddress;
|
|
|
5c27b6 |
@@ -1909,11 +1910,13 @@ virNetDevRxFilterFree;
|
|
|
5c27b6 |
virNetDevRxFilterModeTypeFromString;
|
|
|
5c27b6 |
virNetDevRxFilterModeTypeToString;
|
|
|
5c27b6 |
virNetDevRxFilterNew;
|
|
|
5c27b6 |
+virNetDevSaveNetConfig;
|
|
|
5c27b6 |
virNetDevSetMAC;
|
|
|
5c27b6 |
virNetDevSetMTU;
|
|
|
5c27b6 |
virNetDevSetMTUFromDevice;
|
|
|
5c27b6 |
virNetDevSetName;
|
|
|
5c27b6 |
virNetDevSetNamespace;
|
|
|
5c27b6 |
+virNetDevSetNetConfig;
|
|
|
5c27b6 |
virNetDevSetOnline;
|
|
|
5c27b6 |
virNetDevSetPromiscuous;
|
|
|
5c27b6 |
virNetDevSetRcvAllMulti;
|
|
|
5c27b6 |
diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c
|
|
|
5c27b6 |
index 807b67697..b61ed0f0b 100644
|
|
|
5c27b6 |
--- a/src/util/virnetdev.c
|
|
|
5c27b6 |
+++ b/src/util/virnetdev.c
|
|
|
5c27b6 |
@@ -33,6 +33,7 @@
|
|
|
5c27b6 |
#include "virlog.h"
|
|
|
5c27b6 |
#include "virstring.h"
|
|
|
5c27b6 |
#include "virutil.h"
|
|
|
5c27b6 |
+#include "virjson.h"
|
|
|
5c27b6 |
|
|
|
5c27b6 |
#include <sys/ioctl.h>
|
|
|
5c27b6 |
#include <net/if.h>
|
|
|
5c27b6 |
@@ -1902,7 +1903,551 @@ virNetDevRestoreNetConfig(const char *linkdev, int vf, const char *stateDir)
|
|
|
5c27b6 |
return ret;
|
|
|
5c27b6 |
}
|
|
|
5c27b6 |
|
|
|
5c27b6 |
-#else /* defined(__linux__) && defined(HAVE_LIBNL) */
|
|
|
5c27b6 |
+# define VIR_NETDEV_KEYNAME_ADMIN_MAC "adminMac"
|
|
|
5c27b6 |
+# define VIR_NETDEV_KEYNAME_VLAN_TAG "vlanTag"
|
|
|
5c27b6 |
+# define VIR_NETDEV_KEYNAME_MAC "mac"
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+/**
|
|
|
5c27b6 |
+ * virNetDevSaveNetConfig:
|
|
|
5c27b6 |
+ * @linkdev: name of the interface
|
|
|
5c27b6 |
+ * @vf: vf index if linkdev is a pf
|
|
|
5c27b6 |
+ * @stateDir: directory to store old net config
|
|
|
5c27b6 |
+ * @saveVlan: false if we shouldn't attempt to save vlan tag info
|
|
|
5c27b6 |
+ * (eg for interfaces using 802.1Qbg, since it handles
|
|
|
5c27b6 |
+ * vlan tags internally)
|
|
|
5c27b6 |
+ *
|
|
|
5c27b6 |
+ * Save current MAC address and (if linkdev itself is a VF, or if @vf
|
|
|
5c27b6 |
+ * >= 0) the "admin MAC address" and vlan tag the device described by
|
|
|
5c27b6 |
+ * @linkdev:@vf to @stateDir. (the "admin MAC address" is stored in
|
|
|
5c27b6 |
+ * the PF, and is what the VF MAC will be initialized to the next time
|
|
|
5c27b6 |
+ * its driver is reloaded (either on host or guest).
|
|
|
5c27b6 |
+ *
|
|
|
5c27b6 |
+ * File Format:
|
|
|
5c27b6 |
+ *
|
|
|
5c27b6 |
+ * The file is in json format and will contain 1 or more of the
|
|
|
5c27b6 |
+ * following values:
|
|
|
5c27b6 |
+ *
|
|
|
5c27b6 |
+ * "mac" - VF MAC address (or missing if VF has no host net driver)
|
|
|
5c27b6 |
+ * "vlanTag" - a single vlan tag id
|
|
|
5c27b6 |
+ * "adminMac" - admin MAC address (stored in the PF)
|
|
|
5c27b6 |
+ *
|
|
|
5c27b6 |
+ * For example:
|
|
|
5c27b6 |
+ *
|
|
|
5c27b6 |
+ * {"mac": "9A:11:22:33:44:55",
|
|
|
5c27b6 |
+ * "vlanTag": "42",
|
|
|
5c27b6 |
+ * "adminMac": "00:00:00:00:00:00"
|
|
|
5c27b6 |
+ * }
|
|
|
5c27b6 |
+ *
|
|
|
5c27b6 |
+ * File Name:
|
|
|
5c27b6 |
+ *
|
|
|
5c27b6 |
+ * If the device is a VF and we're allowed to save vlan tag info, the
|
|
|
5c27b6 |
+ * file will be named ${pfDevName_vf#{vf} (e.g. "enp2s0f0_vf5") and
|
|
|
5c27b6 |
+ * will contain at least "adminMac" and "vlanTag" (if the device was bound
|
|
|
5c27b6 |
+ * to a net driver on the host prior to use, it will also have "mac"..
|
|
|
5c27b6 |
+ * If the device isn't a VF, or we're not allowed to save vlan tag
|
|
|
5c27b6 |
+ * info, the file will be named ${linkdev} (e.g. "enp3s0f0") and will
|
|
|
5c27b6 |
+ * contain just linkdev's MAC address.
|
|
|
5c27b6 |
+ *
|
|
|
5c27b6 |
+ * Returns 0 on success, -1 on failure
|
|
|
5c27b6 |
+ *
|
|
|
5c27b6 |
+ */
|
|
|
5c27b6 |
+int
|
|
|
5c27b6 |
+virNetDevSaveNetConfig(const char *linkdev, int vf,
|
|
|
5c27b6 |
+ const char *stateDir,
|
|
|
5c27b6 |
+ bool saveVlan)
|
|
|
5c27b6 |
+{
|
|
|
5c27b6 |
+ int ret = -1;
|
|
|
5c27b6 |
+ const char *pfDevName = NULL;
|
|
|
5c27b6 |
+ char *pfDevOrig = NULL;
|
|
|
5c27b6 |
+ char *vfDevOrig = NULL;
|
|
|
5c27b6 |
+ virMacAddr oldMAC;
|
|
|
5c27b6 |
+ char MACStr[VIR_MAC_STRING_BUFLEN];
|
|
|
5c27b6 |
+ int oldVlanTag = -1;
|
|
|
5c27b6 |
+ char *filePath = NULL;
|
|
|
5c27b6 |
+ char *fileStr = NULL;
|
|
|
5c27b6 |
+ virJSONValuePtr configJSON = NULL;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (vf >= 0) {
|
|
|
5c27b6 |
+ /* linkdev is the PF */
|
|
|
5c27b6 |
+ pfDevName = linkdev;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ /* linkdev should get the VF's netdev name (or NULL if none) */
|
|
|
5c27b6 |
+ if (virNetDevPFGetVF(pfDevName, vf, &vfDevOrig) < 0)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ linkdev = vfDevOrig;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ } else if (saveVlan && virNetDevIsVirtualFunction(linkdev) == 1) {
|
|
|
5c27b6 |
+ /* when vf is -1, linkdev might be a standard netdevice (not
|
|
|
5c27b6 |
+ * SRIOV), or it might be an SRIOV VF. If it's a VF, normalize
|
|
|
5c27b6 |
+ * it to PF + VFname
|
|
|
5c27b6 |
+ */
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (virNetDevGetPhysicalFunction(linkdev, &pfDevOrig) < 0)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ pfDevName = pfDevOrig;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (virNetDevGetVirtualFunctionIndex(pfDevName, linkdev, &vf) < 0)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (!(configJSON = virJSONValueNewObject()))
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ /* if there is a PF, it's now in pfDevName, and linkdev is either
|
|
|
5c27b6 |
+ * the VF's name, or NULL (if the VF isn't bound to a net driver
|
|
|
5c27b6 |
+ * on the host)
|
|
|
5c27b6 |
+ */
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (pfDevName) {
|
|
|
5c27b6 |
+ if (virAsprintf(&filePath, "%s/%s_vf%d", stateDir, pfDevName, vf) < 0)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ /* get admin MAC and vlan tag */
|
|
|
5c27b6 |
+ if (virNetDevGetVfConfig(pfDevName, vf, &oldMAC,
|
|
|
5c27b6 |
+ saveVlan ? &oldVlanTag : NULL) < 0) {
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (virJSONValueObjectAppendString(configJSON,
|
|
|
5c27b6 |
+ VIR_NETDEV_KEYNAME_ADMIN_MAC,
|
|
|
5c27b6 |
+ virMacAddrFormat(&oldMAC, MACStr)) < 0 ||
|
|
|
5c27b6 |
+ virJSONValueObjectAppendNumberInt(configJSON,
|
|
|
5c27b6 |
+ VIR_NETDEV_KEYNAME_VLAN_TAG,
|
|
|
5c27b6 |
+ oldVlanTag) < 0) {
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ } else {
|
|
|
5c27b6 |
+ if (virAsprintf(&filePath, "%s/%s", stateDir, linkdev) < 0)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (linkdev) {
|
|
|
5c27b6 |
+ if (virNetDevGetMAC(linkdev, &oldMAC) < 0)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ /* for interfaces with no pfDevName (i.e. not a VF, this will
|
|
|
5c27b6 |
+ * be the only value in the file.
|
|
|
5c27b6 |
+ */
|
|
|
5c27b6 |
+ if (virJSONValueObjectAppendString(configJSON, VIR_NETDEV_KEYNAME_MAC,
|
|
|
5c27b6 |
+ virMacAddrFormat(&oldMAC, MACStr)) < 0)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (!(fileStr = virJSONValueToString(configJSON, true)))
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (virFileWriteStr(filePath, fileStr, O_CREAT|O_TRUNC|O_WRONLY) < 0) {
|
|
|
5c27b6 |
+ virReportSystemError(errno, _("Unable to preserve mac/vlan tag "
|
|
|
5c27b6 |
+ "for device = %s, vf = %d"), linkdev, vf);
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ ret = 0;
|
|
|
5c27b6 |
+ cleanup:
|
|
|
5c27b6 |
+ VIR_FREE(pfDevOrig);
|
|
|
5c27b6 |
+ VIR_FREE(vfDevOrig);
|
|
|
5c27b6 |
+ VIR_FREE(filePath);
|
|
|
5c27b6 |
+ VIR_FREE(fileStr);
|
|
|
5c27b6 |
+ virJSONValueFree(configJSON);
|
|
|
5c27b6 |
+ return ret;
|
|
|
5c27b6 |
+}
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+/**
|
|
|
5c27b6 |
+ * virNetDevReadNetConfig:
|
|
|
5c27b6 |
+ * @linkdev: name of the interface
|
|
|
5c27b6 |
+ * @vf: vf index if linkdev is a pf
|
|
|
5c27b6 |
+ * @stateDir: directory where net config is stored
|
|
|
5c27b6 |
+ * @adminMAC: returns admin MAC to store in the PF (if this is a VF)
|
|
|
5c27b6 |
+ * @MAC: returns MAC to set on device immediately
|
|
|
5c27b6 |
+ *
|
|
|
5c27b6 |
+ * Read saved MAC address and (if linkdev itself is a VF, or if @vf >=
|
|
|
5c27b6 |
+ * 0) "admin MAC address" and vlan tag of the device described by
|
|
|
5c27b6 |
+ * @linkdev:@vf from a file in @stateDir. (see virNetDevSaveNetConfig
|
|
|
5c27b6 |
+ * for details of file name and format).
|
|
|
5c27b6 |
+ *
|
|
|
5c27b6 |
+ * Returns 0 on success, -1 on failure.
|
|
|
5c27b6 |
+ *
|
|
|
5c27b6 |
+ * The caller MUST free adminMAC, vlan, and MAC when it is finished
|
|
|
5c27b6 |
+ * with them (they will be NULL if they weren't found in the file)
|
|
|
5c27b6 |
+ *
|
|
|
5c27b6 |
+ */
|
|
|
5c27b6 |
+int
|
|
|
5c27b6 |
+virNetDevReadNetConfig(const char *linkdev, int vf,
|
|
|
5c27b6 |
+ const char *stateDir,
|
|
|
5c27b6 |
+ virMacAddrPtr *adminMAC,
|
|
|
5c27b6 |
+ virNetDevVlanPtr *vlan,
|
|
|
5c27b6 |
+ virMacAddrPtr *MAC)
|
|
|
5c27b6 |
+{
|
|
|
5c27b6 |
+ int ret = -1;
|
|
|
5c27b6 |
+ const char *pfDevName = NULL;
|
|
|
5c27b6 |
+ char *pfDevOrig = NULL;
|
|
|
5c27b6 |
+ char *vfDevOrig = NULL;
|
|
|
5c27b6 |
+ char *filePath = NULL;
|
|
|
5c27b6 |
+ char *fileStr = NULL;
|
|
|
5c27b6 |
+ virJSONValuePtr configJSON = NULL;
|
|
|
5c27b6 |
+ const char *MACStr = NULL;
|
|
|
5c27b6 |
+ const char *adminMACStr = NULL;
|
|
|
5c27b6 |
+ int vlanTag = -1;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ *adminMAC = NULL;
|
|
|
5c27b6 |
+ *vlan = NULL;
|
|
|
5c27b6 |
+ *MAC = NULL;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (vf >= 0) {
|
|
|
5c27b6 |
+ /* linkdev is the PF */
|
|
|
5c27b6 |
+ pfDevName = linkdev;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ /* linkdev should get the VF's netdev name (or NULL if none) */
|
|
|
5c27b6 |
+ if (virNetDevPFGetVF(pfDevName, vf, &vfDevOrig) < 0)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ linkdev = vfDevOrig;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ } else if (virNetDevIsVirtualFunction(linkdev) == 1) {
|
|
|
5c27b6 |
+ /* when vf is -1, linkdev might be a standard netdevice (not
|
|
|
5c27b6 |
+ * SRIOV), or it might be an SRIOV VF. If it's a VF, normalize
|
|
|
5c27b6 |
+ * it to PF + VFname
|
|
|
5c27b6 |
+ */
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (virNetDevGetPhysicalFunction(linkdev, &pfDevOrig) < 0)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ pfDevName = pfDevOrig;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (virNetDevGetVirtualFunctionIndex(pfDevName, linkdev, &vf) < 0)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ /* if there is a PF, it's now in pfDevName, and linkdev is either
|
|
|
5c27b6 |
+ * the VF's name, or NULL (if the VF isn't bound to a net driver
|
|
|
5c27b6 |
+ * on the host)
|
|
|
5c27b6 |
+ */
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (pfDevName) {
|
|
|
5c27b6 |
+ if (virAsprintf(&filePath, "%s/%s_vf%d", stateDir, pfDevName, vf) < 0)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (linkdev && !virFileExists(filePath)) {
|
|
|
5c27b6 |
+ /* the device may have been stored in a file named for the
|
|
|
5c27b6 |
+ * VF due to saveVlan == false (or an older version of
|
|
|
5c27b6 |
+ * libvirt), so reset filePath so we'll try the other
|
|
|
5c27b6 |
+ * filename before failing.
|
|
|
5c27b6 |
+ */
|
|
|
5c27b6 |
+ VIR_FREE(filePath);
|
|
|
5c27b6 |
+ pfDevName = NULL;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (!pfDevName) {
|
|
|
5c27b6 |
+ if (virAsprintf(&filePath, "%s/%s", stateDir, linkdev) < 0)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (virFileReadAll(filePath, 128, &fileStr) < 0)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (strchr("0123456789abcdefABCDEF", fileStr[0])) {
|
|
|
5c27b6 |
+ const char *vlanStr = NULL;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ /* old version of file - just two lines of text. Line 1 is the
|
|
|
5c27b6 |
+ * MAC address (or if line 2 is present, line 1 is adminMAC),
|
|
|
5c27b6 |
+ * and line 2 (if present) is the vlan tag
|
|
|
5c27b6 |
+ */
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if ((vlanStr = strchr(fileStr, '\n'))) {
|
|
|
5c27b6 |
+ char *endptr;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ /* if there are 2 lines, the first is adminMAC */
|
|
|
5c27b6 |
+ adminMACStr = fileStr;
|
|
|
5c27b6 |
+ vlanStr++;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if ((virStrToLong_i(vlanStr, &endptr, 10, &vlanTag) < 0) ||
|
|
|
5c27b6 |
+ (endptr && *endptr != '\n' && *endptr != 0)) {
|
|
|
5c27b6 |
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
5c27b6 |
+ _("cannot parse vlan tag '%s' from file '%s'"),
|
|
|
5c27b6 |
+ vlanStr, filePath);
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+ } else {
|
|
|
5c27b6 |
+ /* if there is only one line, it is MAC */
|
|
|
5c27b6 |
+ MACStr = fileStr;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+ } else {
|
|
|
5c27b6 |
+ /* if it doesn't start with a hex digit, it is a modern
|
|
|
5c27b6 |
+ * version of the config file - JSON format as described in
|
|
|
5c27b6 |
+ * preamble to virNetDevSaveNetConfig()
|
|
|
5c27b6 |
+ */
|
|
|
5c27b6 |
+ if (!(configJSON = virJSONValueFromString(fileStr))) {
|
|
|
5c27b6 |
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
5c27b6 |
+ _("invalid json in net device saved "
|
|
|
5c27b6 |
+ "config file '%s': '%.60s'"),
|
|
|
5c27b6 |
+ filePath, fileStr);
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ MACStr = virJSONValueObjectGetString(configJSON,
|
|
|
5c27b6 |
+ VIR_NETDEV_KEYNAME_MAC);
|
|
|
5c27b6 |
+ adminMACStr = virJSONValueObjectGetString(configJSON,
|
|
|
5c27b6 |
+ VIR_NETDEV_KEYNAME_ADMIN_MAC);
|
|
|
5c27b6 |
+ ignore_value(virJSONValueObjectGetNumberInt(configJSON,
|
|
|
5c27b6 |
+ VIR_NETDEV_KEYNAME_VLAN_TAG,
|
|
|
5c27b6 |
+ &vlanTag));
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (!(MACStr || adminMACStr)) {
|
|
|
5c27b6 |
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
5c27b6 |
+ _("network device saved config file '%s' "
|
|
|
5c27b6 |
+ "has unexpected contents, missing both "
|
|
|
5c27b6 |
+ "'MAC' and 'adminMAC': '%.60s'"),
|
|
|
5c27b6 |
+ filePath, fileStr);
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (MACStr) {
|
|
|
5c27b6 |
+ if (VIR_ALLOC(*MAC) < 0)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (virMacAddrParse(MACStr, *MAC) < 0) {
|
|
|
5c27b6 |
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
5c27b6 |
+ _("cannot parse MAC address '%s' from file '%s'"),
|
|
|
5c27b6 |
+ MACStr, filePath);
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (adminMACStr) {
|
|
|
5c27b6 |
+ if (VIR_ALLOC(*adminMAC) < 0)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (virMacAddrParse(adminMACStr, *adminMAC) < 0) {
|
|
|
5c27b6 |
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
5c27b6 |
+ _("cannot parse MAC address '%s' from file '%s'"),
|
|
|
5c27b6 |
+ adminMACStr, filePath);
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (vlanTag != -1) {
|
|
|
5c27b6 |
+ /* construct a simple virNetDevVlan object with a single tag */
|
|
|
5c27b6 |
+ if (VIR_ALLOC(*vlan) < 0)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+ if (VIR_ALLOC((*vlan)->tag) < 0)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+ (*vlan)->nTags = 1;
|
|
|
5c27b6 |
+ (*vlan)->tag[0] = vlanTag;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ /* we won't need the file again */
|
|
|
5c27b6 |
+ ignore_value(unlink(filePath));
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ ret = 0;
|
|
|
5c27b6 |
+ cleanup:
|
|
|
5c27b6 |
+ if (ret < 0) {
|
|
|
5c27b6 |
+ VIR_FREE(*adminMAC);
|
|
|
5c27b6 |
+ VIR_FREE(*MAC);
|
|
|
5c27b6 |
+ VIR_FREE(*vlan);
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ VIR_FREE(pfDevOrig);
|
|
|
5c27b6 |
+ VIR_FREE(vfDevOrig);
|
|
|
5c27b6 |
+ VIR_FREE(filePath);
|
|
|
5c27b6 |
+ VIR_FREE(fileStr);
|
|
|
5c27b6 |
+ virJSONValueFree(configJSON);
|
|
|
5c27b6 |
+ return ret;
|
|
|
5c27b6 |
+}
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+/**
|
|
|
5c27b6 |
+ * virNetDevSetNetConfig:
|
|
|
5c27b6 |
+ * @linkdev: name of the interface
|
|
|
5c27b6 |
+ * @vf: vf index if linkdev is a PF
|
|
|
5c27b6 |
+ * @adminMAC: new admin MAC address (will be stored in PF and
|
|
|
5c27b6 |
+ * used for next initialization of VF driver)
|
|
|
5c27b6 |
+ * @vlan: new vlan tag info (or NULL)
|
|
|
5c27b6 |
+ * @MAC: new MAC address to set on the device immediately
|
|
|
5c27b6 |
+ * @setVlan: true to enable setting vlan tag (even if @vlan is NULL,
|
|
|
5c27b6 |
+ * the interface vlan tag will be set to 0).
|
|
|
5c27b6 |
+ *
|
|
|
5c27b6 |
+ *
|
|
|
5c27b6 |
+ * Set new MAC address and (optionally) admin MAC and vlan tag of
|
|
|
5c27b6 |
+ * @linkdev VF# @vf.
|
|
|
5c27b6 |
+ *
|
|
|
5c27b6 |
+ * Returns 0 on success, -1 on failure
|
|
|
5c27b6 |
+ *
|
|
|
5c27b6 |
+ */
|
|
|
5c27b6 |
+int
|
|
|
5c27b6 |
+virNetDevSetNetConfig(const char *linkdev, int vf,
|
|
|
5c27b6 |
+ const virMacAddr *adminMAC,
|
|
|
5c27b6 |
+ virNetDevVlanPtr vlan,
|
|
|
5c27b6 |
+ const virMacAddr *MAC,
|
|
|
5c27b6 |
+ bool setVlan)
|
|
|
5c27b6 |
+{
|
|
|
5c27b6 |
+ int ret = -1;
|
|
|
5c27b6 |
+ char MACStr[VIR_MAC_STRING_BUFLEN];
|
|
|
5c27b6 |
+ const char *pfDevName = NULL;
|
|
|
5c27b6 |
+ char *pfDevOrig = NULL;
|
|
|
5c27b6 |
+ char *vfDevOrig = NULL;
|
|
|
5c27b6 |
+ int vlanTag = -1;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (vf >= 0) {
|
|
|
5c27b6 |
+ /* linkdev is the PF */
|
|
|
5c27b6 |
+ pfDevName = linkdev;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ /* linkdev should get the VF's netdev name (or NULL if none) */
|
|
|
5c27b6 |
+ if (virNetDevPFGetVF(pfDevName, vf, &vfDevOrig) < 0)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ linkdev = vfDevOrig;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ } else if (virNetDevIsVirtualFunction(linkdev) == 1) {
|
|
|
5c27b6 |
+ /* when vf is -1, linkdev might be a standard netdevice (not
|
|
|
5c27b6 |
+ * SRIOV), or it might be an SRIOV VF. If it's a VF, normalize
|
|
|
5c27b6 |
+ * it to PF + VFname
|
|
|
5c27b6 |
+ */
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (virNetDevGetPhysicalFunction(linkdev, &pfDevOrig) < 0)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ pfDevName = pfDevOrig;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (virNetDevGetVirtualFunctionIndex(pfDevName, linkdev, &vf) < 0)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (!pfDevName) {
|
|
|
5c27b6 |
+ /* if it's not SRIOV, then we can't set the admin MAC address
|
|
|
5c27b6 |
+ * or vlan tag
|
|
|
5c27b6 |
+ */
|
|
|
5c27b6 |
+ if (adminMAC) {
|
|
|
5c27b6 |
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
5c27b6 |
+ _("admin MAC can only be set for SR-IOV VFs, but "
|
|
|
5c27b6 |
+ "%s is not a VF"), linkdev);
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (vlan) {
|
|
|
5c27b6 |
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
5c27b6 |
+ _("vlan can only be set for SR-IOV VFs, but "
|
|
|
5c27b6 |
+ "%s is not a VF"), linkdev);
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ } else {
|
|
|
5c27b6 |
+ bool pfIsOnline;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ /* Assure that PF is online before trying to use it to set
|
|
|
5c27b6 |
+ * anything up for this VF. It *should* be online already,
|
|
|
5c27b6 |
+ * but if it isn't online the changes made to the VF via the
|
|
|
5c27b6 |
+ * PF won't take effect, yet there will be no error
|
|
|
5c27b6 |
+ * reported. In the case that the PF isn't online, we need to
|
|
|
5c27b6 |
+ * fail and report the error, rather than automatically
|
|
|
5c27b6 |
+ * setting it online, since setting an unconfigured interface
|
|
|
5c27b6 |
+ * online automatically turns on IPv6 autoconfig, which may
|
|
|
5c27b6 |
+ * not be what the admin expects, so we require them to
|
|
|
5c27b6 |
+ * explicitly enable the PF in the host system network config.
|
|
|
5c27b6 |
+ */
|
|
|
5c27b6 |
+ if (virNetDevGetOnline(pfDevName, &pfIsOnline) < 0)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (!pfIsOnline) {
|
|
|
5c27b6 |
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
5c27b6 |
+ _("Unable to configure VF %d of PF '%s' "
|
|
|
5c27b6 |
+ "because the PF is not online. Please "
|
|
|
5c27b6 |
+ "change host network config to put the "
|
|
|
5c27b6 |
+ "PF online."),
|
|
|
5c27b6 |
+ vf, pfDevName);
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (vlan) {
|
|
|
5c27b6 |
+ if (vlan->nTags != 1 || vlan->trunk) {
|
|
|
5c27b6 |
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
5c27b6 |
+ _("vlan trunking is not supported "
|
|
|
5c27b6 |
+ "by SR-IOV network devices"));
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (!setVlan) {
|
|
|
5c27b6 |
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
5c27b6 |
+ _("vlan tag set for interface %s but "
|
|
|
5c27b6 |
+ "caller requested it not be set"));
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ vlanTag = vlan->tag[0];
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ } else if (setVlan) {
|
|
|
5c27b6 |
+ vlanTag = 0; /* assure any existing vlan tag is reset */
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (MAC) {
|
|
|
5c27b6 |
+ if (!linkdev) {
|
|
|
5c27b6 |
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
5c27b6 |
+ _("VF %d of PF '%s' is not bound to a net driver, "
|
|
|
5c27b6 |
+ "so its MAC address cannot be set to %s"),
|
|
|
5c27b6 |
+ vf, pfDevName, virMacAddrFormat(MAC, MACStr));
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (virNetDevSetMAC(linkdev, MAC) < 0) {
|
|
|
5c27b6 |
+ /* This may have failed due to the "administratively
|
|
|
5c27b6 |
+ * set" flag being set in the PF for this VF. For now
|
|
|
5c27b6 |
+ * we will just fail, but in the future we should
|
|
|
5c27b6 |
+ * attempt to set the VF MAC via the PF.
|
|
|
5c27b6 |
+ */
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+ if (pfDevOrig) {
|
|
|
5c27b6 |
+ /* if pfDevOrig is set, it means that the caller was
|
|
|
5c27b6 |
+ * *really* only interested in setting the MAC of the VF
|
|
|
5c27b6 |
+ * itself, *not* the admin MAC via the PF. In those cases,
|
|
|
5c27b6 |
+ * the adminMAC was only provided in case we need to set
|
|
|
5c27b6 |
+ * the VF's MAC by temporarily unbinding/rebinding the
|
|
|
5c27b6 |
+ * VF's net driver with the admin MAC set to the desired
|
|
|
5c27b6 |
+ * MAC, and then want to restore the admin MAC to its
|
|
|
5c27b6 |
+ * original setting when we're finished. We would only
|
|
|
5c27b6 |
+ * need to do that if the virNetDevSetMAC() above had
|
|
|
5c27b6 |
+ * failed; since it didn't, we don't need to set the
|
|
|
5c27b6 |
+ * adminMAC, so we are NULLing it out here to avoid that
|
|
|
5c27b6 |
+ * below.
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ * (NB: since setting the admin MAC sets the
|
|
|
5c27b6 |
+ * "administratively set" flag for the VF in the PF's
|
|
|
5c27b6 |
+ * driver, which prevents any future changes to the VF's
|
|
|
5c27b6 |
+ * MAC address, we want to avoid setting the admin MAC as
|
|
|
5c27b6 |
+ * much as possible.)
|
|
|
5c27b6 |
+ */
|
|
|
5c27b6 |
+ adminMAC = NULL;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (adminMAC || vlanTag >= 0) {
|
|
|
5c27b6 |
+ /* Set vlanTag and admin MAC using an RTM_SETLINK request sent to
|
|
|
5c27b6 |
+ * PFdevname+VF#, if mac != NULL this will set the "admin MAC" via
|
|
|
5c27b6 |
+ * the PF, *not* the actual VF MAC - the admin MAC only takes
|
|
|
5c27b6 |
+ * effect the next time the VF's driver is initialized (either in
|
|
|
5c27b6 |
+ * guest or host). if there is a vlanTag to set, it will take
|
|
|
5c27b6 |
+ * effect immediately though.
|
|
|
5c27b6 |
+ */
|
|
|
5c27b6 |
+ if (virNetDevSetVfConfig(pfDevName, vf, adminMAC, vlanTag) < 0)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ ret = 0;
|
|
|
5c27b6 |
+ cleanup:
|
|
|
5c27b6 |
+ VIR_FREE(pfDevOrig);
|
|
|
5c27b6 |
+ VIR_FREE(vfDevOrig);
|
|
|
5c27b6 |
+ return ret;
|
|
|
5c27b6 |
+}
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+#else /* defined(__linux__) && defined(HAVE_LIBNL) && defined(IFLA_VF_MAX) */
|
|
|
5c27b6 |
|
|
|
5c27b6 |
int
|
|
|
5c27b6 |
virNetDevReplaceNetConfig(const char *linkdev ATTRIBUTE_UNUSED,
|
|
|
5c27b6 |
@@ -1927,7 +2472,48 @@ virNetDevRestoreNetConfig(const char *linkdev ATTRIBUTE_UNUSED,
|
|
|
5c27b6 |
return -1;
|
|
|
5c27b6 |
}
|
|
|
5c27b6 |
|
|
|
5c27b6 |
-#endif /* defined(__linux__) && defined(HAVE_LIBNL) */
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+int
|
|
|
5c27b6 |
+virNetDevSaveNetConfig(const char *linkdev ATTRIBUTE_UNUSED,
|
|
|
5c27b6 |
+ int vf ATTRIBUTE_UNUSED,
|
|
|
5c27b6 |
+ const char *stateDir ATTRIBUTE_UNUSED,
|
|
|
5c27b6 |
+ bool saveVlan ATTRIBUTE_UNUSED)
|
|
|
5c27b6 |
+{
|
|
|
5c27b6 |
+ virReportSystemError(ENOSYS, "%s",
|
|
|
5c27b6 |
+ _("Unable to save net device config on this platform"));
|
|
|
5c27b6 |
+ return -1;
|
|
|
5c27b6 |
+}
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+int
|
|
|
5c27b6 |
+virNetDevReadNetConfig(const char *linkdev ATTRIBUTE_UNUSED,
|
|
|
5c27b6 |
+ int vf ATTRIBUTE_UNUSED,
|
|
|
5c27b6 |
+ const char *stateDir ATTRIBUTE_UNUSED,
|
|
|
5c27b6 |
+ virMacAddrPtr *adminMAC ATTRIBUTE_UNUSED,
|
|
|
5c27b6 |
+ virNetDevVLanPtr *vlan ATTRIBUTE_UNUSED,
|
|
|
5c27b6 |
+ virMacAddrPtr *MAC ATTRIBUTE_UNUSED)
|
|
|
5c27b6 |
+{
|
|
|
5c27b6 |
+ virReportSystemError(ENOSYS, "%s",
|
|
|
5c27b6 |
+ _("Unable to read net device config on this platform"));
|
|
|
5c27b6 |
+ return -1;
|
|
|
5c27b6 |
+}
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+int
|
|
|
5c27b6 |
+virNetDevSetNetConfig(const char *linkdev ATTRIBUTE_UNUSED,
|
|
|
5c27b6 |
+ int vf ATTRIBUTE_UNUSED,
|
|
|
5c27b6 |
+ const virMacAddr *adminMAC ATTRIBUTE_UNUSED,
|
|
|
5c27b6 |
+ virNetDevVlanPtr vlan ATTRIBUTE_UNUSED,
|
|
|
5c27b6 |
+ const virMacAddr *MAC ATTRIBUTE_UNUSED,
|
|
|
5c27b6 |
+ bool setVlan ATTRIBUTE_UNUSED)
|
|
|
5c27b6 |
+{
|
|
|
5c27b6 |
+ virReportSystemError(ENOSYS, "%s",
|
|
|
5c27b6 |
+ _("Unable to set net device config on this platform"));
|
|
|
5c27b6 |
+ return -1;
|
|
|
5c27b6 |
+}
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+#endif /* defined(__linux__) && defined(HAVE_LIBNL) && defined(IFLA_VF_MAX) */
|
|
|
5c27b6 |
|
|
|
5c27b6 |
VIR_ENUM_IMPL(virNetDevIfState,
|
|
|
5c27b6 |
VIR_NETDEV_IF_STATE_LAST,
|
|
|
5c27b6 |
diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h
|
|
|
5c27b6 |
index d534a3946..b5abf7a7b 100644
|
|
|
5c27b6 |
--- a/src/util/virnetdev.h
|
|
|
5c27b6 |
+++ b/src/util/virnetdev.h
|
|
|
5c27b6 |
@@ -187,6 +187,28 @@ int virNetDevGetVirtualFunctions(const char *pfname,
|
|
|
5c27b6 |
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
|
|
|
5c27b6 |
ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5) ATTRIBUTE_RETURN_CHECK;
|
|
|
5c27b6 |
|
|
|
5c27b6 |
+int virNetDevSaveNetConfig(const char *linkdev, int vf,
|
|
|
5c27b6 |
+ const char *stateDir,
|
|
|
5c27b6 |
+ bool saveVlan)
|
|
|
5c27b6 |
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+int
|
|
|
5c27b6 |
+virNetDevReadNetConfig(const char *linkdev, int vf,
|
|
|
5c27b6 |
+ const char *stateDir,
|
|
|
5c27b6 |
+ virMacAddrPtr *adminMAC,
|
|
|
5c27b6 |
+ virNetDevVlanPtr *vlan,
|
|
|
5c27b6 |
+ virMacAddrPtr *MAC)
|
|
|
5c27b6 |
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
|
|
|
5c27b6 |
+ ATTRIBUTE_NONNULL(5) ATTRIBUTE_NONNULL(6) ATTRIBUTE_RETURN_CHECK;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+int
|
|
|
5c27b6 |
+virNetDevSetNetConfig(const char *linkdev, int vf,
|
|
|
5c27b6 |
+ const virMacAddr *adminMAC,
|
|
|
5c27b6 |
+ virNetDevVlanPtr vlan,
|
|
|
5c27b6 |
+ const virMacAddr *MAC,
|
|
|
5c27b6 |
+ bool setVLan)
|
|
|
5c27b6 |
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
int virNetDevReplaceNetConfig(const char *linkdev, int vf,
|
|
|
5c27b6 |
const virMacAddr *macaddress,
|
|
|
5c27b6 |
virNetDevVlanPtr vlan,
|
|
|
5c27b6 |
--
|
|
|
5c27b6 |
2.12.2
|
|
|
5c27b6 |
|