From: Shivaprasad G Bhat <sbhat@xxxxxxxxxxxxxxxxxx> It is invalid to have secondary functions without the primary functions part of the domain. Prevents new domain define, but existing ones would not vanish. Signed-off-by: Shivaprasad G Bhat <sbhat@xxxxxxxxxxxxxxxxxx> Signed-off-by: Daniel Henrique Barboza <danielhb413@xxxxxxxxx> --- src/qemu/qemu_domain_address.c | 1 - src/qemu/qemu_domain_address.h | 4 ++ src/qemu/qemu_validate.c | 56 +++++++++++++++++++ .../hostdev-pci-no-primary-function.xml | 23 ++++++++ .../hostdev-pci-validate.args | 30 ++++++++++ .../qemuxml2argvdata/hostdev-pci-validate.xml | 29 ++++++++++ tests/qemuxml2argvtest.c | 8 +++ 7 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 tests/qemuxml2argvdata/hostdev-pci-no-primary-function.xml create mode 100644 tests/qemuxml2argvdata/hostdev-pci-validate.args create mode 100644 tests/qemuxml2argvdata/hostdev-pci-validate.xml diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index f431f4bb15..05ef4de100 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -1434,7 +1434,6 @@ qemuDomainSetupIsolationGroups(virDomainDefPtr def) * with the return value for that callback. * Zero on success. */ -static int qemuDomainPCIHostDevicesIter(qemuDomainPCIHostdevDataPtr data, virDomainPCIHostdevCallback cb) { diff --git a/src/qemu/qemu_domain_address.h b/src/qemu/qemu_domain_address.h index 198f813595..8d51456f5b 100644 --- a/src/qemu/qemu_domain_address.h +++ b/src/qemu/qemu_domain_address.h @@ -25,6 +25,7 @@ #include "domain_conf.h" #include "qemu_conf.h" #include "qemu_capabilities.h" +#include "qemu_domain.h" int qemuDomainGetSCSIControllerModel(const virDomainDef *def, const virDomainControllerDef *cont, @@ -57,6 +58,9 @@ void qemuDomainSetDeviceSlotAggregateIdx(virDomainDefPtr def, virDomainDeviceDefPtr dev); +int qemuDomainPCIHostDevicesIter(qemuDomainPCIHostdevDataPtr data, + virDomainPCIHostdevCallback cb); + int qemuDomainDefDeviceFindSlotAggregateIdx(virDomainDefPtr def, virDomainDeviceDefPtr dev); diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index 584d1375b8..956e3daf7d 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -762,6 +762,59 @@ qemuValidateDefGetVcpuHotplugGranularity(const virDomainDef *def) } +static int +qemuValidatePCIHostdevIsPrimaryFunction(qemuDomainPCIHostdevDataPtr data, + virDomainHostdevDefPtr hostdev) +{ + if (!data->device || !hostdev) + return 0; + + if ((hostdev->source.subsys.u.pci.addr.function == 0) && + (virHostdevPCIDevicesBelongToSameSlot(data->device, hostdev))) + return 1; + + return 0; +} + + +static int qemuValidateDomainDefPCIMultifunctionHostdev(qemuDomainPCIHostdevDataPtr data, + virDomainHostdevDefPtr hostdev) +{ + qemuDomainPCIHostdevdata hostdevIterData = {data->def, NULL, hostdev}; + + if (!virHostdevIsPCIMultifunctionDevice(hostdev) || + hostdev->source.subsys.u.pci.addr.function == 0) + return 0; + + /* If the device is non-zero function but its Primary function is not + * part of the domain, error out. + */ + if (!qemuDomainPCIHostDevicesIter(&hostdevIterData, + qemuValidatePCIHostdevIsPrimaryFunction)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Secondary functions of a PCI multifunction card " + "cannot be assigned to a domain without the " + "Primary function.")); + return -1; + } + + return 0; +} + + +static int qemuValidateDomainDefPCIHostdevs(const virDomainDef *def) +{ + qemuDomainPCIHostdevdata hostdevdata = {def, NULL, NULL}; + + if (qemuDomainPCIHostDevicesIter(&hostdevdata, + qemuValidateDomainDefPCIMultifunctionHostdev)) { + return -1; + } + + return 0; +} + + int qemuValidateDomainDef(const virDomainDef *def, void *opaque) @@ -966,6 +1019,9 @@ qemuValidateDomainDef(const virDomainDef *def, if (qemuValidateDomainDefConsole(def, qemuCaps) < 0) return -1; + if (qemuValidateDomainDefPCIHostdevs(def) < 0) + return -1; + if (cfg->vncTLS && cfg->vncTLSx509secretUUID && !virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_TLS_CREDS_X509)) { for (i = 0; i < def->ngraphics; i++) { diff --git a/tests/qemuxml2argvdata/hostdev-pci-no-primary-function.xml b/tests/qemuxml2argvdata/hostdev-pci-no-primary-function.xml new file mode 100644 index 0000000000..9cd844bbe7 --- /dev/null +++ b/tests/qemuxml2argvdata/hostdev-pci-no-primary-function.xml @@ -0,0 +1,23 @@ +<domain type='kvm'> + <name>delete</name> + <uuid>583a8e8e-f0ce-4f53-89ab-092862148b25</uuid> + <memory unit='KiB'>262144</memory> + <vcpu placement='static'>4</vcpu> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + </os> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='usb' index='0'/> + <controller type='ide' index='0'/> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0005' bus='0x90' slot='0x01' function='0x1'/> + </source> + </hostdev> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/hostdev-pci-validate.args b/tests/qemuxml2argvdata/hostdev-pci-validate.args new file mode 100644 index 0000000000..2a8508991e --- /dev/null +++ b/tests/qemuxml2argvdata/hostdev-pci-validate.args @@ -0,0 +1,30 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/tmp/lib/domain--1-delete \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/tmp/lib/domain--1-delete/.local/share \ +XDG_CACHE_HOME=/tmp/lib/domain--1-delete/.cache \ +XDG_CONFIG_HOME=/tmp/lib/domain--1-delete/.config \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-x86_64 \ +-name delete \ +-S \ +-machine pc,accel=kvm,usb=off,dump-guest-core=off \ +-m 256 \ +-realtime mlock=off \ +-smp 4,sockets=4,cores=1,threads=1 \ +-uuid 583a8e8e-f0ce-4f53-89ab-092862148b25 \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-delete/monitor.sock,\ +server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-no-acpi \ +-usb \ +-device vfio-pci,host=0000:06:12.1,id=hostdev0,bus=pci.0,addr=0x3 \ +-device vfio-pci,host=0000:06:12.2,id=hostdev1,bus=pci.0,addr=0x4 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5 diff --git a/tests/qemuxml2argvdata/hostdev-pci-validate.xml b/tests/qemuxml2argvdata/hostdev-pci-validate.xml new file mode 100644 index 0000000000..54797c2dda --- /dev/null +++ b/tests/qemuxml2argvdata/hostdev-pci-validate.xml @@ -0,0 +1,29 @@ +<domain type='kvm'> + <name>delete</name> + <uuid>583a8e8e-f0ce-4f53-89ab-092862148b25</uuid> + <memory unit='KiB'>262144</memory> + <vcpu placement='static'>4</vcpu> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + </os> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='usb' index='0'/> + <controller type='ide' index='0'/> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0000' bus='0x06' slot='0x12' function='0x1'/> + </source> + </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0000' bus='0x06' slot='0x12' function='0x2'/> + </source> + </hostdev> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index df11669cd5..84e8157e17 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1714,6 +1714,14 @@ mymain(void) QEMU_CAPS_DEVICE_VFIO_PCI); DO_TEST("hostdev-vfio-multidomain", QEMU_CAPS_DEVICE_VFIO_PCI); + DO_TEST("hostdev-pci-validate", + QEMU_CAPS_KVM, + X_QEMU_CAPS_NODEFCONFIG, X_QEMU_CAPS_HOST_PCI_MULTIDOMAIN, + QEMU_CAPS_DEVICE_VFIO_PCI); + DO_TEST_PARSE_ERROR("hostdev-pci-no-primary-function", + QEMU_CAPS_KVM, + X_QEMU_CAPS_NODEFCONFIG, X_QEMU_CAPS_HOST_PCI_MULTIDOMAIN, + QEMU_CAPS_DEVICE_VFIO_PCI); DO_TEST("hostdev-mdev-precreated", QEMU_CAPS_DEVICE_VFIO_PCI); DO_TEST_PARSE_ERROR("hostdev-mdev-src-address-invalid", -- 2.26.2