}
-/**
- * qemuDomainDefGetVcpuHotplugGranularity:
- * @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
-qemuDomainDefGetVcpuHotplugGranularity(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;
-}
-
-
-#define QEMU_MAX_VCPUS_WITHOUT_EIM 255
-
-
-static int
-qemuDomainDefValidateMemory(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
-qemuDomainDefValidateNuma(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);
-
- 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++) {
- g_autofree char * cpumask = NULL;
-
- 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 = virBitmapFormat(virDomainNumaGetNodeCpumask(def->numa, i))))
- return -1;
-
- if (strchr(cpumask, ',') &&
- !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;
- }
-
- return 0;
-}
-
-
-static int
-qemuDomainValidateCpuCount(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;
- }
-
- return 0;
-}
-
-
static int
qemuDomainDeviceDefValidateNVRAM(virDomainNVRAMDefPtr nvram,
const virDomainDef *def,
}
-static int
-qemuDomainDefValidateClockTimers(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:
- 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
-qemuDomainDefValidatePM(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
-qemuDomainDefValidateBoot(const virDomainDef *def,
- virQEMUCapsPtr qemuCaps)
-{
- 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;
-}
-
-static int
-qemuDomainDefValidateConsole(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
qemuSoundCodecTypeToCaps(int type)
{
return 0;
}
-static int
-qemuDomainDefValidate(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->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->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 (qemuDomainDefValidateClockTimers(def, qemuCaps) < 0)
- return -1;
-
- if (qemuDomainDefValidatePM(def, qemuCaps) < 0)
- return -1;
-
- if (qemuDomainDefValidateBoot(def, qemuCaps) < 0)
- 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 = qemuDomainDefGetVcpuHotplugGranularity(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 (qemuDomainValidateCpuCount(def, qemuCaps) < 0)
- 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;
- }
- }
-
- 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 (qemuDomainDefValidateMemory(def, qemuCaps) < 0)
- return -1;
-
- if (qemuDomainDefValidateNuma(def, qemuCaps) < 0)
- return -1;
-
- if (qemuDomainDefValidateConsole(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;
- }
- }
- }
-
- return 0;
-}
-
static bool
qemuDomainNetSupportsCoalesce(virDomainNetType type)
.devicesPostParseCallback = qemuDomainDeviceDefPostParse,
.domainPostParseCallback = qemuDomainDefPostParse,
.assignAddressesCallback = qemuDomainDefAssignAddresses,
- .domainValidateCallback = qemuDomainDefValidate,
+ .domainValidateCallback = qemuValidateDomainDef,
.deviceValidateCallback = qemuDomainDeviceDefValidate,
.features = VIR_DOMAIN_DEF_FEATURE_MEMORY_HOTPLUG |
#include "qemu_validate.h"
#include "qemu_domain.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
}
-int
+static int
qemuValidateDomainDefFeatures(const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
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:
+ 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.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;
+}
+
+
+static int
+qemuValidateDomainCpuCount(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;
+ }
+
+ 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);
+
+ 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++) {
+ g_autofree char * cpumask = NULL;
+
+ 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 = virBitmapFormat(virDomainNumaGetNodeCpumask(def->numa, i))))
+ return -1;
+
+ if (strchr(cpumask, ',') &&
+ !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;
+ }
+
+ 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;
+}
+
+
+/**
+ * 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;
+}
+
+
+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->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->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 (qemuValidateDomainDefClockTimers(def, qemuCaps) < 0)
+ return -1;
+
+ if (qemuValidateDomainDefPM(def, qemuCaps) < 0)
+ return -1;
+
+ if (qemuValidateDomainDefBoot(def, qemuCaps) < 0)
+ 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 (qemuValidateDomainCpuCount(def, qemuCaps) < 0)
+ 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;
+ }
+ }
+
+ 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;
+ }
+ }
+ }
+
+ return 0;
+}