[libvirt] [PATCH v1 3/4] qemu: implement query-cpu-model-comparison via qemu

Collin Walling walling at linux.ibm.com
Mon Apr 16 23:16:08 UTC 2018


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 at 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




More information about the libvir-list mailing list