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(a)linux.ibm.com>
---
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