qemu-caps: Get host model directly from Qemu when available

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>
This commit is contained in:
Jiri Denemark 2017-01-06 08:52:22 +01:00
parent fab9d6e1a9
commit 5d513d4659
4 changed files with 245 additions and 8 deletions

View 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,17 +3038,61 @@ 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 (!virQEMUCapsGuestIsNative(caps->host.arch, qemuCaps->arch))
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;
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)
@ -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

View File

@ -20,7 +20,24 @@
</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>

View File

@ -13021,6 +13021,32 @@
"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": {
},

View File

@ -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'/>