mirror of https://gitee.com/openkylin/libvirt.git
qemu: install port profile and mac address on netdev hostdevs
These changes are applied only if the hostdev has a parent net device (i.e. if it was defined as "<interface type='hostdev'>" rather than just "<hostdev>"). If the parent netdevice has virtual port information, the original virtualport associate functions are called (these set and restore both mac and port profile on an interface). Otherwise, only mac address is set on the device. Note that This is only supported for SR-IOV Virtual Functions (not for standard PCI or USB netdevs), and virtualport association is only supported for 802.1Qbh. For all other types of cards and types of virtualport, a "Config Unsupported" error is returned and the operation fails. Signed-off-by: Roopa Prabhu <roprabhu@cisco.com>
This commit is contained in:
parent
15bbfd8390
commit
ce43483caf
|
@ -750,6 +750,8 @@ virNetDevBandwidthParse;
|
||||||
# netdev_vportprofile_conf.h
|
# netdev_vportprofile_conf.h
|
||||||
virNetDevVPortProfileFormat;
|
virNetDevVPortProfileFormat;
|
||||||
virNetDevVPortProfileParse;
|
virNetDevVPortProfileParse;
|
||||||
|
virNetDevVPortTypeFromString;
|
||||||
|
virNetDevVPortTypeToString;
|
||||||
|
|
||||||
|
|
||||||
# network_conf.h
|
# network_conf.h
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "pci.h"
|
#include "pci.h"
|
||||||
#include "hostusb.h"
|
#include "hostusb.h"
|
||||||
|
#include "virnetdev.h"
|
||||||
|
|
||||||
static pciDeviceList *
|
static pciDeviceList *
|
||||||
qemuGetPciHostDeviceList(virDomainHostdevDefPtr *hostdevs, int nhostdevs)
|
qemuGetPciHostDeviceList(virDomainHostdevDefPtr *hostdevs, int nhostdevs)
|
||||||
|
@ -156,19 +157,192 @@ int qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
qemuDomainHostdevPciSysfsPath(virDomainHostdevDefPtr hostdev, char **sysfs_path)
|
||||||
|
{
|
||||||
|
struct pci_config_address config_address;
|
||||||
|
|
||||||
|
config_address.domain = hostdev->source.subsys.u.pci.domain;
|
||||||
|
config_address.bus = hostdev->source.subsys.u.pci.bus;
|
||||||
|
config_address.slot = hostdev->source.subsys.u.pci.slot;
|
||||||
|
config_address.function = hostdev->source.subsys.u.pci.function;
|
||||||
|
|
||||||
|
return pciConfigAddressToSysfsFile(&config_address, sysfs_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
qemuDomainHostdevIsVirtualFunction(virDomainHostdevDefPtr hostdev)
|
||||||
|
{
|
||||||
|
char *sysfs_path = NULL;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (qemuDomainHostdevPciSysfsPath(hostdev, &sysfs_path) < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = pciDeviceIsVirtualFunction(sysfs_path);
|
||||||
|
|
||||||
|
VIR_FREE(sysfs_path);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
qemuDomainHostdevNetDevice(virDomainHostdevDefPtr hostdev, char **linkdev,
|
||||||
|
int *vf)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
char *sysfs_path = NULL;
|
||||||
|
|
||||||
|
if (qemuDomainHostdevPciSysfsPath(hostdev, &sysfs_path) < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (pciDeviceIsVirtualFunction(sysfs_path) == 1) {
|
||||||
|
if (pciDeviceGetVirtualFunctionInfo(sysfs_path, linkdev,
|
||||||
|
vf) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
} else {
|
||||||
|
if (pciDeviceNetName(sysfs_path, linkdev) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
*vf = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FREE(sysfs_path);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
qemuDomainHostdevNetConfigVirtPortProfile(const char *linkdev, int vf,
|
||||||
|
virNetDevVPortProfilePtr virtPort,
|
||||||
|
const unsigned char *macaddr,
|
||||||
|
const unsigned char *uuid,
|
||||||
|
int associate)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (!virtPort)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
switch(virtPort->virtPortType) {
|
||||||
|
case VIR_NETDEV_VPORT_PROFILE_NONE:
|
||||||
|
case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:
|
||||||
|
case VIR_NETDEV_VPORT_PROFILE_8021QBG:
|
||||||
|
case VIR_NETDEV_VPORT_PROFILE_LAST:
|
||||||
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("virtualport type %s is "
|
||||||
|
"currently not supported on interfaces of type "
|
||||||
|
"hostdev"),
|
||||||
|
virNetDevVPortTypeToString(virtPort->virtPortType));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VIR_NETDEV_VPORT_PROFILE_8021QBH:
|
||||||
|
if (associate)
|
||||||
|
ret = virNetDevVPortProfileAssociate(NULL, virtPort, macaddr,
|
||||||
|
linkdev, vf, uuid,
|
||||||
|
VIR_NETDEV_VPORT_PROFILE_OP_CREATE, false);
|
||||||
|
else
|
||||||
|
ret = virNetDevVPortProfileDisassociate(NULL, virtPort,
|
||||||
|
macaddr, linkdev, vf,
|
||||||
|
VIR_NETDEV_VPORT_PROFILE_OP_DESTROY);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
qemuDomainHostdevNetConfigReplace(virDomainHostdevDefPtr hostdev,
|
||||||
|
const unsigned char *uuid,
|
||||||
|
char *stateDir)
|
||||||
|
{
|
||||||
|
char *linkdev = NULL;
|
||||||
|
virNetDevVPortProfilePtr virtPort;
|
||||||
|
int ret = -1;
|
||||||
|
int vf = -1;
|
||||||
|
int vlanid = -1;
|
||||||
|
int port_profile_associate = 1;
|
||||||
|
int isvf;
|
||||||
|
|
||||||
|
isvf = qemuDomainHostdevIsVirtualFunction(hostdev);
|
||||||
|
if (isvf <= 0) {
|
||||||
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||||
|
_("Interface type hostdev is currently supported on"
|
||||||
|
" SR-IOV Virtual Functions only"));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qemuDomainHostdevNetDevice(hostdev, &linkdev, &vf) < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
virtPort = virDomainNetGetActualVirtPortProfile(
|
||||||
|
hostdev->parent.data.net);
|
||||||
|
if (virtPort)
|
||||||
|
ret = qemuDomainHostdevNetConfigVirtPortProfile(linkdev, vf,
|
||||||
|
virtPort, hostdev->parent.data.net->mac, uuid,
|
||||||
|
port_profile_associate);
|
||||||
|
else
|
||||||
|
/* Set only mac */
|
||||||
|
ret = virNetDevReplaceNetConfig(linkdev, vf,
|
||||||
|
hostdev->parent.data.net->mac, vlanid,
|
||||||
|
stateDir);
|
||||||
|
VIR_FREE(linkdev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
qemuDomainHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev,
|
||||||
|
char *stateDir)
|
||||||
|
{
|
||||||
|
char *linkdev = NULL;
|
||||||
|
virNetDevVPortProfilePtr virtPort;
|
||||||
|
int ret = -1;
|
||||||
|
int vf = -1;
|
||||||
|
int port_profile_associate = 0;
|
||||||
|
int isvf;
|
||||||
|
|
||||||
|
isvf = qemuDomainHostdevIsVirtualFunction(hostdev);
|
||||||
|
if (isvf <= 0) {
|
||||||
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||||
|
_("Interface type hostdev is currently supported on"
|
||||||
|
" SR-IOV Virtual Functions only"));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qemuDomainHostdevNetDevice(hostdev, &linkdev, &vf) < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
virtPort = virDomainNetGetActualVirtPortProfile(
|
||||||
|
hostdev->parent.data.net);
|
||||||
|
if (virtPort)
|
||||||
|
ret = qemuDomainHostdevNetConfigVirtPortProfile(linkdev, vf, virtPort,
|
||||||
|
hostdev->parent.data.net->mac, NULL,
|
||||||
|
port_profile_associate);
|
||||||
|
else
|
||||||
|
ret = virNetDevRestoreNetConfig(linkdev, vf, stateDir);
|
||||||
|
|
||||||
|
VIR_FREE(linkdev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int qemuPrepareHostdevPCIDevices(struct qemud_driver *driver,
|
int qemuPrepareHostdevPCIDevices(struct qemud_driver *driver,
|
||||||
const char *name,
|
const char *name,
|
||||||
|
const unsigned char *uuid,
|
||||||
virDomainHostdevDefPtr *hostdevs,
|
virDomainHostdevDefPtr *hostdevs,
|
||||||
int nhostdevs)
|
int nhostdevs)
|
||||||
{
|
{
|
||||||
pciDeviceList *pcidevs;
|
pciDeviceList *pcidevs;
|
||||||
|
int last_processed_hostdev_vf = -1;
|
||||||
int i;
|
int i;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
if (!(pcidevs = qemuGetPciHostDeviceList(hostdevs, nhostdevs)))
|
if (!(pcidevs = qemuGetPciHostDeviceList(hostdevs, nhostdevs)))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* We have to use 7 loops here. *All* devices must
|
/* We have to use 9 loops here. *All* devices must
|
||||||
* be detached before we reset any of them, because
|
* be detached before we reset any of them, because
|
||||||
* in some cases you have to reset the whole PCI,
|
* in some cases you have to reset the whole PCI,
|
||||||
* which impacts all devices on it. Also, all devices
|
* which impacts all devices on it. Also, all devices
|
||||||
|
@ -225,7 +399,25 @@ int qemuPrepareHostdevPCIDevices(struct qemud_driver *driver,
|
||||||
goto reattachdevs;
|
goto reattachdevs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop 4: Now mark all the devices as active */
|
/* Loop 4: For SRIOV network devices, Now that we have detached the
|
||||||
|
* the network device, set the netdev config */
|
||||||
|
for (i = 0; i < nhostdevs; i++) {
|
||||||
|
virDomainHostdevDefPtr hostdev = hostdevs[i];
|
||||||
|
if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
|
||||||
|
continue;
|
||||||
|
if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
|
||||||
|
continue;
|
||||||
|
if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET &&
|
||||||
|
hostdev->parent.data.net) {
|
||||||
|
if (qemuDomainHostdevNetConfigReplace(hostdev, uuid,
|
||||||
|
driver->stateDir) < 0) {
|
||||||
|
goto resetvfnetconfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last_processed_hostdev_vf = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loop 5: Now mark all the devices as active */
|
||||||
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
|
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
|
||||||
pciDevice *dev = pciDeviceListGet(pcidevs, i);
|
pciDevice *dev = pciDeviceListGet(pcidevs, i);
|
||||||
if (pciDeviceListAdd(driver->activePciHostdevs, dev) < 0) {
|
if (pciDeviceListAdd(driver->activePciHostdevs, dev) < 0) {
|
||||||
|
@ -234,13 +426,13 @@ int qemuPrepareHostdevPCIDevices(struct qemud_driver *driver,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop 5: Now remove the devices from inactive list. */
|
/* Loop 6: Now remove the devices from inactive list. */
|
||||||
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
|
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
|
||||||
pciDevice *dev = pciDeviceListGet(pcidevs, i);
|
pciDevice *dev = pciDeviceListGet(pcidevs, i);
|
||||||
pciDeviceListDel(driver->inactivePciHostdevs, dev);
|
pciDeviceListDel(driver->inactivePciHostdevs, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop 6: Now set the used_by_domain of the device in
|
/* Loop 7: Now set the used_by_domain of the device in
|
||||||
* driver->activePciHostdevs as domain name.
|
* driver->activePciHostdevs as domain name.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
|
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
|
||||||
|
@ -252,7 +444,7 @@ int qemuPrepareHostdevPCIDevices(struct qemud_driver *driver,
|
||||||
pciDeviceSetUsedBy(activeDev, name);
|
pciDeviceSetUsedBy(activeDev, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop 7: Now set the original states for hostdev def */
|
/* Loop 8: Now set the original states for hostdev def */
|
||||||
for (i = 0; i < nhostdevs; i++) {
|
for (i = 0; i < nhostdevs; i++) {
|
||||||
pciDevice *dev;
|
pciDevice *dev;
|
||||||
pciDevice *pcidev;
|
pciDevice *pcidev;
|
||||||
|
@ -284,7 +476,7 @@ int qemuPrepareHostdevPCIDevices(struct qemud_driver *driver,
|
||||||
pciFreeDevice(dev);
|
pciFreeDevice(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop 8: Now steal all the devices from pcidevs */
|
/* Loop 9: Now steal all the devices from pcidevs */
|
||||||
while (pciDeviceListCount(pcidevs) > 0) {
|
while (pciDeviceListCount(pcidevs) > 0) {
|
||||||
pciDevice *dev = pciDeviceListGet(pcidevs, 0);
|
pciDevice *dev = pciDeviceListGet(pcidevs, 0);
|
||||||
pciDeviceListSteal(pcidevs, dev);
|
pciDeviceListSteal(pcidevs, dev);
|
||||||
|
@ -302,6 +494,15 @@ inactivedevs:
|
||||||
pciDeviceListSteal(driver->activePciHostdevs, dev);
|
pciDeviceListSteal(driver->activePciHostdevs, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resetvfnetconfig:
|
||||||
|
for (i = 0; i < last_processed_hostdev_vf; i++) {
|
||||||
|
virDomainHostdevDefPtr hostdev = hostdevs[i];
|
||||||
|
if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET &&
|
||||||
|
hostdev->parent.data.net) {
|
||||||
|
qemuDomainHostdevNetConfigRestore(hostdev, driver->stateDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
reattachdevs:
|
reattachdevs:
|
||||||
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
|
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
|
||||||
pciDevice *dev = pciDeviceListGet(pcidevs, i);
|
pciDevice *dev = pciDeviceListGet(pcidevs, i);
|
||||||
|
@ -317,10 +518,10 @@ static int
|
||||||
qemuPrepareHostPCIDevices(struct qemud_driver *driver,
|
qemuPrepareHostPCIDevices(struct qemud_driver *driver,
|
||||||
virDomainDefPtr def)
|
virDomainDefPtr def)
|
||||||
{
|
{
|
||||||
return qemuPrepareHostdevPCIDevices(driver, def->name, def->hostdevs, def->nhostdevs);
|
return qemuPrepareHostdevPCIDevices(driver, def->name, def->uuid,
|
||||||
|
def->hostdevs, def->nhostdevs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
qemuPrepareHostdevUSBDevices(struct qemud_driver *driver,
|
qemuPrepareHostdevUSBDevices(struct qemud_driver *driver,
|
||||||
const char *name,
|
const char *name,
|
||||||
|
@ -494,8 +695,10 @@ void qemuDomainReAttachHostdevDevices(struct qemud_driver *driver,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Again 3 loops; mark all devices as inactive before reset
|
/* Again 4 loops; mark all devices as inactive before reset
|
||||||
* them and reset all the devices before re-attach */
|
* them and reset all the devices before re-attach.
|
||||||
|
* Attach mac and port profile parameters to devices
|
||||||
|
*/
|
||||||
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
|
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
|
||||||
pciDevice *dev = pciDeviceListGet(pcidevs, i);
|
pciDevice *dev = pciDeviceListGet(pcidevs, i);
|
||||||
pciDevice *activeDev = NULL;
|
pciDevice *activeDev = NULL;
|
||||||
|
@ -514,6 +717,22 @@ void qemuDomainReAttachHostdevDevices(struct qemud_driver *driver,
|
||||||
pciDeviceListSteal(driver->activePciHostdevs, dev);
|
pciDeviceListSteal(driver->activePciHostdevs, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For SRIOV net host devices, unset mac and port profile before
|
||||||
|
* reset and reattach device
|
||||||
|
*/
|
||||||
|
for (i = 0; i < nhostdevs; i++) {
|
||||||
|
virDomainHostdevDefPtr hostdev = hostdevs[i];
|
||||||
|
if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
|
||||||
|
continue;
|
||||||
|
if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
|
||||||
|
continue;
|
||||||
|
if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET &&
|
||||||
|
hostdev->parent.data.net) {
|
||||||
|
qemuDomainHostdevNetConfigRestore(hostdev, driver->stateDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
|
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
|
||||||
pciDevice *dev = pciDeviceListGet(pcidevs, i);
|
pciDevice *dev = pciDeviceListGet(pcidevs, i);
|
||||||
if (pciResetDevice(dev, driver->activePciHostdevs,
|
if (pciResetDevice(dev, driver->activePciHostdevs,
|
||||||
|
@ -540,5 +759,6 @@ void qemuDomainReAttachHostDevices(struct qemud_driver *driver,
|
||||||
if (!def->nhostdevs)
|
if (!def->nhostdevs)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
qemuDomainReAttachHostdevDevices(driver, def->name, def->hostdevs, def->nhostdevs);
|
qemuDomainReAttachHostdevDevices(driver, def->name, def->hostdevs,
|
||||||
|
def->nhostdevs);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ int qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
|
||||||
virDomainDefPtr def);
|
virDomainDefPtr def);
|
||||||
int qemuPrepareHostdevPCIDevices(struct qemud_driver *driver,
|
int qemuPrepareHostdevPCIDevices(struct qemud_driver *driver,
|
||||||
const char *name,
|
const char *name,
|
||||||
|
const unsigned char *uuid,
|
||||||
virDomainHostdevDefPtr *hostdevs,
|
virDomainHostdevDefPtr *hostdevs,
|
||||||
int nhostdevs);
|
int nhostdevs);
|
||||||
int qemuPrepareHostdevUSBDevices(struct qemud_driver *driver,
|
int qemuPrepareHostdevUSBDevices(struct qemud_driver *driver,
|
||||||
|
@ -46,6 +47,11 @@ void qemuDomainReAttachHostdevDevices(struct qemud_driver *driver,
|
||||||
int nhostdevs);
|
int nhostdevs);
|
||||||
void qemuDomainReAttachHostDevices(struct qemud_driver *driver,
|
void qemuDomainReAttachHostDevices(struct qemud_driver *driver,
|
||||||
virDomainDefPtr def);
|
virDomainDefPtr def);
|
||||||
|
int qemuDomainHostdevIsVirtualFunction(virDomainHostdevDefPtr hostdev);
|
||||||
|
int qemuDomainHostdevNetConfigReplace(virDomainHostdevDefPtr hostdev,
|
||||||
|
const unsigned char *uuid,
|
||||||
|
char *stateDir);
|
||||||
|
int qemuDomainHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev,
|
||||||
|
char *stateDir);
|
||||||
|
|
||||||
#endif /* __QEMU_HOSTDEV_H__ */
|
#endif /* __QEMU_HOSTDEV_H__ */
|
||||||
|
|
|
@ -927,7 +927,8 @@ int qemuDomainAttachHostPciDevice(struct qemud_driver *driver,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qemuPrepareHostdevPCIDevices(driver, vm->def->name, &hostdev, 1) < 0)
|
if (qemuPrepareHostdevPCIDevices(driver, vm->def->name, vm->def->uuid,
|
||||||
|
&hostdev, 1) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
||||||
|
@ -1886,6 +1887,13 @@ qemuDomainDetachHostPciDevice(struct qemud_driver *driver,
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For SRIOV net host devices, unset mac and port profile before
|
||||||
|
* reset and reattach device
|
||||||
|
*/
|
||||||
|
if (detach->parent.data.net)
|
||||||
|
qemuDomainHostdevNetConfigRestore(detach, driver->stateDir);
|
||||||
|
|
||||||
pci = pciGetDevice(subsys->u.pci.domain, subsys->u.pci.bus,
|
pci = pciGetDevice(subsys->u.pci.domain, subsys->u.pci.bus,
|
||||||
subsys->u.pci.slot, subsys->u.pci.function);
|
subsys->u.pci.slot, subsys->u.pci.function);
|
||||||
if (pci) {
|
if (pci) {
|
||||||
|
|
Loading…
Reference in New Issue