From: "Collin L. Walling" <walling(a)linux.vnet.ibm.com>
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(a)linux.vnet.ibm.com>
Signed-off-by: Jason J. Herne <jjherne(a)linux.vnet.ibm.com>
---
src/qemu/qemu_capabilities.c | 180 ++++++++++++++++++++++++++++++++++++++++++-
src/qemu/qemu_capabilities.h | 1 +
2 files changed, 177 insertions(+), 4 deletions(-)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 081afc5..793afcc 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -354,6 +354,7 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST,
"gluster.debug_level",
"vhost-scsi",
"drive-iotune-group",
+ "query-cpu-model-expansion",
);
@@ -397,6 +398,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.
@@ -1514,7 +1517,8 @@ struct virQEMUCapsStringFlags virQEMUCapsCommands[] = {
{ "rtc-reset-reinjection", QEMU_CAPS_RTC_RESET_REINJECTION },
{ "migrate-incoming", QEMU_CAPS_INCOMING_DEFER },
{ "query-hotpluggable-cpus", QEMU_CAPS_QUERY_HOTPLUGGABLE_CPUS },
- { "query-qmp-schema", QEMU_CAPS_QUERY_QMP_SCHEMA }
+ { "query-qmp-schema", QEMU_CAPS_QUERY_QMP_SCHEMA },
+ { "query-cpu-model-expansion", QEMU_CAPS_QUERY_CPU_MODEL_EXPANSION},
};
struct virQEMUCapsStringFlags virQEMUCapsMigration[] = {
@@ -2160,6 +2164,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;
@@ -2808,6 +2816,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;
@@ -3017,9 +3037,60 @@ virQEMUCapsCPUFilterFeatures(const char *name,
}
-void
-virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
- virCapsPtr caps)
+static int
+virQEMUCapsCopyCPUModelFromQEMU(virQEMUCapsPtr qemuCaps)
+{
+ virCPUDefPtr cpu = NULL;
+ qemuMonitorCPUModelInfoPtr modelInfo = NULL;
+ size_t i;
+
+ 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 (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 0;
+
+ error:
+ virCPUDefFree(cpu);
+ qemuCaps->hostCPUModel = NULL;
+ virResetLastError();
+ return -1;
+}
+
+
+static void
+virQEMUCapsCopyCPUModelFromHost(virQEMUCapsPtr qemuCaps,
+ virCapsPtr caps)
{
virCPUDefPtr cpu = NULL;
@@ -3052,6 +3123,85 @@ virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
virResetLastError();
}
+void
+virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
+ virCapsPtr caps)
+{
+ switch (qemuCaps->arch) {
+ case VIR_ARCH_S390:
+ case VIR_ARCH_S390X:
+ if (virQEMUCapsCopyCPUModelFromQEMU(qemuCaps) == 0)
+ break;
+
+ default: virQEMUCapsCopyCPUModelFromHost(qemuCaps, caps);
+ }
+}
+
+
+static int
+virQEMUCapsLoadHostCPUModelInfo(virQEMUCapsPtr qemuCaps,
+ xmlXPathContextPtr ctxt,
+ xmlNodePtr hostCPUNode)
+{
+ char *str = NULL;
+ xmlNodePtr *featureNodes = NULL;
+ xmlNodePtr oldnode = ctxt->node;
+ int ret = -1;
+ size_t i;
+ int n;
+
+ if ((str = virXMLPropString(hostCPUNode, "model"))) {
+ if (VIR_ALLOC(qemuCaps->hostCPUModelInfo) < 0)
+ goto cleanup;
+ if (VIR_STRDUP(qemuCaps->hostCPUModelInfo->name, str) < 0)
+ goto cleanup;
+ }
+
+ ctxt->node = hostCPUNode;
+
+ if ((n = virXPathNodeSet("./feature", ctxt, &featureNodes)) > 0) {
+ if (VIR_ALLOC_N(qemuCaps->hostCPUModelInfo->props, n) < 0)
+ goto cleanup;
+
+ qemuCaps->hostCPUModelInfo->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(qemuCaps->hostCPUModelInfo->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")) {
+ qemuCaps->hostCPUModelInfo->props[i].supported = true;
+ } else if (STREQ(str, "no")) {
+ qemuCaps->hostCPUModelInfo->props[i].supported = false;
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("malformed supported value: expected
'yes'"
+ " or 'no'"));
+ goto cleanup;
+ }
+ }
+ }
+
+ ret = 0;
+
+ cleanup:
+ ctxt->node = oldnode;
+ VIR_FREE(str);
+ VIR_FREE(featureNodes);
+ return ret;
+}
+
static int
virQEMUCapsLoadCPUModels(virQEMUCapsPtr qemuCaps,
@@ -3148,6 +3298,7 @@ virQEMUCapsLoadCache(virCapsPtr caps,
size_t i;
int n;
xmlNodePtr *nodes = NULL;
+ xmlNodePtr node = NULL;
xmlXPathContextPtr ctxt = NULL;
char *str = NULL;
long long int l;
@@ -3247,6 +3398,11 @@ virQEMUCapsLoadCache(virCapsPtr caps,
}
VIR_FREE(str);
+ if ((node = virXPathNode("./hostCPU", ctxt)) &&
+ virQEMUCapsLoadHostCPUModelInfo(qemuCaps, ctxt, node) < 0)
+ goto cleanup;
+ node = NULL;
+
if (virQEMUCapsLoadCPUModels(qemuCaps, ctxt, VIR_DOMAIN_VIRT_KVM) < 0 ||
virQEMUCapsLoadCPUModels(qemuCaps, ctxt, VIR_DOMAIN_VIRT_QEMU) < 0)
goto cleanup;
@@ -3440,6 +3596,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);
@@ -4132,6 +4302,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/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index cbab879..71d2570 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -389,6 +389,7 @@ typedef enum {
QEMU_CAPS_GLUSTER_DEBUG_LEVEL, /* -drive gluster.debug_level={0..9} */
QEMU_CAPS_DEVICE_VHOST_SCSI, /* -device vhost-scsi-{ccw,pci} */
QEMU_CAPS_DRIVE_IOTUNE_GROUP, /* -drive throttling.group=<name> */
+ QEMU_CAPS_QUERY_CPU_MODEL_EXPANSION, /* qmp query-cpu-model-expansion */
QEMU_CAPS_LAST /* this must always be the last item */
} virQEMUCapsFlags;
--
2.7.4