Reorganize the module to put all the -cpu argument processing code
together after the -machine to form a logical order of processing for
qemuBuildCommandLine working top down in the module.
Signed-off-by: John Ferlan <jferlan(a)redhat.com>
---
src/qemu/qemu_command.c | 2798 ++++++++++++++++++++++++-----------------------
1 file changed, 1409 insertions(+), 1389 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index ede651a..9dbc4a3 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -383,1012 +383,1419 @@ qemuBuildMachineCommandLine(virCommandPtr cmd,
return 0;
}
+
+/** Start -cpu arguments */
static int
-qemuBuildObjectCommandLinePropsInternal(const char *key,
- const virJSONValue *value,
- virBufferPtr buf,
- bool nested)
+qemuBuildCpuModelArgStr(virQEMUDriverPtr driver,
+ const virDomainDef *def,
+ virBufferPtr buf,
+ virQEMUCapsPtr qemuCaps,
+ bool *hasHwVirt,
+ bool migrating)
{
- virJSONValuePtr elem;
- virBitmapPtr bitmap = NULL;
- ssize_t pos = -1;
- ssize_t end;
+ int ret = -1;
size_t i;
+ virCPUDefPtr host = NULL;
+ virCPUDefPtr guest = NULL;
+ virCPUDefPtr cpu = NULL;
+ virCPUDefPtr featCpu = NULL;
+ size_t ncpus = 0;
+ char **cpus = NULL;
+ virCPUDataPtr data = NULL;
+ virCPUDataPtr hostData = NULL;
+ char *compare_msg = NULL;
+ virCPUCompareResult cmp;
+ const char *preferred;
+ virCapsPtr caps = NULL;
+ bool compareAgainstHost = ((def->virtType == VIR_DOMAIN_VIRT_KVM ||
+ def->cpu->mode != VIR_CPU_MODE_CUSTOM) &&
+ def->cpu->mode != VIR_CPU_MODE_HOST_PASSTHROUGH);
- switch ((virJSONType) value->type) {
- case VIR_JSON_TYPE_STRING:
- virBufferAsprintf(buf, ",%s=%s", key, value->data.string);
- break;
+ if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
+ goto cleanup;
- case VIR_JSON_TYPE_NUMBER:
- virBufferAsprintf(buf, ",%s=%s", key, value->data.number);
- break;
+ host = caps->host.cpu;
- case VIR_JSON_TYPE_BOOLEAN:
- if (value->data.boolean)
- virBufferAsprintf(buf, ",%s=yes", key);
- else
- virBufferAsprintf(buf, ",%s=no", key);
+ if (!host ||
+ !host->model ||
+ (ncpus = virQEMUCapsGetCPUDefinitions(qemuCaps, &cpus)) == 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("CPU specification not supported by hypervisor"));
+ goto cleanup;
+ }
- break;
+ if (!(cpu = virCPUDefCopy(def->cpu)))
+ goto cleanup;
- case VIR_JSON_TYPE_ARRAY:
- if (nested) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("nested -object property arrays are not
supported"));
- return -1;
- }
+ if (cpu->mode == VIR_CPU_MODE_HOST_MODEL &&
+ !migrating &&
+ cpuUpdate(cpu, host) < 0)
+ goto cleanup;
- if (virJSONValueGetArrayAsBitmap(value, &bitmap) == 0) {
- while ((pos = virBitmapNextSetBit(bitmap, pos)) > -1) {
- if ((end = virBitmapNextClearBit(bitmap, pos)) < 0)
- end = virBitmapLastSetBit(bitmap) + 1;
+ /* For non-KVM, CPU features are emulated, so host compat doesn't matter */
+ if (compareAgainstHost) {
+ bool noTSX = false;
- if (end - 1 > pos) {
- virBufferAsprintf(buf, ",%s=%zd-%zd", key, pos, end - 1);
- pos = end;
+ cmp = cpuGuestData(host, cpu, &data, &compare_msg);
+ switch (cmp) {
+ case VIR_CPU_COMPARE_INCOMPATIBLE:
+ if (cpuEncode(host->arch, host, NULL, &hostData,
+ NULL, NULL, NULL, NULL) == 0 &&
+ (!cpuHasFeature(hostData, "hle") ||
+ !cpuHasFeature(hostData, "rtm")) &&
+ (STREQ_NULLABLE(cpu->model, "Haswell") ||
+ STREQ_NULLABLE(cpu->model, "Broadwell")))
+ noTSX = true;
+
+ if (compare_msg) {
+ if (noTSX) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("guest and host CPU are not compatible: "
+ "%s; try using '%s-noTSX' CPU
model"),
+ compare_msg, cpu->model);
} else {
- virBufferAsprintf(buf, ",%s=%zd", key, pos);
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("guest and host CPU are not compatible: "
+ "%s"),
+ compare_msg);
+ }
+ } else {
+ if (noTSX) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("guest CPU is not compatible with host "
+ "CPU; try using '%s-noTSX' CPU
model"),
+ cpu->model);
+ } else {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("guest CPU is not compatible with host "
+ "CPU"));
}
}
- } else {
- /* fallback, treat the array as a non-bitmap, adding the key
- * for each member */
- for (i = 0; i < virJSONValueArraySize(value); i++) {
- elem = virJSONValueArrayGet((virJSONValuePtr)value, i);
+ /* fall through */
+ case VIR_CPU_COMPARE_ERROR:
+ goto cleanup;
- /* recurse to avoid duplicating code */
- if (qemuBuildObjectCommandLinePropsInternal(key, elem, buf,
- true) < 0)
- return -1;
- }
+ default:
+ break;
}
- break;
+ }
- case VIR_JSON_TYPE_OBJECT:
- case VIR_JSON_TYPE_NULL:
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("NULL and OBJECT JSON types can't be converted to
"
- "commandline string"));
- return -1;
+ /* Only 'svm' requires --enable-nesting. The nested
+ * 'vmx' patches now simply hook off the CPU features
+ */
+ if ((def->os.arch == VIR_ARCH_X86_64 || def->os.arch == VIR_ARCH_I686)
&&
+ compareAgainstHost) {
+ int hasSVM = cpuHasFeature(data, "svm");
+ if (hasSVM < 0)
+ goto cleanup;
+ *hasHwVirt = hasSVM > 0 ? true : false;
}
- virBitmapFree(bitmap);
- return 0;
-}
+ if ((cpu->mode == VIR_CPU_MODE_HOST_PASSTHROUGH) ||
+ ((cpu->mode == VIR_CPU_MODE_HOST_MODEL) &&
+ ARCH_IS_PPC64(def->os.arch))) {
+ const char *mode = virCPUModeTypeToString(cpu->mode);
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CPU_HOST)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("CPU mode '%s' is not supported by QEMU"
+ " binary"), mode);
+ goto cleanup;
+ }
+ if (def->virtType != VIR_DOMAIN_VIRT_KVM) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("CPU mode '%s' is only supported with
kvm"),
+ mode);
+ goto cleanup;
+ }
+ virBufferAddLit(buf, "host");
+ if (def->os.arch == VIR_ARCH_ARMV7L &&
+ host->arch == 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"));
+ goto cleanup;
+ }
-static int
-qemuBuildObjectCommandLineProps(const char *key,
- const virJSONValue *value,
- void *opaque)
-{
- return qemuBuildObjectCommandLinePropsInternal(key, value, opaque, false);
-}
+ virBufferAddLit(buf, ",aarch64=off");
+ }
+ if (ARCH_IS_PPC64(def->os.arch) &&
+ cpu->mode == VIR_CPU_MODE_HOST_MODEL &&
+ def->cpu->model != NULL) {
+ virBufferAsprintf(buf, ",compat=%s", def->cpu->model);
+ } else {
+ featCpu = cpu;
+ }
-char *
-qemuBuildObjectCommandlineFromJSON(const char *type,
- const char *alias,
- virJSONValuePtr props)
-{
- virBuffer buf = VIR_BUFFER_INITIALIZER;
- char *ret = NULL;
+ } else {
+ if (VIR_ALLOC(guest) < 0)
+ goto cleanup;
+ if (VIR_STRDUP(guest->vendor_id, cpu->vendor_id) < 0)
+ goto cleanup;
- virBufferAsprintf(&buf, "%s,id=%s", type, alias);
+ if (compareAgainstHost) {
+ guest->arch = host->arch;
+ if (cpu->match == VIR_CPU_MATCH_MINIMUM)
+ preferred = host->model;
+ else
+ preferred = cpu->model;
- if (virJSONValueObjectForeachKeyValue(props,
- qemuBuildObjectCommandLineProps,
- &buf) < 0)
- goto cleanup;
+ guest->type = VIR_CPU_TYPE_GUEST;
+ guest->fallback = cpu->fallback;
+ if (cpuDecode(guest, data,
+ (const char **)cpus, ncpus, preferred) < 0)
+ goto cleanup;
+ } else {
+ guest->arch = def->os.arch;
+ if (VIR_STRDUP(guest->model, cpu->model) < 0)
+ goto cleanup;
+ }
+ virBufferAdd(buf, guest->model, -1);
+ if (guest->vendor_id)
+ virBufferAsprintf(buf, ",vendor=%s", guest->vendor_id);
+ featCpu = guest;
+ }
- if (virBufferCheckError(&buf) < 0)
- goto cleanup;
+ if (featCpu) {
+ for (i = 0; i < featCpu->nfeatures; i++) {
+ char sign;
+ if (featCpu->features[i].policy == VIR_CPU_FEATURE_DISABLE)
+ sign = '-';
+ else
+ sign = '+';
- ret = virBufferContentAndReset(&buf);
+ virBufferAsprintf(buf, ",%c%s", sign,
featCpu->features[i].name);
+ }
+ }
+ ret = 0;
cleanup:
- virBufferFreeAndReset(&buf);
+ virObjectUnref(caps);
+ VIR_FREE(compare_msg);
+ cpuDataFree(data);
+ cpuDataFree(hostData);
+ virCPUDefFree(guest);
+ virCPUDefFree(cpu);
return ret;
}
static int
-qemuBuildDeviceAddressStr(virBufferPtr buf,
- virDomainDefPtr domainDef,
- virDomainDeviceInfoPtr info,
- virQEMUCapsPtr qemuCaps)
+qemuBuildCpuArgStr(virQEMUDriverPtr driver,
+ const virDomainDef *def,
+ virQEMUCapsPtr qemuCaps,
+ char **opt,
+ bool *hasHwVirt,
+ bool migrating)
{
- int ret = -1;
- char *devStr = NULL;
- const char *contAlias = NULL;
+ virArch hostarch = virArchFromHost();
+ const char *default_model;
+ bool have_cpu = false;
+ int ret = -1;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ size_t i;
- if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
- size_t i;
+ *hasHwVirt = false;
- if (!(devStr = virDomainPCIAddressAsString(&info->addr.pci)))
- goto cleanup;
- for (i = 0; i < domainDef->ncontrollers; i++) {
- virDomainControllerDefPtr cont = domainDef->controllers[i];
+ if (def->os.arch == VIR_ARCH_I686)
+ default_model = "qemu32";
+ else
+ default_model = "qemu64";
- if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI &&
- cont->idx == info->addr.pci.bus) {
- contAlias = cont->info.alias;
- if (!contAlias) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Device alias was not set for PCI "
- "controller with index %u required "
- "for device at address %s"),
- info->addr.pci.bus, devStr);
- goto cleanup;
- }
- break;
- }
- }
- if (!contAlias) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Could not find PCI "
- "controller with index %u required "
- "for device at address %s"),
- info->addr.pci.bus, devStr);
+ if (def->cpu &&
+ (def->cpu->mode != VIR_CPU_MODE_CUSTOM || def->cpu->model)) {
+ if (qemuBuildCpuModelArgStr(driver, def, &buf, qemuCaps,
+ hasHwVirt, migrating) < 0)
goto cleanup;
+ have_cpu = true;
+ } else {
+ /*
+ * Need to force a 32-bit guest CPU type if
+ *
+ * 1. guest OS is i686
+ * 2. host OS is x86_64
+ * 3. emulator is qemu-kvm or kvm
+ *
+ * Or
+ *
+ * 1. guest OS is i686
+ * 2. emulator is qemu-system-x86_64
+ */
+ if (def->os.arch == VIR_ARCH_I686 &&
+ ((hostarch == VIR_ARCH_X86_64 &&
+ strstr(def->emulator, "kvm")) ||
+ strstr(def->emulator, "x86_64"))) {
+ virBufferAdd(&buf, default_model, -1);
+ have_cpu = true;
}
+ }
- if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCI_MULTIFUNCTION)) {
- if (info->addr.pci.function != 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("Only PCI device addresses with function=0 "
- "are supported with this QEMU binary"));
- goto cleanup;
- }
- if (info->addr.pci.multi == VIR_TRISTATE_SWITCH_ON) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("'multifunction=on' is not supported with
"
- "this QEMU binary"));
- goto cleanup;
- }
- }
+ /* Handle paravirtual timers */
+ for (i = 0; i < def->clock.ntimers; i++) {
+ virDomainTimerDefPtr timer = def->clock.timers[i];
- if (info->addr.pci.bus != 0 &&
- !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_PCI_BRIDGE)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("Multiple PCI buses are not supported "
- "with this QEMU binary"));
- goto cleanup;
+ if (timer->present == -1)
+ continue;
+
+ if (timer->name == VIR_DOMAIN_TIMER_NAME_KVMCLOCK) {
+ virBufferAsprintf(&buf, "%s,%ckvmclock",
+ have_cpu ? "" : default_model,
+ timer->present ? '+' : '-');
+ have_cpu = true;
+ } else if (timer->name == VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK &&
+ timer->present) {
+ virBufferAsprintf(&buf, "%s,hv_time",
+ have_cpu ? "" : default_model);
+ have_cpu = true;
}
- virBufferAsprintf(buf, ",bus=%s", contAlias);
+ }
- if (info->addr.pci.multi == VIR_TRISTATE_SWITCH_ON)
- virBufferAddLit(buf, ",multifunction=on");
- else if (info->addr.pci.multi == VIR_TRISTATE_SWITCH_OFF)
- virBufferAddLit(buf, ",multifunction=off");
- virBufferAsprintf(buf, ",addr=0x%x", info->addr.pci.slot);
- if (info->addr.pci.function != 0)
- virBufferAsprintf(buf, ".0x%x", info->addr.pci.function);
- } else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) {
- if (!(contAlias = virDomainControllerAliasFind(domainDef,
- VIR_DOMAIN_CONTROLLER_TYPE_USB,
- info->addr.usb.bus)))
- goto cleanup;
- virBufferAsprintf(buf, ",bus=%s.0,port=%s", contAlias,
info->addr.usb.port);
- } else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO) {
- if (info->addr.spaprvio.has_reg)
- virBufferAsprintf(buf, ",reg=0x%llx", info->addr.spaprvio.reg);
- } else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
- if (info->addr.ccw.assigned)
- virBufferAsprintf(buf, ",devno=%x.%x.%04x",
- info->addr.ccw.cssid,
- info->addr.ccw.ssid,
- info->addr.ccw.devno);
- } else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_ISA) {
- virBufferAsprintf(buf, ",iobase=0x%x,irq=0x%x",
- info->addr.isa.iobase,
- info->addr.isa.irq);
+ if (def->apic_eoi) {
+ char sign;
+ if (def->apic_eoi == VIR_TRISTATE_SWITCH_ON)
+ sign = '+';
+ else
+ sign = '-';
+
+ virBufferAsprintf(&buf, "%s,%ckvm_pv_eoi",
+ have_cpu ? "" : default_model,
+ sign);
+ have_cpu = true;
}
- ret = 0;
- cleanup:
- VIR_FREE(devStr);
- return ret;
-}
+ if (def->features[VIR_DOMAIN_FEATURE_PVSPINLOCK]) {
+ char sign;
+ if (def->features[VIR_DOMAIN_FEATURE_PVSPINLOCK] == VIR_TRISTATE_SWITCH_ON)
+ sign = '+';
+ else
+ sign = '-';
-static int
-qemuBuildRomStr(virBufferPtr buf,
- virDomainDeviceInfoPtr info,
- virQEMUCapsPtr qemuCaps)
-{
- if (info->rombar || info->romfile) {
- if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- "%s", _("rombar and romfile are supported only
for PCI devices"));
- return -1;
+ virBufferAsprintf(&buf, "%s,%ckvm_pv_unhalt",
+ have_cpu ? "" : default_model,
+ sign);
+ have_cpu = true;
+ }
+
+ if (def->features[VIR_DOMAIN_FEATURE_HYPERV] == VIR_TRISTATE_SWITCH_ON) {
+ if (!have_cpu) {
+ virBufferAdd(&buf, default_model, -1);
+ have_cpu = true;
}
- if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCI_ROMBAR)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- "%s", _("rombar and romfile not supported in
this QEMU binary"));
- return -1;
+
+ for (i = 0; i < VIR_DOMAIN_HYPERV_LAST; i++) {
+ switch ((virDomainHyperv) i) {
+ case VIR_DOMAIN_HYPERV_RELAXED:
+ case VIR_DOMAIN_HYPERV_VAPIC:
+ if (def->hyperv_features[i] == VIR_TRISTATE_SWITCH_ON)
+ virBufferAsprintf(&buf, ",hv_%s",
+ virDomainHypervTypeToString(i));
+ break;
+
+ case VIR_DOMAIN_HYPERV_SPINLOCKS:
+ if (def->hyperv_features[i] == VIR_TRISTATE_SWITCH_ON)
+ virBufferAsprintf(&buf, ",hv_spinlocks=0x%x",
+ def->hyperv_spinlocks);
+ break;
+
+ /* coverity[dead_error_begin] */
+ case VIR_DOMAIN_HYPERV_LAST:
+ break;
+ }
}
+ }
- switch (info->rombar) {
- case VIR_TRISTATE_SWITCH_OFF:
- virBufferAddLit(buf, ",rombar=0");
- break;
- case VIR_TRISTATE_SWITCH_ON:
- virBufferAddLit(buf, ",rombar=1");
- break;
- default:
+ for (i = 0; i < def->npanics; i++) {
+ if (def->panics[i]->model == VIR_DOMAIN_PANIC_MODEL_HYPERV) {
+ if (!have_cpu) {
+ virBufferAdd(&buf, default_model, -1);
+ have_cpu = true;
+ }
+
+ virBufferAddLit(&buf, ",hv_crash");
break;
}
- if (info->romfile)
- virBufferAsprintf(buf, ",romfile=%s", info->romfile);
}
- return 0;
-}
-static int
-qemuBuildIoEventFdStr(virBufferPtr buf,
- virTristateSwitch use,
- virQEMUCapsPtr qemuCaps)
-{
- if (use && virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_IOEVENTFD))
- virBufferAsprintf(buf, ",ioeventfd=%s",
- virTristateSwitchTypeToString(use));
- return 0;
-}
+ if (def->features[VIR_DOMAIN_FEATURE_KVM] == VIR_TRISTATE_SWITCH_ON) {
+ if (!have_cpu) {
+ virBufferAdd(&buf, default_model, -1);
+ have_cpu = true;
+ }
-#define QEMU_SERIAL_PARAM_ACCEPTED_CHARS \
- "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_ "
+ for (i = 0; i < VIR_DOMAIN_KVM_LAST; i++) {
+ switch ((virDomainKVM) i) {
+ case VIR_DOMAIN_KVM_HIDDEN:
+ if (def->kvm_features[i] == VIR_TRISTATE_SWITCH_ON)
+ virBufferAddLit(&buf, ",kvm=off");
+ break;
-static int
-qemuSafeSerialParamValue(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;
+ /* coverity[dead_error_begin] */
+ case VIR_DOMAIN_KVM_LAST:
+ break;
+ }
+ }
}
- return 0;
-}
-
-static char *
-qemuGetSecretString(virConnectPtr conn,
- const char *scheme,
- bool encoded,
- virStorageAuthDefPtr authdef,
- virSecretUsageType secretUsageType)
-{
- size_t secret_size;
- virSecretPtr sec = NULL;
- char *secret = NULL;
- char uuidStr[VIR_UUID_STRING_BUFLEN];
-
- /* look up secret */
- switch (authdef->secretType) {
- case VIR_STORAGE_SECRET_TYPE_UUID:
- sec = virSecretLookupByUUID(conn, authdef->secret.uuid);
- virUUIDFormat(authdef->secret.uuid, uuidStr);
- break;
- case VIR_STORAGE_SECRET_TYPE_USAGE:
- sec = virSecretLookupByUsage(conn, secretUsageType,
- authdef->secret.usage);
- break;
- }
+ if (def->features[VIR_DOMAIN_FEATURE_PMU]) {
+ virTristateSwitch pmu = def->features[VIR_DOMAIN_FEATURE_PMU];
+ if (!have_cpu)
+ virBufferAdd(&buf, default_model, -1);
- if (!sec) {
- if (authdef->secretType == VIR_STORAGE_SECRET_TYPE_UUID) {
- virReportError(VIR_ERR_NO_SECRET,
- _("%s no secret matches uuid '%s'"),
- scheme, uuidStr);
- } else {
- virReportError(VIR_ERR_NO_SECRET,
- _("%s no secret matches usage value '%s'"),
- scheme, authdef->secret.usage);
- }
- goto cleanup;
+ virBufferAsprintf(&buf, ",pmu=%s",
+ virTristateSwitchTypeToString(pmu));
+ have_cpu = true;
}
- secret = (char *)conn->secretDriver->secretGetValue(sec, &secret_size, 0,
-
VIR_SECRET_GET_VALUE_INTERNAL_CALL);
- if (!secret) {
- if (authdef->secretType == VIR_STORAGE_SECRET_TYPE_UUID) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("could not get value of the secret for "
- "username '%s' using uuid '%s'"),
- authdef->username, uuidStr);
- } else {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("could not get value of the secret for "
- "username '%s' using usage value
'%s'"),
- authdef->username, authdef->secret.usage);
- }
+ if (virBufferCheckError(&buf) < 0)
goto cleanup;
- }
- if (encoded) {
- char *base64 = NULL;
+ *opt = virBufferContentAndReset(&buf);
- base64_encode_alloc(secret, secret_size, &base64);
- VIR_FREE(secret);
- if (!base64) {
- virReportOOMError();
- goto cleanup;
- }
- secret = base64;
- }
+ ret = 0;
cleanup:
- virObjectUnref(sec);
- return secret;
+ return ret;
}
static int
-qemuNetworkDriveGetPort(int protocol,
- const char *port)
+qemuBuildCpuCommandLine(virCommandPtr cmd,
+ virQEMUDriverPtr driver,
+ const virDomainDef *def,
+ virQEMUCapsPtr qemuCaps,
+ bool migrating)
{
- int ret = 0;
+ char *cpu;
+ bool hasHwVirt = false;
- if (port) {
- if (virStrToLong_i(port, NULL, 10, &ret) < 0 || ret < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("failed to parse port number '%s'"),
- port);
- return -1;
- }
+ if (qemuBuildCpuArgStr(driver, def, qemuCaps,
+ &cpu, &hasHwVirt, migrating) < 0)
+ goto error;
- return ret;
+ if (cpu) {
+ virCommandAddArgList(cmd, "-cpu", cpu, NULL);
+ VIR_FREE(cpu);
+
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NESTING) && hasHwVirt)
+ virCommandAddArg(cmd, "-enable-nesting");
}
- switch ((virStorageNetProtocol) protocol) {
- case VIR_STORAGE_NET_PROTOCOL_HTTP:
- return 80;
+ return 0;
- case VIR_STORAGE_NET_PROTOCOL_HTTPS:
- return 443;
+ error:
+ return -1;
+}
- case VIR_STORAGE_NET_PROTOCOL_FTP:
- return 21;
- case VIR_STORAGE_NET_PROTOCOL_FTPS:
- return 990;
+static int
+qemuBuildObjectCommandLinePropsInternal(const char *key,
+ const virJSONValue *value,
+ virBufferPtr buf,
+ bool nested)
+{
+ virJSONValuePtr elem;
+ virBitmapPtr bitmap = NULL;
+ ssize_t pos = -1;
+ ssize_t end;
+ size_t i;
- case VIR_STORAGE_NET_PROTOCOL_TFTP:
- return 69;
+ switch ((virJSONType) value->type) {
+ case VIR_JSON_TYPE_STRING:
+ virBufferAsprintf(buf, ",%s=%s", key, value->data.string);
+ break;
- case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
- return 7000;
+ case VIR_JSON_TYPE_NUMBER:
+ virBufferAsprintf(buf, ",%s=%s", key, value->data.number);
+ break;
- case VIR_STORAGE_NET_PROTOCOL_NBD:
- return 10809;
+ case VIR_JSON_TYPE_BOOLEAN:
+ if (value->data.boolean)
+ virBufferAsprintf(buf, ",%s=yes", key);
+ else
+ virBufferAsprintf(buf, ",%s=no", key);
- case VIR_STORAGE_NET_PROTOCOL_ISCSI:
- case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
- /* no default port specified */
- return 0;
+ break;
- case VIR_STORAGE_NET_PROTOCOL_RBD:
- case VIR_STORAGE_NET_PROTOCOL_LAST:
- case VIR_STORAGE_NET_PROTOCOL_NONE:
- /* not applicable */
+ case VIR_JSON_TYPE_ARRAY:
+ if (nested) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("nested -object property arrays are not
supported"));
return -1;
+ }
+
+ if (virJSONValueGetArrayAsBitmap(value, &bitmap) == 0) {
+ while ((pos = virBitmapNextSetBit(bitmap, pos)) > -1) {
+ if ((end = virBitmapNextClearBit(bitmap, pos)) < 0)
+ end = virBitmapLastSetBit(bitmap) + 1;
+
+ if (end - 1 > pos) {
+ virBufferAsprintf(buf, ",%s=%zd-%zd", key, pos, end - 1);
+ pos = end;
+ } else {
+ virBufferAsprintf(buf, ",%s=%zd", key, pos);
+ }
+ }
+ } else {
+ /* fallback, treat the array as a non-bitmap, adding the key
+ * for each member */
+ for (i = 0; i < virJSONValueArraySize(value); i++) {
+ elem = virJSONValueArrayGet((virJSONValuePtr)value, i);
+
+ /* recurse to avoid duplicating code */
+ if (qemuBuildObjectCommandLinePropsInternal(key, elem, buf,
+ true) < 0)
+ return -1;
+ }
+ }
+ break;
+
+ case VIR_JSON_TYPE_OBJECT:
+ case VIR_JSON_TYPE_NULL:
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("NULL and OBJECT JSON types can't be converted to
"
+ "commandline string"));
+ return -1;
}
- return -1;
+ virBitmapFree(bitmap);
+ return 0;
}
-#define QEMU_DEFAULT_NBD_PORT "10809"
-static char *
-qemuBuildNetworkDriveURI(virStorageSourcePtr src,
- const char *username,
- const char *secret)
+static int
+qemuBuildObjectCommandLineProps(const char *key,
+ const virJSONValue *value,
+ void *opaque)
{
- char *ret = NULL;
- virBuffer buf = VIR_BUFFER_INITIALIZER;
- virURIPtr uri = NULL;
- size_t i;
+ return qemuBuildObjectCommandLinePropsInternal(key, value, opaque, false);
+}
- switch ((virStorageNetProtocol) src->protocol) {
- case VIR_STORAGE_NET_PROTOCOL_NBD:
- if (src->nhosts != 1) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("protocol '%s' accepts only one
host"),
- virStorageNetProtocolTypeToString(src->protocol));
- goto cleanup;
- }
- if (!((src->hosts->name && strchr(src->hosts->name,
':')) ||
- (src->hosts->transport == VIR_STORAGE_NET_HOST_TRANS_TCP
&&
- !src->hosts->name) ||
- (src->hosts->transport == VIR_STORAGE_NET_HOST_TRANS_UNIX
&&
- src->hosts->socket &&
- src->hosts->socket[0] != '/'))) {
+char *
+qemuBuildObjectCommandlineFromJSON(const char *type,
+ const char *alias,
+ virJSONValuePtr props)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ char *ret = NULL;
- virBufferAddLit(&buf, "nbd:");
+ virBufferAsprintf(&buf, "%s,id=%s", type, alias);
- switch (src->hosts->transport) {
- case VIR_STORAGE_NET_HOST_TRANS_TCP:
- virBufferStrcat(&buf, src->hosts->name, NULL);
- virBufferAsprintf(&buf, ":%s",
- src->hosts->port ? src->hosts->port :
- QEMU_DEFAULT_NBD_PORT);
- break;
+ if (virJSONValueObjectForeachKeyValue(props,
+ qemuBuildObjectCommandLineProps,
+ &buf) < 0)
+ goto cleanup;
- case VIR_STORAGE_NET_HOST_TRANS_UNIX:
- if (!src->hosts->socket) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("socket attribute required for "
- "unix transport"));
- goto cleanup;
- }
+ if (virBufferCheckError(&buf) < 0)
+ goto cleanup;
- virBufferAsprintf(&buf, "unix:%s",
src->hosts->socket);
- break;
+ ret = virBufferContentAndReset(&buf);
- default:
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("nbd does not support transport
'%s'"),
-
virStorageNetHostTransportTypeToString(src->hosts->transport));
- goto cleanup;
- }
+ cleanup:
+ virBufferFreeAndReset(&buf);
+ return ret;
+}
- if (src->path)
- virBufferAsprintf(&buf, ":exportname=%s",
src->path);
-
- if (virBufferCheckError(&buf) < 0)
- goto cleanup;
- ret = virBufferContentAndReset(&buf);
- goto cleanup;
- }
- /* fallthrough */
- /* NBD code uses same formatting scheme as others in some cases */
+static int
+qemuBuildDeviceAddressStr(virBufferPtr buf,
+ virDomainDefPtr domainDef,
+ virDomainDeviceInfoPtr info,
+ virQEMUCapsPtr qemuCaps)
+{
+ int ret = -1;
+ char *devStr = NULL;
+ const char *contAlias = NULL;
- case VIR_STORAGE_NET_PROTOCOL_HTTP:
- case VIR_STORAGE_NET_PROTOCOL_HTTPS:
- case VIR_STORAGE_NET_PROTOCOL_FTP:
- case VIR_STORAGE_NET_PROTOCOL_FTPS:
- case VIR_STORAGE_NET_PROTOCOL_TFTP:
- case VIR_STORAGE_NET_PROTOCOL_ISCSI:
- case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
- if (src->nhosts != 1) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("protocol '%s' accepts only one
host"),
- virStorageNetProtocolTypeToString(src->protocol));
- goto cleanup;
- }
+ if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
+ size_t i;
- if (VIR_ALLOC(uri) < 0)
- goto cleanup;
+ if (!(devStr = virDomainPCIAddressAsString(&info->addr.pci)))
+ goto cleanup;
+ for (i = 0; i < domainDef->ncontrollers; i++) {
+ virDomainControllerDefPtr cont = domainDef->controllers[i];
- if (src->hosts->transport == VIR_STORAGE_NET_HOST_TRANS_TCP) {
- if (VIR_STRDUP(uri->scheme,
- virStorageNetProtocolTypeToString(src->protocol)) <
0)
- goto cleanup;
- } else {
- if (virAsprintf(&uri->scheme, "%s+%s",
- virStorageNetProtocolTypeToString(src->protocol),
-
virStorageNetHostTransportTypeToString(src->hosts->transport)) < 0)
+ if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI &&
+ cont->idx == info->addr.pci.bus) {
+ contAlias = cont->info.alias;
+ if (!contAlias) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Device alias was not set for PCI "
+ "controller with index %u required "
+ "for device at address %s"),
+ info->addr.pci.bus, devStr);
goto cleanup;
- }
-
- if ((uri->port = qemuNetworkDriveGetPort(src->protocol,
src->hosts->port)) < 0)
- goto cleanup;
-
- if (src->path) {
- if (src->volume) {
- if (virAsprintf(&uri->path, "/%s%s",
- src->volume, src->path) < 0)
- goto cleanup;
- } else {
- if (virAsprintf(&uri->path, "%s%s",
- src->path[0] == '/' ? "" :
"/",
- src->path) < 0)
- goto cleanup;
- }
- }
-
- if (src->hosts->socket &&
- virAsprintf(&uri->query, "socket=%s",
src->hosts->socket) < 0)
- goto cleanup;
-
- if (username) {
- if (secret) {
- if (virAsprintf(&uri->user, "%s:%s", username,
secret) < 0)
- goto cleanup;
- } else {
- if (VIR_STRDUP(uri->user, username) < 0)
- goto cleanup;
}
+ break;
}
+ }
+ if (!contAlias) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Could not find PCI "
+ "controller with index %u required "
+ "for device at address %s"),
+ info->addr.pci.bus, devStr);
+ goto cleanup;
+ }
- if (VIR_STRDUP(uri->server, src->hosts->name) < 0)
- goto cleanup;
-
- ret = virURIFormat(uri);
-
- break;
-
- case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
- if (!src->path) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("missing disk source for 'sheepdog'
protocol"));
- goto cleanup;
- }
-
- if (src->nhosts == 0) {
- if (virAsprintf(&ret, "sheepdog:%s", src->path) < 0)
- goto cleanup;
- } else if (src->nhosts == 1) {
- if (virAsprintf(&ret, "sheepdog:%s:%s:%s",
- src->hosts->name,
- src->hosts->port ? src->hosts->port :
"7000",
- src->path) < 0)
- goto cleanup;
- } else {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("protocol 'sheepdog' accepts up to one
host"));
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCI_MULTIFUNCTION)) {
+ if (info->addr.pci.function != 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Only PCI device addresses with function=0 "
+ "are supported with this QEMU binary"));
goto cleanup;
}
-
- break;
-
- case VIR_STORAGE_NET_PROTOCOL_RBD:
- if (strchr(src->path, ':')) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("':' not allowed in RBD source volume name
'%s'"),
- src->path);
+ if (info->addr.pci.multi == VIR_TRISTATE_SWITCH_ON) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("'multifunction=on' is not supported with
"
+ "this QEMU binary"));
goto cleanup;
}
+ }
- virBufferStrcat(&buf, "rbd:", src->path, NULL);
-
- if (src->snapshot)
- virBufferEscape(&buf, '\\', ":", "@%s",
src->snapshot);
-
- if (username) {
- virBufferEscape(&buf, '\\', ":",
":id=%s", username);
- virBufferEscape(&buf, '\\', ":",
- ":key=%s:auth_supported=cephx\\;none",
- secret);
- } else {
- virBufferAddLit(&buf, ":auth_supported=none");
- }
-
- if (src->nhosts > 0) {
- virBufferAddLit(&buf, ":mon_host=");
- for (i = 0; i < src->nhosts; i++) {
- if (i)
- virBufferAddLit(&buf, "\\;");
-
- /* assume host containing : is ipv6 */
- if (strchr(src->hosts[i].name, ':'))
- virBufferEscape(&buf, '\\', ":",
"[%s]",
- src->hosts[i].name);
- else
- virBufferAsprintf(&buf, "%s",
src->hosts[i].name);
-
- if (src->hosts[i].port)
- virBufferAsprintf(&buf, "\\:%s",
src->hosts[i].port);
- }
- }
-
- if (src->configFile)
- virBufferEscape(&buf, '\\', ":",
":conf=%s", src->configFile);
-
- if (virBufferCheckError(&buf) < 0)
- goto cleanup;
-
- ret = virBufferContentAndReset(&buf);
- break;
-
+ if (info->addr.pci.bus != 0 &&
+ !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_PCI_BRIDGE)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Multiple PCI buses are not supported "
+ "with this QEMU binary"));
+ goto cleanup;
+ }
+ virBufferAsprintf(buf, ",bus=%s", contAlias);
- case VIR_STORAGE_NET_PROTOCOL_LAST:
- case VIR_STORAGE_NET_PROTOCOL_NONE:
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Unexpected network protocol '%s'"),
- virStorageNetProtocolTypeToString(src->protocol));
+ if (info->addr.pci.multi == VIR_TRISTATE_SWITCH_ON)
+ virBufferAddLit(buf, ",multifunction=on");
+ else if (info->addr.pci.multi == VIR_TRISTATE_SWITCH_OFF)
+ virBufferAddLit(buf, ",multifunction=off");
+ virBufferAsprintf(buf, ",addr=0x%x", info->addr.pci.slot);
+ if (info->addr.pci.function != 0)
+ virBufferAsprintf(buf, ".0x%x", info->addr.pci.function);
+ } else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) {
+ if (!(contAlias = virDomainControllerAliasFind(domainDef,
+ VIR_DOMAIN_CONTROLLER_TYPE_USB,
+ info->addr.usb.bus)))
goto cleanup;
+ virBufferAsprintf(buf, ",bus=%s.0,port=%s", contAlias,
info->addr.usb.port);
+ } else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO) {
+ if (info->addr.spaprvio.has_reg)
+ virBufferAsprintf(buf, ",reg=0x%llx", info->addr.spaprvio.reg);
+ } else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
+ if (info->addr.ccw.assigned)
+ virBufferAsprintf(buf, ",devno=%x.%x.%04x",
+ info->addr.ccw.cssid,
+ info->addr.ccw.ssid,
+ info->addr.ccw.devno);
+ } else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_ISA) {
+ virBufferAsprintf(buf, ",iobase=0x%x,irq=0x%x",
+ info->addr.isa.iobase,
+ info->addr.isa.irq);
}
+ ret = 0;
cleanup:
- virBufferFreeAndReset(&buf);
- virURIFree(uri);
-
+ VIR_FREE(devStr);
return ret;
}
-
-int
-qemuGetDriveSourceString(virStorageSourcePtr src,
- virConnectPtr conn,
- char **source)
+static int
+qemuBuildRomStr(virBufferPtr buf,
+ virDomainDeviceInfoPtr info,
+ virQEMUCapsPtr qemuCaps)
{
- int actualType = virStorageSourceGetActualType(src);
- char *secret = NULL;
- char *username = NULL;
- int ret = -1;
-
- *source = NULL;
-
- /* return 1 for empty sources */
- if (virStorageSourceIsEmpty(src))
- return 1;
+ if (info->rombar || info->romfile) {
+ if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ "%s", _("rombar and romfile are supported only
for PCI devices"));
+ return -1;
+ }
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCI_ROMBAR)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ "%s", _("rombar and romfile not supported in
this QEMU binary"));
+ return -1;
+ }
- if (conn) {
- if (actualType == VIR_STORAGE_TYPE_NETWORK &&
- src->auth &&
- (src->protocol == VIR_STORAGE_NET_PROTOCOL_ISCSI ||
- src->protocol == VIR_STORAGE_NET_PROTOCOL_RBD)) {
- bool encode = false;
- int secretType = VIR_SECRET_USAGE_TYPE_ISCSI;
- const char *protocol = virStorageNetProtocolTypeToString(src->protocol);
- username = src->auth->username;
-
- if (src->protocol == VIR_STORAGE_NET_PROTOCOL_RBD) {
- /* qemu requires the secret to be encoded for RBD */
- encode = true;
- secretType = VIR_SECRET_USAGE_TYPE_CEPH;
- }
-
- if (!(secret = qemuGetSecretString(conn,
- protocol,
- encode,
- src->auth,
- secretType)))
- goto cleanup;
+ switch (info->rombar) {
+ case VIR_TRISTATE_SWITCH_OFF:
+ virBufferAddLit(buf, ",rombar=0");
+ break;
+ case VIR_TRISTATE_SWITCH_ON:
+ virBufferAddLit(buf, ",rombar=1");
+ break;
+ default:
+ break;
}
+ if (info->romfile)
+ virBufferAsprintf(buf, ",romfile=%s", info->romfile);
}
+ return 0;
+}
- switch ((virStorageType) actualType) {
- case VIR_STORAGE_TYPE_BLOCK:
- case VIR_STORAGE_TYPE_FILE:
- case VIR_STORAGE_TYPE_DIR:
- if (VIR_STRDUP(*source, src->path) < 0)
- goto cleanup;
-
- break;
+static int
+qemuBuildIoEventFdStr(virBufferPtr buf,
+ virTristateSwitch use,
+ virQEMUCapsPtr qemuCaps)
+{
+ if (use && virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_IOEVENTFD))
+ virBufferAsprintf(buf, ",ioeventfd=%s",
+ virTristateSwitchTypeToString(use));
+ return 0;
+}
- case VIR_STORAGE_TYPE_NETWORK:
- if (!(*source = qemuBuildNetworkDriveURI(src, username, secret)))
- goto cleanup;
- break;
+#define QEMU_SERIAL_PARAM_ACCEPTED_CHARS \
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_ "
- case VIR_STORAGE_TYPE_VOLUME:
- case VIR_STORAGE_TYPE_NONE:
- case VIR_STORAGE_TYPE_LAST:
- break;
+static int
+qemuSafeSerialParamValue(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;
}
- ret = 0;
-
- cleanup:
- VIR_FREE(secret);
- return ret;
+ return 0;
}
-
-/* Perform disk definition config validity checks */
-int
-qemuCheckDiskConfig(virDomainDiskDefPtr disk)
+static char *
+qemuGetSecretString(virConnectPtr conn,
+ const char *scheme,
+ bool encoded,
+ virStorageAuthDefPtr authdef,
+ virSecretUsageType secretUsageType)
{
- if (virDiskNameToIndex(disk->dst) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("unsupported disk type '%s'"), disk->dst);
- goto error;
- }
+ size_t secret_size;
+ virSecretPtr sec = NULL;
+ char *secret = NULL;
+ char uuidStr[VIR_UUID_STRING_BUFLEN];
- 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"));
- goto error;
- }
+ /* look up secret */
+ switch (authdef->secretType) {
+ case VIR_STORAGE_SECRET_TYPE_UUID:
+ sec = virSecretLookupByUUID(conn, authdef->secret.uuid);
+ virUUIDFormat(authdef->secret.uuid, uuidStr);
+ break;
+ case VIR_STORAGE_SECRET_TYPE_USAGE:
+ sec = virSecretLookupByUsage(conn, secretUsageType,
+ authdef->secret.usage);
+ break;
}
- if ((disk->vendor || disk->product) &&
- disk->bus != VIR_DOMAIN_DISK_BUS_SCSI) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("Only scsi disk supports vendor and product"));
- goto error;
+ if (!sec) {
+ if (authdef->secretType == VIR_STORAGE_SECRET_TYPE_UUID) {
+ virReportError(VIR_ERR_NO_SECRET,
+ _("%s no secret matches uuid '%s'"),
+ scheme, uuidStr);
+ } else {
+ virReportError(VIR_ERR_NO_SECRET,
+ _("%s no secret matches usage value '%s'"),
+ scheme, authdef->secret.usage);
+ }
+ goto cleanup;
}
- 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'"),
- virDomainDiskQEMUBusTypeToString(disk->bus));
- goto error;
- }
- if (disk->src->type == VIR_STORAGE_TYPE_NETWORK) {
- if (disk->src->protocol != VIR_STORAGE_NET_PROTOCOL_ISCSI) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("disk device='lun' is not supported "
- "for protocol='%s'"),
-
virStorageNetProtocolTypeToString(disk->src->protocol));
- goto error;
- }
- } else if (!virDomainDiskSourceIsBlockType(disk->src, true)) {
- goto error;
- }
- if (disk->wwn) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("Setting wwn is not supported for lun device"));
- goto error;
- }
- if (disk->vendor || disk->product) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("Setting vendor or product is not supported "
- "for lun device"));
- goto error;
+ secret = (char *)conn->secretDriver->secretGetValue(sec, &secret_size, 0,
+
VIR_SECRET_GET_VALUE_INTERNAL_CALL);
+ if (!secret) {
+ if (authdef->secretType == VIR_STORAGE_SECRET_TYPE_UUID) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("could not get value of the secret for "
+ "username '%s' using uuid '%s'"),
+ authdef->username, uuidStr);
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("could not get value of the secret for "
+ "username '%s' using usage value
'%s'"),
+ authdef->username, authdef->secret.usage);
}
+ goto cleanup;
}
- return 0;
- error:
- return -1;
-}
+ if (encoded) {
+ char *base64 = NULL;
-/* Check whether the device address is using either 'ccw' or default s390
- * address format and whether that's "legal" for the current qemu and/or
- * guest os.machine type. This is the corollary to the code which doesn't
- * find the address type set using an emulator that supports either 'ccw'
- * or s390 and sets the address type based on the capabilities.
- *
- * If the address is using 'ccw' or s390 and it's not supported, generate
- * an error and return false; otherwise, return true.
- */
-bool
-qemuCheckCCWS390AddressSupport(virDomainDefPtr def,
- virDomainDeviceInfo info,
- virQEMUCapsPtr qemuCaps,
- const char *devicename)
-{
- if (info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
- if (!qemuDomainMachineIsS390CCW(def)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("cannot use CCW address type for device "
- "'%s' using machine type '%s'"),
- devicename, def->os.machine);
- return false;
- } else if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_CCW)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("CCW address type is not supported by "
- "this QEMU"));
- return false;
- }
- } else if (info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) {
- if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_S390)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("virtio S390 address type is not supported by "
- "this QEMU"));
- return false;
+ base64_encode_alloc(secret, secret_size, &base64);
+ VIR_FREE(secret);
+ if (!base64) {
+ virReportOOMError();
+ goto cleanup;
}
+ secret = base64;
}
- return true;
+
+ cleanup:
+ virObjectUnref(sec);
+ return secret;
}
-/* Qemu 1.2 and later have a binary flag -enable-fips that must be
- * used for VNC auth to obey FIPS settings; but the flag only
- * exists on Linux, and with no way to probe for it via QMP. Our
- * solution: if FIPS mode is required, then unconditionally use
- * the flag, regardless of qemu version, for the following matrix:
- *
- * old QEMU new QEMU
- * FIPS enabled doesn't start VNC auth disabled
- * FIPS disabled/missing VNC auth enabled VNC auth enabled
- */
-bool
-qemuCheckFips(void)
+static int
+qemuNetworkDriveGetPort(int protocol,
+ const char *port)
{
- bool ret = false;
+ int ret = 0;
- if (virFileExists("/proc/sys/crypto/fips_enabled")) {
- char *buf = NULL;
+ if (port) {
+ if (virStrToLong_i(port, NULL, 10, &ret) < 0 || ret < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to parse port number '%s'"),
+ port);
+ return -1;
+ }
- if (virFileReadAll("/proc/sys/crypto/fips_enabled", 10, &buf) <
0)
- return ret;
- if (STREQ(buf, "1\n"))
- ret = true;
- VIR_FREE(buf);
+ return ret;
}
- return ret;
-}
-
-
-char *
-qemuBuildDriveStr(virConnectPtr conn,
- virDomainDiskDefPtr disk,
- bool bootable,
- virQEMUCapsPtr qemuCaps)
-{
- virBuffer opt = VIR_BUFFER_INITIALIZER;
- const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus);
- const char *trans =
- virDomainDiskGeometryTransTypeToString(disk->geometry.trans);
- int idx = virDiskNameToIndex(disk->dst);
- int busid = -1, unitid = -1;
- char *source = NULL;
- int actualType = virStorageSourceGetActualType(disk->src);
+ switch ((virStorageNetProtocol) protocol) {
+ case VIR_STORAGE_NET_PROTOCOL_HTTP:
+ return 80;
- if (idx < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("unsupported disk type '%s'"), disk->dst);
- goto error;
- }
+ case VIR_STORAGE_NET_PROTOCOL_HTTPS:
+ return 443;
- switch (disk->bus) {
- case VIR_DOMAIN_DISK_BUS_SCSI:
- if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("unexpected address type for scsi disk"));
- goto error;
- }
+ case VIR_STORAGE_NET_PROTOCOL_FTP:
+ return 21;
- /* 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"));
- goto error;
- }
- busid = disk->info.addr.drive.controller;
- unitid = disk->info.addr.drive.unit;
- break;
+ case VIR_STORAGE_NET_PROTOCOL_FTPS:
+ return 990;
- 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"));
- goto error;
- }
- /* We can only have 1 IDE controller (currently) */
- if (disk->info.addr.drive.controller != 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Only 1 %s controller is supported"), bus);
- goto error;
- }
- busid = disk->info.addr.drive.bus;
- unitid = disk->info.addr.drive.unit;
- break;
+ case VIR_STORAGE_NET_PROTOCOL_TFTP:
+ return 69;
- 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"));
- goto error;
- }
- /* We can only have 1 FDC controller (currently) */
- if (disk->info.addr.drive.controller != 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Only 1 %s controller is supported"), bus);
- goto error;
- }
- /* We can only have 1 FDC bus (currently) */
- if (disk->info.addr.drive.bus != 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Only 1 %s bus is supported"), bus);
- goto error;
- }
- if (disk->info.addr.drive.target != 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("target must be 0 for controller fdc"));
- goto error;
- }
- unitid = disk->info.addr.drive.unit;
+ case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
+ return 7000;
- break;
+ case VIR_STORAGE_NET_PROTOCOL_NBD:
+ return 10809;
- case VIR_DOMAIN_DISK_BUS_VIRTIO:
- idx = -1;
- break;
+ case VIR_STORAGE_NET_PROTOCOL_ISCSI:
+ case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
+ /* no default port specified */
+ return 0;
- case VIR_DOMAIN_DISK_BUS_XEN:
- case VIR_DOMAIN_DISK_BUS_SD:
- /* Xen and SD have no address type currently, so assign
- * based on index */
- break;
+ case VIR_STORAGE_NET_PROTOCOL_RBD:
+ case VIR_STORAGE_NET_PROTOCOL_LAST:
+ case VIR_STORAGE_NET_PROTOCOL_NONE:
+ /* not applicable */
+ return -1;
}
- if (qemuGetDriveSourceString(disk->src, conn, &source) < 0)
- goto error;
+ return -1;
+}
- if (source &&
- !((disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY ||
- disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) &&
- disk->tray_status == VIR_DOMAIN_DISK_TRAY_OPEN)) {
+#define QEMU_DEFAULT_NBD_PORT "10809"
- virBufferAddLit(&opt, "file=");
+static char *
+qemuBuildNetworkDriveURI(virStorageSourcePtr src,
+ const char *username,
+ const char *secret)
+{
+ char *ret = NULL;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ virURIPtr uri = NULL;
+ size_t i;
- switch (actualType) {
- case VIR_STORAGE_TYPE_DIR:
- /* QEMU only supports magic FAT format for now */
- if (disk->src->format > 0 &&
- disk->src->format != VIR_STORAGE_FILE_FAT) {
+ switch ((virStorageNetProtocol) src->protocol) {
+ case VIR_STORAGE_NET_PROTOCOL_NBD:
+ if (src->nhosts != 1) {
virReportError(VIR_ERR_INTERNAL_ERROR,
- _("unsupported disk driver type for
'%s'"),
-
virStorageFileFormatTypeToString(disk->src->format));
- goto error;
+ _("protocol '%s' accepts only one
host"),
+ virStorageNetProtocolTypeToString(src->protocol));
+ goto cleanup;
}
- if (!disk->src->readonly) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("cannot create virtual FAT disks in read-write
mode"));
- goto error;
- }
+ if (!((src->hosts->name && strchr(src->hosts->name,
':')) ||
+ (src->hosts->transport == VIR_STORAGE_NET_HOST_TRANS_TCP
&&
+ !src->hosts->name) ||
+ (src->hosts->transport == VIR_STORAGE_NET_HOST_TRANS_UNIX
&&
+ src->hosts->socket &&
+ src->hosts->socket[0] != '/'))) {
- virBufferAddLit(&opt, "fat:");
+ virBufferAddLit(&buf, "nbd:");
- if (disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
- virBufferAddLit(&opt, "floppy:");
+ switch (src->hosts->transport) {
+ case VIR_STORAGE_NET_HOST_TRANS_TCP:
+ virBufferStrcat(&buf, src->hosts->name, NULL);
+ virBufferAsprintf(&buf, ":%s",
+ src->hosts->port ? src->hosts->port :
+ QEMU_DEFAULT_NBD_PORT);
+ break;
- break;
+ case VIR_STORAGE_NET_HOST_TRANS_UNIX:
+ if (!src->hosts->socket) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("socket attribute required for "
+ "unix transport"));
+ goto cleanup;
+ }
- case VIR_STORAGE_TYPE_BLOCK:
- if (disk->tray_status == VIR_DOMAIN_DISK_TRAY_OPEN) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- disk->src->type == VIR_STORAGE_TYPE_VOLUME ?
- _("tray status 'open' is invalid for block
type volume") :
- _("tray status 'open' is invalid for block
type disk"));
- goto error;
- }
+ virBufferAsprintf(&buf, "unix:%s",
src->hosts->socket);
+ break;
- break;
+ default:
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("nbd does not support transport
'%s'"),
+
virStorageNetHostTransportTypeToString(src->hosts->transport));
+ goto cleanup;
+ }
- default:
- break;
- }
+ if (src->path)
+ virBufferAsprintf(&buf, ":exportname=%s",
src->path);
- virBufferEscape(&opt, ',', ",", "%s,", source);
+ if (virBufferCheckError(&buf) < 0)
+ goto cleanup;
- if (disk->src->format > 0 &&
- disk->src->type != VIR_STORAGE_TYPE_DIR)
- virBufferAsprintf(&opt, "format=%s,",
-
virStorageFileFormatTypeToString(disk->src->format));
- }
- VIR_FREE(source);
+ ret = virBufferContentAndReset(&buf);
+ goto cleanup;
+ }
+ /* fallthrough */
+ /* NBD code uses same formatting scheme as others in some cases */
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE))
- virBufferAddLit(&opt, "if=none");
- else
- virBufferAsprintf(&opt, "if=%s", bus);
+ case VIR_STORAGE_NET_PROTOCOL_HTTP:
+ case VIR_STORAGE_NET_PROTOCOL_HTTPS:
+ case VIR_STORAGE_NET_PROTOCOL_FTP:
+ case VIR_STORAGE_NET_PROTOCOL_FTPS:
+ case VIR_STORAGE_NET_PROTOCOL_TFTP:
+ case VIR_STORAGE_NET_PROTOCOL_ISCSI:
+ case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
+ if (src->nhosts != 1) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("protocol '%s' accepts only one
host"),
+ virStorageNetProtocolTypeToString(src->protocol));
+ goto cleanup;
+ }
- if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
- if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
- if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_CD))
- virBufferAddLit(&opt, ",media=cdrom");
- } else if (disk->bus == VIR_DOMAIN_DISK_BUS_IDE) {
- if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_IDE_CD))
- virBufferAddLit(&opt, ",media=cdrom");
- } else {
- virBufferAddLit(&opt, ",media=cdrom");
- }
- }
+ if (VIR_ALLOC(uri) < 0)
+ goto cleanup;
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
- virBufferAsprintf(&opt, ",id=%s%s", QEMU_DRIVE_HOST_PREFIX,
disk->info.alias);
- } else {
- if (busid == -1 && unitid == -1) {
- if (idx != -1)
- virBufferAsprintf(&opt, ",index=%d", idx);
- } else {
- if (busid != -1)
- virBufferAsprintf(&opt, ",bus=%d", busid);
- if (unitid != -1)
- virBufferAsprintf(&opt, ",unit=%d", unitid);
- }
- }
- if (bootable &&
- virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_BOOT) &&
- (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK ||
+ if (src->hosts->transport == VIR_STORAGE_NET_HOST_TRANS_TCP) {
+ if (VIR_STRDUP(uri->scheme,
+ virStorageNetProtocolTypeToString(src->protocol)) <
0)
+ goto cleanup;
+ } else {
+ if (virAsprintf(&uri->scheme, "%s+%s",
+ virStorageNetProtocolTypeToString(src->protocol),
+
virStorageNetHostTransportTypeToString(src->hosts->transport)) < 0)
+ goto cleanup;
+ }
+
+ if ((uri->port = qemuNetworkDriveGetPort(src->protocol,
src->hosts->port)) < 0)
+ goto cleanup;
+
+ if (src->path) {
+ if (src->volume) {
+ if (virAsprintf(&uri->path, "/%s%s",
+ src->volume, src->path) < 0)
+ goto cleanup;
+ } else {
+ if (virAsprintf(&uri->path, "%s%s",
+ src->path[0] == '/' ? "" :
"/",
+ src->path) < 0)
+ goto cleanup;
+ }
+ }
+
+ if (src->hosts->socket &&
+ virAsprintf(&uri->query, "socket=%s",
src->hosts->socket) < 0)
+ goto cleanup;
+
+ if (username) {
+ if (secret) {
+ if (virAsprintf(&uri->user, "%s:%s", username,
secret) < 0)
+ goto cleanup;
+ } else {
+ if (VIR_STRDUP(uri->user, username) < 0)
+ goto cleanup;
+ }
+ }
+
+ if (VIR_STRDUP(uri->server, src->hosts->name) < 0)
+ goto cleanup;
+
+ ret = virURIFormat(uri);
+
+ break;
+
+ case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
+ if (!src->path) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("missing disk source for 'sheepdog'
protocol"));
+ goto cleanup;
+ }
+
+ if (src->nhosts == 0) {
+ if (virAsprintf(&ret, "sheepdog:%s", src->path) < 0)
+ goto cleanup;
+ } else if (src->nhosts == 1) {
+ if (virAsprintf(&ret, "sheepdog:%s:%s:%s",
+ src->hosts->name,
+ src->hosts->port ? src->hosts->port :
"7000",
+ src->path) < 0)
+ goto cleanup;
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("protocol 'sheepdog' accepts up to one
host"));
+ goto cleanup;
+ }
+
+ break;
+
+ case VIR_STORAGE_NET_PROTOCOL_RBD:
+ if (strchr(src->path, ':')) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("':' not allowed in RBD source volume name
'%s'"),
+ src->path);
+ goto cleanup;
+ }
+
+ virBufferStrcat(&buf, "rbd:", src->path, NULL);
+
+ if (src->snapshot)
+ virBufferEscape(&buf, '\\', ":", "@%s",
src->snapshot);
+
+ if (username) {
+ virBufferEscape(&buf, '\\', ":",
":id=%s", username);
+ virBufferEscape(&buf, '\\', ":",
+ ":key=%s:auth_supported=cephx\\;none",
+ secret);
+ } else {
+ virBufferAddLit(&buf, ":auth_supported=none");
+ }
+
+ if (src->nhosts > 0) {
+ virBufferAddLit(&buf, ":mon_host=");
+ for (i = 0; i < src->nhosts; i++) {
+ if (i)
+ virBufferAddLit(&buf, "\\;");
+
+ /* assume host containing : is ipv6 */
+ if (strchr(src->hosts[i].name, ':'))
+ virBufferEscape(&buf, '\\', ":",
"[%s]",
+ src->hosts[i].name);
+ else
+ virBufferAsprintf(&buf, "%s",
src->hosts[i].name);
+
+ if (src->hosts[i].port)
+ virBufferAsprintf(&buf, "\\:%s",
src->hosts[i].port);
+ }
+ }
+
+ if (src->configFile)
+ virBufferEscape(&buf, '\\', ":",
":conf=%s", src->configFile);
+
+ if (virBufferCheckError(&buf) < 0)
+ goto cleanup;
+
+ ret = virBufferContentAndReset(&buf);
+ break;
+
+
+ case VIR_STORAGE_NET_PROTOCOL_LAST:
+ case VIR_STORAGE_NET_PROTOCOL_NONE:
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unexpected network protocol '%s'"),
+ virStorageNetProtocolTypeToString(src->protocol));
+ goto cleanup;
+ }
+
+ cleanup:
+ virBufferFreeAndReset(&buf);
+ virURIFree(uri);
+
+ return ret;
+}
+
+
+int
+qemuGetDriveSourceString(virStorageSourcePtr src,
+ virConnectPtr conn,
+ char **source)
+{
+ int actualType = virStorageSourceGetActualType(src);
+ char *secret = NULL;
+ char *username = NULL;
+ int ret = -1;
+
+ *source = NULL;
+
+ /* return 1 for empty sources */
+ if (virStorageSourceIsEmpty(src))
+ return 1;
+
+ if (conn) {
+ if (actualType == VIR_STORAGE_TYPE_NETWORK &&
+ src->auth &&
+ (src->protocol == VIR_STORAGE_NET_PROTOCOL_ISCSI ||
+ src->protocol == VIR_STORAGE_NET_PROTOCOL_RBD)) {
+ bool encode = false;
+ int secretType = VIR_SECRET_USAGE_TYPE_ISCSI;
+ const char *protocol = virStorageNetProtocolTypeToString(src->protocol);
+ username = src->auth->username;
+
+ if (src->protocol == VIR_STORAGE_NET_PROTOCOL_RBD) {
+ /* qemu requires the secret to be encoded for RBD */
+ encode = true;
+ secretType = VIR_SECRET_USAGE_TYPE_CEPH;
+ }
+
+ if (!(secret = qemuGetSecretString(conn,
+ protocol,
+ encode,
+ src->auth,
+ secretType)))
+ goto cleanup;
+ }
+ }
+
+ switch ((virStorageType) actualType) {
+ case VIR_STORAGE_TYPE_BLOCK:
+ case VIR_STORAGE_TYPE_FILE:
+ case VIR_STORAGE_TYPE_DIR:
+ if (VIR_STRDUP(*source, src->path) < 0)
+ goto cleanup;
+
+ break;
+
+ case VIR_STORAGE_TYPE_NETWORK:
+ if (!(*source = qemuBuildNetworkDriveURI(src, username, secret)))
+ goto cleanup;
+ break;
+
+ case VIR_STORAGE_TYPE_VOLUME:
+ case VIR_STORAGE_TYPE_NONE:
+ case VIR_STORAGE_TYPE_LAST:
+ break;
+ }
+
+ ret = 0;
+
+ cleanup:
+ VIR_FREE(secret);
+ return ret;
+}
+
+
+/* Perform disk definition config validity checks */
+int
+qemuCheckDiskConfig(virDomainDiskDefPtr disk)
+{
+ if (virDiskNameToIndex(disk->dst) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unsupported disk type '%s'"), disk->dst);
+ goto error;
+ }
+
+ 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"));
+ goto error;
+ }
+ }
+
+ if ((disk->vendor || disk->product) &&
+ disk->bus != VIR_DOMAIN_DISK_BUS_SCSI) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Only scsi disk supports vendor and product"));
+ goto error;
+ }
+
+ 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'"),
+ virDomainDiskQEMUBusTypeToString(disk->bus));
+ goto error;
+ }
+ if (disk->src->type == VIR_STORAGE_TYPE_NETWORK) {
+ if (disk->src->protocol != VIR_STORAGE_NET_PROTOCOL_ISCSI) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("disk device='lun' is not supported "
+ "for protocol='%s'"),
+
virStorageNetProtocolTypeToString(disk->src->protocol));
+ goto error;
+ }
+ } else if (!virDomainDiskSourceIsBlockType(disk->src, true)) {
+ goto error;
+ }
+ if (disk->wwn) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Setting wwn is not supported for lun device"));
+ goto error;
+ }
+ if (disk->vendor || disk->product) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Setting vendor or product is not supported "
+ "for lun device"));
+ goto error;
+ }
+ }
+ return 0;
+ error:
+ return -1;
+}
+
+
+/* Check whether the device address is using either 'ccw' or default s390
+ * address format and whether that's "legal" for the current qemu and/or
+ * guest os.machine type. This is the corollary to the code which doesn't
+ * find the address type set using an emulator that supports either 'ccw'
+ * or s390 and sets the address type based on the capabilities.
+ *
+ * If the address is using 'ccw' or s390 and it's not supported, generate
+ * an error and return false; otherwise, return true.
+ */
+bool
+qemuCheckCCWS390AddressSupport(virDomainDefPtr def,
+ virDomainDeviceInfo info,
+ virQEMUCapsPtr qemuCaps,
+ const char *devicename)
+{
+ if (info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
+ if (!qemuDomainMachineIsS390CCW(def)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("cannot use CCW address type for device "
+ "'%s' using machine type '%s'"),
+ devicename, def->os.machine);
+ return false;
+ } else if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_CCW)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("CCW address type is not supported by "
+ "this QEMU"));
+ return false;
+ }
+ } else if (info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) {
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_S390)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("virtio S390 address type is not supported by "
+ "this QEMU"));
+ return false;
+ }
+ }
+ return true;
+}
+
+
+/* Qemu 1.2 and later have a binary flag -enable-fips that must be
+ * used for VNC auth to obey FIPS settings; but the flag only
+ * exists on Linux, and with no way to probe for it via QMP. Our
+ * solution: if FIPS mode is required, then unconditionally use
+ * the flag, regardless of qemu version, for the following matrix:
+ *
+ * old QEMU new QEMU
+ * FIPS enabled doesn't start VNC auth disabled
+ * FIPS disabled/missing VNC auth enabled VNC auth enabled
+ */
+bool
+qemuCheckFips(void)
+{
+ bool ret = false;
+
+ if (virFileExists("/proc/sys/crypto/fips_enabled")) {
+ char *buf = NULL;
+
+ if (virFileReadAll("/proc/sys/crypto/fips_enabled", 10, &buf) <
0)
+ return ret;
+ if (STREQ(buf, "1\n"))
+ ret = true;
+ VIR_FREE(buf);
+ }
+
+ return ret;
+}
+
+
+char *
+qemuBuildDriveStr(virConnectPtr conn,
+ virDomainDiskDefPtr disk,
+ bool bootable,
+ virQEMUCapsPtr qemuCaps)
+{
+ virBuffer opt = VIR_BUFFER_INITIALIZER;
+ const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus);
+ const char *trans =
+ virDomainDiskGeometryTransTypeToString(disk->geometry.trans);
+ int idx = virDiskNameToIndex(disk->dst);
+ int busid = -1, unitid = -1;
+ char *source = NULL;
+ int actualType = virStorageSourceGetActualType(disk->src);
+
+ if (idx < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unsupported disk type '%s'"), disk->dst);
+ goto error;
+ }
+
+ switch (disk->bus) {
+ case VIR_DOMAIN_DISK_BUS_SCSI:
+ if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("unexpected address type for scsi disk"));
+ goto error;
+ }
+
+ /* 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"));
+ goto error;
+ }
+ busid = disk->info.addr.drive.controller;
+ unitid = disk->info.addr.drive.unit;
+ 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"));
+ goto error;
+ }
+ /* We can only have 1 IDE controller (currently) */
+ if (disk->info.addr.drive.controller != 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Only 1 %s controller is supported"), bus);
+ goto error;
+ }
+ busid = disk->info.addr.drive.bus;
+ unitid = disk->info.addr.drive.unit;
+ 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"));
+ goto error;
+ }
+ /* We can only have 1 FDC controller (currently) */
+ if (disk->info.addr.drive.controller != 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Only 1 %s controller is supported"), bus);
+ goto error;
+ }
+ /* We can only have 1 FDC bus (currently) */
+ if (disk->info.addr.drive.bus != 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Only 1 %s bus is supported"), bus);
+ goto error;
+ }
+ if (disk->info.addr.drive.target != 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("target must be 0 for controller fdc"));
+ goto error;
+ }
+ unitid = disk->info.addr.drive.unit;
+
+ break;
+
+ case VIR_DOMAIN_DISK_BUS_VIRTIO:
+ idx = -1;
+ break;
+
+ case VIR_DOMAIN_DISK_BUS_XEN:
+ case VIR_DOMAIN_DISK_BUS_SD:
+ /* Xen and SD have no address type currently, so assign
+ * based on index */
+ break;
+ }
+
+ if (qemuGetDriveSourceString(disk->src, conn, &source) < 0)
+ goto error;
+
+ if (source &&
+ !((disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY ||
+ disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) &&
+ disk->tray_status == VIR_DOMAIN_DISK_TRAY_OPEN)) {
+
+ virBufferAddLit(&opt, "file=");
+
+ switch (actualType) {
+ case VIR_STORAGE_TYPE_DIR:
+ /* QEMU only supports magic FAT format for now */
+ if (disk->src->format > 0 &&
+ disk->src->format != VIR_STORAGE_FILE_FAT) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unsupported disk driver type for
'%s'"),
+
virStorageFileFormatTypeToString(disk->src->format));
+ goto error;
+ }
+
+ if (!disk->src->readonly) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot create virtual FAT disks in read-write
mode"));
+ goto error;
+ }
+
+ virBufferAddLit(&opt, "fat:");
+
+ if (disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
+ virBufferAddLit(&opt, "floppy:");
+
+ break;
+
+ case VIR_STORAGE_TYPE_BLOCK:
+ if (disk->tray_status == VIR_DOMAIN_DISK_TRAY_OPEN) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ disk->src->type == VIR_STORAGE_TYPE_VOLUME ?
+ _("tray status 'open' is invalid for block
type volume") :
+ _("tray status 'open' is invalid for block
type disk"));
+ goto error;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ virBufferEscape(&opt, ',', ",", "%s,", source);
+
+ if (disk->src->format > 0 &&
+ disk->src->type != VIR_STORAGE_TYPE_DIR)
+ virBufferAsprintf(&opt, "format=%s,",
+
virStorageFileFormatTypeToString(disk->src->format));
+ }
+ VIR_FREE(source);
+
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE))
+ virBufferAddLit(&opt, "if=none");
+ else
+ virBufferAsprintf(&opt, "if=%s", bus);
+
+ if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
+ if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_CD))
+ virBufferAddLit(&opt, ",media=cdrom");
+ } else if (disk->bus == VIR_DOMAIN_DISK_BUS_IDE) {
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_IDE_CD))
+ virBufferAddLit(&opt, ",media=cdrom");
+ } else {
+ virBufferAddLit(&opt, ",media=cdrom");
+ }
+ }
+
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
+ virBufferAsprintf(&opt, ",id=%s%s", QEMU_DRIVE_HOST_PREFIX,
disk->info.alias);
+ } else {
+ if (busid == -1 && unitid == -1) {
+ if (idx != -1)
+ virBufferAsprintf(&opt, ",index=%d", idx);
+ } else {
+ if (busid != -1)
+ virBufferAsprintf(&opt, ",bus=%d", busid);
+ if (unitid != -1)
+ virBufferAsprintf(&opt, ",unit=%d", unitid);
+ }
+ }
+ if (bootable &&
+ virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_BOOT) &&
+ (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK ||
disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) &&
disk->bus != VIR_DOMAIN_DISK_BUS_IDE)
virBufferAddLit(&opt, ",boot=on");
@@ -4569,220 +4976,17 @@ static char *qemuBuildSmbiosBiosStr(virSysinfoBIOSDefPtr def)
virBufferAddLit(&buf, "type=0");
/* 0:Vendor */
- if (def->vendor)
- virBufferAsprintf(&buf, ",vendor=%s", def->vendor);
- /* 0:BIOS Version */
- if (def->version)
- virBufferAsprintf(&buf, ",version=%s", def->version);
- /* 0:BIOS Release Date */
- if (def->date)
- virBufferAsprintf(&buf, ",date=%s", def->date);
- /* 0:System BIOS Major Release and 0:System BIOS Minor Release */
- if (def->release)
- virBufferAsprintf(&buf, ",release=%s", def->release);
-
- if (virBufferCheckError(&buf) < 0)
- goto error;
-
- return virBufferContentAndReset(&buf);
-
- error:
- virBufferFreeAndReset(&buf);
- return NULL;
-}
-
-static char *qemuBuildSmbiosSystemStr(virSysinfoSystemDefPtr def,
- bool skip_uuid)
-{
- virBuffer buf = VIR_BUFFER_INITIALIZER;
-
- if (!def ||
- (!def->manufacturer && !def->product && !def->version
&&
- !def->serial && (!def->uuid || skip_uuid) &&
- def->sku && !def->family))
- return NULL;
-
- virBufferAddLit(&buf, "type=1");
-
- /* 1:Manufacturer */
- if (def->manufacturer)
- virBufferAsprintf(&buf, ",manufacturer=%s",
- def->manufacturer);
- /* 1:Product Name */
- if (def->product)
- virBufferAsprintf(&buf, ",product=%s", def->product);
- /* 1:Version */
- if (def->version)
- virBufferAsprintf(&buf, ",version=%s", def->version);
- /* 1:Serial Number */
- if (def->serial)
- virBufferAsprintf(&buf, ",serial=%s", def->serial);
- /* 1:UUID */
- if (def->uuid && !skip_uuid)
- virBufferAsprintf(&buf, ",uuid=%s", def->uuid);
- /* 1:SKU Number */
- if (def->sku)
- virBufferAsprintf(&buf, ",sku=%s", def->sku);
- /* 1:Family */
- if (def->family)
- virBufferAsprintf(&buf, ",family=%s", def->family);
-
- if (virBufferCheckError(&buf) < 0)
- goto error;
-
- return virBufferContentAndReset(&buf);
-
- error:
- virBufferFreeAndReset(&buf);
- return NULL;
-}
-
-static char *qemuBuildSmbiosBaseBoardStr(virSysinfoBaseBoardDefPtr def)
-{
- virBuffer buf = VIR_BUFFER_INITIALIZER;
-
- if (!def)
- return NULL;
-
- virBufferAddLit(&buf, "type=2");
-
- /* 2:Manufacturer */
- if (def->manufacturer)
- virBufferAsprintf(&buf, ",manufacturer=%s",
- def->manufacturer);
- /* 2:Product Name */
- if (def->product)
- virBufferAsprintf(&buf, ",product=%s", def->product);
- /* 2:Version */
- if (def->version)
- virBufferAsprintf(&buf, ",version=%s", def->version);
- /* 2:Serial Number */
- if (def->serial)
- virBufferAsprintf(&buf, ",serial=%s", def->serial);
- /* 2:Asset Tag */
- if (def->asset)
- virBufferAsprintf(&buf, ",asset=%s", def->asset);
- /* 2:Location */
- if (def->location)
- virBufferAsprintf(&buf, ",location=%s", def->location);
-
- if (virBufferCheckError(&buf) < 0)
- goto error;
-
- return virBufferContentAndReset(&buf);
-
- error:
- virBufferFreeAndReset(&buf);
- return NULL;
-}
-
-static char *
-qemuBuildClockArgStr(virDomainClockDefPtr def)
-{
- virBuffer buf = VIR_BUFFER_INITIALIZER;
-
- switch (def->offset) {
- case VIR_DOMAIN_CLOCK_OFFSET_UTC:
- virBufferAddLit(&buf, "base=utc");
- break;
-
- case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
- case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
- virBufferAddLit(&buf, "base=localtime");
- break;
-
- case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE: {
- time_t now = time(NULL);
- struct tm nowbits;
-
- if (def->data.variable.basis == VIR_DOMAIN_CLOCK_BASIS_LOCALTIME) {
- long localOffset;
-
- /* in the case of basis='localtime', rather than trying to
- * keep that basis (and associated offset from UTC) in the
- * status and deal with adding in the difference each time
- * there is an RTC_CHANGE event, it is simpler and less
- * error prone to just convert the adjustment an offset
- * from UTC right now (and change the status to
- * "basis='utc' to reflect this). This eliminates
- * potential errors in both RTC_CHANGE events and in
- * migration (in the case that the status of DST, or the
- * timezone of the destination host, changed relative to
- * startup).
- */
- if (virTimeLocalOffsetFromUTC(&localOffset) < 0)
- goto error;
- def->data.variable.adjustment += localOffset;
- def->data.variable.basis = VIR_DOMAIN_CLOCK_BASIS_UTC;
- }
-
- now += def->data.variable.adjustment;
- gmtime_r(&now, &nowbits);
-
- /* when an RTC_CHANGE event is received from qemu, we need to
- * have the adjustment used at domain start time available to
- * compute the new offset from UTC. As this new value is
- * itself stored in def->data.variable.adjustment, we need to
- * save a copy of it now.
- */
- def->data.variable.adjustment0 = def->data.variable.adjustment;
-
- virBufferAsprintf(&buf, "base=%d-%02d-%02dT%02d:%02d:%02d",
- nowbits.tm_year + 1900,
- nowbits.tm_mon + 1,
- nowbits.tm_mday,
- nowbits.tm_hour,
- nowbits.tm_min,
- nowbits.tm_sec);
- } break;
-
- default:
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("unsupported clock offset '%s'"),
- virDomainClockOffsetTypeToString(def->offset));
- goto error;
- }
-
- /* Look for an 'rtc' timer element, and add in appropriate clock= and
driftfix= */
- size_t i;
- for (i = 0; i < def->ntimers; i++) {
- if (def->timers[i]->name == VIR_DOMAIN_TIMER_NAME_RTC) {
- switch (def->timers[i]->track) {
- case -1: /* unspecified - use hypervisor default */
- break;
- case VIR_DOMAIN_TIMER_TRACK_BOOT:
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("unsupported rtc timer track '%s'"),
-
virDomainTimerTrackTypeToString(def->timers[i]->track));
- goto error;
- case VIR_DOMAIN_TIMER_TRACK_GUEST:
- virBufferAddLit(&buf, ",clock=vm");
- break;
- case VIR_DOMAIN_TIMER_TRACK_WALL:
- virBufferAddLit(&buf, ",clock=host");
- break;
- }
-
- switch (def->timers[i]->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 */
- virBufferAddLit(&buf, ",driftfix=slew");
- break;
- case VIR_DOMAIN_TIMER_TICKPOLICY_MERGE:
- case VIR_DOMAIN_TIMER_TICKPOLICY_DISCARD:
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("unsupported rtc timer tickpolicy
'%s'"),
-
virDomainTimerTickpolicyTypeToString(def->timers[i]->tickpolicy));
- goto error;
- }
- break; /* no need to check other timers - there is only one rtc */
- }
- }
+ if (def->vendor)
+ virBufferAsprintf(&buf, ",vendor=%s", def->vendor);
+ /* 0:BIOS Version */
+ if (def->version)
+ virBufferAsprintf(&buf, ",version=%s", def->version);
+ /* 0:BIOS Release Date */
+ if (def->date)
+ virBufferAsprintf(&buf, ",date=%s", def->date);
+ /* 0:System BIOS Major Release and 0:System BIOS Minor Release */
+ if (def->release)
+ virBufferAsprintf(&buf, ",release=%s", def->release);
if (virBufferCheckError(&buf) < 0)
goto error;
@@ -4794,378 +4998,207 @@ qemuBuildClockArgStr(virDomainClockDefPtr def)
return NULL;
}
-static int
-qemuBuildCpuModelArgStr(virQEMUDriverPtr driver,
- const virDomainDef *def,
- virBufferPtr buf,
- virQEMUCapsPtr qemuCaps,
- bool *hasHwVirt,
- bool migrating)
+static char *qemuBuildSmbiosSystemStr(virSysinfoSystemDefPtr def,
+ bool skip_uuid)
{
- int ret = -1;
- size_t i;
- virCPUDefPtr host = NULL;
- virCPUDefPtr guest = NULL;
- virCPUDefPtr cpu = NULL;
- virCPUDefPtr featCpu = NULL;
- size_t ncpus = 0;
- char **cpus = NULL;
- virCPUDataPtr data = NULL;
- virCPUDataPtr hostData = NULL;
- char *compare_msg = NULL;
- virCPUCompareResult cmp;
- const char *preferred;
- virCapsPtr caps = NULL;
- bool compareAgainstHost = ((def->virtType == VIR_DOMAIN_VIRT_KVM ||
- def->cpu->mode != VIR_CPU_MODE_CUSTOM) &&
- def->cpu->mode != VIR_CPU_MODE_HOST_PASSTHROUGH);
-
- if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
- goto cleanup;
-
- host = caps->host.cpu;
-
- if (!host ||
- !host->model ||
- (ncpus = virQEMUCapsGetCPUDefinitions(qemuCaps, &cpus)) == 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("CPU specification not supported by hypervisor"));
- goto cleanup;
- }
-
- if (!(cpu = virCPUDefCopy(def->cpu)))
- goto cleanup;
-
- if (cpu->mode == VIR_CPU_MODE_HOST_MODEL &&
- !migrating &&
- cpuUpdate(cpu, host) < 0)
- goto cleanup;
-
- /* For non-KVM, CPU features are emulated, so host compat doesn't matter */
- if (compareAgainstHost) {
- bool noTSX = false;
-
- cmp = cpuGuestData(host, cpu, &data, &compare_msg);
- switch (cmp) {
- case VIR_CPU_COMPARE_INCOMPATIBLE:
- if (cpuEncode(host->arch, host, NULL, &hostData,
- NULL, NULL, NULL, NULL) == 0 &&
- (!cpuHasFeature(hostData, "hle") ||
- !cpuHasFeature(hostData, "rtm")) &&
- (STREQ_NULLABLE(cpu->model, "Haswell") ||
- STREQ_NULLABLE(cpu->model, "Broadwell")))
- noTSX = true;
-
- if (compare_msg) {
- if (noTSX) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("guest and host CPU are not compatible: "
- "%s; try using '%s-noTSX' CPU
model"),
- compare_msg, cpu->model);
- } else {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("guest and host CPU are not compatible: "
- "%s"),
- compare_msg);
- }
- } else {
- if (noTSX) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("guest CPU is not compatible with host "
- "CPU; try using '%s-noTSX' CPU
model"),
- cpu->model);
- } else {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("guest CPU is not compatible with host "
- "CPU"));
- }
- }
- /* fall through */
- case VIR_CPU_COMPARE_ERROR:
- goto cleanup;
-
- default:
- break;
- }
- }
-
- /* Only 'svm' requires --enable-nesting. The nested
- * 'vmx' patches now simply hook off the CPU features
- */
- if ((def->os.arch == VIR_ARCH_X86_64 || def->os.arch == VIR_ARCH_I686)
&&
- compareAgainstHost) {
- int hasSVM = cpuHasFeature(data, "svm");
- if (hasSVM < 0)
- goto cleanup;
- *hasHwVirt = hasSVM > 0 ? true : false;
- }
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
- if ((cpu->mode == VIR_CPU_MODE_HOST_PASSTHROUGH) ||
- ((cpu->mode == VIR_CPU_MODE_HOST_MODEL) &&
- ARCH_IS_PPC64(def->os.arch))) {
- const char *mode = virCPUModeTypeToString(cpu->mode);
- if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CPU_HOST)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("CPU mode '%s' is not supported by QEMU"
- " binary"), mode);
- goto cleanup;
- }
- if (def->virtType != VIR_DOMAIN_VIRT_KVM) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("CPU mode '%s' is only supported with
kvm"),
- mode);
- goto cleanup;
- }
- virBufferAddLit(buf, "host");
+ if (!def ||
+ (!def->manufacturer && !def->product && !def->version
&&
+ !def->serial && (!def->uuid || skip_uuid) &&
+ def->sku && !def->family))
+ return NULL;
- if (def->os.arch == VIR_ARCH_ARMV7L &&
- host->arch == 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"));
- goto cleanup;
- }
+ virBufferAddLit(&buf, "type=1");
- virBufferAddLit(buf, ",aarch64=off");
- }
+ /* 1:Manufacturer */
+ if (def->manufacturer)
+ virBufferAsprintf(&buf, ",manufacturer=%s",
+ def->manufacturer);
+ /* 1:Product Name */
+ if (def->product)
+ virBufferAsprintf(&buf, ",product=%s", def->product);
+ /* 1:Version */
+ if (def->version)
+ virBufferAsprintf(&buf, ",version=%s", def->version);
+ /* 1:Serial Number */
+ if (def->serial)
+ virBufferAsprintf(&buf, ",serial=%s", def->serial);
+ /* 1:UUID */
+ if (def->uuid && !skip_uuid)
+ virBufferAsprintf(&buf, ",uuid=%s", def->uuid);
+ /* 1:SKU Number */
+ if (def->sku)
+ virBufferAsprintf(&buf, ",sku=%s", def->sku);
+ /* 1:Family */
+ if (def->family)
+ virBufferAsprintf(&buf, ",family=%s", def->family);
- if (ARCH_IS_PPC64(def->os.arch) &&
- cpu->mode == VIR_CPU_MODE_HOST_MODEL &&
- def->cpu->model != NULL) {
- virBufferAsprintf(buf, ",compat=%s", def->cpu->model);
- } else {
- featCpu = cpu;
- }
+ if (virBufferCheckError(&buf) < 0)
+ goto error;
- } else {
- if (VIR_ALLOC(guest) < 0)
- goto cleanup;
- if (VIR_STRDUP(guest->vendor_id, cpu->vendor_id) < 0)
- goto cleanup;
+ return virBufferContentAndReset(&buf);
- if (compareAgainstHost) {
- guest->arch = host->arch;
- if (cpu->match == VIR_CPU_MATCH_MINIMUM)
- preferred = host->model;
- else
- preferred = cpu->model;
+ error:
+ virBufferFreeAndReset(&buf);
+ return NULL;
+}
- guest->type = VIR_CPU_TYPE_GUEST;
- guest->fallback = cpu->fallback;
- if (cpuDecode(guest, data,
- (const char **)cpus, ncpus, preferred) < 0)
- goto cleanup;
- } else {
- guest->arch = def->os.arch;
- if (VIR_STRDUP(guest->model, cpu->model) < 0)
- goto cleanup;
- }
- virBufferAdd(buf, guest->model, -1);
- if (guest->vendor_id)
- virBufferAsprintf(buf, ",vendor=%s", guest->vendor_id);
- featCpu = guest;
- }
+static char *qemuBuildSmbiosBaseBoardStr(virSysinfoBaseBoardDefPtr def)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
- if (featCpu) {
- for (i = 0; i < featCpu->nfeatures; i++) {
- char sign;
- if (featCpu->features[i].policy == VIR_CPU_FEATURE_DISABLE)
- sign = '-';
- else
- sign = '+';
+ if (!def)
+ return NULL;
- virBufferAsprintf(buf, ",%c%s", sign,
featCpu->features[i].name);
- }
- }
+ virBufferAddLit(&buf, "type=2");
- ret = 0;
- cleanup:
- virObjectUnref(caps);
- VIR_FREE(compare_msg);
- cpuDataFree(data);
- cpuDataFree(hostData);
- virCPUDefFree(guest);
- virCPUDefFree(cpu);
- return ret;
+ /* 2:Manufacturer */
+ if (def->manufacturer)
+ virBufferAsprintf(&buf, ",manufacturer=%s",
+ def->manufacturer);
+ /* 2:Product Name */
+ if (def->product)
+ virBufferAsprintf(&buf, ",product=%s", def->product);
+ /* 2:Version */
+ if (def->version)
+ virBufferAsprintf(&buf, ",version=%s", def->version);
+ /* 2:Serial Number */
+ if (def->serial)
+ virBufferAsprintf(&buf, ",serial=%s", def->serial);
+ /* 2:Asset Tag */
+ if (def->asset)
+ virBufferAsprintf(&buf, ",asset=%s", def->asset);
+ /* 2:Location */
+ if (def->location)
+ virBufferAsprintf(&buf, ",location=%s", def->location);
+
+ if (virBufferCheckError(&buf) < 0)
+ goto error;
+
+ return virBufferContentAndReset(&buf);
+
+ error:
+ virBufferFreeAndReset(&buf);
+ return NULL;
}
-static int
-qemuBuildCpuArgStr(virQEMUDriverPtr driver,
- const virDomainDef *def,
- virQEMUCapsPtr qemuCaps,
- virArch hostarch,
- char **opt,
- bool *hasHwVirt,
- bool migrating)
+static char *
+qemuBuildClockArgStr(virDomainClockDefPtr def)
{
- const char *default_model;
- bool have_cpu = false;
- int ret = -1;
virBuffer buf = VIR_BUFFER_INITIALIZER;
- size_t i;
- *hasHwVirt = false;
-
- if (def->os.arch == VIR_ARCH_I686)
- default_model = "qemu32";
- else
- default_model = "qemu64";
+ switch (def->offset) {
+ case VIR_DOMAIN_CLOCK_OFFSET_UTC:
+ virBufferAddLit(&buf, "base=utc");
+ break;
- if (def->cpu &&
- (def->cpu->mode != VIR_CPU_MODE_CUSTOM || def->cpu->model)) {
- if (qemuBuildCpuModelArgStr(driver, def, &buf, qemuCaps,
- hasHwVirt, migrating) < 0)
- goto cleanup;
- have_cpu = true;
- } else {
- /*
- * Need to force a 32-bit guest CPU type if
- *
- * 1. guest OS is i686
- * 2. host OS is x86_64
- * 3. emulator is qemu-kvm or kvm
- *
- * Or
- *
- * 1. guest OS is i686
- * 2. emulator is qemu-system-x86_64
- */
- if (def->os.arch == VIR_ARCH_I686 &&
- ((hostarch == VIR_ARCH_X86_64 &&
- strstr(def->emulator, "kvm")) ||
- strstr(def->emulator, "x86_64"))) {
- virBufferAdd(&buf, default_model, -1);
- have_cpu = true;
- }
- }
+ case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
+ case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
+ virBufferAddLit(&buf, "base=localtime");
+ break;
- /* Handle paravirtual timers */
- for (i = 0; i < def->clock.ntimers; i++) {
- virDomainTimerDefPtr timer = def->clock.timers[i];
+ case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE: {
+ time_t now = time(NULL);
+ struct tm nowbits;
- if (timer->present == -1)
- continue;
+ if (def->data.variable.basis == VIR_DOMAIN_CLOCK_BASIS_LOCALTIME) {
+ long localOffset;
- if (timer->name == VIR_DOMAIN_TIMER_NAME_KVMCLOCK) {
- virBufferAsprintf(&buf, "%s,%ckvmclock",
- have_cpu ? "" : default_model,
- timer->present ? '+' : '-');
- have_cpu = true;
- } else if (timer->name == VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK &&
- timer->present) {
- virBufferAsprintf(&buf, "%s,hv_time",
- have_cpu ? "" : default_model);
- have_cpu = true;
+ /* in the case of basis='localtime', rather than trying to
+ * keep that basis (and associated offset from UTC) in the
+ * status and deal with adding in the difference each time
+ * there is an RTC_CHANGE event, it is simpler and less
+ * error prone to just convert the adjustment an offset
+ * from UTC right now (and change the status to
+ * "basis='utc' to reflect this). This eliminates
+ * potential errors in both RTC_CHANGE events and in
+ * migration (in the case that the status of DST, or the
+ * timezone of the destination host, changed relative to
+ * startup).
+ */
+ if (virTimeLocalOffsetFromUTC(&localOffset) < 0)
+ goto error;
+ def->data.variable.adjustment += localOffset;
+ def->data.variable.basis = VIR_DOMAIN_CLOCK_BASIS_UTC;
}
- }
- if (def->apic_eoi) {
- char sign;
- if (def->apic_eoi == VIR_TRISTATE_SWITCH_ON)
- sign = '+';
- else
- sign = '-';
+ now += def->data.variable.adjustment;
+ gmtime_r(&now, &nowbits);
- virBufferAsprintf(&buf, "%s,%ckvm_pv_eoi",
- have_cpu ? "" : default_model,
- sign);
- have_cpu = true;
- }
+ /* when an RTC_CHANGE event is received from qemu, we need to
+ * have the adjustment used at domain start time available to
+ * compute the new offset from UTC. As this new value is
+ * itself stored in def->data.variable.adjustment, we need to
+ * save a copy of it now.
+ */
+ def->data.variable.adjustment0 = def->data.variable.adjustment;
- if (def->features[VIR_DOMAIN_FEATURE_PVSPINLOCK]) {
- char sign;
- if (def->features[VIR_DOMAIN_FEATURE_PVSPINLOCK] == VIR_TRISTATE_SWITCH_ON)
- sign = '+';
- else
- sign = '-';
+ virBufferAsprintf(&buf, "base=%d-%02d-%02dT%02d:%02d:%02d",
+ nowbits.tm_year + 1900,
+ nowbits.tm_mon + 1,
+ nowbits.tm_mday,
+ nowbits.tm_hour,
+ nowbits.tm_min,
+ nowbits.tm_sec);
+ } break;
- virBufferAsprintf(&buf, "%s,%ckvm_pv_unhalt",
- have_cpu ? "" : default_model,
- sign);
- have_cpu = true;
+ default:
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unsupported clock offset '%s'"),
+ virDomainClockOffsetTypeToString(def->offset));
+ goto error;
}
- if (def->features[VIR_DOMAIN_FEATURE_HYPERV] == VIR_TRISTATE_SWITCH_ON) {
- if (!have_cpu) {
- virBufferAdd(&buf, default_model, -1);
- have_cpu = true;
- }
-
- for (i = 0; i < VIR_DOMAIN_HYPERV_LAST; i++) {
- switch ((virDomainHyperv) i) {
- case VIR_DOMAIN_HYPERV_RELAXED:
- case VIR_DOMAIN_HYPERV_VAPIC:
- if (def->hyperv_features[i] == VIR_TRISTATE_SWITCH_ON)
- virBufferAsprintf(&buf, ",hv_%s",
- virDomainHypervTypeToString(i));
+ /* Look for an 'rtc' timer element, and add in appropriate clock= and
driftfix= */
+ size_t i;
+ for (i = 0; i < def->ntimers; i++) {
+ if (def->timers[i]->name == VIR_DOMAIN_TIMER_NAME_RTC) {
+ switch (def->timers[i]->track) {
+ case -1: /* unspecified - use hypervisor default */
break;
-
- case VIR_DOMAIN_HYPERV_SPINLOCKS:
- if (def->hyperv_features[i] == VIR_TRISTATE_SWITCH_ON)
- virBufferAsprintf(&buf, ",hv_spinlocks=0x%x",
- def->hyperv_spinlocks);
+ case VIR_DOMAIN_TIMER_TRACK_BOOT:
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unsupported rtc timer track '%s'"),
+
virDomainTimerTrackTypeToString(def->timers[i]->track));
+ goto error;
+ case VIR_DOMAIN_TIMER_TRACK_GUEST:
+ virBufferAddLit(&buf, ",clock=vm");
break;
-
- /* coverity[dead_error_begin] */
- case VIR_DOMAIN_HYPERV_LAST:
+ case VIR_DOMAIN_TIMER_TRACK_WALL:
+ virBufferAddLit(&buf, ",clock=host");
break;
}
- }
- }
-
- for (i = 0; i < def->npanics; i++) {
- if (def->panics[i]->model == VIR_DOMAIN_PANIC_MODEL_HYPERV) {
- if (!have_cpu) {
- virBufferAdd(&buf, default_model, -1);
- have_cpu = true;
- }
-
- virBufferAddLit(&buf, ",hv_crash");
- break;
- }
- }
-
- if (def->features[VIR_DOMAIN_FEATURE_KVM] == VIR_TRISTATE_SWITCH_ON) {
- if (!have_cpu) {
- virBufferAdd(&buf, default_model, -1);
- have_cpu = true;
- }
- for (i = 0; i < VIR_DOMAIN_KVM_LAST; i++) {
- switch ((virDomainKVM) i) {
- case VIR_DOMAIN_KVM_HIDDEN:
- if (def->kvm_features[i] == VIR_TRISTATE_SWITCH_ON)
- virBufferAddLit(&buf, ",kvm=off");
+ switch (def->timers[i]->tickpolicy) {
+ case -1:
+ case VIR_DOMAIN_TIMER_TICKPOLICY_DELAY:
+ /* This is the default - missed ticks delivered when
+ next scheduled, at normal rate */
break;
-
- /* coverity[dead_error_begin] */
- case VIR_DOMAIN_KVM_LAST:
+ case VIR_DOMAIN_TIMER_TICKPOLICY_CATCHUP:
+ /* deliver ticks at a faster rate until caught up */
+ virBufferAddLit(&buf, ",driftfix=slew");
break;
+ case VIR_DOMAIN_TIMER_TICKPOLICY_MERGE:
+ case VIR_DOMAIN_TIMER_TICKPOLICY_DISCARD:
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unsupported rtc timer tickpolicy
'%s'"),
+
virDomainTimerTickpolicyTypeToString(def->timers[i]->tickpolicy));
+ goto error;
}
+ break; /* no need to check other timers - there is only one rtc */
}
}
- if (def->features[VIR_DOMAIN_FEATURE_PMU]) {
- virTristateSwitch pmu = def->features[VIR_DOMAIN_FEATURE_PMU];
- if (!have_cpu)
- virBufferAdd(&buf, default_model, -1);
-
- virBufferAsprintf(&buf, ",pmu=%s",
- virTristateSwitchTypeToString(pmu));
- have_cpu = true;
- }
-
if (virBufferCheckError(&buf) < 0)
- goto cleanup;
-
- *opt = virBufferContentAndReset(&buf);
+ goto error;
- ret = 0;
+ return virBufferContentAndReset(&buf);
- cleanup:
- return ret;
+ error:
+ virBufferFreeAndReset(&buf);
+ return NULL;
}
static char *
@@ -6723,11 +6756,9 @@ qemuBuildCommandLine(virConnectPtr conn,
virErrorPtr originalError = NULL;
size_t i, j;
char uuid[VIR_UUID_STRING_BUFLEN];
- char *cpu;
char *smp;
int spicecnt = 0;
int last_good_net = -1;
- bool hasHwVirt = false;
virCommandPtr cmd = NULL;
bool allowReboot = true;
bool emitBootindex = false;
@@ -6758,7 +6789,6 @@ qemuBuildCommandLine(virConnectPtr conn,
VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL,
VIR_DOMAIN_CONTROLLER_TYPE_CCID,
};
- virArch hostarch = virArchFromHost();
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
virBuffer boot_buf = VIR_BUFFER_INITIALIZER;
char *boot_order_str = NULL, *boot_opts_str = NULL;
@@ -6807,19 +6837,9 @@ qemuBuildCommandLine(virConnectPtr conn,
if (qemuBuildMachineCommandLine(cmd, def, qemuCaps) < 0)
goto error;
- if (qemuBuildCpuArgStr(driver, def, qemuCaps,
- hostarch, &cpu, &hasHwVirt, !!migrateURI) < 0)
+ if (qemuBuildCpuCommandLine(cmd, driver, def, qemuCaps, !!migrateURI) < 0)
goto error;
- if (cpu) {
- virCommandAddArgList(cmd, "-cpu", cpu, NULL);
- VIR_FREE(cpu);
-
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NESTING) &&
- hasHwVirt)
- virCommandAddArg(cmd, "-enable-nesting");
- }
-
if (qemuBuildDomainLoaderCommandLine(cmd, def, qemuCaps) < 0)
goto error;
--
2.5.0