2008-05-22 16:18:40 +00:00
|
|
|
#include <config.h>
|
2008-06-26 09:37:51 +00:00
|
|
|
#ifdef WITH_QEMU
|
2008-05-16 16:51:30 +00:00
|
|
|
|
2010-03-09 18:22:22 +00:00
|
|
|
# include "testutilsqemu.h"
|
2017-07-21 12:24:51 +00:00
|
|
|
# include "testutilshostcpus.h"
|
2010-03-09 18:22:22 +00:00
|
|
|
# include "testutils.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
# include "viralloc.h"
|
2010-04-16 06:01:59 +00:00
|
|
|
# include "cpu_conf.h"
|
2010-04-20 21:22:49 +00:00
|
|
|
# include "qemu/qemu_driver.h"
|
2010-12-17 16:41:51 +00:00
|
|
|
# include "qemu/qemu_domain.h"
|
2018-12-13 14:53:50 +00:00
|
|
|
# define LIBVIRT_QEMU_CAPSPRIV_H_ALLOW
|
2015-09-09 14:03:14 +00:00
|
|
|
# include "qemu/qemu_capspriv.h"
|
2013-05-03 12:52:21 +00:00
|
|
|
# include "virstring.h"
|
2017-07-19 15:01:56 +00:00
|
|
|
# include "virfilecache.h"
|
2020-02-16 21:59:28 +00:00
|
|
|
# include "virutil.h"
|
2013-05-03 12:52:21 +00:00
|
|
|
|
|
|
|
# define VIR_FROM_THIS VIR_FROM_QEMU
|
2008-05-16 16:51:30 +00:00
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
virCPUDef *cpuDefault;
|
|
|
|
virCPUDef *cpuHaswell;
|
|
|
|
virCPUDef *cpuPower8;
|
|
|
|
virCPUDef *cpuPower9;
|
2015-03-23 16:19:28 +00:00
|
|
|
|
2016-12-20 09:10:05 +00:00
|
|
|
|
2019-12-02 12:19:44 +00:00
|
|
|
static const char *qemu_emulators[VIR_ARCH_LAST] = {
|
|
|
|
[VIR_ARCH_I686] = "/usr/bin/qemu-system-i386",
|
|
|
|
[VIR_ARCH_X86_64] = "/usr/bin/qemu-system-x86_64",
|
|
|
|
[VIR_ARCH_AARCH64] = "/usr/bin/qemu-system-aarch64",
|
|
|
|
[VIR_ARCH_ARMV7L] = "/usr/bin/qemu-system-arm",
|
|
|
|
[VIR_ARCH_PPC64] = "/usr/bin/qemu-system-ppc64",
|
|
|
|
[VIR_ARCH_PPC] = "/usr/bin/qemu-system-ppc",
|
|
|
|
[VIR_ARCH_RISCV32] = "/usr/bin/qemu-system-riscv32",
|
|
|
|
[VIR_ARCH_RISCV64] = "/usr/bin/qemu-system-riscv64",
|
2020-11-18 17:06:45 +00:00
|
|
|
[VIR_ARCH_S390X] = "/usr/bin/qemu-system-s390x",
|
|
|
|
[VIR_ARCH_SPARC] = "/usr/bin/qemu-system-sparc",
|
2019-12-02 12:19:44 +00:00
|
|
|
};
|
2009-09-10 10:19:12 +00:00
|
|
|
|
2019-12-02 12:19:44 +00:00
|
|
|
static const virArch arch_alias[VIR_ARCH_LAST] = {
|
|
|
|
[VIR_ARCH_PPC64LE] = VIR_ARCH_PPC64,
|
|
|
|
[VIR_ARCH_ARMV6L] = VIR_ARCH_ARMV7L,
|
|
|
|
};
|
2009-09-10 10:19:12 +00:00
|
|
|
|
2019-12-02 12:19:44 +00:00
|
|
|
static const char *const i386_machines[] = {
|
2022-01-05 08:21:14 +00:00
|
|
|
"pc", NULL
|
2019-12-02 12:19:44 +00:00
|
|
|
};
|
2022-01-05 08:21:14 +00:00
|
|
|
|
2020-01-22 09:28:19 +00:00
|
|
|
static const char *const x86_64_machines[] = {
|
2022-01-05 08:21:14 +00:00
|
|
|
"pc", "q35", NULL
|
2019-12-02 12:19:44 +00:00
|
|
|
};
|
|
|
|
static const char *const aarch64_machines[] = {
|
2020-01-22 16:46:57 +00:00
|
|
|
"virt", "virt-2.6", "versatilepb", NULL
|
2019-12-02 12:19:44 +00:00
|
|
|
};
|
|
|
|
static const char *const arm_machines[] = {
|
2022-01-04 15:10:31 +00:00
|
|
|
"vexpress-a9", "virt", NULL
|
2019-12-02 12:19:44 +00:00
|
|
|
};
|
|
|
|
static const char *const ppc64_machines[] = {
|
|
|
|
"pseries", NULL
|
|
|
|
};
|
|
|
|
static const char *const ppc_machines[] = {
|
2022-01-04 15:10:31 +00:00
|
|
|
"ppce500", NULL
|
2019-12-02 12:19:44 +00:00
|
|
|
};
|
|
|
|
static const char *const riscv32_machines[] = {
|
2022-01-04 15:10:31 +00:00
|
|
|
"virt", NULL
|
2019-12-02 12:19:44 +00:00
|
|
|
};
|
|
|
|
static const char *const riscv64_machines[] = {
|
2022-01-04 15:10:31 +00:00
|
|
|
"virt", NULL
|
2019-12-02 12:19:44 +00:00
|
|
|
};
|
|
|
|
static const char *const s390x_machines[] = {
|
2021-09-22 09:15:00 +00:00
|
|
|
"s390-ccw-virtio", NULL
|
2019-12-02 12:19:44 +00:00
|
|
|
};
|
2020-11-18 17:06:45 +00:00
|
|
|
static const char *const sparc_machines[] = {
|
2022-01-04 15:10:31 +00:00
|
|
|
"SS-5", NULL
|
2020-11-18 17:06:45 +00:00
|
|
|
};
|
2009-09-10 10:19:12 +00:00
|
|
|
|
2019-12-02 12:19:44 +00:00
|
|
|
static const char *const *qemu_machines[VIR_ARCH_LAST] = {
|
|
|
|
[VIR_ARCH_I686] = i386_machines,
|
2020-01-22 09:28:19 +00:00
|
|
|
[VIR_ARCH_X86_64] = x86_64_machines,
|
2019-12-02 12:19:44 +00:00
|
|
|
[VIR_ARCH_AARCH64] = aarch64_machines,
|
|
|
|
[VIR_ARCH_ARMV7L] = arm_machines,
|
|
|
|
[VIR_ARCH_PPC64] = ppc64_machines,
|
|
|
|
[VIR_ARCH_PPC] = ppc_machines,
|
|
|
|
[VIR_ARCH_RISCV32] = riscv32_machines,
|
|
|
|
[VIR_ARCH_RISCV64] = riscv64_machines,
|
|
|
|
[VIR_ARCH_S390X] = s390x_machines,
|
2020-11-18 17:06:45 +00:00
|
|
|
[VIR_ARCH_SPARC] = sparc_machines,
|
2019-12-02 12:19:44 +00:00
|
|
|
};
|
2009-09-10 10:19:12 +00:00
|
|
|
|
2019-12-02 12:19:44 +00:00
|
|
|
static const char *const *kvm_machines[VIR_ARCH_LAST] = {
|
|
|
|
[VIR_ARCH_I686] = i386_machines,
|
2020-01-22 09:28:19 +00:00
|
|
|
[VIR_ARCH_X86_64] = x86_64_machines,
|
2019-12-02 12:19:44 +00:00
|
|
|
[VIR_ARCH_AARCH64] = aarch64_machines,
|
|
|
|
[VIR_ARCH_ARMV7L] = arm_machines,
|
|
|
|
[VIR_ARCH_PPC64] = ppc64_machines,
|
|
|
|
[VIR_ARCH_PPC] = ppc_machines,
|
|
|
|
[VIR_ARCH_RISCV32] = riscv32_machines,
|
|
|
|
[VIR_ARCH_RISCV64] = riscv64_machines,
|
|
|
|
[VIR_ARCH_S390X] = s390x_machines,
|
|
|
|
};
|
Fix default console type setting
The default console type may vary based on the OS type. ie a Xen
paravirt guests wants a 'xen' console, while a fullvirt guests
wants a 'serial' console.
A plain integer default console type in the capabilities does
not suffice. Instead introduce a callback that is passed the
OS type.
* src/conf/capabilities.h: Use a callback for default console
type
* src/conf/domain_conf.c, src/conf/domain_conf.h: Use callback
for default console type. Add missing LXC/OpenVZ console types.
* src/esx/esx_driver.c, src/libxl/libxl_conf.c,
src/lxc/lxc_conf.c, src/openvz/openvz_conf.c,
src/phyp/phyp_driver.c, src/qemu/qemu_capabilities.c,
src/uml/uml_conf.c, src/vbox/vbox_tmpl.c,
src/vmware/vmware_conf.c, src/xen/xen_hypervisor.c,
src/xenapi/xenapi_driver.c: Set default console type callback
2011-10-20 13:56:20 +00:00
|
|
|
|
2022-01-06 10:45:25 +00:00
|
|
|
static const char *const *hvf_machines[VIR_ARCH_LAST] = {
|
|
|
|
[VIR_ARCH_I686] = NULL,
|
|
|
|
[VIR_ARCH_X86_64] = x86_64_machines,
|
|
|
|
[VIR_ARCH_AARCH64] = aarch64_machines,
|
|
|
|
[VIR_ARCH_ARMV7L] = NULL,
|
|
|
|
[VIR_ARCH_PPC64] = NULL,
|
|
|
|
[VIR_ARCH_PPC] = NULL,
|
|
|
|
[VIR_ARCH_RISCV32] = NULL,
|
|
|
|
[VIR_ARCH_RISCV64] = NULL,
|
|
|
|
[VIR_ARCH_S390X] = NULL,
|
|
|
|
};
|
|
|
|
|
2020-05-25 17:13:43 +00:00
|
|
|
static const char *qemu_default_ram_id[VIR_ARCH_LAST] = {
|
|
|
|
[VIR_ARCH_I686] = "pc.ram",
|
|
|
|
[VIR_ARCH_X86_64] = "pc.ram",
|
|
|
|
[VIR_ARCH_AARCH64] = "mach-virt.ram",
|
|
|
|
[VIR_ARCH_ARMV7L] = "vexpress.highmem",
|
|
|
|
[VIR_ARCH_PPC64] = "ppc_spapr.ram",
|
|
|
|
[VIR_ARCH_PPC] = "ppc_spapr.ram",
|
2020-11-18 17:06:45 +00:00
|
|
|
[VIR_ARCH_S390X] = "s390.ram",
|
|
|
|
[VIR_ARCH_SPARC] = "sun4m.ram",
|
2020-05-25 17:13:43 +00:00
|
|
|
};
|
2019-11-26 16:53:53 +00:00
|
|
|
|
|
|
|
char *
|
|
|
|
virFindFileInPath(const char *file)
|
|
|
|
{
|
|
|
|
if (g_str_has_prefix(file, "qemu-system") ||
|
|
|
|
g_str_equal(file, "qemu-kvm")) {
|
|
|
|
return g_strdup_printf("/usr/bin/%s", file);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Nothing in tests should be relying on real files
|
|
|
|
* in host OS, so we return NULL to try to force
|
|
|
|
* an error in such a case
|
|
|
|
*/
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-11-29 10:40:39 +00:00
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
virCapsHostNUMA *
|
2019-11-29 10:40:39 +00:00
|
|
|
virCapabilitiesHostNUMANewHost(void)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Build a NUMA topology with cell_id (NUMA node id
|
|
|
|
* being 3(0 + 3),4(1 + 3), 5 and 6
|
|
|
|
*/
|
|
|
|
return virTestCapsBuildNUMATopology(3);
|
|
|
|
}
|
|
|
|
|
2021-12-08 19:53:45 +00:00
|
|
|
void
|
|
|
|
virHostCPUX86GetCPUID(uint32_t leaf,
|
|
|
|
uint32_t extended,
|
|
|
|
uint32_t *eax,
|
|
|
|
uint32_t *ebx,
|
|
|
|
uint32_t *ecx,
|
|
|
|
uint32_t *edx)
|
|
|
|
{
|
|
|
|
if (eax)
|
|
|
|
*eax = 0;
|
|
|
|
if (ebx)
|
|
|
|
*ebx = 0;
|
|
|
|
if (ecx)
|
|
|
|
*ecx = 0;
|
|
|
|
if (edx)
|
|
|
|
*edx = 0;
|
|
|
|
if (leaf == 0x8000001F && extended == 0) {
|
|
|
|
if (ecx)
|
|
|
|
*ecx = 509;
|
|
|
|
if (edx)
|
|
|
|
*edx = 451;
|
|
|
|
}
|
|
|
|
}
|
2019-11-29 10:40:39 +00:00
|
|
|
|
2016-12-19 22:52:33 +00:00
|
|
|
static int
|
2021-03-11 07:16:13 +00:00
|
|
|
testQemuAddGuest(virCaps *caps,
|
2022-01-06 11:32:25 +00:00
|
|
|
virArch arch,
|
|
|
|
testQemuHostOS hostOS)
|
2016-12-19 22:52:33 +00:00
|
|
|
{
|
2019-12-02 12:19:44 +00:00
|
|
|
size_t nmachines;
|
2021-03-11 07:16:13 +00:00
|
|
|
virCapsGuestMachine **machines = NULL;
|
|
|
|
virCapsGuest *guest;
|
2019-12-02 12:19:44 +00:00
|
|
|
virArch emu_arch = arch;
|
2016-12-19 22:52:33 +00:00
|
|
|
|
2019-12-02 12:19:44 +00:00
|
|
|
if (arch_alias[arch] != VIR_ARCH_NONE)
|
|
|
|
emu_arch = arch_alias[arch];
|
2016-12-19 22:52:33 +00:00
|
|
|
|
2019-12-02 12:19:44 +00:00
|
|
|
if (qemu_emulators[emu_arch] == NULL)
|
|
|
|
return 0;
|
2016-12-19 22:52:33 +00:00
|
|
|
|
2019-12-02 12:19:44 +00:00
|
|
|
nmachines = g_strv_length((gchar **)qemu_machines[emu_arch]);
|
|
|
|
machines = virCapabilitiesAllocMachines(qemu_machines[emu_arch],
|
|
|
|
nmachines);
|
|
|
|
if (machines == NULL)
|
2016-12-19 22:52:33 +00:00
|
|
|
goto error;
|
|
|
|
|
2021-10-07 08:47:27 +00:00
|
|
|
guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM,
|
|
|
|
arch, qemu_emulators[emu_arch],
|
|
|
|
NULL, nmachines, machines);
|
2016-12-19 22:52:33 +00:00
|
|
|
|
|
|
|
machines = NULL;
|
2019-12-02 12:19:44 +00:00
|
|
|
nmachines = 0;
|
|
|
|
|
|
|
|
if (arch == VIR_ARCH_I686 ||
|
|
|
|
arch == VIR_ARCH_X86_64)
|
|
|
|
virCapabilitiesAddGuestFeature(guest, VIR_CAPS_GUEST_FEATURE_TYPE_CPUSELECTION);
|
2016-12-19 22:52:33 +00:00
|
|
|
|
2021-10-07 08:47:28 +00:00
|
|
|
virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_QEMU,
|
|
|
|
NULL, NULL, 0, NULL);
|
2016-12-19 22:52:33 +00:00
|
|
|
|
2022-01-06 11:32:25 +00:00
|
|
|
if (hostOS == HOST_OS_LINUX) {
|
|
|
|
if (kvm_machines[emu_arch] != NULL) {
|
|
|
|
nmachines = g_strv_length((char **)kvm_machines[emu_arch]);
|
|
|
|
machines = virCapabilitiesAllocMachines(kvm_machines[emu_arch],
|
|
|
|
nmachines);
|
|
|
|
if (machines == NULL)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_KVM,
|
|
|
|
qemu_emulators[emu_arch],
|
|
|
|
NULL, nmachines, machines);
|
|
|
|
}
|
2020-11-18 17:06:45 +00:00
|
|
|
}
|
2016-12-19 22:52:33 +00:00
|
|
|
|
2022-01-06 10:45:25 +00:00
|
|
|
if (hostOS == HOST_OS_MACOS) {
|
|
|
|
if (hvf_machines[emu_arch] != NULL) {
|
|
|
|
nmachines = g_strv_length((char **)hvf_machines[emu_arch]);
|
|
|
|
machines = virCapabilitiesAllocMachines(hvf_machines[emu_arch],
|
|
|
|
nmachines);
|
|
|
|
if (machines == NULL)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_HVF,
|
|
|
|
qemu_emulators[emu_arch],
|
|
|
|
NULL, nmachines, machines);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-22 09:15:27 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virCapabilitiesFreeMachines(machines, nmachines);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-03-05 15:17:24 +00:00
|
|
|
|
2022-01-06 11:32:25 +00:00
|
|
|
static virCaps*
|
|
|
|
testQemuCapsInitImpl(testQemuHostOS hostOS)
|
2014-03-18 08:13:43 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virCaps *caps;
|
2019-12-02 12:19:44 +00:00
|
|
|
size_t i;
|
2008-05-16 16:51:30 +00:00
|
|
|
|
2015-03-23 16:19:28 +00:00
|
|
|
if (!(caps = virCapabilitiesNew(VIR_ARCH_X86_64, false, false)))
|
2008-05-16 16:51:30 +00:00
|
|
|
return NULL;
|
|
|
|
|
2014-09-03 17:06:55 +00:00
|
|
|
/* Add dummy 'none' security_driver. This is equal to setting
|
|
|
|
* security_driver = "none" in qemu.conf. */
|
2020-09-22 23:04:17 +00:00
|
|
|
caps->host.secModels = g_new0(virCapsHostSecModel, 1);
|
2014-09-03 17:06:55 +00:00
|
|
|
caps->host.nsecModels = 1;
|
|
|
|
|
2019-10-20 11:49:46 +00:00
|
|
|
caps->host.secModels[0].model = g_strdup("none");
|
|
|
|
caps->host.secModels[0].doi = g_strdup("0");
|
2014-09-03 17:06:55 +00:00
|
|
|
|
2019-11-29 10:40:39 +00:00
|
|
|
if (!(caps->host.numa = virCapabilitiesHostNUMANewHost()))
|
tests: Create full host NUMA topology in more cases
vircapstest has code to add a full host NUMA topology, that
is, one that includes all information about nodes and CPUs
including IDs; testQemuCapsInit(), which is used to create a
mock virCapsPtr for QEMU tests, however, just fakes it by
setting nnumaCell_max to some number.
While the latter approach has served us well so far, we're
going to need all the information to be filled in soon. In
order to do that, we can just move the existing code from
vircapstest to testutils and, with some renaming and
trivial tweaking, use it as-is.
Interestingly, the NUMA topology generated by the function
is rigged up so that the NUMA nodes aren't (necessarily)
numbered starting from 0, which is a nice way to spot
mistaken assumptions in our codebase.
Signed-off-by: Andrea Bolognani <abologna@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
2018-04-10 15:42:14 +00:00
|
|
|
goto cleanup;
|
2015-07-24 14:06:33 +00:00
|
|
|
|
2019-12-02 12:19:44 +00:00
|
|
|
for (i = 0; i < VIR_ARCH_LAST; i++) {
|
2022-01-06 11:32:25 +00:00
|
|
|
if (testQemuAddGuest(caps, i, hostOS) < 0)
|
2019-12-02 12:19:44 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2014-01-02 10:42:56 +00:00
|
|
|
|
2009-11-30 19:01:31 +00:00
|
|
|
if (virTestGetDebug()) {
|
2020-07-28 19:57:28 +00:00
|
|
|
g_autofree char *caps_str = NULL;
|
2009-09-10 10:07:20 +00:00
|
|
|
|
|
|
|
caps_str = virCapabilitiesFormatXML(caps);
|
|
|
|
if (!caps_str)
|
|
|
|
goto cleanup;
|
|
|
|
|
2015-04-23 17:38:00 +00:00
|
|
|
VIR_TEST_DEBUG("QEMU driver capabilities:\n%s", caps_str);
|
2009-09-10 10:07:20 +00:00
|
|
|
}
|
|
|
|
|
2008-05-16 16:51:30 +00:00
|
|
|
return caps;
|
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
cleanup:
|
2016-08-04 11:16:55 +00:00
|
|
|
caps->host.cpu = NULL;
|
2013-02-01 12:26:18 +00:00
|
|
|
virObjectUnref(caps);
|
2008-05-16 16:51:30 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2013-05-17 10:34:24 +00:00
|
|
|
|
2022-01-06 11:32:25 +00:00
|
|
|
virCaps*
|
|
|
|
testQemuCapsInit(void)
|
|
|
|
{
|
|
|
|
return testQemuCapsInitImpl(HOST_OS_LINUX);
|
|
|
|
}
|
|
|
|
|
2022-01-06 10:45:25 +00:00
|
|
|
virCaps*
|
|
|
|
testQemuCapsInitMacOS(void)
|
|
|
|
{
|
|
|
|
return testQemuCapsInitImpl(HOST_OS_MACOS);
|
|
|
|
}
|
|
|
|
|
2013-05-17 10:34:24 +00:00
|
|
|
|
2016-08-04 11:16:55 +00:00
|
|
|
void
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuTestSetHostArch(virQEMUDriver *driver,
|
2016-08-04 11:16:55 +00:00
|
|
|
virArch arch)
|
|
|
|
{
|
|
|
|
if (arch == VIR_ARCH_NONE)
|
|
|
|
arch = VIR_ARCH_X86_64;
|
2019-11-26 17:51:22 +00:00
|
|
|
|
|
|
|
virTestHostArch = arch;
|
|
|
|
driver->hostarch = virArchFromHost();
|
|
|
|
driver->caps->host.arch = virArchFromHost();
|
2019-11-29 10:40:39 +00:00
|
|
|
qemuTestSetHostCPU(driver, arch, NULL);
|
2016-08-04 11:16:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuTestSetHostCPU(virQEMUDriver *driver,
|
2019-11-29 10:40:39 +00:00
|
|
|
virArch arch,
|
2021-03-11 07:16:13 +00:00
|
|
|
virCPUDef *cpu)
|
2016-08-04 11:16:55 +00:00
|
|
|
{
|
|
|
|
if (!cpu) {
|
|
|
|
if (ARCH_IS_X86(arch))
|
|
|
|
cpu = cpuDefault;
|
2016-09-13 20:27:09 +00:00
|
|
|
else if (ARCH_IS_PPC64(arch))
|
|
|
|
cpu = cpuPower8;
|
2016-08-04 11:16:55 +00:00
|
|
|
}
|
|
|
|
|
2019-12-18 17:16:19 +00:00
|
|
|
g_unsetenv("VIR_TEST_MOCK_FAKE_HOST_CPU");
|
2017-07-21 12:24:51 +00:00
|
|
|
if (cpu) {
|
|
|
|
if (cpu->model)
|
2019-12-18 17:16:19 +00:00
|
|
|
g_setenv("VIR_TEST_MOCK_FAKE_HOST_CPU", cpu->model, TRUE);
|
2017-07-21 12:24:51 +00:00
|
|
|
}
|
2019-11-29 10:40:39 +00:00
|
|
|
if (driver) {
|
|
|
|
if (cpu)
|
|
|
|
driver->caps->host.arch = cpu->arch;
|
|
|
|
driver->caps->host.cpu = cpu;
|
|
|
|
|
|
|
|
virCPUDefFree(driver->hostcpu);
|
|
|
|
if (cpu)
|
|
|
|
virCPUDefRef(cpu);
|
|
|
|
driver->hostcpu = cpu;
|
|
|
|
}
|
2016-08-04 11:16:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
virQEMUCaps *
|
2018-04-04 07:17:52 +00:00
|
|
|
qemuTestParseCapabilitiesArch(virArch arch,
|
|
|
|
const char *capsFile)
|
2014-06-27 14:39:27 +00:00
|
|
|
{
|
2021-08-20 11:35:05 +00:00
|
|
|
g_autoptr(virQEMUCaps) qemuCaps = NULL;
|
2020-02-21 07:28:13 +00:00
|
|
|
g_autofree char *binary = g_strdup_printf("/usr/bin/qemu-system-%s",
|
|
|
|
virArchToString(arch));
|
2014-06-27 14:39:27 +00:00
|
|
|
|
2019-12-10 10:23:14 +00:00
|
|
|
if (!(qemuCaps = virQEMUCapsNewBinary(binary)) ||
|
2020-06-18 13:44:16 +00:00
|
|
|
virQEMUCapsLoadCache(arch, qemuCaps, capsFile, true) < 0)
|
2021-08-20 11:35:05 +00:00
|
|
|
return NULL;
|
2014-06-27 14:39:27 +00:00
|
|
|
|
2021-08-20 11:35:05 +00:00
|
|
|
return g_steal_pointer(&qemuCaps);
|
2014-06-27 14:39:27 +00:00
|
|
|
}
|
2015-09-15 06:16:02 +00:00
|
|
|
|
2018-04-04 07:17:52 +00:00
|
|
|
|
2015-09-15 06:16:02 +00:00
|
|
|
void qemuTestDriverFree(virQEMUDriver *driver)
|
|
|
|
{
|
2015-09-22 14:12:39 +00:00
|
|
|
virMutexDestroy(&driver->lock);
|
2020-05-07 20:31:04 +00:00
|
|
|
if (driver->config) {
|
|
|
|
virFileDeleteTree(driver->config->stateDir);
|
|
|
|
virFileDeleteTree(driver->config->configDir);
|
|
|
|
}
|
2017-07-19 15:01:56 +00:00
|
|
|
virObjectUnref(driver->qemuCapsCache);
|
2015-09-15 06:16:02 +00:00
|
|
|
virObjectUnref(driver->xmlopt);
|
|
|
|
virObjectUnref(driver->caps);
|
|
|
|
virObjectUnref(driver->config);
|
2016-07-29 16:06:51 +00:00
|
|
|
virObjectUnref(driver->securityManager);
|
2021-07-30 08:34:50 +00:00
|
|
|
|
|
|
|
virCPUDefFree(cpuDefault);
|
|
|
|
virCPUDefFree(cpuHaswell);
|
|
|
|
virCPUDefFree(cpuPower8);
|
|
|
|
virCPUDefFree(cpuPower9);
|
2015-09-15 06:16:02 +00:00
|
|
|
}
|
|
|
|
|
2022-01-04 16:11:30 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
qemuTestCapsPopulateFakeMachines(virQEMUCaps *caps,
|
2022-01-06 11:32:25 +00:00
|
|
|
virArch arch,
|
|
|
|
testQemuHostOS hostOS)
|
2022-01-04 16:11:30 +00:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
const char *defaultRAMid = NULL;
|
|
|
|
|
|
|
|
/* default-ram-id appeared in QEMU 5.2.0. Reflect
|
|
|
|
* this in our capabilities, i.e. set it for new
|
|
|
|
* enough versions only. */
|
|
|
|
if (virQEMUCapsGetVersion(caps) >= 5002000)
|
|
|
|
defaultRAMid = qemu_default_ram_id[arch];
|
|
|
|
|
|
|
|
virQEMUCapsSetArch(caps, arch);
|
|
|
|
|
|
|
|
for (i = 0; qemu_machines[arch][i] != NULL; i++) {
|
|
|
|
virQEMUCapsAddMachine(caps,
|
|
|
|
VIR_DOMAIN_VIRT_QEMU,
|
|
|
|
qemu_machines[arch][i],
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
false,
|
|
|
|
false,
|
|
|
|
true,
|
|
|
|
defaultRAMid,
|
|
|
|
false);
|
|
|
|
virQEMUCapsSet(caps, QEMU_CAPS_TCG);
|
|
|
|
}
|
|
|
|
|
2022-01-06 11:32:25 +00:00
|
|
|
if (hostOS == HOST_OS_LINUX) {
|
|
|
|
if (kvm_machines[arch] != NULL) {
|
|
|
|
for (i = 0; kvm_machines[arch][i] != NULL; i++) {
|
|
|
|
virQEMUCapsAddMachine(caps,
|
|
|
|
VIR_DOMAIN_VIRT_KVM,
|
|
|
|
kvm_machines[arch][i],
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
false,
|
|
|
|
false,
|
|
|
|
true,
|
|
|
|
defaultRAMid,
|
|
|
|
false);
|
|
|
|
virQEMUCapsSet(caps, QEMU_CAPS_KVM);
|
|
|
|
}
|
2022-01-04 16:11:30 +00:00
|
|
|
}
|
|
|
|
}
|
2022-01-06 10:45:25 +00:00
|
|
|
|
|
|
|
if (hostOS == HOST_OS_MACOS) {
|
|
|
|
if (hvf_machines[arch] != NULL) {
|
|
|
|
for (i = 0; hvf_machines[arch][i] != NULL; i++) {
|
|
|
|
virQEMUCapsAddMachine(caps,
|
|
|
|
VIR_DOMAIN_VIRT_HVF,
|
|
|
|
hvf_machines[arch][i],
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
false,
|
|
|
|
false,
|
|
|
|
true,
|
|
|
|
defaultRAMid,
|
|
|
|
false);
|
|
|
|
virQEMUCapsSet(caps, QEMU_CAPS_HVF);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-01-04 16:11:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-01-05 19:53:18 +00:00
|
|
|
static int
|
|
|
|
qemuTestCapsCacheInsertData(virFileCache *cache,
|
|
|
|
const char *binary,
|
|
|
|
virQEMUCaps *caps)
|
|
|
|
{
|
|
|
|
if (virFileCacheInsertData(cache, binary, virObjectRef(caps)) < 0) {
|
|
|
|
virObjectUnref(caps);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-01-06 11:32:25 +00:00
|
|
|
static int
|
|
|
|
qemuTestCapsCacheInsertImpl(virFileCache *cache,
|
|
|
|
virQEMUCaps *caps,
|
|
|
|
testQemuHostOS hostOS)
|
2015-09-09 14:03:14 +00:00
|
|
|
{
|
2022-01-04 16:11:30 +00:00
|
|
|
size_t i;
|
2019-12-02 12:19:44 +00:00
|
|
|
|
2022-01-05 19:53:18 +00:00
|
|
|
if (caps && virQEMUCapsGetArch(caps) != VIR_ARCH_NONE) {
|
|
|
|
/* for capabilities which have architecture set we populate only the
|
|
|
|
* given architecture and poison all other so that the test doesn't
|
|
|
|
* accidentally test a weird combination */
|
|
|
|
virArch arch = virQEMUCapsGetArch(caps);
|
|
|
|
g_autoptr(virQEMUCaps) emptyCaps = virQEMUCapsNew();
|
|
|
|
g_autoptr(virQEMUCaps) copyCaps = NULL;
|
|
|
|
virQEMUCaps *effCaps = caps;
|
2020-01-23 12:23:35 +00:00
|
|
|
|
2022-01-05 19:53:18 +00:00
|
|
|
if (!emptyCaps)
|
2020-11-20 12:39:37 +00:00
|
|
|
return -1;
|
|
|
|
|
2022-01-05 19:53:18 +00:00
|
|
|
if (arch_alias[arch] != VIR_ARCH_NONE)
|
|
|
|
arch = arch_alias[arch];
|
2020-01-23 12:23:35 +00:00
|
|
|
|
2022-01-05 19:53:18 +00:00
|
|
|
if (qemu_emulators[arch]) {
|
|
|
|
/* if we are dealing with fake caps we need to populate machine types */
|
|
|
|
if (!virQEMUCapsHasMachines(caps)) {
|
|
|
|
if (!(copyCaps = effCaps = virQEMUCapsNewCopy(caps)))
|
|
|
|
return -1;
|
|
|
|
|
2022-01-06 11:32:25 +00:00
|
|
|
qemuTestCapsPopulateFakeMachines(copyCaps, arch, hostOS);
|
2022-01-05 19:53:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (qemuTestCapsCacheInsertData(cache, qemu_emulators[arch], effCaps) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < G_N_ELEMENTS(qemu_emulators); i++) {
|
|
|
|
if (!qemu_emulators[i])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (i == arch)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (qemuTestCapsCacheInsertData(cache, qemu_emulators[i], emptyCaps) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* in case when caps are missing or are missing architecture, we populate
|
|
|
|
* everything */
|
|
|
|
for (i = 0; i < G_N_ELEMENTS(qemu_emulators); i++) {
|
|
|
|
g_autoptr(virQEMUCaps) tmp = NULL;
|
|
|
|
|
|
|
|
if (qemu_emulators[i] == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (caps)
|
|
|
|
tmp = virQEMUCapsNewCopy(caps);
|
|
|
|
else
|
|
|
|
tmp = virQEMUCapsNew();
|
|
|
|
|
|
|
|
if (!tmp)
|
|
|
|
return -1;
|
|
|
|
|
2022-01-06 11:32:25 +00:00
|
|
|
qemuTestCapsPopulateFakeMachines(tmp, i, hostOS);
|
2022-01-05 19:53:18 +00:00
|
|
|
|
|
|
|
if (qemuTestCapsCacheInsertData(cache, qemu_emulators[i], tmp) < 0)
|
|
|
|
return -1;
|
2017-04-11 12:02:06 +00:00
|
|
|
}
|
|
|
|
}
|
2015-09-09 14:03:14 +00:00
|
|
|
|
2017-04-11 12:02:06 +00:00
|
|
|
return 0;
|
2015-09-09 14:03:14 +00:00
|
|
|
}
|
|
|
|
|
2022-01-06 11:32:25 +00:00
|
|
|
int
|
|
|
|
qemuTestCapsCacheInsert(virFileCache *cache,
|
|
|
|
virQEMUCaps *caps)
|
|
|
|
{
|
|
|
|
return qemuTestCapsCacheInsertImpl(cache, caps, HOST_OS_LINUX);
|
|
|
|
}
|
|
|
|
|
2022-01-06 10:45:25 +00:00
|
|
|
int
|
|
|
|
qemuTestCapsCacheInsertMacOS(virFileCache *cache,
|
|
|
|
virQEMUCaps *caps)
|
|
|
|
{
|
|
|
|
return qemuTestCapsCacheInsertImpl(cache, caps, HOST_OS_MACOS);
|
|
|
|
}
|
|
|
|
|
2017-04-11 12:02:06 +00:00
|
|
|
|
2020-05-07 20:31:04 +00:00
|
|
|
# define STATEDIRTEMPLATE abs_builddir "/qemustatedir-XXXXXX"
|
|
|
|
# define CONFIGDIRTEMPLATE abs_builddir "/qemuconfigdir-XXXXXX"
|
2017-03-06 07:27:23 +00:00
|
|
|
|
2015-09-15 06:16:02 +00:00
|
|
|
int qemuTestDriverInit(virQEMUDriver *driver)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virSecurityManager *mgr = NULL;
|
2020-05-07 20:31:04 +00:00
|
|
|
char statedir[] = STATEDIRTEMPLATE;
|
|
|
|
char configdir[] = CONFIGDIRTEMPLATE;
|
2016-03-23 15:19:26 +00:00
|
|
|
|
2016-01-18 08:11:19 +00:00
|
|
|
memset(driver, 0, sizeof(*driver));
|
|
|
|
|
2019-11-29 10:40:39 +00:00
|
|
|
if (!(cpuDefault = virCPUDefCopy(&cpuDefaultData)) ||
|
|
|
|
!(cpuHaswell = virCPUDefCopy(&cpuHaswellData)) ||
|
|
|
|
!(cpuPower8 = virCPUDefCopy(&cpuPower8Data)) ||
|
|
|
|
!(cpuPower9 = virCPUDefCopy(&cpuPower9Data)))
|
|
|
|
return -1;
|
|
|
|
|
2015-09-22 14:12:39 +00:00
|
|
|
if (virMutexInit(&driver->lock) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2019-11-26 17:51:22 +00:00
|
|
|
driver->hostarch = virArchFromHost();
|
2020-05-07 20:31:04 +00:00
|
|
|
driver->config = virQEMUDriverConfigNew(false, NULL);
|
2015-09-15 06:16:02 +00:00
|
|
|
if (!driver->config)
|
2015-09-22 14:12:39 +00:00
|
|
|
goto error;
|
2015-09-15 06:16:02 +00:00
|
|
|
|
2020-05-07 20:31:04 +00:00
|
|
|
/* Do this early so that qemuTestDriverFree() doesn't see (unlink) the real
|
|
|
|
* dirs. */
|
|
|
|
VIR_FREE(driver->config->stateDir);
|
|
|
|
VIR_FREE(driver->config->configDir);
|
|
|
|
|
2016-03-15 12:54:24 +00:00
|
|
|
/* Overwrite some default paths so it's consistent for tests. */
|
|
|
|
VIR_FREE(driver->config->libDir);
|
|
|
|
VIR_FREE(driver->config->channelTargetDir);
|
2019-10-20 11:49:46 +00:00
|
|
|
driver->config->libDir = g_strdup("/tmp/lib");
|
|
|
|
driver->config->channelTargetDir = g_strdup("/tmp/channel");
|
2016-03-15 12:54:24 +00:00
|
|
|
|
2020-05-07 20:31:04 +00:00
|
|
|
if (!g_mkdtemp(statedir)) {
|
|
|
|
fprintf(stderr, "Cannot create fake stateDir");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
driver->config->stateDir = g_strdup(statedir);
|
|
|
|
|
|
|
|
if (!g_mkdtemp(configdir)) {
|
|
|
|
fprintf(stderr, "Cannot create fake configDir");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
driver->config->configDir = g_strdup(configdir);
|
|
|
|
|
2015-09-15 06:16:02 +00:00
|
|
|
driver->caps = testQemuCapsInit();
|
|
|
|
if (!driver->caps)
|
|
|
|
goto error;
|
|
|
|
|
2015-09-09 14:03:15 +00:00
|
|
|
/* Using /dev/null for libDir and cacheDir automatically produces errors
|
|
|
|
* upon attempt to use any of them */
|
2019-04-12 19:21:05 +00:00
|
|
|
driver->qemuCapsCache = virQEMUCapsCacheNew("/dev/null", "/dev/null", 0, 0);
|
2015-09-09 14:03:15 +00:00
|
|
|
if (!driver->qemuCapsCache)
|
|
|
|
goto error;
|
|
|
|
|
2019-11-26 18:57:30 +00:00
|
|
|
driver->xmlopt = virQEMUDriverCreateXMLConf(driver, "none");
|
2015-09-15 06:16:02 +00:00
|
|
|
if (!driver->xmlopt)
|
|
|
|
goto error;
|
|
|
|
|
2017-04-11 12:02:06 +00:00
|
|
|
if (qemuTestCapsCacheInsert(driver->qemuCapsCache, NULL) < 0)
|
2015-09-09 14:03:15 +00:00
|
|
|
goto error;
|
|
|
|
|
2018-10-02 13:08:28 +00:00
|
|
|
if (!(mgr = virSecurityManagerNew("none", "qemu",
|
2016-03-23 15:19:26 +00:00
|
|
|
VIR_SECURITY_MANAGER_PRIVILEGED)))
|
|
|
|
goto error;
|
|
|
|
if (!(driver->securityManager = virSecurityManagerNewStack(mgr)))
|
|
|
|
goto error;
|
|
|
|
|
2019-11-29 10:40:39 +00:00
|
|
|
qemuTestSetHostCPU(driver, driver->hostarch, NULL);
|
|
|
|
|
2015-09-15 06:16:02 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
2016-03-23 15:19:26 +00:00
|
|
|
virObjectUnref(mgr);
|
2015-09-15 06:16:02 +00:00
|
|
|
qemuTestDriverFree(driver);
|
|
|
|
return -1;
|
|
|
|
}
|
2015-09-09 14:03:14 +00:00
|
|
|
|
2016-05-10 09:35:43 +00:00
|
|
|
int
|
2021-03-11 07:16:13 +00:00
|
|
|
testQemuCapsSetGIC(virQEMUCaps *qemuCaps,
|
2016-05-10 09:35:43 +00:00
|
|
|
int gic)
|
|
|
|
{
|
|
|
|
virGICCapability *gicCapabilities = NULL;
|
|
|
|
size_t ngicCapabilities = 0;
|
|
|
|
|
2020-09-22 23:04:17 +00:00
|
|
|
gicCapabilities = g_new0(virGICCapability, 2);
|
2016-05-10 09:35:43 +00:00
|
|
|
|
|
|
|
# define IMPL_BOTH \
|
|
|
|
VIR_GIC_IMPLEMENTATION_KERNEL|VIR_GIC_IMPLEMENTATION_EMULATED
|
|
|
|
|
|
|
|
if (gic & GIC_V2) {
|
|
|
|
gicCapabilities[ngicCapabilities].version = VIR_GIC_VERSION_2;
|
|
|
|
gicCapabilities[ngicCapabilities].implementation = IMPL_BOTH;
|
|
|
|
ngicCapabilities++;
|
|
|
|
}
|
|
|
|
if (gic & GIC_V3) {
|
|
|
|
gicCapabilities[ngicCapabilities].version = VIR_GIC_VERSION_3;
|
|
|
|
gicCapabilities[ngicCapabilities].implementation = IMPL_BOTH;
|
|
|
|
ngicCapabilities++;
|
|
|
|
}
|
|
|
|
|
|
|
|
# undef IMPL_BOTH
|
|
|
|
|
|
|
|
virQEMUCapsSetGICCapabilities(qemuCaps,
|
|
|
|
gicCapabilities, ngicCapabilities);
|
|
|
|
|
2020-01-06 21:57:49 +00:00
|
|
|
return 0;
|
2016-05-10 09:35:43 +00:00
|
|
|
}
|
|
|
|
|
2008-06-26 09:37:51 +00:00
|
|
|
#endif
|
2018-04-18 08:47:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
char *
|
2019-04-16 10:26:22 +00:00
|
|
|
testQemuGetLatestCapsForArch(const char *arch,
|
2018-04-18 08:47:31 +00:00
|
|
|
const char *suffix)
|
|
|
|
{
|
|
|
|
struct dirent *ent;
|
2020-10-25 21:50:51 +00:00
|
|
|
g_autoptr(DIR) dir = NULL;
|
2018-04-18 08:47:31 +00:00
|
|
|
int rc;
|
2020-07-28 19:57:28 +00:00
|
|
|
g_autofree char *fullsuffix = NULL;
|
2018-04-18 08:47:31 +00:00
|
|
|
unsigned long maxver = 0;
|
|
|
|
unsigned long ver;
|
2020-02-07 14:51:26 +00:00
|
|
|
g_autofree char *maxname = NULL;
|
2018-04-18 08:47:31 +00:00
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
fullsuffix = g_strdup_printf("%s.%s", arch, suffix);
|
2018-04-18 08:47:31 +00:00
|
|
|
|
2019-04-16 10:26:22 +00:00
|
|
|
if (virDirOpen(&dir, TEST_QEMU_CAPS_PATH) < 0)
|
2020-10-27 21:49:11 +00:00
|
|
|
return NULL;
|
2018-04-18 08:47:31 +00:00
|
|
|
|
2019-04-16 10:26:22 +00:00
|
|
|
while ((rc = virDirRead(dir, &ent, TEST_QEMU_CAPS_PATH)) > 0) {
|
2020-07-28 20:01:22 +00:00
|
|
|
g_autofree char *tmp = NULL;
|
2018-04-18 08:47:31 +00:00
|
|
|
|
2019-10-20 11:49:46 +00:00
|
|
|
tmp = g_strdup(STRSKIP(ent->d_name, "caps_"));
|
2018-04-18 08:47:31 +00:00
|
|
|
|
2019-10-20 11:49:46 +00:00
|
|
|
if (!tmp)
|
2018-04-18 08:47:31 +00:00
|
|
|
continue;
|
|
|
|
|
2019-03-07 09:18:38 +00:00
|
|
|
if (!virStringStripSuffix(tmp, fullsuffix))
|
2018-04-18 08:47:31 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (virParseVersionString(tmp, &ver, false) < 0) {
|
2019-05-03 08:31:02 +00:00
|
|
|
VIR_TEST_DEBUG("skipping caps file '%s'", ent->d_name);
|
2018-04-18 08:47:31 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ver > maxver) {
|
2020-02-07 14:51:26 +00:00
|
|
|
g_free(maxname);
|
|
|
|
maxname = g_strdup(ent->d_name);
|
2018-04-18 08:47:31 +00:00
|
|
|
maxver = ver;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc < 0)
|
2020-10-27 21:49:11 +00:00
|
|
|
return NULL;
|
2018-04-18 08:47:31 +00:00
|
|
|
|
|
|
|
if (!maxname) {
|
2019-05-03 08:45:58 +00:00
|
|
|
VIR_TEST_VERBOSE("failed to find capabilities for '%s' in '%s'",
|
2019-04-16 10:26:22 +00:00
|
|
|
arch, TEST_QEMU_CAPS_PATH);
|
2020-10-27 21:49:11 +00:00
|
|
|
return NULL;
|
2018-04-18 08:47:31 +00:00
|
|
|
}
|
|
|
|
|
2020-10-27 21:49:11 +00:00
|
|
|
return g_strdup_printf("%s/%s", TEST_QEMU_CAPS_PATH, maxname);
|
2018-04-18 08:47:31 +00:00
|
|
|
}
|
2019-03-07 14:54:55 +00:00
|
|
|
|
|
|
|
|
2020-10-22 17:04:18 +00:00
|
|
|
GHashTable *
|
2019-03-31 16:43:44 +00:00
|
|
|
testQemuGetLatestCaps(void)
|
|
|
|
{
|
|
|
|
const char *archs[] = {
|
|
|
|
"aarch64",
|
|
|
|
"ppc64",
|
|
|
|
"riscv64",
|
|
|
|
"s390x",
|
|
|
|
"x86_64",
|
|
|
|
};
|
2021-07-05 14:22:08 +00:00
|
|
|
g_autoptr(GHashTable) capslatest = virHashNew(g_free);
|
2019-03-31 16:43:44 +00:00
|
|
|
size_t i;
|
|
|
|
|
2019-05-03 08:45:58 +00:00
|
|
|
VIR_TEST_VERBOSE("");
|
2019-03-31 16:43:44 +00:00
|
|
|
|
2019-10-15 11:55:26 +00:00
|
|
|
for (i = 0; i < G_N_ELEMENTS(archs); ++i) {
|
2019-04-16 10:26:22 +00:00
|
|
|
char *cap = testQemuGetLatestCapsForArch(archs[i], "xml");
|
2019-03-31 16:43:44 +00:00
|
|
|
|
|
|
|
if (!cap || virHashAddEntry(capslatest, archs[i], cap) < 0)
|
2021-07-05 14:22:49 +00:00
|
|
|
return NULL;
|
2019-03-31 16:43:44 +00:00
|
|
|
|
2019-05-03 08:45:58 +00:00
|
|
|
VIR_TEST_VERBOSE("latest caps for %s: %s", archs[i], cap);
|
2019-03-31 16:43:44 +00:00
|
|
|
}
|
|
|
|
|
2019-05-03 08:45:58 +00:00
|
|
|
VIR_TEST_VERBOSE("");
|
|
|
|
|
2021-07-05 14:22:08 +00:00
|
|
|
return g_steal_pointer(&capslatest);
|
2019-03-31 16:43:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-03-07 14:54:55 +00:00
|
|
|
int
|
2019-04-16 10:33:14 +00:00
|
|
|
testQemuCapsIterate(const char *suffix,
|
2019-03-07 14:54:55 +00:00
|
|
|
testQemuCapsIterateCallback callback,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
struct dirent *ent;
|
2020-10-25 21:50:51 +00:00
|
|
|
g_autoptr(DIR) dir = NULL;
|
2019-03-07 14:54:55 +00:00
|
|
|
int rc;
|
2019-10-25 11:59:46 +00:00
|
|
|
bool fail = false;
|
2019-03-07 14:54:55 +00:00
|
|
|
|
|
|
|
if (!callback)
|
|
|
|
return 0;
|
|
|
|
|
2019-10-22 16:34:03 +00:00
|
|
|
/* Validate suffix */
|
|
|
|
if (!STRPREFIX(suffix, ".")) {
|
|
|
|
VIR_TEST_VERBOSE("malformed suffix '%s'", suffix);
|
2020-10-27 21:49:11 +00:00
|
|
|
return -1;
|
2019-10-22 16:34:03 +00:00
|
|
|
}
|
|
|
|
|
2019-04-16 10:33:14 +00:00
|
|
|
if (virDirOpen(&dir, TEST_QEMU_CAPS_PATH) < 0)
|
2020-10-27 21:49:11 +00:00
|
|
|
return -1;
|
2019-03-07 14:54:55 +00:00
|
|
|
|
2019-06-04 18:56:58 +00:00
|
|
|
while ((rc = virDirRead(dir, &ent, TEST_QEMU_CAPS_PATH)) > 0) {
|
2019-10-22 16:31:09 +00:00
|
|
|
g_autofree char *tmp = g_strdup(ent->d_name);
|
2019-10-22 14:08:10 +00:00
|
|
|
char *version = NULL;
|
2019-03-07 14:54:55 +00:00
|
|
|
char *archName = NULL;
|
|
|
|
|
|
|
|
/* Strip the trailing suffix, moving on if it's not present */
|
|
|
|
if (!virStringStripSuffix(tmp, suffix))
|
|
|
|
continue;
|
|
|
|
|
2019-10-22 14:08:10 +00:00
|
|
|
/* Strip the leading prefix */
|
|
|
|
if (!(version = STRSKIP(tmp, "caps_"))) {
|
|
|
|
VIR_TEST_VERBOSE("malformed file name '%s'", ent->d_name);
|
2020-10-27 21:49:11 +00:00
|
|
|
return -1;
|
2019-10-22 14:08:10 +00:00
|
|
|
}
|
|
|
|
|
2019-10-22 16:31:09 +00:00
|
|
|
/* Find the last dot */
|
|
|
|
if (!(archName = strrchr(tmp, '.'))) {
|
|
|
|
VIR_TEST_VERBOSE("malformed file name '%s'", ent->d_name);
|
2020-10-27 21:49:11 +00:00
|
|
|
return -1;
|
2019-10-22 16:31:09 +00:00
|
|
|
}
|
2019-03-07 14:54:55 +00:00
|
|
|
|
2019-10-22 14:08:10 +00:00
|
|
|
/* The version number and the architecture name are separated by
|
|
|
|
* a dot: overwriting that dot with \0 results in both being usable
|
|
|
|
* as independent, null-terminated strings */
|
2019-03-07 14:54:55 +00:00
|
|
|
archName[0] = '\0';
|
|
|
|
archName++;
|
|
|
|
|
2019-10-22 13:44:37 +00:00
|
|
|
/* Run the user-provided callback.
|
|
|
|
*
|
|
|
|
* We skip the dot that, as verified earlier, starts the suffix
|
|
|
|
* to make it nicer to rebuild the original file name from inside
|
|
|
|
* the callback.
|
|
|
|
*/
|
2019-10-22 14:08:10 +00:00
|
|
|
if (callback(TEST_QEMU_CAPS_PATH, "caps", version,
|
2019-10-25 11:59:46 +00:00
|
|
|
archName, suffix + 1, opaque) < 0)
|
|
|
|
fail = true;
|
2019-03-07 14:54:55 +00:00
|
|
|
}
|
|
|
|
|
2019-10-25 11:59:46 +00:00
|
|
|
if (rc < 0 || fail)
|
2020-10-27 21:49:11 +00:00
|
|
|
return -1;
|
2019-03-07 14:54:55 +00:00
|
|
|
|
2020-10-27 21:49:11 +00:00
|
|
|
return 0;
|
2019-03-07 14:54:55 +00:00
|
|
|
}
|
2019-03-31 15:49:34 +00:00
|
|
|
|
|
|
|
|
2021-08-17 13:30:44 +00:00
|
|
|
void
|
2019-03-31 15:49:34 +00:00
|
|
|
testQemuInfoSetArgs(struct testQemuInfo *info,
|
2021-08-17 14:26:58 +00:00
|
|
|
struct testQemuConf *conf, ...)
|
2019-03-31 15:49:34 +00:00
|
|
|
{
|
|
|
|
va_list argptr;
|
|
|
|
testQemuInfoArgName argname;
|
|
|
|
int flag;
|
|
|
|
|
2021-08-17 13:30:44 +00:00
|
|
|
if (!(info->args.fakeCaps = virQEMUCapsNew()))
|
2021-08-16 14:42:18 +00:00
|
|
|
abort();
|
|
|
|
|
2021-08-17 14:26:58 +00:00
|
|
|
info->conf = conf;
|
2021-08-17 13:30:44 +00:00
|
|
|
info->args.newargs = true;
|
2021-08-17 14:26:58 +00:00
|
|
|
|
|
|
|
va_start(argptr, conf);
|
2021-08-17 12:24:13 +00:00
|
|
|
while ((argname = va_arg(argptr, testQemuInfoArgName)) != ARG_END) {
|
2019-03-31 15:49:34 +00:00
|
|
|
switch (argname) {
|
|
|
|
case ARG_QEMU_CAPS:
|
2021-08-17 13:30:44 +00:00
|
|
|
info->args.fakeCapsUsed = true;
|
2019-03-31 15:49:34 +00:00
|
|
|
|
|
|
|
while ((flag = va_arg(argptr, int)) < QEMU_CAPS_LAST)
|
2021-08-17 13:30:44 +00:00
|
|
|
virQEMUCapsSet(info->args.fakeCaps, flag);
|
2019-03-31 15:49:34 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ARG_GIC:
|
2021-08-17 13:30:44 +00:00
|
|
|
info->args.gic = va_arg(argptr, int);
|
2019-03-31 15:49:34 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ARG_MIGRATE_FROM:
|
|
|
|
info->migrateFrom = va_arg(argptr, char *);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ARG_MIGRATE_FD:
|
|
|
|
info->migrateFd = va_arg(argptr, int);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ARG_FLAGS:
|
|
|
|
info->flags = va_arg(argptr, int);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ARG_PARSEFLAGS:
|
|
|
|
info->parseFlags = va_arg(argptr, int);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ARG_CAPS_ARCH:
|
2021-08-17 13:30:44 +00:00
|
|
|
info->args.capsarch = va_arg(argptr, char *);
|
2019-03-31 15:49:34 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ARG_CAPS_VER:
|
2021-08-17 13:30:44 +00:00
|
|
|
info->args.capsver = va_arg(argptr, char *);
|
2019-03-31 15:49:34 +00:00
|
|
|
break;
|
|
|
|
|
2022-01-06 11:32:33 +00:00
|
|
|
case ARG_HOST_OS:
|
|
|
|
info->args.hostOS = va_arg(argptr, int);
|
|
|
|
break;
|
|
|
|
|
2019-03-31 15:49:34 +00:00
|
|
|
case ARG_END:
|
|
|
|
default:
|
2021-08-17 13:30:44 +00:00
|
|
|
info->args.invalidarg = true;
|
|
|
|
break;
|
2019-03-31 15:49:34 +00:00
|
|
|
}
|
2021-08-17 13:30:44 +00:00
|
|
|
|
|
|
|
if (info->args.invalidarg)
|
|
|
|
break;
|
2019-03-31 15:49:34 +00:00
|
|
|
}
|
|
|
|
|
2021-08-17 13:30:44 +00:00
|
|
|
va_end(argptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
testQemuInfoInitArgs(struct testQemuInfo *info)
|
|
|
|
{
|
|
|
|
g_autofree char *capsfile = NULL;
|
|
|
|
|
|
|
|
if (!info->args.newargs)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
info->args.newargs = false;
|
|
|
|
|
|
|
|
if (info->args.invalidarg) {
|
2021-08-25 12:50:25 +00:00
|
|
|
fprintf(stderr, "Invalid argument encountered by 'testQemuInfoSetArgs'\n");
|
2021-08-17 13:30:44 +00:00
|
|
|
return -1;
|
2019-03-31 15:49:34 +00:00
|
|
|
}
|
|
|
|
|
2021-08-17 13:30:44 +00:00
|
|
|
if (!!info->args.capsarch ^ !!info->args.capsver) {
|
|
|
|
fprintf(stderr, "ARG_CAPS_ARCH and ARG_CAPS_VER must be specified together.\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info->args.capsarch && info->args.capsver) {
|
2019-03-31 15:49:34 +00:00
|
|
|
bool stripmachinealiases = false;
|
2021-03-11 07:16:13 +00:00
|
|
|
virQEMUCaps *cachedcaps = NULL;
|
2019-03-31 15:49:34 +00:00
|
|
|
|
2021-08-17 13:30:44 +00:00
|
|
|
info->arch = virArchFromString(info->args.capsarch);
|
2019-10-24 15:51:42 +00:00
|
|
|
|
2021-08-17 13:30:44 +00:00
|
|
|
if (STREQ(info->args.capsver, "latest")) {
|
|
|
|
capsfile = g_strdup(virHashLookup(info->conf->capslatest, info->args.capsarch));
|
2021-09-22 08:53:58 +00:00
|
|
|
|
|
|
|
if (!capsfile) {
|
|
|
|
fprintf(stderr, "'latest' caps for '%s' were not found\n", info->args.capsarch);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-03-31 15:49:34 +00:00
|
|
|
stripmachinealiases = true;
|
2021-02-19 15:31:42 +00:00
|
|
|
} else {
|
|
|
|
capsfile = g_strdup_printf("%s/caps_%s.%s.xml",
|
2021-08-17 13:30:44 +00:00
|
|
|
TEST_QEMU_CAPS_PATH,
|
|
|
|
info->args.capsver,
|
|
|
|
info->args.capsarch);
|
2021-02-19 15:31:42 +00:00
|
|
|
}
|
2019-03-31 15:49:34 +00:00
|
|
|
|
2021-08-17 14:26:58 +00:00
|
|
|
if (!g_hash_table_lookup_extended(info->conf->capscache, capsfile, NULL, (void **) &cachedcaps)) {
|
2021-08-16 14:42:18 +00:00
|
|
|
if (!(cachedcaps = qemuTestParseCapabilitiesArch(info->arch, capsfile)))
|
2021-08-17 13:30:44 +00:00
|
|
|
return -1;
|
2021-02-19 15:46:45 +00:00
|
|
|
|
2021-08-17 14:26:58 +00:00
|
|
|
g_hash_table_insert(info->conf->capscache, g_strdup(capsfile), cachedcaps);
|
2021-02-19 15:46:45 +00:00
|
|
|
}
|
|
|
|
|
2021-08-16 14:42:18 +00:00
|
|
|
if (!(info->qemuCaps = virQEMUCapsNewCopy(cachedcaps)))
|
2021-08-17 13:30:44 +00:00
|
|
|
return -1;
|
2019-03-31 15:49:34 +00:00
|
|
|
|
2021-12-09 14:57:05 +00:00
|
|
|
if (info->args.fakeCapsUsed) {
|
|
|
|
size_t i;
|
|
|
|
for (i = 0; i < QEMU_CAPS_LAST; i++) {
|
|
|
|
if (virQEMUCapsGet(info->args.fakeCaps, i)) {
|
|
|
|
virQEMUCapsSet(info->qemuCaps, i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-05-17 08:51:15 +00:00
|
|
|
if (stripmachinealiases)
|
2021-08-16 14:42:18 +00:00
|
|
|
virQEMUCapsStripMachineAliases(info->qemuCaps);
|
2021-05-17 08:51:15 +00:00
|
|
|
|
2019-03-31 15:49:34 +00:00
|
|
|
info->flags |= FLAG_REAL_CAPS;
|
2020-05-15 12:33:10 +00:00
|
|
|
|
|
|
|
/* provide path to the replies file for schema testing */
|
|
|
|
capsfile[strlen(capsfile) - 3] = '\0';
|
|
|
|
info->schemafile = g_strdup_printf("%sreplies", capsfile);
|
2021-08-16 14:42:18 +00:00
|
|
|
} else {
|
2021-08-17 13:30:44 +00:00
|
|
|
info->qemuCaps = g_steal_pointer(&info->args.fakeCaps);
|
2019-03-31 15:49:34 +00:00
|
|
|
}
|
|
|
|
|
2021-08-17 13:30:44 +00:00
|
|
|
if (info->args.gic != GIC_NONE &&
|
|
|
|
testQemuCapsSetGIC(info->qemuCaps, info->args.gic) < 0)
|
|
|
|
return -1;
|
2019-03-31 15:49:34 +00:00
|
|
|
|
2021-08-17 13:30:44 +00:00
|
|
|
return 0;
|
2019-03-31 15:49:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
testQemuInfoClear(struct testQemuInfo *info)
|
|
|
|
{
|
|
|
|
VIR_FREE(info->infile);
|
|
|
|
VIR_FREE(info->outfile);
|
2020-05-15 12:33:10 +00:00
|
|
|
VIR_FREE(info->schemafile);
|
2020-09-22 11:57:39 +00:00
|
|
|
VIR_FREE(info->errfile);
|
2019-03-31 15:49:34 +00:00
|
|
|
virObjectUnref(info->qemuCaps);
|
2021-08-17 13:30:44 +00:00
|
|
|
g_clear_pointer(&info->args.fakeCaps, virObjectUnref);
|
2019-03-31 15:49:34 +00:00
|
|
|
}
|