[libvirt] [PATCH 7/9] qemu-caps: Get host model directly from Qemu when available

Jason J. Herne jjherne at linux.vnet.ibm.com
Sun Dec 18 19:22:27 UTC 2016


When qmp query-cpu-model-expansion is available probe Qemu for its view of the
host model. In kvm environments this can provide a more complete view of the
host model because features supported by Qemu and Kvm can be considered.

Signed-off-by: Collin L. Walling <walling at linux.vnet.ibm.com>
Signed-off-by: Jason J. Herne <jjherne at linux.vnet.ibm.com>

# Conflicts:
#	tests/qemucapabilitiesdata/caps_2.8.0.s390x.replies

Signed-off-by: Jason J. Herne <jjherne at linux.vnet.ibm.com>
---
 src/qemu/qemu_capabilities.c                       | 185 ++++++++++++++++++++-
 tests/domaincapsschemadata/qemu_2.7.0.s390x.xml    |   4 +-
 tests/domaincapsschemadata/qemu_2.8.0.s390x.xml    |  17 +-
 .../qemucapabilitiesdata/caps_2.8.0.s390x.replies  |  26 +++
 tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml    |  17 ++
 5 files changed, 239 insertions(+), 10 deletions(-)

diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index bff30ed..7d33b19 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -399,6 +399,8 @@ struct _virQEMUCaps {
     size_t ngicCapabilities;
     virGICCapability *gicCapabilities;
 
+    qemuMonitorCPUModelInfoPtr hostCPUModelInfo;
+
     /* Anything below is not stored in the cache since the values are
      * re-computed from the other fields or external data sources every
      * time we probe QEMU or load the results from the cache.
@@ -2163,6 +2165,10 @@ virQEMUCapsPtr virQEMUCapsNewCopy(virQEMUCapsPtr qemuCaps)
         !(ret->hostCPUModel = virCPUDefCopy(qemuCaps->hostCPUModel)))
         goto error;
 
+    if (qemuCaps->hostCPUModelInfo &&
+        !(ret->hostCPUModelInfo = qemuMonitorCPUModelInfoCopy(qemuCaps->hostCPUModelInfo)))
+        goto error;
+
     if (VIR_ALLOC_N(ret->machineTypes, qemuCaps->nmachineTypes) < 0)
         goto error;
     ret->nmachineTypes = qemuCaps->nmachineTypes;
@@ -2811,6 +2817,18 @@ virQEMUCapsProbeQMPCPUDefinitions(virQEMUCapsPtr qemuCaps,
     return ret;
 }
 
+static int
+virQEMUCapsProbeQMPHostCPU(virQEMUCapsPtr qemuCaps,
+                           qemuMonitorPtr mon)
+{
+    if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_QUERY_CPU_MODEL_EXPANSION) ||
+        !virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM))
+        return 0;
+
+    return qemuMonitorGetCPUModelExpansion(mon, "static", "host",
+                                           &qemuCaps->hostCPUModelInfo);
+}
+
 struct tpmTypeToCaps {
     int type;
     virQEMUCapsFlags caps;
@@ -3020,18 +3038,62 @@ virQEMUCapsCPUFilterFeatures(const char *name,
 }
 
 
-void
-virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
-                            virCapsPtr caps)
+static void
+virQEMUCapsCopyCPUModelFromQEMU(virQEMUCapsPtr qemuCaps)
 {
     virCPUDefPtr cpu = NULL;
+    qemuMonitorCPUModelInfoPtr modelInfo = NULL;
+    size_t i;
 
-    if (!caps)
-        return;
+    if (!(modelInfo = qemuCaps->hostCPUModelInfo)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("missing host CPU model info from QEMU capabilities"
+                         " for binary %s"), qemuCaps->binary);
+        goto error;
+    }
 
-    if (!virQEMUCapsGuestIsNative(caps->host.arch, qemuCaps->arch))
+    if (VIR_ALLOC(cpu) < 0)
         goto error;
 
+    if (VIR_STRDUP(cpu->model, modelInfo->name) < 0 ||
+        VIR_ALLOC_N(cpu->features, modelInfo->nprops) < 0)
+        goto error;
+
+    cpu->nfeatures_max = modelInfo->nprops;
+    cpu->nfeatures = 0;
+    cpu->sockets = cpu->cores = cpu->threads = 0;
+    cpu->type = VIR_CPU_TYPE_GUEST;
+    cpu->mode = VIR_CPU_MODE_CUSTOM;
+    cpu->match = VIR_CPU_MATCH_EXACT;
+
+    for (i = 0; i < modelInfo->nprops; i++) {
+        if (VIR_STRDUP(cpu->features[i].name, modelInfo->props[i].name) < 0)
+            goto error;
+
+        if (modelInfo->props[i].supported)
+            cpu->features[i].policy = VIR_CPU_FEATURE_REQUIRE;
+        else
+            cpu->features[i].policy = VIR_CPU_FEATURE_DISABLE;
+
+        cpu->nfeatures++;
+    }
+
+    qemuCaps->hostCPUModel = cpu;
+    return;
+
+ error:
+    virCPUDefFree(cpu);
+    qemuCaps->hostCPUModel = NULL;
+    virResetLastError();
+}
+
+
+static void
+virQEMUCapsCopyCPUModelFromHost(virQEMUCapsPtr qemuCaps,
+                                virCapsPtr caps)
+{
+    virCPUDefPtr cpu = NULL;
+
     if (caps->host.cpu && caps->host.cpu->model) {
         if (VIR_ALLOC(cpu) < 0)
             goto error;
@@ -3055,6 +3117,98 @@ virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
     virResetLastError();
 }
 
+void
+virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
+                            virCapsPtr caps)
+{
+    if (!caps || !virQEMUCapsGuestIsNative(caps->host.arch, qemuCaps->arch))
+        return;
+
+    switch (qemuCaps->arch) {
+    case VIR_ARCH_S390:
+    case VIR_ARCH_S390X:
+        virQEMUCapsCopyCPUModelFromQEMU(qemuCaps);
+        break;
+    default: virQEMUCapsCopyCPUModelFromHost(qemuCaps, caps);
+    }
+}
+
+
+static int
+virQEMUCapsLoadHostCPUModelInfo(virQEMUCapsPtr qemuCaps,
+                                xmlXPathContextPtr ctxt)
+{
+    char *str = NULL;
+    xmlNodePtr hostCPUNode;
+    xmlNodePtr *featureNodes = NULL;
+    xmlNodePtr oldnode = ctxt->node;
+    qemuMonitorCPUModelInfoPtr hostCPU = NULL;
+    int ret = -1;
+    size_t i;
+    int n;
+
+    if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_QUERY_CPU_MODEL_EXPANSION)) {
+        ret = 0;
+        goto cleanup;
+    }
+
+    if (!(hostCPUNode = virXPathNode("./hostCPU", ctxt)) ||
+        VIR_ALLOC(hostCPU) < 0)
+        goto cleanup;
+
+    if ((str = virXMLPropString(hostCPUNode, "model"))) {
+        if (VIR_STRDUP(hostCPU->name, str) < 0)
+            goto cleanup;
+    }
+
+    ctxt->node = hostCPUNode;
+
+    if ((n = virXPathNodeSet("./feature", ctxt, &featureNodes)) > 0) {
+        if (VIR_ALLOC_N(hostCPU->props, n) < 0)
+            goto cleanup;
+
+        hostCPU->nprops = n;
+
+        for (i = 0; i < n; i++) {
+            if (!(str = virXMLPropString(featureNodes[i], "name"))) {
+                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                               _("missing 'name' element for a host CPU model"
+                                 " feature in QEMU capabilities cache"));
+                goto cleanup;
+            }
+            if (VIR_STRDUP(hostCPU->props[i].name, str) < 0)
+                goto cleanup;
+            if (!(str = virXMLPropString(featureNodes[i], "supported"))) {
+                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                               _("missing 'supported' element for a host CPU"
+                                 " model feature in QEMU capabilities cache"));
+                goto cleanup;
+            }
+            if (STREQ(str, "yes")) {
+                hostCPU->props[i].supported = true;
+            } else if (STREQ(str, "no")) {
+                hostCPU->props[i].supported = false;
+            } else {
+                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                               _("malformed supported value: expected 'yes'"
+                                 " or 'no'"));
+                goto cleanup;
+            }
+        }
+    }
+
+    qemuCaps->hostCPUModelInfo = hostCPU;
+    hostCPU = NULL;
+    ret = 0;
+
+ cleanup:
+    ctxt->node = oldnode;
+    VIR_FREE(str);
+    VIR_FREE(featureNodes);
+    qemuMonitorCPUModelInfoFree(hostCPU);
+    return ret;
+}
+
 
 static int
 virQEMUCapsLoadCPUModels(virQEMUCapsPtr qemuCaps,
@@ -3250,6 +3404,9 @@ virQEMUCapsLoadCache(virCapsPtr caps,
     }
     VIR_FREE(str);
 
+    if (virQEMUCapsLoadHostCPUModelInfo(qemuCaps, ctxt) < 0)
+        goto cleanup;
+
     if (virQEMUCapsLoadCPUModels(qemuCaps, ctxt, VIR_DOMAIN_VIRT_KVM) < 0 ||
         virQEMUCapsLoadCPUModels(qemuCaps, ctxt, VIR_DOMAIN_VIRT_QEMU) < 0)
         goto cleanup;
@@ -3443,6 +3600,20 @@ virQEMUCapsFormatCache(virQEMUCapsPtr qemuCaps,
     virBufferAsprintf(&buf, "<arch>%s</arch>\n",
                       virArchToString(qemuCaps->arch));
 
+    if (qemuCaps->hostCPUModelInfo) {
+        virBufferAsprintf(&buf, "<hostCPU model='%s'>\n",
+                          qemuCaps->hostCPUModelInfo->name);
+        virBufferAdjustIndent(&buf, 2);
+        for (i = 0; i < qemuCaps->hostCPUModelInfo->nprops; i++) {
+            virBufferAsprintf(&buf, "<feature name='%s' supported='%s'/>\n",
+                              qemuCaps->hostCPUModelInfo->props[i].name,
+                              qemuCaps->hostCPUModelInfo->props[i].supported ?
+                              "yes" : "no");
+        }
+        virBufferAdjustIndent(&buf, -2);
+        virBufferAddLit(&buf, "</hostCPU>\n");
+    }
+
     virQEMUCapsFormatCPUModels(qemuCaps, &buf, VIR_DOMAIN_VIRT_KVM);
     virQEMUCapsFormatCPUModels(qemuCaps, &buf, VIR_DOMAIN_VIRT_QEMU);
 
@@ -4135,6 +4306,8 @@ virQEMUCapsInitQMPMonitor(virQEMUCapsPtr qemuCaps,
     if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_QUERY_QMP_SCHEMA) &&
         virQEMUCapsProbeQMPSchemaCapabilities(qemuCaps, mon) < 0)
         goto cleanup;
+    if (virQEMUCapsProbeQMPHostCPU(qemuCaps, mon) < 0)
+        goto cleanup;
 
     /* 'intel-iommu' shows up as a device since 2.2.0, but can
      * not be used with -device until 2.7.0. Before that it
diff --git a/tests/domaincapsschemadata/qemu_2.7.0.s390x.xml b/tests/domaincapsschemadata/qemu_2.7.0.s390x.xml
index 9f181d3..999e279 100644
--- a/tests/domaincapsschemadata/qemu_2.7.0.s390x.xml
+++ b/tests/domaincapsschemadata/qemu_2.7.0.s390x.xml
@@ -20,9 +20,7 @@
   </os>
   <cpu>
     <mode name='host-passthrough' supported='yes'/>
-    <mode name='host-model' supported='yes'>
-      <model fallback='allow'></model>
-    </mode>
+    <mode name='host-model' supported='no'/>
     <mode name='custom' supported='no'/>
   </cpu>
   <devices>
diff --git a/tests/domaincapsschemadata/qemu_2.8.0.s390x.xml b/tests/domaincapsschemadata/qemu_2.8.0.s390x.xml
index 0b792b2..efe3459 100644
--- a/tests/domaincapsschemadata/qemu_2.8.0.s390x.xml
+++ b/tests/domaincapsschemadata/qemu_2.8.0.s390x.xml
@@ -21,7 +21,22 @@
   <cpu>
     <mode name='host-passthrough' supported='yes'/>
     <mode name='host-model' supported='yes'>
-      <model fallback='allow'></model>
+      <model fallback='allow'>zEC12.2-base</model>
+      <feature policy='require' name='aefsi'/>
+      <feature policy='require' name='msa5'/>
+      <feature policy='require' name='msa4'/>
+      <feature policy='require' name='msa3'/>
+      <feature policy='require' name='msa2'/>
+      <feature policy='require' name='msa1'/>
+      <feature policy='require' name='sthyi'/>
+      <feature policy='require' name='edat'/>
+      <feature policy='require' name='ri'/>
+      <feature policy='require' name='edat2'/>
+      <feature policy='require' name='ipter'/>
+      <feature policy='require' name='esop'/>
+      <feature policy='require' name='cte'/>
+      <feature policy='require' name='te'/>
+      <feature policy='require' name='cmm'/>
     </mode>
     <mode name='custom' supported='yes'>
       <model usable='unknown'>z10EC-base</model>
diff --git a/tests/qemucapabilitiesdata/caps_2.8.0.s390x.replies b/tests/qemucapabilitiesdata/caps_2.8.0.s390x.replies
index 3ccad4f..0405d5d 100644
--- a/tests/qemucapabilitiesdata/caps_2.8.0.s390x.replies
+++ b/tests/qemucapabilitiesdata/caps_2.8.0.s390x.replies
@@ -13023,6 +13023,32 @@
 
 {
   "return": {
+    "model": {
+      "name": "zEC12.2-base",
+      "props": {
+        "aefsi": true,
+        "msa5": true,
+        "msa4": true,
+        "msa3": true,
+        "msa2": true,
+        "msa1": true,
+        "sthyi": true,
+        "edat": true,
+        "ri": true,
+        "edat2": true,
+        "ipter": true,
+        "esop": true,
+        "cte": true,
+        "te": true,
+        "cmm": true
+      }
+    }
+  },
+  "id": "libvirt-48"
+}
+
+{
+  "return": {
   },
   "id": "libvirt-1"
 }
diff --git a/tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml
index 1b955cf..c4c9bf9 100644
--- a/tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml
+++ b/tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml
@@ -133,6 +133,23 @@
   <kvmVersion>0</kvmVersion>
   <package></package>
   <arch>s390x</arch>
+  <hostCPU model='zEC12.2-base'>
+    <feature name='aefsi' supported='yes'/>
+    <feature name='msa5' supported='yes'/>
+    <feature name='msa4' supported='yes'/>
+    <feature name='msa3' supported='yes'/>
+    <feature name='msa2' supported='yes'/>
+    <feature name='msa1' supported='yes'/>
+    <feature name='sthyi' supported='yes'/>
+    <feature name='edat' supported='yes'/>
+    <feature name='ri' supported='yes'/>
+    <feature name='edat2' supported='yes'/>
+    <feature name='ipter' supported='yes'/>
+    <feature name='esop' supported='yes'/>
+    <feature name='cte' supported='yes'/>
+    <feature name='te' supported='yes'/>
+    <feature name='cmm' supported='yes'/>
+  </hostCPU>
   <cpu type='kvm' name='z10EC-base'/>
   <cpu type='kvm' name='z9EC-base'/>
   <cpu type='kvm' name='z196.2-base'/>
-- 
2.7.4




More information about the libvir-list mailing list