Interfaces with QEMU to compare two CPU models. The command takes two CPU models, A and B, that are given a model name and an optional list of CPU features. Through the query-cpu-model-comparison command sent to QEMU via QMP, a third CPU model, C, is returned that contains the comparison result (identical, superset, subset, incompatible) as its model name as well as a list of properties (aka CPU features) responsible for this result. Signed-off-by: Collin Walling <walling@xxxxxxxxxxxxx> --- src/qemu/qemu_capabilities.c | 53 ++++++++++++++++++ src/qemu/qemu_capabilities.h | 6 ++ src/qemu/qemu_monitor.c | 14 +++++ src/qemu/qemu_monitor.h | 6 ++ src/qemu/qemu_monitor_json.c | 128 +++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 6 ++ 6 files changed, 213 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index d2eb813..d385ad8 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -468,6 +468,7 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST, "virtio-tablet-ccw", "qcow2-luks", "pcie-pci-bridge", + "query-cpu-model-comparison", ); @@ -1030,6 +1031,7 @@ struct virQEMUCapsStringFlags virQEMUCapsCommands[] = { { "query-hotpluggable-cpus", QEMU_CAPS_QUERY_HOTPLUGGABLE_CPUS }, { "query-qmp-schema", QEMU_CAPS_QUERY_QMP_SCHEMA }, { "query-cpu-model-expansion", QEMU_CAPS_QUERY_CPU_MODEL_EXPANSION }, + { "query-cpu-model-comparison", QEMU_CAPS_QUERY_CPU_MODEL_COMPARISON }, { "query-cpu-definitions", QEMU_CAPS_QUERY_CPU_DEFINITIONS }, { "query-named-block-nodes", QEMU_CAPS_QUERY_NAMED_BLOCK_NODES }, }; @@ -4930,3 +4932,54 @@ virQEMUCapsSetMicrocodeVersion(virQEMUCapsPtr qemuCaps, { qemuCaps->microcodeVersion = microcodeVersion; } + + +static virQEMUCapsInitQMPCommandPtr +virQEMUCapsSetupBinary(char *binary) +{ + virQEMUCapsInitQMPCommandPtr cmd; + char *qmperr = NULL; + + if (!(cmd = virQEMUCapsInitQMPCommandNew(binary, "/tmp", -1, -1, &qmperr))) + goto cleanup; + + if (virQEMUCapsInitQMPCommandRun(cmd, false) != 0) + goto cleanup; + + if (qemuMonitorSetCapabilities(cmd->mon) < 0) { + VIR_DEBUG("Failed to set monitor capabilities %s", + virGetLastErrorMessage()); + goto cleanup; + } + + return cmd; + + cleanup: + virQEMUCapsInitQMPCommandFree(cmd); + return NULL; +} + + +qemuMonitorCPUModelInfoPtr +virQEMUCapsProbeQMPCPUModelComparison(char *binary, + virCPUDefPtr cpuA, + virCPUDefPtr cpuB) +{ + virQEMUCapsInitQMPCommandPtr cmd; + qemuMonitorCPUModelInfoPtr cpuC = NULL; + qemuMonitorCPUModelInfoPtr ret = NULL; + + if (!(cmd = virQEMUCapsSetupBinary(binary))) + goto cleanup; + + if (qemuMonitorGetCPUModelComparison(cmd->mon, cpuA, cpuB, &cpuC) < 0) + goto cleanup; + + ret = cpuC; + cpuC = NULL; + + cleanup: + virQEMUCapsInitQMPCommandFree(cmd); + qemuMonitorCPUModelInfoFree(cpuC); + return ret; +} diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index a959931..f27a359 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -452,6 +452,7 @@ typedef enum { QEMU_CAPS_DEVICE_VIRTIO_TABLET_CCW, /* -device virtio-tablet-ccw */ QEMU_CAPS_QCOW2_LUKS, /* qcow2 format support LUKS encryption */ QEMU_CAPS_DEVICE_PCIE_PCI_BRIDGE, /* -device pcie-pci-bridge */ + QEMU_CAPS_QUERY_CPU_MODEL_COMPARISON, /* qmp query-cpu-model-comparison */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; @@ -578,4 +579,9 @@ bool virQEMUCapsGuestIsNative(virArch host, bool virQEMUCapsCPUFilterFeatures(const char *name, void *opaque); +qemuMonitorCPUModelInfoPtr +virQEMUCapsProbeQMPCPUModelComparison(char *binary, + virCPUDefPtr cpuA, + virCPUDefPtr cpuB); + #endif /* __QEMU_CAPABILITIES_H__*/ diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 22f0522..1981b62 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -3792,6 +3792,20 @@ qemuMonitorCPUModelInfoFree(qemuMonitorCPUModelInfoPtr model_info) } +int +qemuMonitorGetCPUModelComparison(qemuMonitorPtr mon, + virCPUDefPtr cpuA, + virCPUDefPtr cpuB, + qemuMonitorCPUModelInfoPtr *cpuC) +{ + VIR_DEBUG("cpuA=%p cpuB=%p", cpuA, cpuB); + + QEMU_CHECK_MONITOR_JSON(mon); + + return qemuMonitorJSONGetCPUModelComparison(mon, cpuA, cpuB, cpuC); +} + + qemuMonitorCPUModelInfoPtr qemuMonitorCPUModelInfoCopy(const qemuMonitorCPUModelInfo *orig) { diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 9556a51..cc30184 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1072,6 +1072,12 @@ int qemuMonitorGetCPUModelExpansion(qemuMonitorPtr mon, void qemuMonitorCPUModelInfoFree(qemuMonitorCPUModelInfoPtr model_info); +int +qemuMonitorGetCPUModelComparison(qemuMonitorPtr mon, + virCPUDefPtr modelA, + virCPUDefPtr modelB, + qemuMonitorCPUModelInfoPtr *cpuC); + qemuMonitorCPUModelInfoPtr qemuMonitorCPUModelInfoCopy(const qemuMonitorCPUModelInfo *orig); diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 57c2c4d..c1759ec 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -5466,6 +5466,134 @@ qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon, } +static virJSONValuePtr +qemuMonitorJSONConvertCPUDefToJSON(virCPUDefPtr cpu) +{ + virJSONValuePtr value; + virJSONValuePtr feats = NULL; + size_t i; + + if (!(value = virJSONValueNewObject()) || + !(feats = virJSONValueNewObject())) + goto cleanup; + + if (virJSONValueObjectAppendString(value, "name", cpu->model) < 0) + goto cleanup; + + for (i = 0; i < cpu->nfeatures; i++) { + char *name = cpu->features[i].name; + bool enabled = false; + + if (cpu->type == VIR_CPU_TYPE_HOST || + cpu->features[i].policy == VIR_CPU_FEATURE_REQUIRE) + enabled = true; + + if (virJSONValueObjectAppendBoolean(feats, name, enabled) < 0) + goto cleanup; + } + + if (virJSONValueObjectAppend(value, "props", feats) < 0) + goto cleanup; + + return value; + + cleanup: + virJSONValueFree(value); + virJSONValueFree(feats); + return NULL; +} + + +static int +qemuMonitorJSONParseCPUModelPropName(size_t pos ATTRIBUTE_UNUSED, + virJSONValuePtr item, + void *opaque) +{ + return qemuMonitorJSONParseCPUModelProperty(virJSONValueGetString(item), + item, opaque); +} + + +int +qemuMonitorJSONGetCPUModelComparison(qemuMonitorPtr mon, + virCPUDefPtr modelA, + virCPUDefPtr modelB, + qemuMonitorCPUModelInfoPtr *cpuC) +{ + int ret = -1; + virJSONValuePtr modela; + virJSONValuePtr modelb = NULL; + virJSONValuePtr cmd = NULL; + virJSONValuePtr reply = NULL; + virJSONValuePtr data; + const char *result; + virJSONValuePtr props; + qemuMonitorCPUModelInfoPtr modelc = NULL; + + if (!(modela = qemuMonitorJSONConvertCPUDefToJSON(modelA)) || + !(modelb = qemuMonitorJSONConvertCPUDefToJSON(modelB))) + goto cleanup; + + if (!(cmd = qemuMonitorJSONMakeCommand("query-cpu-model-comparison", + "a:modela", &modela, + "a:modelb", &modelb, + NULL))) + goto cleanup; + + /* Clean up of cmd will free the below virJSONValuePtrs */ + modela = NULL; + modelb = NULL; + + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) + goto cleanup; + + if (qemuMonitorJSONCheckError(cmd, reply) < 0) + goto cleanup; + + data = virJSONValueObjectGetObject(reply, "return"); + + if (!(result = virJSONValueObjectGetString(data, "result"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-cpu-model-expansion reply data was missing " + "'result'")); + goto cleanup; + } + + if (!(props = virJSONValueObjectGetArray(data, "responsible-properties"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-cpu-model-expansion reply data was missing " + "'responsible-properties'")); + goto cleanup; + } + + if (VIR_ALLOC(modelc) < 0) + goto cleanup; + + if (VIR_STRDUP(modelc->name, result) < 0) + goto cleanup; + + if (VIR_ALLOC_N(modelc->props, virJSONValueArraySize(props)) < 0) + goto cleanup; + + if (virJSONValueArrayForeachSteal(props, + qemuMonitorJSONParseCPUModelPropName, + modelc) < 0) + goto cleanup; + + ret = 0; + *cpuC = modelc; + modelc = NULL; + + cleanup: + qemuMonitorCPUModelInfoFree(modelc); + virJSONValueFree(cmd); + virJSONValueFree(reply); + virJSONValueFree(modela); + virJSONValueFree(modelb); + return ret; +} + + int qemuMonitorJSONGetCommands(qemuMonitorPtr mon, char ***commands) { diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 045df49..ad9ae73 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -361,6 +361,12 @@ int qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon, qemuMonitorCPUModelInfoPtr *model_info) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(5); +int qemuMonitorJSONGetCPUModelComparison(qemuMonitorPtr mon, + virCPUDefPtr modelA, + virCPUDefPtr modelB, + qemuMonitorCPUModelInfoPtr *cpuC) + ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4); + int qemuMonitorJSONGetCommands(qemuMonitorPtr mon, char ***commands) ATTRIBUTE_NONNULL(2); -- 2.7.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list