/*
* qemu_validate.c: QEMU general validation functions
*
* Copyright IBM Corp, 2020
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*/
#include
#include "qemu_validate.h"
#include "qemu_block.h"
#include "qemu_command.h"
#include "qemu_domain.h"
#include "domain_conf.h"
#include "virlog.h"
#include "virutil.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
#define QEMU_MAX_VCPUS_WITHOUT_EIM 255
VIR_LOG_INIT("qemu.qemu_validate");
static int
qemuValidateDomainDefPSeriesFeature(const virDomainDef *def,
virQEMUCapsPtr qemuCaps,
int feature)
{
const char *str;
if (def->features[feature] != VIR_TRISTATE_SWITCH_ABSENT &&
!qemuDomainIsPSeries(def)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("The '%s' feature is not supported for "
"architecture '%s' or machine type '%s'"),
virDomainFeatureTypeToString(feature),
virArchToString(def->os.arch),
def->os.machine);
return -1;
}
if (def->features[feature] == VIR_TRISTATE_SWITCH_ABSENT)
return 0;
switch (feature) {
case VIR_DOMAIN_FEATURE_HPT:
if (def->features[feature] != VIR_TRISTATE_SWITCH_ON)
break;
if (def->hpt_resizing != VIR_DOMAIN_HPT_RESIZING_NONE) {
if (!virQEMUCapsGet(qemuCaps,
QEMU_CAPS_MACHINE_PSERIES_RESIZE_HPT)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("HTP resizing is not supported by this "
"QEMU binary"));
return -1;
}
str = virDomainHPTResizingTypeToString(def->hpt_resizing);
if (!str) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Invalid setting for HPT resizing"));
return -1;
}
}
if (def->hpt_maxpagesize > 0 &&
!virQEMUCapsGet(qemuCaps,
QEMU_CAPS_MACHINE_PSERIES_CAP_HPT_MAX_PAGE_SIZE)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Configuring the page size for HPT guests "
"is not supported by this QEMU binary"));
return -1;
}
break;
case VIR_DOMAIN_FEATURE_HTM:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_MACHINE_PSERIES_CAP_HTM)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("HTM configuration is not supported by this "
"QEMU binary"));
return -1;
}
str = virTristateSwitchTypeToString(def->features[feature]);
if (!str) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Invalid setting for HTM state"));
return -1;
}
break;
case VIR_DOMAIN_FEATURE_NESTED_HV:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_MACHINE_PSERIES_CAP_NESTED_HV)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Nested HV configuration is not supported by "
"this QEMU binary"));
return -1;
}
str = virTristateSwitchTypeToString(def->features[feature]);
if (!str) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Invalid setting for nested HV state"));
return -1;
}
break;
case VIR_DOMAIN_FEATURE_CCF_ASSIST:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_MACHINE_PSERIES_CAP_CCF_ASSIST)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("ccf-assist configuration is not supported by "
"this QEMU binary"));
return -1;
}
str = virTristateSwitchTypeToString(def->features[feature]);
if (!str) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Invalid setting for ccf-assist state"));
return -1;
}
break;
case VIR_DOMAIN_FEATURE_CFPC:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_MACHINE_PSERIES_CAP_CFPC)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("cfpc configuration is not supported by "
"this QEMU binary"));
return -1;
}
break;
case VIR_DOMAIN_FEATURE_SBBC:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_MACHINE_PSERIES_CAP_SBBC)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("sbbc configuration is not supported by "
"this QEMU binary"));
return -1;
}
break;
case VIR_DOMAIN_FEATURE_IBS:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_MACHINE_PSERIES_CAP_IBS)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("ibs configuration is not supported by "
"this QEMU binary"));
return -1;
}
break;
}
return 0;
}
static int
qemuValidateDomainDefFeatures(const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
size_t i;
for (i = 0; i < VIR_DOMAIN_FEATURE_LAST; i++) {
const char *featureName = virDomainFeatureTypeToString(i);
switch ((virDomainFeature) i) {
case VIR_DOMAIN_FEATURE_IOAPIC:
if (def->features[i] != VIR_DOMAIN_IOAPIC_NONE) {
if (!ARCH_IS_X86(def->os.arch)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("The '%s' feature is not supported for "
"architecture '%s' or machine type '%s'"),
featureName,
virArchToString(def->os.arch),
def->os.machine);
return -1;
}
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_MACHINE_KERNEL_IRQCHIP)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("I/O APIC tuning is not supported by "
"this QEMU binary"));
return -1;
}
switch ((virDomainIOAPIC) def->features[i]) {
case VIR_DOMAIN_IOAPIC_QEMU:
if (!virQEMUCapsGet(qemuCaps,
QEMU_CAPS_MACHINE_KERNEL_IRQCHIP_SPLIT)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("split I/O APIC is not supported by this "
"QEMU binary"));
return -1;
}
break;
case VIR_DOMAIN_IOAPIC_KVM:
case VIR_DOMAIN_IOAPIC_NONE:
case VIR_DOMAIN_IOAPIC_LAST:
break;
}
}
break;
case VIR_DOMAIN_FEATURE_HPT:
case VIR_DOMAIN_FEATURE_HTM:
case VIR_DOMAIN_FEATURE_NESTED_HV:
case VIR_DOMAIN_FEATURE_CCF_ASSIST:
case VIR_DOMAIN_FEATURE_CFPC:
case VIR_DOMAIN_FEATURE_SBBC:
case VIR_DOMAIN_FEATURE_IBS:
if (qemuValidateDomainDefPSeriesFeature(def, qemuCaps, i) < 0)
return -1;
break;
case VIR_DOMAIN_FEATURE_GIC:
if (def->features[i] == VIR_TRISTATE_SWITCH_ON &&
!qemuDomainIsARMVirt(def)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("The '%s' feature is not supported for "
"architecture '%s' or machine type '%s'"),
featureName,
virArchToString(def->os.arch),
def->os.machine);
return -1;
}
break;
case VIR_DOMAIN_FEATURE_SMM:
if (def->features[i] != VIR_TRISTATE_SWITCH_ABSENT &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_MACHINE_SMM_OPT)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("smm is not available with this QEMU binary"));
return -1;
}
break;
case VIR_DOMAIN_FEATURE_KVM:
if (def->kvm_features[VIR_DOMAIN_KVM_DEDICATED] == VIR_TRISTATE_SWITCH_ON &&
(!def->cpu || def->cpu->mode != VIR_CPU_MODE_HOST_PASSTHROUGH)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("kvm-hint-dedicated=on is only applicable "
"for cpu host-passthrough"));
return -1;
}
break;
case VIR_DOMAIN_FEATURE_VMPORT:
if (def->features[i] != VIR_TRISTATE_SWITCH_ABSENT &&
!virQEMUCapsSupportsVmport(qemuCaps, def)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("vmport is not available "
"with this QEMU binary"));
return -1;
}
break;
case VIR_DOMAIN_FEATURE_VMCOREINFO:
if (def->features[i] == VIR_TRISTATE_SWITCH_ON &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VMCOREINFO)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("vmcoreinfo is not available "
"with this QEMU binary"));
return -1;
}
break;
case VIR_DOMAIN_FEATURE_APIC:
/* The kvm_pv_eoi feature is x86-only. */
if (def->features[i] != VIR_TRISTATE_SWITCH_ABSENT &&
def->apic_eoi != VIR_TRISTATE_SWITCH_ABSENT &&
!ARCH_IS_X86(def->os.arch)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("The 'eoi' attribute of the '%s' feature "
"is not supported for architecture '%s' or "
"machine type '%s'"),
featureName,
virArchToString(def->os.arch),
def->os.machine);
return -1;
}
break;
case VIR_DOMAIN_FEATURE_PVSPINLOCK:
if (def->features[i] != VIR_TRISTATE_SWITCH_ABSENT &&
!ARCH_IS_X86(def->os.arch)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("The '%s' feature is not supported for "
"architecture '%s' or machine type '%s'"),
featureName,
virArchToString(def->os.arch),
def->os.machine);
return -1;
}
break;
case VIR_DOMAIN_FEATURE_HYPERV:
if (def->features[i] != VIR_TRISTATE_SWITCH_ABSENT &&
!ARCH_IS_X86(def->os.arch) && !qemuDomainIsARMVirt(def)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Hyperv features are not supported for "
"architecture '%s' or machine type '%s'"),
virArchToString(def->os.arch),
def->os.machine);
return -1;
}
break;
case VIR_DOMAIN_FEATURE_PMU:
if (def->features[i] == VIR_TRISTATE_SWITCH_OFF &&
ARCH_IS_PPC64(def->os.arch)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("PMU is always enabled for architecture '%s'"),
virArchToString(def->os.arch));
return -1;
}
break;
case VIR_DOMAIN_FEATURE_XEN:
case VIR_DOMAIN_FEATURE_ACPI:
case VIR_DOMAIN_FEATURE_PAE:
case VIR_DOMAIN_FEATURE_HAP:
case VIR_DOMAIN_FEATURE_VIRIDIAN:
case VIR_DOMAIN_FEATURE_PRIVNET:
case VIR_DOMAIN_FEATURE_CAPABILITIES:
case VIR_DOMAIN_FEATURE_MSRS:
case VIR_DOMAIN_FEATURE_LAST:
break;
}
}
return 0;
}
static int
qemuValidateDomainDefCpu(virQEMUDriverPtr driver,
const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
virCPUDefPtr cpu = def->cpu;
if (!cpu)
return 0;
if (!cpu->model && cpu->mode == VIR_CPU_MODE_CUSTOM)
return 0;
switch ((virCPUMode) cpu->mode) {
case VIR_CPU_MODE_HOST_PASSTHROUGH:
if (def->os.arch == VIR_ARCH_ARMV7L &&
driver->hostarch == VIR_ARCH_AARCH64) {
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CPU_AARCH64_OFF)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("QEMU binary does not support CPU "
"host-passthrough for armv7l on "
"aarch64 host"));
return -1;
}
}
if (cpu->migratable &&
cpu->migratable != VIR_TRISTATE_SWITCH_OFF &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CPU_MIGRATABLE)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Migratable attribute for host-passthrough "
"CPU is not supported by QEMU binary"));
return -1;
}
break;
case VIR_CPU_MODE_HOST_MODEL:
/* qemu_command.c will error out if cpu->mode is HOST_MODEL for
* every arch but PPC64. However, we can't move this validation
* here because non-PPC64 archs will translate HOST_MODEL to
* something else during domain start, changing cpu->mode to
* CUSTOM.
*/
break;
case VIR_CPU_MODE_CUSTOM:
case VIR_CPU_MODE_LAST:
break;
}
return 0;
}
static int
qemuValidateDomainDefClockTimers(const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
size_t i;
for (i = 0; i < def->clock.ntimers; i++) {
virDomainTimerDefPtr timer = def->clock.timers[i];
switch ((virDomainTimerNameType)timer->name) {
case VIR_DOMAIN_TIMER_NAME_PLATFORM:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("unsupported timer type (name) '%s'"),
virDomainTimerNameTypeToString(timer->name));
return -1;
case VIR_DOMAIN_TIMER_NAME_TSC:
case VIR_DOMAIN_TIMER_NAME_KVMCLOCK:
case VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK:
if (!ARCH_IS_X86(def->os.arch) && timer->present == 1) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Configuring the '%s' timer is not supported "
"for virtType=%s arch=%s machine=%s guests"),
virDomainTimerNameTypeToString(timer->name),
virDomainVirtTypeToString(def->virtType),
virArchToString(def->os.arch),
def->os.machine);
return -1;
}
break;
case VIR_DOMAIN_TIMER_NAME_LAST:
break;
case VIR_DOMAIN_TIMER_NAME_RTC:
switch (timer->track) {
case -1: /* unspecified - use hypervisor default */
case VIR_DOMAIN_TIMER_TRACK_GUEST:
case VIR_DOMAIN_TIMER_TRACK_WALL:
break;
case VIR_DOMAIN_TIMER_TRACK_BOOT:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("unsupported rtc timer track '%s'"),
virDomainTimerTrackTypeToString(timer->track));
return -1;
}
switch (timer->tickpolicy) {
case -1:
case VIR_DOMAIN_TIMER_TICKPOLICY_DELAY:
/* This is the default - missed ticks delivered when
next scheduled, at normal rate */
break;
case VIR_DOMAIN_TIMER_TICKPOLICY_CATCHUP:
/* deliver ticks at a faster rate until caught up */
break;
case VIR_DOMAIN_TIMER_TICKPOLICY_MERGE:
case VIR_DOMAIN_TIMER_TICKPOLICY_DISCARD:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("unsupported rtc timer tickpolicy '%s'"),
virDomainTimerTickpolicyTypeToString(
timer->tickpolicy));
return -1;
}
break;
case VIR_DOMAIN_TIMER_NAME_PIT:
switch (timer->tickpolicy) {
case -1:
case VIR_DOMAIN_TIMER_TICKPOLICY_DELAY:
case VIR_DOMAIN_TIMER_TICKPOLICY_DISCARD:
break;
case VIR_DOMAIN_TIMER_TICKPOLICY_CATCHUP:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM_PIT_TICK_POLICY)) {
/* can't catchup if we don't have kvm-pit */
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("unsupported pit tickpolicy '%s'"),
virDomainTimerTickpolicyTypeToString(
timer->tickpolicy));
return -1;
}
break;
case VIR_DOMAIN_TIMER_TICKPOLICY_MERGE:
/* no way to support this mode for pit in qemu */
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("unsupported pit tickpolicy '%s'"),
virDomainTimerTickpolicyTypeToString(
timer->tickpolicy));
return -1;
}
break;
case VIR_DOMAIN_TIMER_NAME_HPET:
/* no hpet timer available. The only possible action
is to raise an error if present="yes" */
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_NO_HPET) &&
timer->present == 1) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
"%s", _("hpet timer is not supported"));
return -1;
}
break;
case VIR_DOMAIN_TIMER_NAME_ARMVTIMER:
if (def->virtType != VIR_DOMAIN_VIRT_KVM ||
!qemuDomainIsARMVirt(def)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Configuring the '%s' timer is not supported "
"for virtType=%s arch=%s machine=%s guests"),
virDomainTimerNameTypeToString(timer->name),
virDomainVirtTypeToString(def->virtType),
virArchToString(def->os.arch),
def->os.machine);
return -1;
}
if (timer->present == 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("The '%s' timer can't be disabled"),
virDomainTimerNameTypeToString(timer->name));
return -1;
}
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CPU_KVM_NO_ADJVTIME)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Configuring the '%s' timer is not supported "
"with this QEMU binary"),
virDomainTimerNameTypeToString(timer->name));
return -1;
}
switch (timer->tickpolicy) {
case -1:
case VIR_DOMAIN_TIMER_TICKPOLICY_DELAY:
case VIR_DOMAIN_TIMER_TICKPOLICY_DISCARD:
break;
case VIR_DOMAIN_TIMER_TICKPOLICY_CATCHUP:
case VIR_DOMAIN_TIMER_TICKPOLICY_MERGE:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("The '%s' timer does not support tickpolicy '%s'"),
virDomainTimerNameTypeToString(timer->name),
virDomainTimerTickpolicyTypeToString(timer->tickpolicy));
return -1;
}
break;
}
}
return 0;
}
static int
qemuValidateDomainDefPM(const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
bool q35Dom = qemuDomainIsQ35(def);
if (def->pm.s3) {
bool q35ICH9_S3 = q35Dom &&
virQEMUCapsGet(qemuCaps, QEMU_CAPS_ICH9_DISABLE_S3);
if (!q35ICH9_S3 && !virQEMUCapsGet(qemuCaps, QEMU_CAPS_PIIX_DISABLE_S3)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
"%s", _("setting ACPI S3 not supported"));
return -1;
}
}
if (def->pm.s4) {
bool q35ICH9_S4 = q35Dom &&
virQEMUCapsGet(qemuCaps, QEMU_CAPS_ICH9_DISABLE_S4);
if (!q35ICH9_S4 && !virQEMUCapsGet(qemuCaps, QEMU_CAPS_PIIX_DISABLE_S4)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
"%s", _("setting ACPI S4 not supported"));
return -1;
}
}
return 0;
}
static int
qemuValidateDomainDefBoot(const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
if (def->os.loader &&
def->os.loader->secure == VIR_TRISTATE_BOOL_YES) {
/* These are the QEMU implementation limitations. But we
* have to live with them for now. */
if (!qemuDomainIsQ35(def)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Secure boot is supported with q35 machine types only"));
return -1;
}
/* Now, technically it is possible to have secure boot on
* 32bits too, but that would require some -cpu xxx magic
* too. Not worth it unless we are explicitly asked. */
if (def->os.arch != VIR_ARCH_X86_64) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Secure boot is supported for x86_64 architecture only"));
return -1;
}
/* SMM will be enabled by qemuFirmwareFillDomain() if needed. */
if (def->os.firmware == VIR_DOMAIN_OS_DEF_FIRMWARE_NONE &&
def->features[VIR_DOMAIN_FEATURE_SMM] != VIR_TRISTATE_SWITCH_ON) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Secure boot requires SMM feature enabled"));
return -1;
}
}
if (def->os.bios.rt_set) {
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_REBOOT_TIMEOUT)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("reboot timeout is not supported "
"by this QEMU binary"));
return -1;
}
}
if (def->os.bm_timeout_set) {
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SPLASH_TIMEOUT)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("splash timeout is not supported "
"by this QEMU binary"));
return -1;
}
}
return 0;
}
/**
* qemuValidateDefGetVcpuHotplugGranularity:
* @def: domain definition
*
* With QEMU 2.7 and newer, vCPUs can only be hotplugged in groups that
* respect the guest's hotplug granularity; because of that, QEMU will
* not allow guests to start unless the initial number of vCPUs is a
* multiple of the hotplug granularity.
*
* Returns the vCPU hotplug granularity.
*/
static unsigned int
qemuValidateDefGetVcpuHotplugGranularity(const virDomainDef *def)
{
/* If the guest CPU topology has not been configured, assume we
* can hotplug vCPUs one at a time */
if (!def->cpu || def->cpu->sockets == 0)
return 1;
/* For pSeries guests, hotplug can only be performed one core
* at a time, so the vCPU hotplug granularity is the number
* of threads per core */
if (qemuDomainIsPSeries(def))
return def->cpu->threads;
/* In all other cases, we can hotplug vCPUs one at a time */
return 1;
}
static int
qemuValidateDomainVCpuTopology(const virDomainDef *def, virQEMUCapsPtr qemuCaps)
{
unsigned int maxCpus = virQEMUCapsGetMachineMaxCpus(qemuCaps, def->virtType,
def->os.machine);
if (virDomainDefGetVcpus(def) == 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Domain requires at least 1 vCPU"));
return -1;
}
if (maxCpus > 0 && virDomainDefGetVcpusMax(def) > maxCpus) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Maximum CPUs greater than specified machine "
"type limit %u"), maxCpus);
return -1;
}
/* QEMU 2.7 (detected via the availability of query-hotpluggable-cpus)
* enforces stricter rules than previous versions when it comes to guest
* CPU topology. Verify known constraints are respected */
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_QUERY_HOTPLUGGABLE_CPUS)) {
unsigned int topologycpus;
unsigned int granularity;
unsigned int numacpus;
/* Starting from QEMU 2.5, max vCPU count and overall vCPU topology
* must agree. We only actually enforce this with QEMU 2.7+, due
* to the capability check above */
if (virDomainDefGetVcpusTopology(def, &topologycpus) == 0) {
if (topologycpus != virDomainDefGetVcpusMax(def)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("CPU topology doesn't match maximum vcpu count"));
return -1;
}
numacpus = virDomainNumaGetCPUCountTotal(def->numa);
if ((numacpus != 0) && (topologycpus != numacpus)) {
VIR_WARN("CPU topology doesn't match numa CPU count; "
"partial NUMA mapping is obsoleted and will "
"be removed in future");
}
}
/* vCPU hotplug granularity must be respected */
granularity = qemuValidateDefGetVcpuHotplugGranularity(def);
if ((virDomainDefGetVcpus(def) % granularity) != 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("vCPUs count must be a multiple of the vCPU "
"hotplug granularity (%u)"),
granularity);
return -1;
}
}
if (ARCH_IS_X86(def->os.arch) &&
virDomainDefGetVcpusMax(def) > QEMU_MAX_VCPUS_WITHOUT_EIM) {
if (!qemuDomainIsQ35(def)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("more than %d vCPUs are only supported on "
"q35-based machine types"),
QEMU_MAX_VCPUS_WITHOUT_EIM);
return -1;
}
if (!def->iommu || def->iommu->eim != VIR_TRISTATE_SWITCH_ON) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("more than %d vCPUs require extended interrupt "
"mode enabled on the iommu device"),
QEMU_MAX_VCPUS_WITHOUT_EIM);
return -1;
}
}
return 0;
}
static int
qemuValidateDomainDefMemory(const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
const long system_page_size = virGetSystemPageSizeKB();
const virDomainMemtune *mem = &def->mem;
if (mem->nhugepages == 0)
return 0;
if (mem->allocation == VIR_DOMAIN_MEMORY_ALLOCATION_ONDEMAND) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("hugepages are not allowed with memory "
"allocation ondemand"));
return -1;
}
if (mem->source == VIR_DOMAIN_MEMORY_SOURCE_ANONYMOUS) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("hugepages are not allowed with anonymous "
"memory source"));
return -1;
}
if (mem->source == VIR_DOMAIN_MEMORY_SOURCE_MEMFD &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_MEMFD_HUGETLB)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("hugepages is not supported with memfd memory source"));
return -1;
}
/* We can't guarantee any other mem.access
* if no guest NUMA nodes are defined. */
if (mem->hugepages[0].size != system_page_size &&
virDomainNumaGetNodeCount(def->numa) == 0 &&
mem->access != VIR_DOMAIN_MEMORY_ACCESS_DEFAULT &&
mem->access != VIR_DOMAIN_MEMORY_ACCESS_PRIVATE) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("memory access mode '%s' not supported "
"without guest numa node"),
virDomainMemoryAccessTypeToString(mem->access));
return -1;
}
if (mem->nosharepages && !virQEMUCapsGet(qemuCaps, QEMU_CAPS_MEM_MERGE)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("disable shared memory is not available "
"with this QEMU binary"));
return -1;
}
return 0;
}
static int
qemuValidateDomainDefNuma(const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
const long system_page_size = virGetSystemPageSizeKB();
size_t ncells = virDomainNumaGetNodeCount(def->numa);
size_t i;
bool hasMemoryCap = virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_RAM) ||
virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_FILE) ||
virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_MEMFD);
bool needBacking = false;
if (virDomainNumatuneHasPerNodeBinding(def->numa) && !hasMemoryCap) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Per-node memory binding is not supported "
"with this QEMU"));
return -1;
}
if (def->mem.nhugepages &&
def->mem.hugepages[0].size != system_page_size &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_FILE)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("huge pages per NUMA node are not "
"supported with this QEMU"));
return -1;
}
for (i = 0; i < ncells; i++) {
virBitmapPtr cpumask = virDomainNumaGetNodeCpumask(def->numa, i);
if (!hasMemoryCap &&
virDomainNumaGetNodeMemoryAccessMode(def->numa, i)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Shared memory mapping is not supported "
"with this QEMU"));
return -1;
}
if (cpumask) {
g_autofree char * cpumaskStr = NULL;
if (!(cpumaskStr = virBitmapFormat(cpumask)))
return -1;
if (strchr(cpumaskStr, ',') &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_NUMA)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("disjoint NUMA cpu ranges are not supported "
"with this QEMU"));
return -1;
}
}
}
if (virDomainNumaNodesDistancesAreBeingSet(def->numa) &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_NUMA_DIST)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("setting NUMA distances is not "
"supported with this qemu"));
return -1;
}
if (!virQEMUCapsGetMachineNumaMemSupported(qemuCaps,
def->virtType,
def->os.machine)) {
needBacking = true;
}
if (virDomainNumaHasHMAT(def->numa)) {
needBacking = true;
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_NUMA_HMAT)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("HMAT is not supported with this QEMU"));
return -1;
}
}
if (needBacking && !hasMemoryCap) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("NUMA without specified memory backing is not "
"supported with this QEMU binary"));
return -1;
}
return 0;
}
static int
qemuValidateDomainDefConsole(const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
size_t i;
/* Explicit console devices */
for (i = 0; i < def->nconsoles; i++) {
virDomainChrDefPtr console = def->consoles[i];
switch (console->targetType) {
case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SCLP:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_SCLPCONSOLE)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("sclpconsole is not supported in this QEMU binary"));
return -1;
}
break;
case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SCLPLM:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_SCLPLMCONSOLE)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("sclplmconsole is not supported in this QEMU binary"));
return -1;
}
break;
case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO:
case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL:
break;
default:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("unsupported console target type %s"),
NULLSTR(virDomainChrConsoleTargetTypeToString(console->targetType)));
return -1;
}
}
return 0;
}
static int
qemuValidateDomainDefSysinfo(const virSysinfoDef *def,
virQEMUCapsPtr qemuCaps)
{
size_t i;
if (def->type == VIR_SYSINFO_FWCFG &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_FW_CFG)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("fw_cfg is not supported with this QEMU"));
return -1;
}
for (i = 0; i < def->nfw_cfgs; i++) {
const virSysinfoFWCfgDef *f = &def->fw_cfgs[i];
if (!STRPREFIX(f->name, "opt/")) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Invalid firmware name"));
return -1;
}
if (STRPREFIX(f->name, "opt/ovmf/") ||
STRPREFIX(f->name, "opt/org.qemu/")) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("That firmware name is reserved"));
return -1;
}
}
return 0;
}
static int
qemuValidateDomainDefPanic(const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
size_t i;
for (i = 0; i < def->npanics; i++) {
switch ((virDomainPanicModel) def->panics[i]->model) {
case VIR_DOMAIN_PANIC_MODEL_S390:
/* For s390 guests, the hardware provides the same
* functionality as the pvpanic device. The address
* cannot be configured by the user */
if (!ARCH_IS_S390(def->os.arch)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("only S390 guests support "
"panic device of model 's390'"));
return -1;
}
if (def->panics[i]->info.type !=
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("setting the panic device address is not "
"supported for model 's390'"));
return -1;
}
break;
case VIR_DOMAIN_PANIC_MODEL_HYPERV:
/* Panic with model 'hyperv' is not a device, it should
* be configured in cpu commandline. The address
* cannot be configured by the user */
if (!ARCH_IS_X86(def->os.arch)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("only i686 and x86_64 guests support "
"panic device of model 'hyperv'"));
return -1;
}
if (def->panics[i]->info.type !=
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("setting the panic device address is not "
"supported for model 'hyperv'"));
return -1;
}
break;
case VIR_DOMAIN_PANIC_MODEL_PSERIES:
/* For pSeries guests, the firmware provides the same
* functionality as the pvpanic device. The address
* cannot be configured by the user */
if (!qemuDomainIsPSeries(def)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("only pSeries guests support panic device "
"of model 'pseries'"));
return -1;
}
if (def->panics[i]->info.type !=
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("setting the panic device address is not "
"supported for model 'pseries'"));
return -1;
}
break;
case VIR_DOMAIN_PANIC_MODEL_ISA:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_PANIC)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("the QEMU binary does not support the "
"ISA panic device"));
return -1;
}
if (def->panics[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
def->panics[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_ISA) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("panic is supported only "
"with ISA address type"));
return -1;
}
break;
/* default model value was changed before in post parse */
case VIR_DOMAIN_PANIC_MODEL_DEFAULT:
case VIR_DOMAIN_PANIC_MODEL_LAST:
break;
}
}
return 0;
}
int
qemuValidateDomainDef(const virDomainDef *def,
void *opaque)
{
virQEMUDriverPtr driver = opaque;
g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
g_autoptr(virQEMUCaps) qemuCaps = NULL;
size_t i;
if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache,
def->emulator)))
return -1;
if (def->os.type != VIR_DOMAIN_OSTYPE_HVM) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Emulator '%s' does not support os type '%s'"),
def->emulator, virDomainOSTypeToString(def->os.type));
return -1;
}
if (!virQEMUCapsIsArchSupported(qemuCaps, def->os.arch)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Emulator '%s' does not support arch '%s'"),
def->emulator, virArchToString(def->os.arch));
return -1;
}
if (!virQEMUCapsIsVirtTypeSupported(qemuCaps, def->virtType)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Emulator '%s' does not support virt type '%s'"),
def->emulator, virDomainVirtTypeToString(def->virtType));
return -1;
}
if (qemuCaps &&
!virQEMUCapsIsMachineSupported(qemuCaps, def->virtType, def->os.machine)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Emulator '%s' does not support machine type '%s'"),
def->emulator, def->os.machine);
return -1;
}
if (def->mem.min_guarantee) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Parameter 'min_guarantee' not supported by QEMU."));
return -1;
}
/* On x86, UEFI requires ACPI */
if ((def->os.firmware == VIR_DOMAIN_OS_DEF_FIRMWARE_EFI ||
virDomainDefHasOldStyleUEFI(def)) &&
ARCH_IS_X86(def->os.arch) &&
def->features[VIR_DOMAIN_FEATURE_ACPI] != VIR_TRISTATE_SWITCH_ON) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("UEFI requires ACPI on this architecture"));
return -1;
}
/* On aarch64, ACPI requires UEFI */
if (def->features[VIR_DOMAIN_FEATURE_ACPI] == VIR_TRISTATE_SWITCH_ON &&
def->os.arch == VIR_ARCH_AARCH64 &&
(def->os.firmware != VIR_DOMAIN_OS_DEF_FIRMWARE_EFI &&
!virDomainDefHasOldStyleUEFI(def))) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("ACPI requires UEFI on this architecture"));
return -1;
}
if (def->genidRequested &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VMGENID)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("this QEMU does not support the 'genid' capability"));
return -1;
}
/* Serial graphics adapter */
if (def->os.bios.useserial == VIR_TRISTATE_BOOL_YES) {
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SGA)) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("qemu does not support SGA"));
return -1;
}
if (!def->nserials) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("need at least one serial port to use SGA"));
return -1;
}
}
if (qemuValidateDomainDefCpu(driver, def, qemuCaps) < 0)
return -1;
if (qemuDomainDefValidateMemoryHotplug(def, qemuCaps, NULL) < 0)
return -1;
if (qemuValidateDomainDefClockTimers(def, qemuCaps) < 0)
return -1;
if (qemuValidateDomainDefPM(def, qemuCaps) < 0)
return -1;
if (qemuValidateDomainDefBoot(def, qemuCaps) < 0)
return -1;
if (qemuValidateDomainVCpuTopology(def, qemuCaps) < 0)
return -1;
if (def->nresctrls &&
def->virtType != VIR_DOMAIN_VIRT_KVM) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("cachetune is only supported for KVM domains"));
return -1;
}
if (qemuValidateDomainDefFeatures(def, qemuCaps) < 0)
return -1;
if (qemuValidateDomainDefMemory(def, qemuCaps) < 0)
return -1;
if (qemuValidateDomainDefNuma(def, qemuCaps) < 0)
return -1;
if (qemuValidateDomainDefConsole(def, qemuCaps) < 0)
return -1;
if (cfg->vncTLS && cfg->vncTLSx509secretUUID &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_TLS_CREDS_X509)) {
for (i = 0; i < def->ngraphics; i++) {
if (def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("encrypted VNC TLS keys are not supported with "
"this QEMU binary"));
return -1;
}
}
}
for (i = 0; i < def->nsysinfo; i++) {
if (qemuValidateDomainDefSysinfo(def->sysinfo[i], qemuCaps) < 0)
return -1;
}
if (qemuValidateDomainDefPanic(def, qemuCaps) < 0)
return -1;
if (def->sev &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SEV_GUEST)) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("SEV launch security is not supported with "
"this QEMU binary"));
return -1;
}
return 0;
}
static int
qemuValidateDomainDeviceDefZPCIAddress(virDomainDeviceInfoPtr info,
virQEMUCapsPtr qemuCaps)
{
virZPCIDeviceAddressPtr zpci = &info->addr.pci.zpci;
if (virZPCIDeviceAddressIsPresent(zpci) &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_ZPCI)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
"%s",
_("This QEMU binary doesn't support zPCI"));
return -1;
}
/* We don't need to check fid because fid covers
* all range of uint32 type.
*/
if (zpci->uid.isSet &&
(zpci->uid.value > VIR_DOMAIN_DEVICE_ZPCI_MAX_UID ||
zpci->uid.value == 0)) {
virReportError(VIR_ERR_XML_ERROR,
_("Invalid PCI address uid='0x%.4x', "
"must be > 0x0000 and <= 0x%.4x"),
zpci->uid.value,
VIR_DOMAIN_DEVICE_ZPCI_MAX_UID);
return -1;
}
return 0;
}
static int
qemuValidateDomainDeviceDefAddress(const virDomainDeviceDef *dev,
virQEMUCapsPtr qemuCaps)
{
virDomainDeviceInfoPtr info;
if (!(info = virDomainDeviceGetInfo((virDomainDeviceDef *)dev)))
return 0;
switch ((virDomainDeviceAddressType) info->type) {
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
if (qemuValidateDomainDeviceDefZPCIAddress(info, qemuCaps) < 0)
return -1;
break;
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE:
/* Address validation might happen before we have had a chance to
* automatically assign addresses to devices for which the user
* didn't specify one themselves */
break;
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO: {
virDomainDeviceSpaprVioAddressPtr addr = &(info->addr.spaprvio);
if (addr->has_reg && addr->reg > 0xffffffff) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("spapr-vio reg='0x%llx' exceeds maximum "
"possible value (0xffffffff)"),
addr->reg);
return -1;
}
break;
}
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL:
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID:
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB:
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390:
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW:
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO:
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_ISA:
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DIMM:
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_UNASSIGNED:
/* No validation for these address types yet */
break;
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST:
default:
virReportEnumRangeError(virDomainDeviceAddressType, info->type);
return -1;
}
return 0;
}
static bool
qemuValidateNetSupportsCoalesce(virDomainNetType type)
{
switch (type) {
case VIR_DOMAIN_NET_TYPE_NETWORK:
case VIR_DOMAIN_NET_TYPE_BRIDGE:
return true;
case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
case VIR_DOMAIN_NET_TYPE_ETHERNET:
case VIR_DOMAIN_NET_TYPE_DIRECT:
case VIR_DOMAIN_NET_TYPE_HOSTDEV:
case VIR_DOMAIN_NET_TYPE_USER:
case VIR_DOMAIN_NET_TYPE_SERVER:
case VIR_DOMAIN_NET_TYPE_CLIENT:
case VIR_DOMAIN_NET_TYPE_MCAST:
case VIR_DOMAIN_NET_TYPE_INTERNAL:
case VIR_DOMAIN_NET_TYPE_UDP:
case VIR_DOMAIN_NET_TYPE_VDPA:
case VIR_DOMAIN_NET_TYPE_LAST:
break;
}
return false;
}
static int
qemuValidateDomainVirtioOptions(const virDomainVirtioOptions *virtio,
virQEMUCapsPtr qemuCaps)
{
if (!virtio)
return 0;
if (virtio->iommu != VIR_TRISTATE_SWITCH_ABSENT &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_PCI_IOMMU_PLATFORM)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("the iommu setting is not supported "
"with this QEMU binary"));
return -1;
}
if (virtio->ats != VIR_TRISTATE_SWITCH_ABSENT &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_PCI_ATS)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("the ats setting is not supported with this "
"QEMU binary"));
return -1;
}
if (virtio->packed != VIR_TRISTATE_SWITCH_ABSENT &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_PACKED_QUEUES)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("the packed setting is not supported with this "
"QEMU binary"));
return -1;
}
return 0;
}
static int
qemuValidateDomainDeviceDefNetwork(const virDomainNetDef *net,
virQEMUCapsPtr qemuCaps)
{
bool hasIPv4 = false;
bool hasIPv6 = false;
size_t i;
if (net->type == VIR_DOMAIN_NET_TYPE_USER) {
if (net->guestIP.nroutes) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Invalid attempt to set network interface "
"guest-side IP route, not supported by QEMU"));
return -1;
}
for (i = 0; i < net->guestIP.nips; i++) {
const virNetDevIPAddr *ip = net->guestIP.ips[i];
if (VIR_SOCKET_ADDR_VALID(&net->guestIP.ips[i]->peer)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Invalid attempt to set peer IP for guest"));
return -1;
}
if (VIR_SOCKET_ADDR_IS_FAMILY(&ip->address, AF_INET)) {
if (hasIPv4) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Only one IPv4 address per "
"interface is allowed"));
return -1;
}
hasIPv4 = true;
if (ip->prefix > 0 &&
(ip->prefix < 4 || ip->prefix > 27)) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("invalid prefix, must be in range of 4-27"));
return -1;
}
}
if (VIR_SOCKET_ADDR_IS_FAMILY(&ip->address, AF_INET6)) {
if (hasIPv6) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Only one IPv6 address per "
"interface is allowed"));
return -1;
}
hasIPv6 = true;
if (ip->prefix > 120) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("prefix too long"));
return -1;
}
}
}
} else if (net->type == VIR_DOMAIN_NET_TYPE_VDPA) {
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_NETDEV_VHOST_VDPA)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("vDPA devices are not supported with this QEMU binary"));
return -1;
}
if (net->model != VIR_DOMAIN_NET_MODEL_VIRTIO) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("invalid model for interface of type '%s': '%s'"),
virDomainNetTypeToString(net->type),
virDomainNetModelTypeToString(net->model));
return -1;
}
} else if (net->guestIP.nroutes || net->guestIP.nips) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Invalid attempt to set network interface "
"guest-side IP route and/or address info, "
"not supported by QEMU"));
return -1;
}
if (virDomainNetIsVirtioModel(net)) {
if (net->driver.virtio.txmode &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_TX_ALG)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("virtio-net-pci 'tx' option not supported in "
"this QEMU binary"));
return -1;
}
if (net->driver.virtio.rx_queue_size &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_NET_RX_QUEUE_SIZE)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("virtio rx_queue_size option is not supported "
"with this QEMU binary"));
return -1;
}
if (net->driver.virtio.tx_queue_size &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_NET_TX_QUEUE_SIZE)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("virtio tx_queue_size option is not supported "
"with this QEMU binary"));
return -1;
}
if (net->mtu &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_NET_HOST_MTU)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("setting MTU is not supported with this "
"QEMU binary"));
return -1;
}
if (net->driver.virtio.rx_queue_size & (net->driver.virtio.rx_queue_size - 1)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("rx_queue_size has to be a power of two"));
return -1;
}
if (net->driver.virtio.tx_queue_size & (net->driver.virtio.tx_queue_size - 1)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("tx_queue_size has to be a power of two"));
return -1;
}
if (qemuValidateDomainVirtioOptions(net->virtio, qemuCaps) < 0)
return -1;
}
if (net->mtu &&
!qemuDomainNetSupportsMTU(net->type)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("setting MTU on interface type %s is not supported yet"),
virDomainNetTypeToString(net->type));
return -1;
}
if (net->teaming.type != VIR_DOMAIN_NET_TEAMING_TYPE_NONE &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_NET_FAILOVER)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("virtio-net failover (teaming) is not supported with this QEMU binary"));
return -1;
}
if (net->teaming.type == VIR_DOMAIN_NET_TEAMING_TYPE_PERSISTENT
&& !virDomainNetIsVirtioModel(net)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("virtio-net teaming persistent interface must be , not '%s'"),
virDomainNetGetModelString(net));
return -1;
}
if (net->teaming.type == VIR_DOMAIN_NET_TEAMING_TYPE_TRANSIENT &&
net->type != VIR_DOMAIN_NET_TYPE_HOSTDEV &&
net->type != VIR_DOMAIN_NET_TYPE_NETWORK) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("virtio-net teaming transient interface must be type='hostdev', not '%s'"),
virDomainNetTypeToString(net->type));
return -1;
}
if (net->coalesce && !qemuValidateNetSupportsCoalesce(net->type)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("coalesce settings on interface type %s are not supported"),
virDomainNetTypeToString(net->type));
return -1;
}
return 0;
}
static int
qemuValidateDomainChrSourceReconnectDef(const virDomainChrSourceReconnectDef *def)
{
if (def->enabled == VIR_TRISTATE_BOOL_YES &&
def->timeout == 0) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("chardev reconnect source timeout cannot be '0'"));
return -1;
}
return 0;
}
static int
qemuValidateChrSerialTargetTypeToAddressType(int targetType)
{
switch ((virDomainChrSerialTargetType)targetType) {
case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_ISA:
return VIR_DOMAIN_DEVICE_ADDRESS_TYPE_ISA;
case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_USB:
return VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB;
case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_PCI:
return VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_SPAPR_VIO:
return VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO;
case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_SYSTEM:
case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_SCLP:
case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_LAST:
case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_NONE:
break;
}
return VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE;
}
static int
qemuValidateChrSerialTargetModelToTargetType(int targetModel)
{
switch ((virDomainChrSerialTargetModel) targetModel) {
case VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_ISA_SERIAL:
return VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_ISA;
case VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_USB_SERIAL:
return VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_USB;
case VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_PCI_SERIAL:
return VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_PCI;
case VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_SPAPR_VTY:
return VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_SPAPR_VIO;
case VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_PL011:
case VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_16550A:
return VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_SYSTEM;
case VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_SCLPCONSOLE:
case VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_SCLPLMCONSOLE:
return VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_SCLP;
case VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_NONE:
case VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_LAST:
break;
}
return VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_NONE;
}
static int
qemuValidateDomainChrTargetDef(const virDomainChrDef *chr)
{
int expected;
switch ((virDomainChrDeviceType)chr->deviceType) {
case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
/* Validate target type */
switch ((virDomainChrSerialTargetType)chr->targetType) {
case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_ISA:
case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_USB:
case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_PCI:
case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_SPAPR_VIO:
expected = qemuValidateChrSerialTargetTypeToAddressType(chr->targetType);
if (chr->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
chr->info.type != expected) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Target type '%s' requires address type '%s'"),
virDomainChrSerialTargetTypeToString(chr->targetType),
virDomainDeviceAddressTypeToString(expected));
return -1;
}
break;
case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_SYSTEM:
case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_SCLP:
if (chr->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Target type '%s' cannot have an "
"associated address"),
virDomainChrSerialTargetTypeToString(chr->targetType));
return -1;
}
break;
case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_NONE:
case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_LAST:
break;
}
/* Validate target model */
switch ((virDomainChrSerialTargetModel) chr->targetModel) {
case VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_ISA_SERIAL:
case VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_USB_SERIAL:
case VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_PCI_SERIAL:
case VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_SPAPR_VTY:
case VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_PL011:
case VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_SCLPCONSOLE:
case VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_SCLPLMCONSOLE:
case VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_16550A:
expected = qemuValidateChrSerialTargetModelToTargetType(chr->targetModel);
if (chr->targetType != expected) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Target model '%s' requires target type '%s'"),
virDomainChrSerialTargetModelTypeToString(chr->targetModel),
virDomainChrSerialTargetTypeToString(expected));
return -1;
}
break;
case VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_NONE:
case VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_LAST:
break;
}
break;
case VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE:
case VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL:
case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL:
case VIR_DOMAIN_CHR_DEVICE_TYPE_LAST:
/* Nothing to do */
break;
}
return 0;
}
static int
qemuValidateDomainChrSourceDef(const virDomainChrSourceDef *def,
virQEMUCapsPtr qemuCaps)
{
switch ((virDomainChrType)def->type) {
case VIR_DOMAIN_CHR_TYPE_TCP:
if (qemuValidateDomainChrSourceReconnectDef(&def->data.tcp.reconnect) < 0)
return -1;
break;
case VIR_DOMAIN_CHR_TYPE_UNIX:
if (qemuValidateDomainChrSourceReconnectDef(&def->data.nix.reconnect) < 0)
return -1;
break;
case VIR_DOMAIN_CHR_TYPE_FILE:
if (def->data.file.append != VIR_TRISTATE_SWITCH_ABSENT &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CHARDEV_FILE_APPEND)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("append not supported in this QEMU binary"));
return -1;
}
break;
case VIR_DOMAIN_CHR_TYPE_NULL:
case VIR_DOMAIN_CHR_TYPE_VC:
case VIR_DOMAIN_CHR_TYPE_PTY:
case VIR_DOMAIN_CHR_TYPE_DEV:
case VIR_DOMAIN_CHR_TYPE_PIPE:
case VIR_DOMAIN_CHR_TYPE_STDIO:
case VIR_DOMAIN_CHR_TYPE_UDP:
case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
case VIR_DOMAIN_CHR_TYPE_NMDM:
case VIR_DOMAIN_CHR_TYPE_LAST:
break;
}
if (def->logfile) {
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CHARDEV_LOGFILE)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("logfile not supported in this QEMU binary"));
return -1;
}
}
return 0;
}
static int
qemuValidateDomainChrDef(const virDomainChrDef *dev,
const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
if (qemuValidateDomainChrSourceDef(dev->source, qemuCaps) < 0)
return -1;
if (qemuValidateDomainChrTargetDef(dev) < 0)
return -1;
if (dev->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL &&
(ARCH_IS_S390(def->os.arch) || qemuDomainIsPSeries(def))) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("parallel ports are not supported"));
return -1;
}
if (dev->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL) {
bool isCompatible = true;
if (dev->targetType == VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_SYSTEM) {
if (dev->targetModel == VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_PL011 &&
!qemuDomainIsARMVirt(def)) {
isCompatible = false;
}
if (dev->targetModel == VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_16550A &&
!qemuDomainIsRISCVVirt(def)) {
isCompatible = false;
}
}
if (!qemuDomainIsPSeries(def) &&
(dev->targetType == VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_SPAPR_VIO ||
dev->targetModel == VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_SPAPR_VTY)) {
isCompatible = false;
}
if (!ARCH_IS_S390(def->os.arch) &&
(dev->targetType == VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_SCLP ||
dev->targetModel == VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_SCLPCONSOLE ||
dev->targetModel == VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_SCLPLMCONSOLE)) {
isCompatible = false;
}
if (!isCompatible) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Serial device with target type '%s' and "
"target model '%s' not compatible with guest "
"architecture or machine type"),
virDomainChrSerialTargetTypeToString(dev->targetType),
virDomainChrSerialTargetModelTypeToString(dev->targetModel));
return -1;
}
}
return 0;
}
static int
qemuValidateDomainSmartcardDef(const virDomainSmartcardDef *def,
virQEMUCapsPtr qemuCaps)
{
switch (def->type) {
case VIR_DOMAIN_SMARTCARD_TYPE_HOST:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CCID_EMULATED)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("this QEMU binary lacks smartcard host "
"mode support"));
return -1;
}
break;
case VIR_DOMAIN_SMARTCARD_TYPE_HOST_CERTIFICATES:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CCID_EMULATED)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("this QEMU binary lacks smartcard host "
"mode support"));
return -1;
}
break;
case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CCID_PASSTHRU)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("this QEMU binary lacks smartcard "
"passthrough mode support"));
return -1;
}
break;
default:
virReportEnumRangeError(virDomainSmartcardType, def->type);
return -1;
}
if (def->type == VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH &&
qemuValidateDomainChrSourceDef(def->data.passthru, qemuCaps) < 0)
return -1;
return 0;
}
static int
qemuValidateDomainRNGDef(const virDomainRNGDef *def,
virQEMUCapsPtr qemuCaps)
{
switch ((virDomainRNGBackend) def->backend) {
case VIR_DOMAIN_RNG_BACKEND_RANDOM:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_RNG_RANDOM)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("this qemu doesn't support the rng-random "
"backend"));
return -1;
}
break;
case VIR_DOMAIN_RNG_BACKEND_EGD:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_RNG_EGD)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("this qemu doesn't support the rng-egd "
"backend"));
return -1;
}
if (qemuValidateDomainChrSourceDef(def->source.chardev, qemuCaps) < 0)
return -1;
break;
case VIR_DOMAIN_RNG_BACKEND_BUILTIN:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_RNG_BUILTIN)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("this qemu doesn't support the rng-builtin "
"backend"));
return -1;
}
break;
case VIR_DOMAIN_RNG_BACKEND_LAST:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("unknown rng-random backend"));
return -1;
}
switch ((virDomainRNGModel) def->model) {
case VIR_DOMAIN_RNG_MODEL_VIRTIO:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VIRTIO_RNG)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("domain configuration does not support rng model '%s'"),
virDomainRNGModelTypeToString(def->model));
return -1;
}
break;
case VIR_DOMAIN_RNG_MODEL_VIRTIO_TRANSITIONAL:
case VIR_DOMAIN_RNG_MODEL_VIRTIO_NON_TRANSITIONAL:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_PCI_TRANSITIONAL) &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("domain configuration does not support rng model '%s'"),
virDomainRNGModelTypeToString(def->model));
return -1;
}
break;
case VIR_DOMAIN_RNG_MODEL_LAST:
break;
}
if (qemuValidateDomainVirtioOptions(def->virtio, qemuCaps) < 0)
return -1;
return 0;
}
static int
qemuValidateDomainRedirdevDef(const virDomainRedirdevDef *dev,
const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
if (qemuValidateDomainChrSourceDef(dev->source, qemuCaps) < 0)
return -1;
if (dev->bus != VIR_DOMAIN_REDIRDEV_BUS_USB) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Redirection bus %s is not supported by QEMU"),
virDomainRedirdevBusTypeToString(dev->bus));
return -1;
}
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_USB_REDIR)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("USB redirection is not supported "
"by this version of QEMU"));
return -1;
}
if (def->redirfilter && def->redirfilter->nusbdevs &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_USB_REDIR_FILTER)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("USB redirection filter is not "
"supported by this version of QEMU"));
return -1;
}
return 0;
}
static int
qemuValidateDomainWatchdogDef(const virDomainWatchdogDef *dev,
const virDomainDef *def)
{
switch ((virDomainWatchdogModel) dev->model) {
case VIR_DOMAIN_WATCHDOG_MODEL_I6300ESB:
if (dev->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
dev->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("%s model of watchdog can go only on PCI bus"),
virDomainWatchdogModelTypeToString(dev->model));
return -1;
}
break;
case VIR_DOMAIN_WATCHDOG_MODEL_IB700:
if (dev->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("%s model of watchdog does not support configuring the address"),
virDomainWatchdogModelTypeToString(dev->model));
return -1;
}
break;
case VIR_DOMAIN_WATCHDOG_MODEL_DIAG288:
if (dev->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("%s model of watchdog is virtual and cannot go on any bus."),
virDomainWatchdogModelTypeToString(dev->model));
return -1;
}
if (!(ARCH_IS_S390(def->os.arch))) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("%s model of watchdog is allowed for s390 and s390x only"),
virDomainWatchdogModelTypeToString(dev->model));
return -1;
}
break;
case VIR_DOMAIN_WATCHDOG_MODEL_LAST:
break;
}
return 0;
}
static int
qemuValidateDomainMdevDefVFIOPCI(const virDomainHostdevDef *hostdev,
const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
const virDomainHostdevSubsysMediatedDev *dev;
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VFIO_PCI)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("VFIO PCI device assignment is not "
"supported by this version of QEMU"));
return -1;
}
/* VFIO-PCI does not support boot */
if (hostdev->info->bootIndex) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("booting from assigned devices is not "
"supported by mediated devices of "
"model vfio-pci"));
return -1;
}
dev = &hostdev->source.subsys.u.mdev;
if (dev->display == VIR_TRISTATE_SWITCH_ABSENT)
return 0;
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VFIO_PCI_DISPLAY)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("display property of device vfio-pci is "
"not supported by this version of QEMU"));
return -1;
}
if (dev->model != VIR_MDEV_MODEL_TYPE_VFIO_PCI) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_(" attribute 'display' is only supported"
" with model='vfio-pci'"));
return -1;
}
if (dev->display == VIR_TRISTATE_SWITCH_ON) {
if (def->ngraphics == 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("graphics device is needed for attribute value "
"'display=on' in "));
return -1;
}
}
return 0;
}
static int
qemuValidateDomainMdevDefVFIOAP(const virDomainHostdevDef *hostdev,
const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
size_t i;
bool vfioap_found = false;
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VFIO_AP)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("VFIO AP device assignment is not "
"supported by this version of QEMU"));
return -1;
}
/* VFIO-AP does not support boot */
if (hostdev->info->bootIndex) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("booting from assigned devices is not "
"supported by mediated devices of "
"model vfio-ap"));
return -1;
}
/* VFIO-AP is restricted to a single mediated device only */
for (i = 0; i < def->nhostdevs; i++) {
virDomainHostdevDefPtr hdev = def->hostdevs[i];
if (virHostdevIsMdevDevice(hdev) &&
hdev->source.subsys.u.mdev.model == VIR_MDEV_MODEL_TYPE_VFIO_AP) {
if (vfioap_found) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Only one hostdev of model vfio-ap is "
"supported"));
return -1;
}
vfioap_found = true;
}
}
return 0;
}
static int
qemuValidateDomainMdevDef(const virDomainHostdevDef *hostdev,
const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
const virDomainHostdevSubsysMediatedDev *mdevsrc;
mdevsrc = &hostdev->source.subsys.u.mdev;
switch ((virMediatedDeviceModelType) mdevsrc->model) {
case VIR_MDEV_MODEL_TYPE_VFIO_PCI:
return qemuValidateDomainMdevDefVFIOPCI(hostdev, def, qemuCaps);
case VIR_MDEV_MODEL_TYPE_VFIO_AP:
return qemuValidateDomainMdevDefVFIOAP(hostdev, def, qemuCaps);
case VIR_MDEV_MODEL_TYPE_VFIO_CCW:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VFIO_CCW)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("VFIO CCW device assignment is not "
"supported by this version of QEMU"));
return -1;
}
break;
case VIR_MDEV_MODEL_TYPE_LAST:
default:
virReportEnumRangeError(virMediatedDeviceModelType,
mdevsrc->model);
return -1;
}
return 0;
}
static int
qemuValidateDomainDeviceDefHostdev(const virDomainHostdevDef *hostdev,
const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
int backend;
/* forbid capabilities mode hostdev in this kind of hypervisor */
if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("hostdev mode 'capabilities' is not "
"supported in %s"),
virDomainVirtTypeToString(def->virtType));
return -1;
}
if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
switch ((virDomainHostdevSubsysType) hostdev->source.subsys.type) {
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
break;
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
backend = hostdev->source.subsys.u.pci.backend;
if (backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VFIO_PCI)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("VFIO PCI device assignment is not "
"supported by this version of qemu"));
return -1;
}
}
if (hostdev->writeFiltering != VIR_TRISTATE_BOOL_ABSENT) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Write filtering of PCI device configuration "
"space is not supported by qemu"));
return -1;
}
break;
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST:
if (hostdev->info->bootIndex) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("booting from assigned devices is not "
"supported by vhost SCSI devices"));
return -1;
}
if (hostdev->source.subsys.u.scsi_host.protocol ==
VIR_DOMAIN_HOSTDEV_SUBSYS_SCSI_HOST_PROTOCOL_TYPE_VHOST &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VHOST_SCSI)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("This QEMU doesn't support vhost-scsi devices"));
return -1;
}
break;
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
return qemuValidateDomainMdevDef(hostdev, def, qemuCaps);
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
default:
virReportEnumRangeError(virDomainHostdevSubsysType,
hostdev->source.subsys.type);
return -1;
}
}
return 0;
}
static int
qemuValidateDomainDeviceDefVideo(const virDomainVideoDef *video,
virQEMUCapsPtr qemuCaps)
{
/* there's no properties to validate for NONE video devices */
if (video->type == VIR_DOMAIN_VIDEO_TYPE_NONE)
return 0;
if (!video->primary &&
video->type != VIR_DOMAIN_VIDEO_TYPE_QXL &&
video->type != VIR_DOMAIN_VIDEO_TYPE_VIRTIO) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("video type '%s' is only valid as primary "
"video device"),
virDomainVideoTypeToString(video->type));
return -1;
}
if (video->accel && video->accel->accel2d == VIR_TRISTATE_SWITCH_ON) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("qemu does not support the accel2d setting"));
return -1;
}
if (video->type == VIR_DOMAIN_VIDEO_TYPE_QXL) {
if (video->vram > (UINT_MAX / 1024)) {
virReportError(VIR_ERR_OVERFLOW,
_("value for 'vram' must be less than '%u'"),
UINT_MAX / 1024);
return -1;
}
if (video->ram > (UINT_MAX / 1024)) {
virReportError(VIR_ERR_OVERFLOW,
_("value for 'ram' must be less than '%u'"),
UINT_MAX / 1024);
return -1;
}
if (video->vgamem) {
if (video->vgamem < 1024) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("value for 'vgamem' must be at least 1 MiB "
"(1024 KiB)"));
return -1;
}
if (video->vgamem != VIR_ROUND_UP_POWER_OF_TWO(video->vgamem)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("value for 'vgamem' must be power of two"));
return -1;
}
}
}
if (video->type != VIR_DOMAIN_VIDEO_TYPE_VGA &&
video->type != VIR_DOMAIN_VIDEO_TYPE_QXL &&
video->type != VIR_DOMAIN_VIDEO_TYPE_VIRTIO &&
video->type != VIR_DOMAIN_VIDEO_TYPE_BOCHS) {
if (video->res) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("model resolution is not supported"));
return -1;
}
}
if (video->type == VIR_DOMAIN_VIDEO_TYPE_VGA ||
video->type == VIR_DOMAIN_VIDEO_TYPE_VMVGA) {
if (video->vram && video->vram < 1024) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
"%s", _("value for 'vram' must be at least "
"1 MiB (1024 KiB)"));
return -1;
}
}
if (video->backend == VIR_DOMAIN_VIDEO_BACKEND_TYPE_VHOSTUSER) {
if (video->type == VIR_DOMAIN_VIDEO_TYPE_VIRTIO &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VHOST_USER_GPU)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("this QEMU does not support 'vhost-user' video device"));
return -1;
}
} else if (video->accel) {
if (video->accel->accel3d == VIR_TRISTATE_SWITCH_ON &&
(video->type != VIR_DOMAIN_VIDEO_TYPE_VIRTIO ||
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_GPU_VIRGL))) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("%s 3d acceleration is not supported"),
virDomainVideoTypeToString(video->type));
return -1;
}
}
if (qemuValidateDomainVirtioOptions(video->virtio, qemuCaps) < 0)
return -1;
if (video->type == VIR_DOMAIN_VIDEO_TYPE_RAMFB &&
video->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("'address' is not supported for 'ramfb' video devices"));
return -1;
}
return 0;
}
#define QEMU_SERIAL_PARAM_ACCEPTED_CHARS \
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_ .+"
static int
qemuValidateDomainDeviceDefDiskSerial(const char *value)
{
if (strspn(value, QEMU_SERIAL_PARAM_ACCEPTED_CHARS) != strlen(value)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("driver serial '%s' contains unsafe characters"),
value);
return -1;
}
return 0;
}
static int
qemuValidateDomainDeviceDefDiskFrontend(const virDomainDiskDef *disk,
const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
virDomainDeviceInfoPtr diskInfo;
int cModel;
if (disk->geometry.cylinders > 0 &&
disk->geometry.heads > 0 &&
disk->geometry.sectors > 0) {
if (disk->bus == VIR_DOMAIN_DISK_BUS_USB ||
disk->bus == VIR_DOMAIN_DISK_BUS_SD) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("CHS geometry can not be set for '%s' bus"),
virDomainDiskBusTypeToString(disk->bus));
return -1;
}
if (disk->geometry.trans != VIR_DOMAIN_DISK_TRANS_DEFAULT &&
disk->bus != VIR_DOMAIN_DISK_BUS_IDE) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("CHS translation mode can only be set for 'ide' bus not '%s'"),
virDomainDiskBusTypeToString(disk->bus));
return -1;
}
}
if (disk->serial && disk->bus == VIR_DOMAIN_DISK_BUS_SD) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Serial property not supported for drive bus '%s'"),
virDomainDiskBusTypeToString(disk->bus));
return -1;
}
if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM &&
(disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO ||
disk->bus == VIR_DOMAIN_DISK_BUS_SD)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("disk type of '%s' does not support ejectable media"),
disk->dst);
return -1;
}
if (disk->copy_on_read == VIR_TRISTATE_SWITCH_ON) {
if (disk->src->readonly) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("copy_on_read is not compatible with read-only disk '%s'"),
disk->dst);
return -1;
}
if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM ||
disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("copy_on_read is not supported with removable disk '%s'"),
disk->dst);
return -1;
}
}
if (disk->wwn) {
if ((disk->bus != VIR_DOMAIN_DISK_BUS_IDE) &&
(disk->bus != VIR_DOMAIN_DISK_BUS_SCSI)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Only ide and scsi disk support wwn"));
return -1;
}
if (disk->bus == VIR_DOMAIN_DISK_BUS_IDE &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_IDE_DRIVE_WWN)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Setting wwn for ide disk is not supported "
"by this QEMU"));
return -1;
}
if (disk->bus != VIR_DOMAIN_DISK_BUS_SCSI &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_DISK_WWN)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Setting wwn for scsi disk is not supported "
"by this QEMU"));
return -1;
}
}
if (disk->vendor || disk->product) {
if (disk->bus != VIR_DOMAIN_DISK_BUS_SCSI) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Only scsi disk supports vendor and product"));
return -1;
}
/* Properties wwn, vendor and product were introduced in the
* same QEMU release (1.2.0).
*/
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_DISK_WWN)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Setting vendor or product for scsi disk is not "
"supported by this QEMU"));
return -1;
}
}
if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
/* make sure that both the bus supports type='lun' (SG_IO). */
if (disk->bus != VIR_DOMAIN_DISK_BUS_VIRTIO &&
disk->bus != VIR_DOMAIN_DISK_BUS_SCSI) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("disk device='lun' is not supported for bus='%s'"),
virDomainDiskBusTypeToString(disk->bus));
return -1;
}
if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_BLOCK)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("This QEMU doesn't support scsi-block for "
"lun passthrough"));
return -1;
}
if (disk->copy_on_read == VIR_TRISTATE_SWITCH_ON) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("copy_on_read is not compatible with 'lun' disk '%s'"),
disk->dst);
return -1;
}
if (qemuDomainDefValidateDiskLunSource(disk->src) < 0)
return -1;
if (disk->wwn) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Setting wwn is not supported for lun device"));
return -1;
}
if (disk->vendor || disk->product) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Setting vendor or product is not supported "
"for lun device"));
return -1;
}
}
switch (disk->bus) {
case VIR_DOMAIN_DISK_BUS_SCSI:
diskInfo = (virDomainDeviceInfoPtr)&disk->info;
cModel = qemuDomainFindSCSIControllerModel(def, diskInfo);
if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("unexpected address type for scsi disk"));
return -1;
}
/* Setting bus= attr for SCSI drives, causes a controller
* to be created. Yes this is slightly odd. It is not possible
* to have > 1 bus on a SCSI controller (yet). */
if (disk->info.addr.drive.bus != 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("SCSI controller only supports 1 bus"));
return -1;
}
/* We allow hotplug/hotunplug disks without a controller,
* hence we don't error out if cModel is < 0. These
* validations were originally made under the assumption of
* a controller being found though. */
if (cModel > 0) {
if (cModel == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC) {
if (disk->info.addr.drive.target != 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("target must be 0 for controller "
"model 'lsilogic'"));
return -1;
}
} else if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_DISK_CHANNEL)) {
if (disk->info.addr.drive.target > 7) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("This QEMU doesn't support target "
"greater than 7"));
return -1;
}
if (disk->info.addr.drive.bus != 0 &&
disk->info.addr.drive.unit != 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("This QEMU only supports both bus and "
"unit equal to 0"));
return -1;
}
}
}
break;
case VIR_DOMAIN_DISK_BUS_IDE:
if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("unexpected address type for ide disk"));
return -1;
}
/* We can only have 1 IDE controller (currently) */
if (disk->info.addr.drive.controller != 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Only 1 IDE controller is supported"));
return -1;
}
if (disk->info.addr.drive.target != 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("target must be 0 for ide controller"));
return -1;
}
break;
case VIR_DOMAIN_DISK_BUS_FDC:
if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("unexpected address type for fdc disk"));
return -1;
}
/* We can only have 1 FDC controller (currently) */
if (disk->info.addr.drive.controller != 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Only 1 fdc controller is supported"));
return -1;
}
/* We can only have 1 FDC bus (currently) */
if (disk->info.addr.drive.bus != 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Only 1 fdc bus is supported"));
return -1;
}
if (disk->info.addr.drive.target != 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("target must be 0 for controller fdc"));
return -1;
}
break;
case VIR_DOMAIN_DISK_BUS_SATA:
if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("unexpected address type for sata disk"));
return -1;
}
if (disk->info.addr.drive.bus != 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("bus must be 0 for sata controller"));
return -1;
}
if (disk->info.addr.drive.target != 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("target must be 0 for sata controller"));
return -1;
}
break;
case VIR_DOMAIN_DISK_BUS_VIRTIO:
if (disk->queues &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_BLK_NUM_QUEUES)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("num-queues property isn't supported by this "
"QEMU binary"));
return -1;
}
break;
case VIR_DOMAIN_DISK_BUS_USB:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_USB_STORAGE)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("This QEMU doesn't support '-device "
"usb-storage'"));
return -1;
}
if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("unexpected address type for usb disk"));
return -1;
}
if (disk->removable != VIR_TRISTATE_SWITCH_ABSENT &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_USB_STORAGE_REMOVABLE)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("This QEMU doesn't support setting the "
"removable flag of USB storage devices"));
return -1;
}
break;
case VIR_DOMAIN_DISK_BUS_XEN:
case VIR_DOMAIN_DISK_BUS_SD:
break;
}
if (disk->src->readonly &&
disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
if (disk->bus == VIR_DOMAIN_DISK_BUS_IDE) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("readonly ide disks are not supported"));
return -1;
}
if (disk->bus == VIR_DOMAIN_DISK_BUS_SATA) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("readonly sata disks are not supported"));
return -1;
}
}
if (disk->iomode == VIR_DOMAIN_DISK_IO_NATIVE &&
disk->cachemode != VIR_DOMAIN_DISK_CACHE_DIRECTSYNC &&
disk->cachemode != VIR_DOMAIN_DISK_CACHE_DISABLE) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("native I/O needs either no disk cache "
"or directsync cache mode, QEMU will fallback "
"to aio=threads"));
return -1;
}
if (qemuCaps) {
if (disk->serial &&
disk->bus == VIR_DOMAIN_DISK_BUS_SCSI &&
disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("scsi-block 'lun' devices do not support the "
"serial property"));
return -1;
}
if (disk->discard &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_DISCARD)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("discard is not supported by this QEMU binary"));
return -1;
}
if (disk->detect_zeroes &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_DETECT_ZEROES)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("detect_zeroes is not supported by this QEMU binary"));
return -1;
}
if (disk->iomode == VIR_DOMAIN_DISK_IO_URING) {
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_AIO_IO_URING)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("io uring is not supported by this QEMU binary"));
return -1;
}
}
}
if (disk->serial &&
qemuValidateDomainDeviceDefDiskSerial(disk->serial) < 0)
return -1;
return 0;
}
/**
* qemuValidateDomainDeviceDefDiskBlkdeviotune:
* @disk: disk configuration
* @qemuCaps: qemu capabilities, NULL if checking cold-configuration
*
* Checks whether block io tuning settings make sense. Returns -1 on error and
* reports a proper libvirt error.
*/
static int
qemuValidateDomainDeviceDefDiskBlkdeviotune(const virDomainDiskDef *disk,
const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
/* group_name by itself is ignored by qemu */
if (disk->blkdeviotune.group_name &&
!virDomainBlockIoTuneInfoHasAny(&disk->blkdeviotune)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("group_name can be configured only together with "
"settings"));
return -1;
}
/* checking def here is only for calling from tests */
if (disk->blkdeviotune.group_name) {
size_t i;
for (i = 0; i < def->ndisks; i++) {
virDomainDiskDefPtr d = def->disks[i];
if (STREQ(d->dst, disk->dst) ||
STRNEQ_NULLABLE(d->blkdeviotune.group_name,
disk->blkdeviotune.group_name))
continue;
if (!virDomainBlockIoTuneInfoEqual(&d->blkdeviotune,
&disk->blkdeviotune)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("different iotunes for disks %s and %s"),
disk->dst, d->dst);
return -1;
}
}
}
if (disk->blkdeviotune.total_bytes_sec > QEMU_BLOCK_IOTUNE_MAX ||
disk->blkdeviotune.read_bytes_sec > QEMU_BLOCK_IOTUNE_MAX ||
disk->blkdeviotune.write_bytes_sec > QEMU_BLOCK_IOTUNE_MAX ||
disk->blkdeviotune.total_iops_sec > QEMU_BLOCK_IOTUNE_MAX ||
disk->blkdeviotune.read_iops_sec > QEMU_BLOCK_IOTUNE_MAX ||
disk->blkdeviotune.write_iops_sec > QEMU_BLOCK_IOTUNE_MAX ||
disk->blkdeviotune.total_bytes_sec_max > QEMU_BLOCK_IOTUNE_MAX ||
disk->blkdeviotune.read_bytes_sec_max > QEMU_BLOCK_IOTUNE_MAX ||
disk->blkdeviotune.write_bytes_sec_max > QEMU_BLOCK_IOTUNE_MAX ||
disk->blkdeviotune.total_iops_sec_max > QEMU_BLOCK_IOTUNE_MAX ||
disk->blkdeviotune.read_iops_sec_max > QEMU_BLOCK_IOTUNE_MAX ||
disk->blkdeviotune.write_iops_sec_max > QEMU_BLOCK_IOTUNE_MAX ||
disk->blkdeviotune.size_iops_sec > QEMU_BLOCK_IOTUNE_MAX) {
virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
_("block I/O throttle limit must "
"be no more than %llu using QEMU"), QEMU_BLOCK_IOTUNE_MAX);
return -1;
}
if (qemuCaps) {
/* block I/O throttling 1.7 */
if (virDomainBlockIoTuneInfoHasMax(&disk->blkdeviotune) &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_IOTUNE_MAX)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("there are some block I/O throttling parameters "
"that are not supported with this QEMU binary"));
return -1;
}
/* block I/O group 2.4 */
if (disk->blkdeviotune.group_name &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_IOTUNE_GROUP)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("the block I/O throttling group parameter is "
"not supported with this QEMU binary"));
return -1;
}
/* block I/O throttling length 2.6 */
if (virDomainBlockIoTuneInfoHasMaxLength(&disk->blkdeviotune) &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_IOTUNE_MAX_LENGTH)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("there are some block I/O throttling length parameters "
"that are not supported with this QEMU binary"));
return -1;
}
}
return 0;
}
static int
qemuValidateDomainDeviceDefDiskTransient(const virDomainDiskDef *disk,
virQEMUCapsPtr qemuCaps)
{
virStorageType actualType = virStorageSourceGetActualType(disk->src);
if (!disk->transient)
return 0;
if (virStorageSourceIsEmpty(disk->src)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("transient disk '%s' must not be empty"), disk->dst);
return -1;
}
if (disk->src->readonly) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("transient disk '%s' must not be read-only"), disk->dst);
return -1;
}
if (actualType != VIR_STORAGE_TYPE_FILE) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("transient disk supported only with 'file' type (%s)"),
disk->dst);
return -1;
}
if (disk->device != VIR_DOMAIN_DISK_DEVICE_DISK) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("transient disk supported only with 'disk' device (%s)"),
disk->dst);
return -1;
}
if (qemuCaps && !virQEMUCapsGet(qemuCaps, QEMU_CAPS_BLOCKDEV)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("transient disk not supported by this QEMU binary (%s)"),
disk->dst);
return -1;
}
return 0;
}
int
qemuValidateDomainDeviceDefDisk(const virDomainDiskDef *disk,
const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
const char *driverName = virDomainDiskGetDriver(disk);
bool isSD = qemuDiskBusIsSD(disk->bus);
virStorageSourcePtr n;
int idx;
int partition;
if (qemuValidateDomainDeviceDefDiskFrontend(disk, def, qemuCaps) < 0)
return -1;
if (qemuValidateDomainDeviceDefDiskBlkdeviotune(disk, def, qemuCaps) < 0)
return -1;
if (qemuValidateDomainDeviceDefDiskTransient(disk, qemuCaps) < 0)
return -1;
if (disk->src->shared && !disk->src->readonly &&
!qemuBlockStorageSourceSupportsConcurrentAccess(disk->src)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("shared access for disk '%s' requires use of "
"supported storage format"), disk->dst);
return -1;
}
if (driverName && STRNEQ(driverName, "qemu")) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("unsupported driver name '%s' for disk '%s'"),
driverName, disk->dst);
return -1;
}
if (virDiskNameParse(disk->dst, &idx, &partition) < 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("invalid disk target '%s'"), disk->dst);
return -1;
}
if (partition != 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("invalid disk target '%s', partitions can't appear in disk targets"),
disk->dst);
return -1;
}
for (n = disk->src; virStorageSourceIsBacking(n); n = n->backingStore) {
/* blockdev support is masked out for 'sd' disks */
if (qemuDomainValidateStorageSource(n, qemuCaps, isSD) < 0)
return -1;
}
if (disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO &&
qemuValidateDomainVirtioOptions(disk->virtio, qemuCaps) < 0) {
return -1;
}
return 0;
}
/**
* @qemuCaps: QEMU capabilities
* @model: SCSI model to check
*
* Using the @qemuCaps, let's ensure the provided @model can be supported
*
* Returns true if acceptable, false otherwise with error message set.
*/
static bool
qemuValidateCheckSCSIControllerModel(virQEMUCapsPtr qemuCaps,
int model)
{
switch ((virDomainControllerModelSCSI) model) {
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_LSI)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("This QEMU doesn't support "
"the LSI 53C895A SCSI controller"));
return false;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI:
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_TRANSITIONAL:
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_NON_TRANSITIONAL:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_SCSI)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("This QEMU doesn't support "
"virtio scsi controller"));
return false;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_IBMVSCSI:
/*TODO: need checking work here if necessary */
break;
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_MPTSAS1068)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("This QEMU doesn't support "
"the LSI SAS1068 (MPT Fusion) controller"));
return false;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1078:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_MEGASAS)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("This QEMU doesn't support "
"the LSI SAS1078 (MegaRAID) controller"));
return false;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VMPVSCSI:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_PVSCSI)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("This QEMU doesn't support "
"the pvscsi (VMware paravirtual SCSI) controller"));
return false;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_AUTO:
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Unsupported controller model: %s"),
virDomainControllerModelSCSITypeToString(model));
return false;
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_DEFAULT:
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST:
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Unexpected SCSI controller model %d"),
model);
return false;
}
return true;
}
static int
qemuValidateDomainDeviceDefControllerSATA(const virDomainControllerDef *controller,
const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
/* first SATA controller on Q35 machines is implicit */
if (controller->idx == 0 && qemuDomainIsQ35(def))
return 0;
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_ICH9_AHCI)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("SATA is not supported with this QEMU binary"));
return -1;
}
return 0;
}
static int
qemuValidateDomainDeviceDefControllerIDE(const virDomainControllerDef *controller,
const virDomainDef *def)
{
/* first IDE controller is implicit on various machines */
if (controller->idx == 0 && qemuDomainHasBuiltinIDE(def))
return 0;
/* Since we currently only support the integrated IDE
* controller on various boards, if we ever get to here, it's
* because some other machinetype had an IDE controller
* specified, or one with a single IDE controller had multiple
* IDE controllers specified.
*/
if (qemuDomainHasBuiltinIDE(def))
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Only a single IDE controller is supported "
"for this machine type"));
else
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("IDE controllers are unsupported for "
"this QEMU binary or machine type"));
return -1;
}
/* qemuValidateCheckSCSIControllerIOThreads:
* @controller: Pointer to controller def
* @def: Pointer to domain def
*
* If this controller definition has iothreads set, let's make sure the
* configuration is right before adding to the command line
*
* Returns true if either supported or there are no iothreads for controller;
* otherwise, returns false if configuration is not quite right.
*/
static bool
qemuValidateCheckSCSIControllerIOThreads(const virDomainControllerDef *controller,
const virDomainDef *def)
{
if (!controller->iothread)
return true;
if (controller->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
controller->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI &&
controller->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("virtio-scsi IOThreads only available for virtio "
"pci and virtio ccw controllers"));
return false;
}
/* Can we find the controller iothread in the iothreadid list? */
if (!virDomainIOThreadIDFind(def, controller->iothread)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("controller iothread '%u' not defined in iothreadid"),
controller->iothread);
return false;
}
return true;
}
static int
qemuValidateDomainDeviceDefControllerSCSI(const virDomainControllerDef *controller,
const virDomainDef *def)
{
switch ((virDomainControllerModelSCSI) controller->model) {
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI:
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_TRANSITIONAL:
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_NON_TRANSITIONAL:
if (!qemuValidateCheckSCSIControllerIOThreads(controller, def))
return -1;
break;
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_AUTO:
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC:
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC:
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068:
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VMPVSCSI:
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_IBMVSCSI:
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1078:
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_DEFAULT:
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST:
break;
}
return 0;
}
/**
* virValidateControllerPCIModelNameToQEMUCaps:
* @modelName: model name
*
* Maps model names for PCI controllers (virDomainControllerPCIModelName)
* to the QEMU capabilities required to use them (virQEMUCapsFlags).
*
* Returns: the QEMU capability itself (>0) on success; 0 if no QEMU
* capability is needed; <0 on error.
*/
static int
virValidateControllerPCIModelNameToQEMUCaps(int modelName)
{
switch ((virDomainControllerPCIModelName) modelName) {
case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PCI_BRIDGE:
return QEMU_CAPS_DEVICE_PCI_BRIDGE;
case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_I82801B11_BRIDGE:
return QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE;
case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_IOH3420:
return QEMU_CAPS_DEVICE_IOH3420;
case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_X3130_UPSTREAM:
return QEMU_CAPS_DEVICE_X3130_UPSTREAM;
case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_XIO3130_DOWNSTREAM:
return QEMU_CAPS_DEVICE_XIO3130_DOWNSTREAM;
case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PXB:
return QEMU_CAPS_DEVICE_PXB;
case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PXB_PCIE:
return QEMU_CAPS_DEVICE_PXB_PCIE;
case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PCIE_ROOT_PORT:
return QEMU_CAPS_DEVICE_PCIE_ROOT_PORT;
case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE:
return QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE;
case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PCIE_PCI_BRIDGE:
return QEMU_CAPS_DEVICE_PCIE_PCI_BRIDGE;
case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE:
return 0;
case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_LAST:
default:
return -1;
}
return -1;
}
static int
qemuValidateDomainDeviceDefControllerAttributes(const virDomainControllerDef *controller,
virQEMUCapsPtr qemuCaps)
{
if (!(controller->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI &&
(controller->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI ||
controller->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_TRANSITIONAL ||
controller->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_NON_TRANSITIONAL))) {
if (controller->queues) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("'queues' is only supported by virtio-scsi controller"));
return -1;
}
if (controller->cmd_per_lun) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("'cmd_per_lun' is only supported by virtio-scsi controller"));
return -1;
}
if (controller->max_sectors) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("'max_sectors' is only supported by virtio-scsi controller"));
return -1;
}
if (controller->ioeventfd) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("'ioeventfd' is only supported by virtio-scsi controller"));
return -1;
}
if (controller->iothread) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("'iothread' is only supported for virtio-scsi controller"));
return -1;
}
if (qemuValidateDomainVirtioOptions(controller->virtio, qemuCaps) < 0)
return -1;
}
if (controller->type == VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL &&
qemuValidateDomainVirtioOptions(controller->virtio, qemuCaps) < 0) {
return -1;
}
return 0;
}
#define virReportControllerMissingOption(cont, model, modelName, option) \
virReportError(VIR_ERR_INTERNAL_ERROR, \
_("Required option '%s' is not set for PCI controller " \
"with index '%d', model '%s' and modelName '%s'"), \
(option), (cont->idx), (model), (modelName));
#define virReportControllerInvalidOption(cont, model, modelName, option) \
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, \
_("Option '%s' is not valid for PCI controller " \
"with index '%d', model '%s' and modelName '%s'"), \
(option), (cont->idx), (model), (modelName));
#define virReportControllerInvalidValue(cont, model, modelName, option) \
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, \
_("Option '%s' has invalid value for PCI controller " \
"with index '%d', model '%s' and modelName '%s'"), \
(option), (cont->idx), (model), (modelName));
static int
qemuValidateDomainDeviceDefControllerPCI(const virDomainControllerDef *cont,
const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
const virDomainPCIControllerOpts *pciopts = &cont->opts.pciopts;
const char *model = virDomainControllerModelPCITypeToString(cont->model);
const char *modelName = virDomainControllerPCIModelNameTypeToString(pciopts->modelName);
int cap = virValidateControllerPCIModelNameToQEMUCaps(pciopts->modelName);
if (!model) {
virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
return -1;
}
if (!modelName) {
virReportEnumRangeError(virDomainControllerPCIModelName, pciopts->modelName);
return -1;
}
/* modelName */
switch ((virDomainControllerModelPCI) cont->model) {
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
/* modelName should have been set automatically */
if (pciopts->modelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE) {
virReportControllerMissingOption(cont, model, modelName, "modelName");
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
/* modelName must be set for pSeries guests, but it's an error
* for it to be set for any other guest */
if (qemuDomainIsPSeries(def)) {
if (pciopts->modelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE) {
virReportControllerMissingOption(cont, model, modelName, "modelName");
return -1;
}
} else {
if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE) {
virReportControllerInvalidOption(cont, model, modelName, "modelName");
return -1;
}
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE) {
virReportControllerInvalidOption(cont, model, modelName, "modelName");
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
default:
virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
return -1;
}
/* modelName (cont'd) */
switch ((virDomainControllerModelPCI) cont->model) {
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE &&
pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE) {
virReportControllerInvalidValue(cont, model, modelName, "modelName");
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PCI_BRIDGE) {
virReportControllerInvalidValue(cont, model, modelName, "modelName");
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_I82801B11_BRIDGE) {
virReportControllerInvalidValue(cont, model, modelName, "modelName");
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_IOH3420 &&
pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PCIE_ROOT_PORT) {
virReportControllerInvalidValue(cont, model, modelName, "modelName");
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_X3130_UPSTREAM) {
virReportControllerInvalidValue(cont, model, modelName, "modelName");
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_XIO3130_DOWNSTREAM) {
virReportControllerInvalidValue(cont, model, modelName, "modelName");
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PXB) {
virReportControllerInvalidValue(cont, model, modelName, "modelName");
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PXB_PCIE) {
virReportControllerInvalidValue(cont, model, modelName, "modelName");
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE) {
virReportControllerInvalidValue(cont, model, modelName, "modelName");
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PCIE_PCI_BRIDGE) {
virReportControllerInvalidValue(cont, model, modelName, "modelName");
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
default:
virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
return -1;
}
/* index */
switch ((virDomainControllerModelPCI) cont->model) {
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
if (cont->idx == 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Index for '%s' controllers must be > 0"),
model);
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
/* pSeries guests can have multiple PHBs, so it's expected that
* the index will not be zero for some of them */
if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT &&
pciopts->modelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE) {
break;
}
/* For all other pci-root and pcie-root controllers, though,
* the index must be zero */
if (cont->idx != 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Index for '%s' controllers must be 0"),
model);
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
default:
virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
return -1;
}
/* targetIndex */
switch ((virDomainControllerModelPCI) cont->model) {
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
/* PHBs for pSeries guests must have been assigned a targetIndex */
if (pciopts->targetIndex == -1 &&
pciopts->modelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE) {
virReportControllerMissingOption(cont, model, modelName, "targetIndex");
return -1;
}
/* targetIndex only applies to PHBs, so for any other pci-root
* controller it being present is an error */
if (pciopts->targetIndex != -1 &&
pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE) {
virReportControllerInvalidOption(cont, model, modelName, "targetIndex");
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
if (pciopts->targetIndex != -1) {
virReportControllerInvalidOption(cont, model, modelName, "targetIndex");
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
default:
virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
return -1;
}
/* pcihole64 */
switch ((virDomainControllerModelPCI) cont->model) {
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
if (pciopts->pcihole64 || pciopts->pcihole64size != 0) {
if (!qemuDomainIsI440FX(def)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Setting the 64-bit PCI hole size is not "
"supported for machine '%s'"), def->os.machine);
return -1;
}
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_I440FX_PCI_HOLE64_SIZE)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("64-bit PCI hole size setting is not supported "
"with this QEMU binary"));
return -1;
}
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
if (pciopts->pcihole64 || pciopts->pcihole64size != 0) {
if (!qemuDomainIsQ35(def)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Setting the 64-bit PCI hole size is not "
"supported for machine '%s'"), def->os.machine);
return -1;
}
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_Q35_PCI_HOLE64_SIZE)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("64-bit PCI hole size setting is not supported "
"with this QEMU binary"));
return -1;
}
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
if (pciopts->pcihole64 ||
pciopts->pcihole64size != 0) {
virReportControllerInvalidOption(cont, model, modelName, "pcihole64");
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
default:
virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
return -1;
}
/* busNr */
switch ((virDomainControllerModelPCI) cont->model) {
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
if (pciopts->busNr == -1) {
virReportControllerMissingOption(cont, model, modelName, "busNr");
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
if (pciopts->busNr != -1) {
virReportControllerInvalidOption(cont, model, modelName, "busNr");
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
default:
virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
return -1;
}
/* numaNode */
switch ((virDomainControllerModelPCI) cont->model) {
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
/* numaNode can be used for these controllers, but it's not set
* automatically so it can be missing */
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
/* Only PHBs support numaNode */
if (pciopts->numaNode != -1 &&
pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE) {
virReportControllerInvalidOption(cont, model, modelName, "numaNode");
return -1;
}
/* However, the default PHB doesn't support numaNode */
if (pciopts->numaNode != -1 &&
pciopts->modelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE &&
pciopts->targetIndex == 0) {
virReportControllerInvalidOption(cont, model, modelName, "numaNode");
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
if (pciopts->numaNode != -1) {
virReportControllerInvalidOption(cont, model, modelName, "numaNode");
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
default:
virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
return -1;
}
/* chassisNr */
switch ((virDomainControllerModelPCI) cont->model) {
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
if (pciopts->chassisNr == -1) {
virReportControllerMissingOption(cont, model, modelName, "chassisNr");
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
if (pciopts->chassisNr != -1) {
virReportControllerInvalidOption(cont, model, modelName, "chassisNr");
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
default:
virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
return -1;
}
/* chassis and port */
switch ((virDomainControllerModelPCI) cont->model) {
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
if (pciopts->chassis == -1) {
virReportControllerMissingOption(cont, model, modelName, "chassis");
return -1;
}
if (pciopts->port == -1) {
virReportControllerMissingOption(cont, model, modelName, "port");
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
if (pciopts->chassis != -1) {
virReportControllerInvalidOption(cont, model, modelName, "chassis");
return -1;
}
if (pciopts->port != -1) {
virReportControllerInvalidOption(cont, model, modelName, "port");
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
default:
virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
}
/* hotplug */
if (pciopts->hotplug != VIR_TRISTATE_SWITCH_ABSENT) {
switch ((virDomainControllerModelPCI) cont->model) {
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCIE_ROOT_PORT_HOTPLUG)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("setting the hotplug property on a '%s' device is not supported by this QEMU binary"),
modelName);
return -1;
}
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
virReportControllerInvalidOption(cont, model, modelName, "hotplug");
return -1;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
default:
virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
}
}
/* QEMU device availability */
if (cap < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Unknown QEMU device for '%s' controller"),
modelName);
return -1;
}
if (cap > 0 && !virQEMUCapsGet(qemuCaps, cap)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("The '%s' device is not supported by this QEMU binary"),
modelName);
return -1;
}
/* PHBs didn't support numaNode from the very beginning, so an extra
* capability check is required */
if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT &&
pciopts->modelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE &&
pciopts->numaNode != -1 &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SPAPR_PCI_HOST_BRIDGE_NUMA_NODE)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Option '%s' is not supported by '%s' device with this QEMU binary"),
"numaNode", modelName);
return -1;
}
return 0;
}
#undef virReportControllerInvalidValue
#undef virReportControllerInvalidOption
#undef virReportControllerMissingOption
static int
qemuValidateDomainDeviceDefController(const virDomainControllerDef *controller,
const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
int ret = 0;
if (!qemuDomainCheckCCWS390AddressSupport(def, &controller->info, qemuCaps,
"controller"))
return -1;
if (controller->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI &&
!qemuValidateCheckSCSIControllerModel(qemuCaps, controller->model))
return -1;
if (qemuValidateDomainDeviceDefControllerAttributes(controller, qemuCaps) < 0)
return -1;
switch ((virDomainControllerType)controller->type) {
case VIR_DOMAIN_CONTROLLER_TYPE_IDE:
ret = qemuValidateDomainDeviceDefControllerIDE(controller, def);
break;
case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
ret = qemuValidateDomainDeviceDefControllerSCSI(controller, def);
break;
case VIR_DOMAIN_CONTROLLER_TYPE_PCI:
ret = qemuValidateDomainDeviceDefControllerPCI(controller, def,
qemuCaps);
break;
case VIR_DOMAIN_CONTROLLER_TYPE_SATA:
ret = qemuValidateDomainDeviceDefControllerSATA(controller, def,
qemuCaps);
break;
case VIR_DOMAIN_CONTROLLER_TYPE_FDC:
case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL:
case VIR_DOMAIN_CONTROLLER_TYPE_CCID:
case VIR_DOMAIN_CONTROLLER_TYPE_USB:
case VIR_DOMAIN_CONTROLLER_TYPE_XENBUS:
case VIR_DOMAIN_CONTROLLER_TYPE_ISA:
case VIR_DOMAIN_CONTROLLER_TYPE_LAST:
break;
}
return ret;
}
static int
qemuValidateDomainDeviceDefSPICEGraphics(const virDomainGraphicsDef *graphics,
virQEMUDriverPtr driver,
virQEMUCapsPtr qemuCaps)
{
g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
virDomainGraphicsListenDefPtr glisten = NULL;
int tlsPort = graphics->data.spice.tlsPort;
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SPICE)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("spice graphics are not supported with this QEMU"));
return -1;
}
glisten = virDomainGraphicsGetListen((virDomainGraphicsDefPtr)graphics, 0);
if (!glisten) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("missing listen element"));
return -1;
}
switch (glisten->type) {
case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_SOCKET:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SPICE_UNIX)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("unix socket for spice graphics are not supported "
"with this QEMU"));
return -1;
}
break;
case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS:
case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK:
if (tlsPort > 0 && !cfg->spiceTLS) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("spice TLS port set in XML configuration, "
"but TLS is disabled in qemu.conf"));
return -1;
}
break;
case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NONE:
break;
case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_LAST:
break;
}
if (graphics->data.spice.filetransfer == VIR_TRISTATE_BOOL_NO &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SPICE_FILE_XFER_DISABLE)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("This QEMU can't disable file transfers through spice"));
return -1;
}
if (graphics->data.spice.gl == VIR_TRISTATE_BOOL_YES) {
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SPICE_GL)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("This QEMU doesn't support spice OpenGL"));
return -1;
}
if (graphics->data.spice.rendernode &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SPICE_RENDERNODE)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("This QEMU doesn't support spice OpenGL rendernode"));
return -1;
}
}
return 0;
}
static int
qemuValidateDomainDeviceDefGraphics(const virDomainGraphicsDef *graphics,
const virDomainDef *def,
virQEMUDriverPtr driver,
virQEMUCapsPtr qemuCaps)
{
bool have_egl_headless = false;
size_t i;
for (i = 0; i < def->ngraphics; i++) {
if (def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS) {
have_egl_headless = true;
break;
}
}
/* Only VNC and SPICE can be paired with egl-headless, the other types
* either don't make sense to pair with egl-headless or aren't even
* supported by QEMU.
*/
if (have_egl_headless) {
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_EGL_HEADLESS)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("egl-headless display is not supported with this "
"QEMU binary"));
return -1;
}
if (graphics->type != VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS &&
graphics->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
graphics->type != VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("graphics type 'egl-headless' is only supported "
"with one of: 'vnc', 'spice' graphics types"));
return -1;
}
/* '-spice gl=on' and '-display egl-headless' are mutually
* exclusive
*/
if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE &&
graphics->data.spice.gl == VIR_TRISTATE_BOOL_YES) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("multiple OpenGL displays are not supported "
"by QEMU"));
return -1;
}
}
switch (graphics->type) {
case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
if (graphics->data.sdl.gl != VIR_TRISTATE_BOOL_ABSENT) {
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SDL_GL)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("OpenGL for SDL is not supported with this QEMU "
"binary"));
return -1;
}
}
break;
case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VNC)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("vnc graphics are not supported with this QEMU"));
return -1;
}
break;
case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
if (qemuValidateDomainDeviceDefSPICEGraphics(graphics, driver,
qemuCaps) < 0)
return -1;
break;
case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS:
if (graphics->data.egl_headless.rendernode &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_EGL_HEADLESS_RENDERNODE)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("This QEMU doesn't support OpenGL rendernode "
"with egl-headless graphics type"));
return -1;
}
break;
case VIR_DOMAIN_GRAPHICS_TYPE_RDP:
case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("unsupported graphics type '%s'"),
virDomainGraphicsTypeToString(graphics->type));
return -1;
case VIR_DOMAIN_GRAPHICS_TYPE_LAST:
default:
return -1;
}
return 0;
}
static int
qemuValidateDomainDefVirtioFSSharedMemory(const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
const char *defaultRAMId = virQEMUCapsGetMachineDefaultRAMid(qemuCaps,
def->virtType,
def->os.machine);
size_t numa_nodes = virDomainNumaGetNodeCount(def->numa);
size_t i;
if (numa_nodes == 0 &&
!(defaultRAMId && def->mem.access == VIR_DOMAIN_MEMORY_ACCESS_SHARED)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("virtiofs requires shared memory"));
return -1;
}
for (i = 0; i < numa_nodes; i++) {
virDomainMemoryAccess node_access =
virDomainNumaGetNodeMemoryAccessMode(def->numa, i);
switch (node_access) {
case VIR_DOMAIN_MEMORY_ACCESS_DEFAULT:
if (def->mem.access != VIR_DOMAIN_MEMORY_ACCESS_SHARED) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("virtiofs requires shared memory"));
return -1;
}
break;
case VIR_DOMAIN_MEMORY_ACCESS_SHARED:
break;
case VIR_DOMAIN_MEMORY_ACCESS_PRIVATE:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("virtiofs requires shared memory"));
return -1;
case VIR_DOMAIN_MEMORY_ACCESS_LAST:
default:
virReportEnumRangeError(virDomainMemoryAccess, node_access);
return -1;
}
}
return 0;
}
static int
qemuValidateDomainDeviceDefFS(virDomainFSDefPtr fs,
const virDomainDef *def,
virQEMUDriverPtr driver,
virQEMUCapsPtr qemuCaps)
{
if (fs->type != VIR_DOMAIN_FS_TYPE_MOUNT) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("only supports mount filesystem type"));
return -1;
}
if (fs->multidevs != VIR_DOMAIN_FS_MODEL_DEFAULT &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_FSDEV_MULTIDEVS))
{
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("multidevs is not supported with this QEMU binary"));
return -1;
}
if ((fs->fmode != 0) || (fs->dmode != 0)) {
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_FSDEV_CREATEMODE)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("fmode and dmode are not supported with this QEMU binary"));
return -1;
}
if (fs->accessmode != VIR_DOMAIN_FS_ACCESSMODE_MAPPED) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("fmode and dmode must be used with accessmode=mapped"));
return -1;
}
}
switch ((virDomainFSDriverType) fs->fsdriver) {
case VIR_DOMAIN_FS_DRIVER_TYPE_DEFAULT:
case VIR_DOMAIN_FS_DRIVER_TYPE_PATH:
break;
case VIR_DOMAIN_FS_DRIVER_TYPE_HANDLE:
if (fs->accessmode != VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("only supports passthrough accessmode"));
return -1;
}
break;
case VIR_DOMAIN_FS_DRIVER_TYPE_LOOP:
case VIR_DOMAIN_FS_DRIVER_TYPE_NBD:
case VIR_DOMAIN_FS_DRIVER_TYPE_PLOOP:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Filesystem driver type not supported"));
return -1;
case VIR_DOMAIN_FS_DRIVER_TYPE_VIRTIOFS:
if (fs->readonly) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("virtiofs does not yet support read-only mode"));
return -1;
}
if (!driver->privileged) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("virtiofs is not yet supported in session mode"));
return -1;
}
if (fs->accessmode != VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("virtiofs only supports passthrough accessmode"));
return -1;
}
if (fs->wrpolicy != VIR_DOMAIN_FS_WRPOLICY_DEFAULT) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("virtiofs does not support wrpolicy"));
return -1;
}
if (fs->model != VIR_DOMAIN_FS_MODEL_DEFAULT) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("virtiofs does not support model"));
return -1;
}
if (fs->format != VIR_STORAGE_FILE_NONE) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("virtiofs does not support format"));
return -1;
}
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VHOST_USER_FS)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("virtiofs is not supported with this QEMU binary"));
return -1;
}
if (fs->multidevs != VIR_DOMAIN_FS_MULTIDEVS_DEFAULT) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("virtiofs does not support multidevs"));
return -1;
}
if ((fs->fmode != 0) || (fs->dmode != 0)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("virtiofs does not support fmode and dmode"));
return -1;
}
if (qemuValidateDomainDefVirtioFSSharedMemory(def, qemuCaps) < 0)
return -1;
break;
case VIR_DOMAIN_FS_DRIVER_TYPE_LAST:
default:
virReportEnumRangeError(virDomainFSDriverType, fs->fsdriver);
return -1;
}
if (qemuValidateDomainVirtioOptions(fs->virtio, qemuCaps) < 0)
return -1;
return 0;
}
static int
qemuSoundCodecTypeToCaps(int type)
{
switch (type) {
case VIR_DOMAIN_SOUND_CODEC_TYPE_DUPLEX:
return QEMU_CAPS_HDA_DUPLEX;
case VIR_DOMAIN_SOUND_CODEC_TYPE_MICRO:
return QEMU_CAPS_HDA_MICRO;
case VIR_DOMAIN_SOUND_CODEC_TYPE_OUTPUT:
return QEMU_CAPS_HDA_OUTPUT;
default:
return -1;
}
}
static int
qemuValidateDomainDeviceDefSound(virDomainSoundDefPtr sound,
virQEMUCapsPtr qemuCaps)
{
size_t i;
switch ((virDomainSoundModel) sound->model) {
case VIR_DOMAIN_SOUND_MODEL_USB:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_USB_AUDIO)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("usb-audio controller is not supported "
"by this QEMU binary"));
return -1;
}
break;
case VIR_DOMAIN_SOUND_MODEL_ICH9:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_ICH9_INTEL_HDA)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("The ich9-intel-hda audio controller "
"is not supported in this QEMU binary"));
return -1;
}
break;
case VIR_DOMAIN_SOUND_MODEL_ES1370:
case VIR_DOMAIN_SOUND_MODEL_AC97:
case VIR_DOMAIN_SOUND_MODEL_ICH6:
case VIR_DOMAIN_SOUND_MODEL_SB16:
case VIR_DOMAIN_SOUND_MODEL_PCSPK:
break;
case VIR_DOMAIN_SOUND_MODEL_ICH7:
case VIR_DOMAIN_SOUND_MODEL_LAST:
virReportError(VIR_ERR_INTERNAL_ERROR,
_("sound card model '%s' is not supported by qemu"),
virDomainSoundModelTypeToString(sound->model));
return -1;
}
if (sound->model == VIR_DOMAIN_SOUND_MODEL_ICH6 ||
sound->model == VIR_DOMAIN_SOUND_MODEL_ICH9) {
for (i = 0; i < sound->ncodecs; i++) {
const char *stype;
int type, flags;
type = sound->codecs[i]->type;
stype = qemuSoundCodecTypeToString(type);
flags = qemuSoundCodecTypeToCaps(type);
if (flags == -1 || !virQEMUCapsGet(qemuCaps, flags)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("%s not supported in this QEMU binary"), stype);
return -1;
}
}
}
return 0;
}
static int
qemuValidateDomainDeviceDefVsock(const virDomainVsockDef *vsock,
const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VHOST_VSOCK)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("vsock device is not supported "
"with this QEMU binary"));
return -1;
}
if (!qemuDomainCheckCCWS390AddressSupport(def, &vsock->info, qemuCaps,
"vsock"))
return -1;
return 0;
}
static int
qemuValidateDomainDeviceDefTPM(virDomainTPMDef *tpm,
const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
virQEMUCapsFlags flag;
switch (tpm->version) {
case VIR_DOMAIN_TPM_VERSION_1_2:
/* TPM 1.2 + CRB do not work */
if (tpm->type == VIR_DOMAIN_TPM_TYPE_EMULATOR &&
tpm->model == VIR_DOMAIN_TPM_MODEL_CRB) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Unsupported interface %s for TPM 1.2"),
virDomainTPMModelTypeToString(tpm->model));
return -1;
}
/* TPM 1.2 + SPAPR do not work with any 'type' (backend) */
if (tpm->model == VIR_DOMAIN_TPM_MODEL_SPAPR) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("TPM 1.2 is not supported with the SPAPR device model"));
return -1;
}
break;
case VIR_DOMAIN_TPM_VERSION_2_0:
case VIR_DOMAIN_TPM_VERSION_DEFAULT:
case VIR_DOMAIN_TPM_VERSION_LAST:
break;
}
switch (tpm->type) {
case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_TPM_PASSTHROUGH))
goto no_support;
break;
case VIR_DOMAIN_TPM_TYPE_EMULATOR:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_TPM_EMULATOR))
goto no_support;
break;
case VIR_DOMAIN_TPM_TYPE_LAST:
break;
}
switch (tpm->model) {
case VIR_DOMAIN_TPM_MODEL_TIS:
flag = QEMU_CAPS_DEVICE_TPM_TIS;
break;
case VIR_DOMAIN_TPM_MODEL_CRB:
flag = QEMU_CAPS_DEVICE_TPM_CRB;
break;
case VIR_DOMAIN_TPM_MODEL_SPAPR:
flag = QEMU_CAPS_DEVICE_TPM_SPAPR;
break;
case VIR_DOMAIN_TPM_MODEL_SPAPR_PROXY:
if (!ARCH_IS_PPC64(def->os.arch)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("TPM Proxy model %s is only available for "
"PPC64 guests"),
virDomainTPMModelTypeToString(tpm->model));
return -1;
}
/* TPM Proxy devices have 'passthrough' backend */
if (tpm->type != VIR_DOMAIN_TPM_TYPE_PASSTHROUGH) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("TPM Proxy model %s requires "
"'Passthrough' backend"),
virDomainTPMModelTypeToString(tpm->model));
}
flag = QEMU_CAPS_DEVICE_SPAPR_TPM_PROXY;
break;
case VIR_DOMAIN_TPM_MODEL_LAST:
default:
virReportEnumRangeError(virDomainTPMModel, tpm->model);
return -1;
}
if (!virQEMUCapsGet(qemuCaps, flag)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("The QEMU executable %s does not support TPM "
"model %s"),
def->emulator,
virDomainTPMModelTypeToString(tpm->model));
return -1;
}
return 0;
no_support:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("The QEMU executable %s does not support TPM "
"backend type %s"),
def->emulator,
virDomainTPMBackendTypeToString(tpm->type));
return -1;
}
static int
qemuValidateDomainDeviceDefInput(const virDomainInputDef *input,
const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
const char *baseName;
int cap;
int ccwCap;
if (input->bus == VIR_DOMAIN_INPUT_BUS_PS2 && !ARCH_IS_X86(def->os.arch) &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_I8042)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("%s is not supported by this QEMU binary"),
virDomainInputBusTypeToString(input->bus));
return -1;
}
if (input->bus == VIR_DOMAIN_INPUT_BUS_USB &&
input->type == VIR_DOMAIN_INPUT_TYPE_KBD &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_USB_KBD)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("usb keyboard is not supported by this "
"QEMU binary"));
return -1;
}
if (input->bus != VIR_DOMAIN_INPUT_BUS_VIRTIO)
return 0;
/* Only type=passthrough supports model=virtio-(non-)transitional */
switch ((virDomainInputModel)input->model) {
case VIR_DOMAIN_INPUT_MODEL_VIRTIO_TRANSITIONAL:
case VIR_DOMAIN_INPUT_MODEL_VIRTIO_NON_TRANSITIONAL:
switch ((virDomainInputType)input->type) {
case VIR_DOMAIN_INPUT_TYPE_MOUSE:
case VIR_DOMAIN_INPUT_TYPE_TABLET:
case VIR_DOMAIN_INPUT_TYPE_KBD:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("virtio (non-)transitional models are not "
"supported for input type=%s"),
virDomainInputTypeToString(input->type));
return -1;
case VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH:
break;
case VIR_DOMAIN_INPUT_TYPE_LAST:
default:
virReportEnumRangeError(virDomainInputType,
input->type);
return -1;
}
break;
case VIR_DOMAIN_INPUT_MODEL_VIRTIO:
case VIR_DOMAIN_INPUT_MODEL_DEFAULT:
break;
case VIR_DOMAIN_INPUT_MODEL_LAST:
default:
virReportEnumRangeError(virDomainInputModel,
input->model);
return -1;
}
switch ((virDomainInputType)input->type) {
case VIR_DOMAIN_INPUT_TYPE_MOUSE:
baseName = "virtio-mouse";
cap = QEMU_CAPS_VIRTIO_MOUSE;
ccwCap = QEMU_CAPS_DEVICE_VIRTIO_MOUSE_CCW;
break;
case VIR_DOMAIN_INPUT_TYPE_TABLET:
baseName = "virtio-tablet";
cap = QEMU_CAPS_VIRTIO_TABLET;
ccwCap = QEMU_CAPS_DEVICE_VIRTIO_TABLET_CCW;
break;
case VIR_DOMAIN_INPUT_TYPE_KBD:
baseName = "virtio-keyboard";
cap = QEMU_CAPS_VIRTIO_KEYBOARD;
ccwCap = QEMU_CAPS_DEVICE_VIRTIO_KEYBOARD_CCW;
break;
case VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH:
baseName = "virtio-input-host";
cap = QEMU_CAPS_VIRTIO_INPUT_HOST;
ccwCap = QEMU_CAPS_LAST;
break;
case VIR_DOMAIN_INPUT_TYPE_LAST:
default:
virReportEnumRangeError(virDomainInputType,
input->type);
return -1;
}
if (!virQEMUCapsGet(qemuCaps, cap) ||
(input->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW &&
!virQEMUCapsGet(qemuCaps, ccwCap))) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("%s is not supported by this QEMU binary"),
baseName);
return -1;
}
if (qemuValidateDomainVirtioOptions(input->virtio, qemuCaps) < 0)
return -1;
return 0;
}
static int
qemuValidateDomainDeviceDefMemballoon(const virDomainMemballoonDef *memballoon,
virQEMUCapsPtr qemuCaps)
{
if (!memballoon ||
memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_NONE) {
return 0;
}
if (memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO &&
memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO_TRANSITIONAL &&
memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO_NON_TRANSITIONAL) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Memory balloon device type '%s' is not supported by this version of qemu"),
virDomainMemballoonModelTypeToString(memballoon->model));
return -1;
}
if (memballoon->autodeflate != VIR_TRISTATE_SWITCH_ABSENT &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_BALLOON_AUTODEFLATE)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("deflate-on-oom is not supported by this QEMU binary"));
return -1;
}
if (memballoon->free_page_reporting != VIR_TRISTATE_SWITCH_ABSENT &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_BALLOON_FREE_PAGE_REPORTING)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("freePageReporting is not supported by this QEMU binary"));
return -1;
}
if (qemuValidateDomainVirtioOptions(memballoon->virtio, qemuCaps) < 0)
return -1;
return 0;
}
static int
qemuValidateDomainDeviceDefIOMMU(const virDomainIOMMUDef *iommu,
const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
switch (iommu->model) {
case VIR_DOMAIN_IOMMU_MODEL_INTEL:
if (!qemuDomainIsQ35(def)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("IOMMU device: '%s' is only supported with "
"Q35 machines"),
virDomainIOMMUModelTypeToString(iommu->model));
return -1;
}
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_INTEL_IOMMU) &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_MACHINE_IOMMU)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("IOMMU device: '%s' is not supported with "
"this QEMU binary"),
virDomainIOMMUModelTypeToString(iommu->model));
return -1;
}
break;
case VIR_DOMAIN_IOMMU_MODEL_SMMUV3:
if (!qemuDomainIsARMVirt(def)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("IOMMU device: '%s' is only supported with "
"ARM Virt machines"),
virDomainIOMMUModelTypeToString(iommu->model));
return -1;
}
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_MACHINE_VIRT_IOMMU)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("IOMMU device: '%s' is not supported with "
"this QEMU binary"),
virDomainIOMMUModelTypeToString(iommu->model));
return -1;
}
break;
case VIR_DOMAIN_IOMMU_MODEL_LAST:
default:
virReportEnumRangeError(virDomainIOMMUModel, iommu->model);
return -1;
}
/* These capability checks ensure we're not trying to use features
* of Intel IOMMU that the QEMU binary does not support, but they
* also make sure we report an error when trying to use features
* that are not implemented by SMMUv3 */
if (iommu->intremap != VIR_TRISTATE_SWITCH_ABSENT &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_INTEL_IOMMU_INTREMAP)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("iommu: interrupt remapping is not supported "
"with this QEMU binary"));
return -1;
}
if (iommu->caching_mode != VIR_TRISTATE_SWITCH_ABSENT &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_INTEL_IOMMU_CACHING_MODE)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("iommu: caching mode is not supported "
"with this QEMU binary"));
return -1;
}
if (iommu->eim != VIR_TRISTATE_SWITCH_ABSENT &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_INTEL_IOMMU_EIM)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("iommu: eim is not supported "
"with this QEMU binary"));
return -1;
}
if (iommu->iotlb != VIR_TRISTATE_SWITCH_ABSENT &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_INTEL_IOMMU_DEVICE_IOTLB)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("iommu: device IOTLB is not supported "
"with this QEMU binary"));
return -1;
}
if (iommu->aw_bits > 0 &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_INTEL_IOMMU_AW_BITS)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("iommu: aw_bits is not supported "
"with this QEMU binary"));
return -1;
}
return 0;
}
static int
qemuValidateDomainDeviceDefNVRAM(virDomainNVRAMDefPtr nvram,
const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
if (!nvram)
return 0;
if (qemuDomainIsPSeries(def)) {
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_NVRAM)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("nvram device is not supported by "
"this QEMU binary"));
return -1;
}
} else {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("nvram device is only supported for PPC64"));
return -1;
}
if (!(nvram->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO &&
nvram->info.addr.spaprvio.has_reg)) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("nvram address type must be spaprvio"));
return -1;
}
return 0;
}
static int
qemuValidateDomainDeviceDefHub(virDomainHubDefPtr hub,
virQEMUCapsPtr qemuCaps)
{
if (hub->type != VIR_DOMAIN_HUB_TYPE_USB) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("hub type %s not supported"),
virDomainHubTypeToString(hub->type));
return -1;
}
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_USB_HUB)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("usb-hub not supported by QEMU binary"));
return -1;
}
return 0;
}
static int
qemuValidateDomainDeviceDefMemory(virDomainMemoryDefPtr mem,
virQEMUCapsPtr qemuCaps)
{
if (mem->model == VIR_DOMAIN_MEMORY_MODEL_NVDIMM) {
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_NVDIMM)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("nvdimm isn't supported by this QEMU binary"));
return -1;
}
if (mem->readonly &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_NVDIMM_UNARMED)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("nvdimm readonly property is not available "
"with this QEMU binary"));
return -1;
}
}
return 0;
}
static int
qemuValidateDomainDeviceDefShmem(virDomainShmemDefPtr shmem,
virQEMUCapsPtr qemuCaps)
{
switch (shmem->model) {
case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_IVSHMEM)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("ivshmem device is not supported "
"with this QEMU binary"));
return -1;
}
break;
case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM_PLAIN:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_IVSHMEM_PLAIN)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("shmem model '%s' is not supported "
"by this QEMU binary"),
virDomainShmemModelTypeToString(shmem->model));
return -1;
}
break;
case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM_DOORBELL:
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_IVSHMEM_DOORBELL)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("shmem model '%s' is not supported "
"by this QEMU binary"),
virDomainShmemModelTypeToString(shmem->model));
return -1;
}
}
return 0;
}
int
qemuValidateDomainDeviceDef(const virDomainDeviceDef *dev,
const virDomainDef *def,
void *opaque)
{
int ret = 0;
virQEMUDriverPtr driver = opaque;
g_autoptr(virQEMUCaps) qemuCaps = NULL;
g_autoptr(virDomainCaps) domCaps = NULL;
if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache,
def->emulator)))
return -1;
if (!(domCaps = virQEMUDriverGetDomainCapabilities(driver, qemuCaps,
def->os.machine,
def->os.arch,
def->virtType)))
return -1;
if ((ret = qemuValidateDomainDeviceDefAddress(dev, qemuCaps)) < 0)
return ret;
if ((ret = virDomainCapsDeviceDefValidate(domCaps, dev, def)) < 0)
return ret;
switch ((virDomainDeviceType)dev->type) {
case VIR_DOMAIN_DEVICE_NET:
ret = qemuValidateDomainDeviceDefNetwork(dev->data.net, qemuCaps);
break;
case VIR_DOMAIN_DEVICE_CHR:
ret = qemuValidateDomainChrDef(dev->data.chr, def, qemuCaps);
break;
case VIR_DOMAIN_DEVICE_SMARTCARD:
ret = qemuValidateDomainSmartcardDef(dev->data.smartcard, qemuCaps);
break;
case VIR_DOMAIN_DEVICE_RNG:
ret = qemuValidateDomainRNGDef(dev->data.rng, qemuCaps);
break;
case VIR_DOMAIN_DEVICE_REDIRDEV:
ret = qemuValidateDomainRedirdevDef(dev->data.redirdev, def, qemuCaps);
break;
case VIR_DOMAIN_DEVICE_WATCHDOG:
ret = qemuValidateDomainWatchdogDef(dev->data.watchdog, def);
break;
case VIR_DOMAIN_DEVICE_HOSTDEV:
ret = qemuValidateDomainDeviceDefHostdev(dev->data.hostdev, def,
qemuCaps);
break;
case VIR_DOMAIN_DEVICE_VIDEO:
ret = qemuValidateDomainDeviceDefVideo(dev->data.video, qemuCaps);
break;
case VIR_DOMAIN_DEVICE_DISK:
ret = qemuValidateDomainDeviceDefDisk(dev->data.disk, def, qemuCaps);
break;
case VIR_DOMAIN_DEVICE_CONTROLLER:
ret = qemuValidateDomainDeviceDefController(dev->data.controller, def,
qemuCaps);
break;
case VIR_DOMAIN_DEVICE_VSOCK:
ret = qemuValidateDomainDeviceDefVsock(dev->data.vsock, def, qemuCaps);
break;
case VIR_DOMAIN_DEVICE_TPM:
ret = qemuValidateDomainDeviceDefTPM(dev->data.tpm, def, qemuCaps);
break;
case VIR_DOMAIN_DEVICE_GRAPHICS:
ret = qemuValidateDomainDeviceDefGraphics(dev->data.graphics, def,
driver, qemuCaps);
break;
case VIR_DOMAIN_DEVICE_INPUT:
ret = qemuValidateDomainDeviceDefInput(dev->data.input, def, qemuCaps);
break;
case VIR_DOMAIN_DEVICE_MEMBALLOON:
ret = qemuValidateDomainDeviceDefMemballoon(dev->data.memballoon, qemuCaps);
break;
case VIR_DOMAIN_DEVICE_IOMMU:
ret = qemuValidateDomainDeviceDefIOMMU(dev->data.iommu, def, qemuCaps);
break;
case VIR_DOMAIN_DEVICE_FS:
ret = qemuValidateDomainDeviceDefFS(dev->data.fs, def, driver, qemuCaps);
break;
case VIR_DOMAIN_DEVICE_NVRAM:
ret = qemuValidateDomainDeviceDefNVRAM(dev->data.nvram, def, qemuCaps);
break;
case VIR_DOMAIN_DEVICE_HUB:
ret = qemuValidateDomainDeviceDefHub(dev->data.hub, qemuCaps);
break;
case VIR_DOMAIN_DEVICE_SOUND:
ret = qemuValidateDomainDeviceDefSound(dev->data.sound, qemuCaps);
break;
case VIR_DOMAIN_DEVICE_MEMORY:
ret = qemuValidateDomainDeviceDefMemory(dev->data.memory, qemuCaps);
break;
case VIR_DOMAIN_DEVICE_SHMEM:
ret = qemuValidateDomainDeviceDefShmem(dev->data.shmem, qemuCaps);
break;
case VIR_DOMAIN_DEVICE_LEASE:
case VIR_DOMAIN_DEVICE_PANIC:
case VIR_DOMAIN_DEVICE_AUDIO:
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_LAST:
break;
}
return ret;
}