On Thu, Jan 05, 2023 at 09:35:00 +0100, Michal Privoznik wrote: > Now that we have qemuMonitorGetCPUModelExpansion() aware of > Hyper-V Enlightenments, we can start querying it. Two conditions > need to be met: > > 1) KVM is in use, > 2) Arch is either x86 or arm. > > It may look like modifying the first call to > qemuMonitorGetCPUModelExpansion() inside of > virQEMUCapsProbeQMPHostCPU() would be sufficient but it is not. > We really need to ask QEMU for full expansion and the first call > does not guarantee that. > > For the test data, I've just copied whatever > 'query-cpu-model-expansion' returned earlier, therefore there are > no hv-* props. But that's okay - the full expansion is not stored > in cache (and thus not formatted in > tests/qemucapabilitiesdata/caps_*.replies files either). This is > purely runtime thing. > > Signed-off-by: Michal Privoznik <mprivozn@xxxxxxxxxx> > --- [...] > diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c > index 4c75eea64e..93585f5af1 100644 > --- a/src/qemu/qemu_capabilities.c > +++ b/src/qemu/qemu_capabilities.c [...] > @@ -3029,6 +3036,66 @@ virQEMUCapsProbeCPUDefinitionsTest(virQEMUCaps *qemuCaps, > } > > > +static int > +virQEMUCapsProbeHypervCapabilities(virQEMUCaps *qemuCaps, > + qemuMonitorCPUModelInfo *fullQEMU) > +{ > + g_autofree virDomainCapsFeatureHyperv *hvcaps = NULL; > + size_t i; > + > + if (!fullQEMU) > + return 0; > + > + hvcaps = g_new0(virDomainCapsFeatureHyperv, 1); > + hvcaps->features.report = true; > + > + for (i = 0; i <fullQEMU->nprops; i++) { Space after < > + qemuMonitorCPUProperty prop = fullQEMU->props[i]; > + const char *name; > + int hvprop; > + > + if (!(name = STRSKIP(prop.name, "hv-"))) > + continue; > + > + hvprop = virDomainHypervTypeFromString(name); > + > + if (hvprop < 0) { > + /* Some names are different. For instance QEMU reports hv-vendor-id > + * but we have it as vendor_id (because of XML). Replace hyphens > + * with underscores and try again. */ > + g_autofree char *underscoreName = NULL; > + > + underscoreName = virStringReplace(name, "-", "_"); > + > + hvprop = virDomainHypervTypeFromString(underscoreName); > + if (hvprop < 0) { > + VIR_DEBUG("Not yet implement Hyper-V enlightenment: %s", > + prop.name); > + continue; > + } > + } > + > + if ((prop.type == QEMU_MONITOR_CPU_PROPERTY_BOOLEAN && > + prop.value.boolean) || > + (prop.type == QEMU_MONITOR_CPU_PROPERTY_NUMBER && > + prop.value.number > 0) || > + (prop.type == QEMU_MONITOR_CPU_PROPERTY_STRING && > + prop.value.string)) > + VIR_DOMAIN_CAPS_ENUM_SET(hvcaps->features, hvprop); > + > + } > + > + if (hvcaps->features.values) { > + hvcaps->supported = VIR_TRISTATE_BOOL_YES; > + } else { > + hvcaps->supported = VIR_TRISTATE_BOOL_NO; After some testing with older qemus I've noticed that old qemu is reporting an incomplete list of the hyperv features it supports. Thus even with qemu-4.2 I get: <hyperv supported='yes'> <enum name='features'> <value>spinlocks</value> <value>vendor_id</value> </enum> </hyperv> So I think the best course of actions will be to document that with older qemus the list may be incomplete. The problem will fix itself once we drop support for old qemus. Still, if the data is not present we can't claim that hyperv is not supported though, so the assignment below should be skipped in such case. > + } > + > + qemuCaps->hypervCapabilities = g_steal_pointer(&hvcaps); > + return 0; > +} > + > + > static int > virQEMUCapsProbeQMPHostCPU(virQEMUCaps *qemuCaps, > virQEMUCapsAccel *accel, [...] > @@ -4848,6 +4977,33 @@ virQEMUCapsFormatSGXInfo(virQEMUCaps *qemuCaps, > } > > > +static void > +virQEMUCapsFormatHypervCapabilities(virQEMUCaps *qemuCaps, > + virBuffer *buf) > +{ > + virDomainCapsFeatureHyperv *hvcaps = qemuCaps->hypervCapabilities; > + virBuffer attrBuf = VIR_BUFFER_INITIALIZER; > + virBuffer childBuf = VIR_BUFFER_INIT_CHILD(buf); g_auto() > + > + virBufferAsprintf(&attrBuf, " supported='%s'", > + virTristateBoolTypeToString(hvcaps->supported)); > + > + if (hvcaps->supported) { > + size_t i; > + > + for (i = 0; i < sizeof(hvcaps->features.values) * CHAR_BIT; i++) { > + if (!(hvcaps->features.values & (1U << i))) > + continue; > + > + virBufferAsprintf(&childBuf, "<cap name='%s'/>\n", > + virDomainHypervTypeToString(i)); > + } > + } > + > + return virXMLFormatElement(buf, "hypervCapabilities", &attrBuf, &childBuf); > +} > + > + > char * > virQEMUCapsFormatCache(virQEMUCaps *qemuCaps) > { Reviewed-by: Peter Krempa <pkrempa@xxxxxxxxxx>