]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu-caps: Get host model directly from Qemu when available
authorJiri Denemark <jdenemar@redhat.com>
Fri, 6 Jan 2017 07:52:22 +0000 (08:52 +0100)
committerJiri Denemark <jdenemar@redhat.com>
Fri, 6 Jan 2017 11:24:57 +0000 (12:24 +0100)
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@linux.vnet.ibm.com>
Signed-off-by: Jason J. Herne <jjherne@linux.vnet.ibm.com>
src/qemu/qemu_capabilities.c
tests/domaincapsschemadata/qemu_2.8.0.s390x.xml
tests/qemucapabilitiesdata/caps_2.8.0.s390x.replies
tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml

index 996f273ee1da2e0ad7f6d3c7f5f7a949a0e1a418..2512e4838e03f716876c6c9a136af0e96eb95698 100644 (file)
@@ -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;
@@ -3056,6 +3118,102 @@ virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
 }
 
 
+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 (!(hostCPUNode = virXPathNode("./hostCPU", ctxt))) {
+        ret = 0;
+        goto cleanup;
+    }
+
+    if (VIR_ALLOC(hostCPU) < 0)
+        goto cleanup;
+
+    if (!(hostCPU->name = virXMLPropString(hostCPUNode, "model"))) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("missing host CPU model name in QEMU "
+                         "capabilities cache"));
+        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++) {
+            hostCPU->props[i].name = virXMLPropString(featureNodes[i], "name");
+            if (!hostCPU->props[i].name) {
+                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                               _("missing 'name' attribute for a host CPU"
+                                 " model feature in QEMU capabilities cache"));
+                goto cleanup;
+            }
+
+            if (!(str = virXMLPropString(featureNodes[i], "supported"))) {
+                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                               _("missing 'supported' attribute 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,
+                               _("invalid supported value: '%s'"), str);
+                goto cleanup;
+            }
+            VIR_FREE(str);
+        }
+    }
+
+    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,
                          xmlXPathContextPtr ctxt,
@@ -3250,6 +3408,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 +3604,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 +4310,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
index 92946f4549bd6e9e3af1c8755e80a651f0456afa..efe345962a4d7039f76ef97a2dd8bcc04197791c 100644 (file)
   </os>
   <cpu>
     <mode name='host-passthrough' supported='yes'/>
-    <mode name='host-model' supported='no'/>
+    <mode name='host-model' supported='yes'>
+      <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>
       <model usable='unknown'>z9EC-base</model>
index 3ccad4f4d52facf92fb597f8d1b19a041b5129bb..0405d5d7b3d35ba249c8d4ce7accb74f26b810cc 100644 (file)
   "id": "libvirt-47"
 }
 
+{
+  "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": {
   },
index 1b955cf238f65089b6f57af5fb0aa56416f96482..c4c9bf9d53a0e1b71c22f285f2fbf222718c2f3e 100644 (file)
   <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'/>