[libvirt PATCH v2 00/14] Improve CPU model reporting in domain capabilities

See individual patches for details. Patches 4 and 6 were truncated as they include a lot of boring changes in tests, complete patches are available in my gitlab repo: git fetch git@gitlab.com:jirkade/libvirt.git domaincaps Version 2: - original patch 10/11 was replaced by several new patches going in a bit different way of getting usability blockers Jiri Denemark (14): conf: virDomainCapsCPUModelsAdd never fails cpu_ppc64: Avoid repeated loading of CPU map qemu: Do not pass qemuCaps to virQEMUCapsCPUFeature{To,From}QEMU domain_capabilities: Add vendor attribute for CPU models Introduce virCPUGetVendorForModel and use it in QEMU driver cpu_x86: Implement virCPUGetVendorForModel cpu_ppc64: Implement virCPUGetVendorForModel cpu_arm: Don't implement virCPUGetVendorForModel docs: Enhance documentation of CPU models in domain caps Document specifics of virConnectBaselineHypervisorCPU qemu_capabilities: Translate CPU blockers virsh: Add --model option for hypervisor-cpu-baseline virsh: Add completer for hypervisor-cpu-baseline --model NEWS: Document CPU reporting improvements NEWS.rst | 22 +++ docs/formatdomaincaps.rst | 30 +++- docs/manpages/virsh.rst | 14 +- src/conf/domain_capabilities.c | 35 +++-- src/conf/domain_capabilities.h | 13 +- src/conf/schemas/domaincaps.rng | 3 + src/cpu/cpu.c | 25 +++ src/cpu/cpu.h | 8 + src/cpu/cpu_arm.c | 1 + src/cpu/cpu_ppc64.c | 67 ++++++-- src/cpu/cpu_x86.c | 19 +++ src/libvirt-host.c | 9 ++ src/libvirt_private.syms | 1 + src/qemu/qemu_capabilities.c | 85 +++++++--- src/qemu/qemu_capabilities.h | 8 +- src/qemu/qemu_command.c | 2 +- src/qemu/qemu_monitor.c | 7 +- src/qemu/qemu_monitor.h | 5 +- src/qemu/qemu_monitor_json.c | 11 +- src/qemu/qemu_monitor_json.h | 1 - src/qemu/qemu_process.c | 12 +- tests/cputest.c | 15 +- .../domaincapsdata/qemu_4.2.0-q35.x86_64.xml | 104 ++++++------ .../domaincapsdata/qemu_4.2.0-tcg.x86_64.xml | 104 ++++++------ .../qemu_4.2.0-virt.aarch64.xml | 72 ++++----- tests/domaincapsdata/qemu_4.2.0.aarch64.xml | 72 ++++----- tests/domaincapsdata/qemu_4.2.0.ppc64.xml | 6 +- tests/domaincapsdata/qemu_4.2.0.s390x.xml | 148 +++++++++--------- tests/domaincapsdata/qemu_4.2.0.x86_64.xml | 104 ++++++------ .../domaincapsdata/qemu_5.0.0-q35.x86_64.xml | 108 ++++++------- .../domaincapsdata/qemu_5.0.0-tcg.x86_64.xml | 108 ++++++------- .../qemu_5.0.0-virt.aarch64.xml | 74 ++++----- tests/domaincapsdata/qemu_5.0.0.aarch64.xml | 74 ++++----- tests/domaincapsdata/qemu_5.0.0.ppc64.xml | 8 +- tests/domaincapsdata/qemu_5.0.0.x86_64.xml | 108 ++++++------- .../domaincapsdata/qemu_5.1.0-q35.x86_64.xml | 108 ++++++------- .../domaincapsdata/qemu_5.1.0-tcg.x86_64.xml | 108 ++++++------- tests/domaincapsdata/qemu_5.1.0.x86_64.xml | 108 ++++++------- .../domaincapsdata/qemu_5.2.0-q35.x86_64.xml | 108 ++++++------- .../domaincapsdata/qemu_5.2.0-tcg.x86_64.xml | 108 ++++++------- .../qemu_5.2.0-virt.aarch64.xml | 74 ++++----- tests/domaincapsdata/qemu_5.2.0.aarch64.xml | 74 ++++----- tests/domaincapsdata/qemu_5.2.0.ppc64.xml | 8 +- tests/domaincapsdata/qemu_5.2.0.s390x.xml | 148 +++++++++--------- tests/domaincapsdata/qemu_5.2.0.x86_64.xml | 108 ++++++------- .../domaincapsdata/qemu_6.0.0-q35.x86_64.xml | 110 ++++++------- .../domaincapsdata/qemu_6.0.0-tcg.x86_64.xml | 110 ++++++------- .../qemu_6.0.0-virt.aarch64.xml | 76 ++++----- tests/domaincapsdata/qemu_6.0.0.aarch64.xml | 76 ++++----- tests/domaincapsdata/qemu_6.0.0.s390x.xml | 148 +++++++++--------- tests/domaincapsdata/qemu_6.0.0.x86_64.xml | 110 ++++++------- .../domaincapsdata/qemu_6.1.0-q35.x86_64.xml | 110 ++++++------- .../domaincapsdata/qemu_6.1.0-tcg.x86_64.xml | 110 ++++++------- tests/domaincapsdata/qemu_6.1.0.x86_64.xml | 110 ++++++------- .../domaincapsdata/qemu_6.2.0-q35.x86_64.xml | 110 ++++++------- .../domaincapsdata/qemu_6.2.0-tcg.x86_64.xml | 110 ++++++------- .../qemu_6.2.0-virt.aarch64.xml | 78 ++++----- tests/domaincapsdata/qemu_6.2.0.aarch64.xml | 78 ++++----- tests/domaincapsdata/qemu_6.2.0.ppc64.xml | 8 +- tests/domaincapsdata/qemu_6.2.0.x86_64.xml | 110 ++++++------- .../domaincapsdata/qemu_7.0.0-q35.x86_64.xml | 110 ++++++------- .../domaincapsdata/qemu_7.0.0-tcg.x86_64.xml | 110 ++++++------- .../qemu_7.0.0-virt.aarch64.xml | 78 ++++----- tests/domaincapsdata/qemu_7.0.0.aarch64.xml | 78 ++++----- tests/domaincapsdata/qemu_7.0.0.ppc64.xml | 8 +- tests/domaincapsdata/qemu_7.0.0.x86_64.xml | 110 ++++++------- .../domaincapsdata/qemu_7.1.0-q35.x86_64.xml | 106 ++++++------- .../domaincapsdata/qemu_7.1.0-tcg.x86_64.xml | 106 ++++++------- tests/domaincapsdata/qemu_7.1.0.x86_64.xml | 106 ++++++------- tools/virsh-completer-host.c | 50 ++++++ tools/virsh-completer-host.h | 5 + tools/virsh-host.c | 24 ++- tools/virsh.h | 7 +- tools/vsh.h | 27 ++++ 74 files changed, 2549 insertions(+), 2265 deletions(-) -- 2.38.0

Since the function always returns 0, we can just return void and make callers simpler. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com> --- Notes: Version 2: - no change src/conf/domain_capabilities.c | 24 +++++++++--------------- src/conf/domain_capabilities.h | 11 ++++++----- src/qemu/qemu_capabilities.c | 9 ++++----- tests/cputest.c | 14 ++++---------- 4 files changed, 23 insertions(+), 35 deletions(-) diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c index 653123f293..123c80a560 100644 --- a/src/conf/domain_capabilities.c +++ b/src/conf/domain_capabilities.c @@ -155,37 +155,33 @@ virDomainCapsCPUModelsNew(size_t nmodels) virDomainCapsCPUModels * virDomainCapsCPUModelsCopy(virDomainCapsCPUModels *old) { - g_autoptr(virDomainCapsCPUModels) cpuModels = NULL; + virDomainCapsCPUModels *cpuModels = NULL; size_t i; if (!(cpuModels = virDomainCapsCPUModelsNew(old->nmodels))) return NULL; for (i = 0; i < old->nmodels; i++) { - if (virDomainCapsCPUModelsAdd(cpuModels, - old->models[i].name, - old->models[i].usable, - old->models[i].blockers, - old->models[i].deprecated) < 0) - return NULL; + virDomainCapsCPUModelsAdd(cpuModels, + old->models[i].name, + old->models[i].usable, + old->models[i].blockers, + old->models[i].deprecated); } - return g_steal_pointer(&cpuModels); + return cpuModels; } -int +void virDomainCapsCPUModelsAdd(virDomainCapsCPUModels *cpuModels, const char *name, virDomainCapsCPUUsable usable, char **blockers, bool deprecated) { - g_autofree char * nameCopy = NULL; virDomainCapsCPUModel *cpu; - nameCopy = g_strdup(name); - VIR_RESIZE_N(cpuModels->models, cpuModels->nmodels_max, cpuModels->nmodels, 1); @@ -193,11 +189,9 @@ virDomainCapsCPUModelsAdd(virDomainCapsCPUModels *cpuModels, cpuModels->nmodels++; cpu->usable = usable; - cpu->name = g_steal_pointer(&nameCopy); + cpu->name = g_strdup(name); cpu->blockers = g_strdupv(blockers); cpu->deprecated = deprecated; - - return 0; } diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h index a526969cda..7333276231 100644 --- a/src/conf/domain_capabilities.h +++ b/src/conf/domain_capabilities.h @@ -244,11 +244,12 @@ virDomainCaps *virDomainCapsNew(const char *path, virDomainCapsCPUModels *virDomainCapsCPUModelsNew(size_t nmodels); virDomainCapsCPUModels *virDomainCapsCPUModelsCopy(virDomainCapsCPUModels *old); -int virDomainCapsCPUModelsAdd(virDomainCapsCPUModels *cpuModels, - const char *name, - virDomainCapsCPUUsable usable, - char **blockers, - bool deprecated); +void +virDomainCapsCPUModelsAdd(virDomainCapsCPUModels *cpuModels, + const char *name, + virDomainCapsCPUUsable usable, + char **blockers, + bool deprecated); virDomainCapsCPUModel * virDomainCapsCPUModelsGet(virDomainCapsCPUModels *cpuModels, const char *name); diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 68aefe1d86..c12e6dac69 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -2179,7 +2179,7 @@ virQEMUCapsCPUDefsToModels(qemuMonitorCPUDefs *defs, const char **modelAllowed, const char **modelForbidden) { - g_autoptr(virDomainCapsCPUModels) cpuModels = NULL; + virDomainCapsCPUModels *cpuModels = NULL; size_t i; if (!(cpuModels = virDomainCapsCPUModelsNew(defs->ncpus))) @@ -2194,12 +2194,11 @@ virQEMUCapsCPUDefsToModels(qemuMonitorCPUDefs *defs, if (modelForbidden && g_strv_contains(modelForbidden, cpu->name)) continue; - if (virDomainCapsCPUModelsAdd(cpuModels, cpu->name, cpu->usable, - cpu->blockers, cpu->deprecated) < 0) - return NULL; + virDomainCapsCPUModelsAdd(cpuModels, cpu->name, cpu->usable, + cpu->blockers, cpu->deprecated); } - return g_steal_pointer(&cpuModels); + return cpuModels; } diff --git a/tests/cputest.c b/tests/cputest.c index b7ec79dfc6..9d24b9d0f5 100644 --- a/tests/cputest.c +++ b/tests/cputest.c @@ -823,9 +823,8 @@ cpuTestUpdateLive(const void *arg) usable = hvModel->usable; } - if (virDomainCapsCPUModelsAdd(models, expected->model, - usable, blockers, false) < 0) - return -1; + virDomainCapsCPUModelsAdd(models, expected->model, + usable, blockers, false); cpu->fallback = VIR_CPU_FALLBACK_ALLOW; ignore_value(virCPUTranslate(data->arch, cpu, models)); @@ -902,16 +901,11 @@ cpuTestInitModels(const char **list) return NULL; for (model = list; *model; model++) { - if (virDomainCapsCPUModelsAdd(cpus, *model, - VIR_DOMCAPS_CPU_USABLE_UNKNOWN, NULL, false) < 0) - goto error; + virDomainCapsCPUModelsAdd(cpus, *model, + VIR_DOMCAPS_CPU_USABLE_UNKNOWN, NULL, false); } return cpus; - - error: - virObjectUnref(cpus); - return NULL; } -- 2.38.0

The ppc64 CPU code still has to load and parse the CPU map everytime it needs to look at it, which can make some operations pretty slow. Other archs already switched to loading the CPU map once and keeping the parsed structure in memory. Let's switch ppc64 as well. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com> --- Notes: Version 2: - no change src/cpu/cpu_ppc64.c | 47 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/src/cpu/cpu_ppc64.c b/src/cpu/cpu_ppc64.c index cd2df4ba4a..9997e14a89 100644 --- a/src/cpu/cpu_ppc64.c +++ b/src/cpu/cpu_ppc64.c @@ -53,6 +53,12 @@ struct _ppc64_map { struct _ppc64_model **models; }; +static virCPUppc64Map *cpuMap; + +int virCPUppc64DriverOnceInit(void); +VIR_ONCE_GLOBAL_INIT(virCPUppc64Driver); + + /* Convert a legacy CPU definition by transforming * model names to generation names: * POWER7_v2.1 => POWER7 @@ -365,8 +371,8 @@ ppc64ModelParse(xmlXPathContextPtr ctxt, } -static struct _ppc64_map * -ppc64LoadMap(void) +static virCPUppc64Map * +virCPUppc64LoadMap(void) { g_autoptr(virCPUppc64Map) map = NULL; @@ -378,12 +384,33 @@ ppc64LoadMap(void) return g_steal_pointer(&map); } + +int +virCPUppc64DriverOnceInit(void) +{ + if (!(cpuMap = virCPUppc64LoadMap())) + return -1; + + return 0; +} + + +static virCPUppc64Map * +virCPUppc64GetMap(void) +{ + if (virCPUppc64DriverInitialize() < 0) + return NULL; + + return cpuMap; +} + + static virCPUCompareResult ppc64Compute(virCPUDef *host, const virCPUDef *other, char **message) { - g_autoptr(virCPUppc64Map) map = NULL; + virCPUppc64Map *map = NULL; g_autoptr(virCPUppc64Model) host_model = NULL; g_autoptr(virCPUppc64Model) guest_model = NULL; g_autoptr(virCPUDef) cpu = NULL; @@ -428,7 +455,7 @@ ppc64Compute(virCPUDef *host, return VIR_CPU_COMPARE_INCOMPATIBLE; } - if (!(map = ppc64LoadMap())) + if (!(map = virCPUppc64GetMap())) return VIR_CPU_COMPARE_ERROR; /* Host CPU information */ @@ -526,10 +553,10 @@ ppc64DriverDecode(virCPUDef *cpu, const virCPUData *data, virDomainCapsCPUModels *models) { - g_autoptr(virCPUppc64Map) map = NULL; + virCPUppc64Map *map = NULL; const virCPUppc64Model *model; - if (!data || !(map = ppc64LoadMap())) + if (!data || !(map = virCPUppc64GetMap())) return -1; if (!(model = ppc64ModelFindPVR(map, data->data.ppc64.pvr[0].value))) { @@ -656,13 +683,13 @@ virCPUppc64Baseline(virCPUDef **cpus, const char **features G_GNUC_UNUSED, bool migratable G_GNUC_UNUSED) { - g_autoptr(virCPUppc64Map) map = NULL; + virCPUppc64Map *map = NULL; const virCPUppc64Model *model; const virCPUppc64Vendor *vendor = NULL; g_autoptr(virCPUDef) cpu = NULL; size_t i; - if (!(map = ppc64LoadMap())) + if (!(map = virCPUppc64GetMap())) return NULL; if (!(model = ppc64ModelFind(map, cpus[0]->model))) { @@ -737,10 +764,10 @@ virCPUppc64Baseline(virCPUDef **cpus, static int virCPUppc64DriverGetModels(char ***models) { - g_autoptr(virCPUppc64Map) map = NULL; + virCPUppc64Map *map = NULL; size_t i; - if (!(map = ppc64LoadMap())) + if (!(map = virCPUppc64GetMap())) return -1; if (models) { -- 2.38.0

The only part of qemuCaps both functions are interested in is the CPU architecture. Changing them to expect just virArch makes the functions more reusable. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com> --- Notes: Version 2: - no change src/qemu/qemu_capabilities.c | 18 +++++++++--------- src/qemu/qemu_capabilities.h | 4 ++-- src/qemu/qemu_command.c | 2 +- src/qemu/qemu_monitor.c | 7 +++---- src/qemu/qemu_monitor.h | 5 ++--- src/qemu/qemu_monitor_json.c | 11 ++++------- src/qemu/qemu_monitor_json.h | 1 - src/qemu/qemu_process.c | 12 +----------- 8 files changed, 22 insertions(+), 38 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index c12e6dac69..f366e6797c 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -3108,7 +3108,7 @@ virQEMUCapsGetCPUFeatures(virQEMUCaps *qemuCaps, if (migratable && prop->migratable == VIR_TRISTATE_BOOL_NO) continue; - list[n++] = g_strdup(virQEMUCapsCPUFeatureFromQEMU(qemuCaps, prop->name)); + list[n++] = g_strdup(virQEMUCapsCPUFeatureFromQEMU(qemuCaps->arch, prop->name)); } *features = g_steal_pointer(&list); @@ -3434,14 +3434,14 @@ virQEMUCapsCPUFeatureTranslationTable virQEMUCapsCPUFeaturesX86[] = { static const char * -virQEMUCapsCPUFeatureTranslate(virQEMUCaps *qemuCaps, +virQEMUCapsCPUFeatureTranslate(virArch arch, const char *feature, bool reversed) { virQEMUCapsCPUFeatureTranslationTable *table = NULL; virQEMUCapsCPUFeatureTranslationTable *entry; - if (ARCH_IS_X86(qemuCaps->arch)) + if (ARCH_IS_X86(arch)) table = virQEMUCapsCPUFeaturesX86; if (!table || @@ -3460,18 +3460,18 @@ virQEMUCapsCPUFeatureTranslate(virQEMUCaps *qemuCaps, const char * -virQEMUCapsCPUFeatureToQEMU(virQEMUCaps *qemuCaps, +virQEMUCapsCPUFeatureToQEMU(virArch arch, const char *feature) { - return virQEMUCapsCPUFeatureTranslate(qemuCaps, feature, false); + return virQEMUCapsCPUFeatureTranslate(arch, feature, false); } const char * -virQEMUCapsCPUFeatureFromQEMU(virQEMUCaps *qemuCaps, +virQEMUCapsCPUFeatureFromQEMU(virArch arch, const char *feature) { - return virQEMUCapsCPUFeatureTranslate(qemuCaps, feature, true); + return virQEMUCapsCPUFeatureTranslate(arch, feature, true); } @@ -3510,7 +3510,7 @@ virQEMUCapsInitCPUModelS390(virQEMUCaps *qemuCaps, for (i = 0; i < modelInfo->nprops; i++) { virCPUFeatureDef *feature = cpu->features + cpu->nfeatures; qemuMonitorCPUProperty *prop = modelInfo->props + i; - const char *name = virQEMUCapsCPUFeatureFromQEMU(qemuCaps, prop->name); + const char *name = virQEMUCapsCPUFeatureFromQEMU(qemuCaps->arch, prop->name); if (prop->type != QEMU_MONITOR_CPU_PROPERTY_BOOLEAN) continue; @@ -3545,7 +3545,7 @@ virQEMUCapsGetCPUModelX86Data(virQEMUCaps *qemuCaps, for (i = 0; i < model->nprops; i++) { qemuMonitorCPUProperty *prop = model->props + i; - const char *name = virQEMUCapsCPUFeatureFromQEMU(qemuCaps, prop->name); + const char *name = virQEMUCapsCPUFeatureFromQEMU(qemuCaps->arch, prop->name); switch (prop->type) { case QEMU_MONITOR_CPU_PROPERTY_BOOLEAN: diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index ca919ff368..904ee54f60 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -838,11 +838,11 @@ bool virQEMUCapsCPUFilterFeatures(const char *name, void *opaque); const char * -virQEMUCapsCPUFeatureToQEMU(virQEMUCaps *qemuCaps, +virQEMUCapsCPUFeatureToQEMU(virArch arch, const char *feature); const char * -virQEMUCapsCPUFeatureFromQEMU(virQEMUCaps *qemuCaps, +virQEMUCapsCPUFeatureFromQEMU(virArch arch, const char *feature); virSEVCapability * diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 7ec44736d3..150824f2e1 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6111,7 +6111,7 @@ qemuBuildCpuModelArgStr(virQEMUDriver *driver, for (i = 0; i < cpu->nfeatures; i++) { const char *featname = - virQEMUCapsCPUFeatureToQEMU(qemuCaps, cpu->features[i].name); + virQEMUCapsCPUFeatureToQEMU(def->os.arch, cpu->features[i].name); switch ((virCPUFeaturePolicy) cpu->features[i].policy) { case VIR_CPU_FEATURE_FORCE: case VIR_CPU_FEATURE_REQUIRE: diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index c2808c75a3..5eba154d96 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -3633,12 +3633,11 @@ qemuMonitorGetGuestCPU(qemuMonitor *mon, virArch arch, const char *cpuQOMPath, qemuMonitorCPUFeatureTranslationCallback translate, - void *opaque, virCPUData **enabled, virCPUData **disabled) { - VIR_DEBUG("arch=%s cpuQOMPath=%s translate=%p opaque=%p enabled=%p disabled=%p", - virArchToString(arch), cpuQOMPath, translate, opaque, enabled, disabled); + VIR_DEBUG("arch=%s cpuQOMPath=%s translate=%p enabled=%p disabled=%p", + virArchToString(arch), cpuQOMPath, translate, enabled, disabled); QEMU_CHECK_MONITOR(mon); @@ -3646,7 +3645,7 @@ qemuMonitorGetGuestCPU(qemuMonitor *mon, if (disabled) *disabled = NULL; - return qemuMonitorJSONGetGuestCPU(mon, arch, cpuQOMPath, translate, opaque, + return qemuMonitorJSONGetGuestCPU(mon, arch, cpuQOMPath, translate, enabled, disabled); } diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 4d770486be..4fead0a998 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1219,14 +1219,13 @@ int qemuMonitorGetGuestCPUx86(qemuMonitor *mon, virCPUData **data, virCPUData **disabled); -typedef const char *(*qemuMonitorCPUFeatureTranslationCallback)(const char *name, - void *opaque); +typedef const char *(*qemuMonitorCPUFeatureTranslationCallback)(virArch arch, + const char *name); int qemuMonitorGetGuestCPU(qemuMonitor *mon, virArch arch, const char *cpuQOMPath, qemuMonitorCPUFeatureTranslationCallback translate, - void *opaque, virCPUData **enabled, virCPUData **disabled); diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index b63400354b..f54b4609a9 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -6781,7 +6781,6 @@ static int qemuMonitorJSONGetCPUData(qemuMonitor *mon, const char *cpuQOMPath, qemuMonitorCPUFeatureTranslationCallback translate, - void *opaque, virCPUData *data) { qemuMonitorJSONObjectProperty prop = { .type = QEMU_MONITOR_OBJECT_PROPERTY_BOOLEAN }; @@ -6801,7 +6800,7 @@ qemuMonitorJSONGetCPUData(qemuMonitor *mon, continue; if (translate) - name = translate(name, opaque); + name = translate(data->arch, name); if (virCPUDataAddFeature(data, name) < 0) return -1; @@ -6815,7 +6814,6 @@ static int qemuMonitorJSONGetCPUDataDisabled(qemuMonitor *mon, const char *cpuQOMPath, qemuMonitorCPUFeatureTranslationCallback translate, - void *opaque, virCPUData *data) { g_auto(GStrv) props = NULL; @@ -6829,7 +6827,7 @@ qemuMonitorJSONGetCPUDataDisabled(qemuMonitor *mon, const char *name = *p; if (translate) - name = translate(name, opaque); + name = translate(data->arch, name); if (virCPUDataAddFeature(data, name) < 0) return -1; @@ -6859,7 +6857,6 @@ qemuMonitorJSONGetGuestCPU(qemuMonitor *mon, virArch arch, const char *cpuQOMPath, qemuMonitorCPUFeatureTranslationCallback translate, - void *opaque, virCPUData **enabled, virCPUData **disabled) { @@ -6870,11 +6867,11 @@ qemuMonitorJSONGetGuestCPU(qemuMonitor *mon, !(cpuDisabled = virCPUDataNew(arch))) return -1; - if (qemuMonitorJSONGetCPUData(mon, cpuQOMPath, translate, opaque, cpuEnabled) < 0) + if (qemuMonitorJSONGetCPUData(mon, cpuQOMPath, translate, cpuEnabled) < 0) return -1; if (disabled && - qemuMonitorJSONGetCPUDataDisabled(mon, cpuQOMPath, translate, opaque, cpuDisabled) < 0) + qemuMonitorJSONGetCPUDataDisabled(mon, cpuQOMPath, translate, cpuDisabled) < 0) return -1; *enabled = g_steal_pointer(&cpuEnabled); diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index a53e6423df..f14d0b5bae 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -605,7 +605,6 @@ qemuMonitorJSONGetGuestCPU(qemuMonitor *mon, virArch arch, const char *cpuQOMPath, qemuMonitorCPUFeatureTranslationCallback translate, - void *opaque, virCPUData **enabled, virCPUData **disabled); diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index cec4a64526..d78e91efed 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -4295,16 +4295,6 @@ qemuProcessVerifyCPUFeatures(virDomainDef *def, } -static const char * -qemuProcessTranslateCPUFeatures(const char *name, - void *opaque) -{ - virQEMUCaps *qemuCaps = opaque; - - return virQEMUCapsCPUFeatureFromQEMU(qemuCaps, name); -} - - /* returns the QOM path to the first vcpu */ static const char * qemuProcessGetVCPUQOMPath(virDomainObj *vm) @@ -4349,7 +4339,7 @@ qemuProcessFetchGuestCPU(virDomainObj *vm, rc = qemuMonitorGetGuestCPU(priv->mon, vm->def->os.arch, cpuQOMPath, - qemuProcessTranslateCPUFeatures, priv->qemuCaps, + virQEMUCapsCPUFeatureFromQEMU, &dataEnabled, &dataDisabled); } else { rc = qemuMonitorGetGuestCPUx86(priv->mon, cpuQOMPath, &dataEnabled, &dataDisabled); -- 2.38.0

Even though several CPU models from various vendors are reported as usable on a given host, user may still want to use only those that match the host vendor. Currently the only place where users can check the vendor of each CPU model is our CPU map, which is considered internal and users should not really be using it directly. So to allow for such filtering we now advertise the vendor of each CPU model in domain capabilities. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com> --- Notes: Version 2: - no change docs/formatdomaincaps.rst | 12 +- src/conf/domain_capabilities.c | 13 +- src/conf/domain_capabilities.h | 4 +- src/conf/schemas/domaincaps.rng | 3 + src/qemu/qemu_capabilities.c | 2 +- tests/cputest.c | 5 +- .../domaincapsdata/qemu_4.2.0-q35.x86_64.xml | 104 ++++++------ .../domaincapsdata/qemu_4.2.0-tcg.x86_64.xml | 104 ++++++------ .../qemu_4.2.0-virt.aarch64.xml | 72 ++++----- tests/domaincapsdata/qemu_4.2.0.aarch64.xml | 72 ++++----- tests/domaincapsdata/qemu_4.2.0.ppc64.xml | 6 +- tests/domaincapsdata/qemu_4.2.0.s390x.xml | 148 +++++++++--------- tests/domaincapsdata/qemu_4.2.0.x86_64.xml | 104 ++++++------ .../domaincapsdata/qemu_5.0.0-q35.x86_64.xml | 108 ++++++------- .../domaincapsdata/qemu_5.0.0-tcg.x86_64.xml | 108 ++++++------- .../qemu_5.0.0-virt.aarch64.xml | 74 ++++----- tests/domaincapsdata/qemu_5.0.0.aarch64.xml | 74 ++++----- tests/domaincapsdata/qemu_5.0.0.ppc64.xml | 8 +- tests/domaincapsdata/qemu_5.0.0.x86_64.xml | 108 ++++++------- .../domaincapsdata/qemu_5.1.0-q35.x86_64.xml | 108 ++++++------- .../domaincapsdata/qemu_5.1.0-tcg.x86_64.xml | 108 ++++++------- tests/domaincapsdata/qemu_5.1.0.x86_64.xml | 108 ++++++------- .../domaincapsdata/qemu_5.2.0-q35.x86_64.xml | 108 ++++++------- .../domaincapsdata/qemu_5.2.0-tcg.x86_64.xml | 108 ++++++------- .../qemu_5.2.0-virt.aarch64.xml | 74 ++++----- tests/domaincapsdata/qemu_5.2.0.aarch64.xml | 74 ++++----- tests/domaincapsdata/qemu_5.2.0.ppc64.xml | 8 +- tests/domaincapsdata/qemu_5.2.0.s390x.xml | 148 +++++++++--------- tests/domaincapsdata/qemu_5.2.0.x86_64.xml | 108 ++++++------- .../domaincapsdata/qemu_6.0.0-q35.x86_64.xml | 110 ++++++------- .../domaincapsdata/qemu_6.0.0-tcg.x86_64.xml | 110 ++++++------- .../qemu_6.0.0-virt.aarch64.xml | 76 ++++----- tests/domaincapsdata/qemu_6.0.0.aarch64.xml | 76 ++++----- tests/domaincapsdata/qemu_6.0.0.s390x.xml | 148 +++++++++--------- tests/domaincapsdata/qemu_6.0.0.x86_64.xml | 110 ++++++------- .../domaincapsdata/qemu_6.1.0-q35.x86_64.xml | 110 ++++++------- .../domaincapsdata/qemu_6.1.0-tcg.x86_64.xml | 110 ++++++------- tests/domaincapsdata/qemu_6.1.0.x86_64.xml | 110 ++++++------- .../domaincapsdata/qemu_6.2.0-q35.x86_64.xml | 110 ++++++------- .../domaincapsdata/qemu_6.2.0-tcg.x86_64.xml | 110 ++++++------- .../qemu_6.2.0-virt.aarch64.xml | 78 ++++----- tests/domaincapsdata/qemu_6.2.0.aarch64.xml | 78 ++++----- tests/domaincapsdata/qemu_6.2.0.ppc64.xml | 8 +- tests/domaincapsdata/qemu_6.2.0.x86_64.xml | 110 ++++++------- .../domaincapsdata/qemu_7.0.0-q35.x86_64.xml | 110 ++++++------- .../domaincapsdata/qemu_7.0.0-tcg.x86_64.xml | 110 ++++++------- .../qemu_7.0.0-virt.aarch64.xml | 78 ++++----- tests/domaincapsdata/qemu_7.0.0.aarch64.xml | 78 ++++----- tests/domaincapsdata/qemu_7.0.0.ppc64.xml | 8 +- tests/domaincapsdata/qemu_7.0.0.x86_64.xml | 110 ++++++------- .../domaincapsdata/qemu_7.1.0-q35.x86_64.xml | 106 ++++++------- .../domaincapsdata/qemu_7.1.0-tcg.x86_64.xml | 106 ++++++------- tests/domaincapsdata/qemu_7.1.0.x86_64.xml | 106 ++++++------- 53 files changed, 2183 insertions(+), 2164 deletions(-) diff --git a/docs/formatdomaincaps.rst b/docs/formatdomaincaps.rst index 70f46b972a..6ce780fb69 100644 --- a/docs/formatdomaincaps.rst +++ b/docs/formatdomaincaps.rst @@ -191,9 +191,10 @@ CPUs <formatdomain.html#cpu-model-and-topology>`__. <feature policy='require' name='vmx'/> </mode> <mode name='custom' supported='yes'> - <model usable='no' deprecated='no'>Broadwell</model> - <model usable='yes' deprecated='no'>Broadwell-noTSX</model> - <model usable='no' deprecated='yes'>Haswell</model> + <model usable='no' deprecated='no' vendor='Intel'>Broadwell</model> + <model usable='yes' deprecated='no' vendor='Intel'>Broadwell-noTSX</model> + <model usable='no' deprecated='yes' vendor='Intel'>Haswell</model> + <model usable='no' deprecated='no' vendor='AMD'>EPYC-Milan</model> ... </mode> </cpu> @@ -226,7 +227,10 @@ more details about it: CPU of such model is expected to have. A special value ``unknown`` indicates libvirt does not have enough information to provide the usability data. The ``deprecated`` attribute reflects the hypervisor's policy on usage of this - model :since:`(since 7.1.0)` . + model :since:`(since 7.1.0)`. The ``vendor`` attribute :since:`(since 8.9.0)` + contains the vendor of the CPU model for users who want to use CPU models + with specific vendors only. CPU models with undefined vendor will be listed + with ``vendor='unkwnown'``. I/O Threads ~~~~~~~~~~~ diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c index 123c80a560..b5d8288982 100644 --- a/src/conf/domain_capabilities.c +++ b/src/conf/domain_capabilities.c @@ -105,6 +105,7 @@ virDomainCapsCPUModelsDispose(void *obj) for (i = 0; i < cpuModels->nmodels; i++) { g_free(cpuModels->models[i].name); g_strfreev(cpuModels->models[i].blockers); + g_free(cpuModels->models[i].vendor); } g_free(cpuModels->models); @@ -166,7 +167,8 @@ virDomainCapsCPUModelsCopy(virDomainCapsCPUModels *old) old->models[i].name, old->models[i].usable, old->models[i].blockers, - old->models[i].deprecated); + old->models[i].deprecated, + old->models[i].vendor); } return cpuModels; @@ -178,7 +180,8 @@ virDomainCapsCPUModelsAdd(virDomainCapsCPUModels *cpuModels, const char *name, virDomainCapsCPUUsable usable, char **blockers, - bool deprecated) + bool deprecated, + const char *vendor) { virDomainCapsCPUModel *cpu; @@ -192,6 +195,7 @@ virDomainCapsCPUModelsAdd(virDomainCapsCPUModels *cpuModels, cpu->name = g_strdup(name); cpu->blockers = g_strdupv(blockers); cpu->deprecated = deprecated; + cpu->vendor = g_strdup(vendor); } @@ -377,6 +381,11 @@ virDomainCapsCPUCustomFormat(virBuffer *buf, if (model->deprecated) virBufferAddLit(buf, " deprecated='yes'"); + if (model->vendor) + virBufferAsprintf(buf, " vendor='%s'", model->vendor); + else + virBufferAddLit(buf, " vendor='unknown'"); + virBufferAsprintf(buf, ">%s</model>\n", model->name); } diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h index 7333276231..f5fa1fb8e3 100644 --- a/src/conf/domain_capabilities.h +++ b/src/conf/domain_capabilities.h @@ -159,6 +159,7 @@ struct _virDomainCapsCPUModel { virDomainCapsCPUUsable usable; char **blockers; /* NULL-terminated list of usability blockers */ bool deprecated; + char *vendor; }; typedef struct _virDomainCapsCPUModels virDomainCapsCPUModels; @@ -249,7 +250,8 @@ virDomainCapsCPUModelsAdd(virDomainCapsCPUModels *cpuModels, const char *name, virDomainCapsCPUUsable usable, char **blockers, - bool deprecated); + bool deprecated, + const char *vendor); virDomainCapsCPUModel * virDomainCapsCPUModelsGet(virDomainCapsCPUModels *cpuModels, const char *name); diff --git a/src/conf/schemas/domaincaps.rng b/src/conf/schemas/domaincaps.rng index 9cbc2467ab..c4cb9afeba 100644 --- a/src/conf/schemas/domaincaps.rng +++ b/src/conf/schemas/domaincaps.rng @@ -159,6 +159,9 @@ <ref name="virYesNo"/> </attribute> </optional> + <attribute name='vendor'> + <text/> + </attribute> <text/> </element> </zeroOrMore> diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index f366e6797c..5af5de8fc5 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -2195,7 +2195,7 @@ virQEMUCapsCPUDefsToModels(qemuMonitorCPUDefs *defs, continue; virDomainCapsCPUModelsAdd(cpuModels, cpu->name, cpu->usable, - cpu->blockers, cpu->deprecated); + cpu->blockers, cpu->deprecated, NULL); } return cpuModels; diff --git a/tests/cputest.c b/tests/cputest.c index 9d24b9d0f5..52e0022ac3 100644 --- a/tests/cputest.c +++ b/tests/cputest.c @@ -824,7 +824,7 @@ cpuTestUpdateLive(const void *arg) } virDomainCapsCPUModelsAdd(models, expected->model, - usable, blockers, false); + usable, blockers, false, expected->vendor); cpu->fallback = VIR_CPU_FALLBACK_ALLOW; ignore_value(virCPUTranslate(data->arch, cpu, models)); @@ -902,7 +902,8 @@ cpuTestInitModels(const char **list) for (model = list; *model; model++) { virDomainCapsCPUModelsAdd(cpus, *model, - VIR_DOMCAPS_CPU_USABLE_UNKNOWN, NULL, false); + VIR_DOMCAPS_CPU_USABLE_UNKNOWN, + NULL, false, NULL); } return cpus; diff --git a/tests/domaincapsdata/qemu_4.2.0-q35.x86_64.xml b/tests/domaincapsdata/qemu_4.2.0-q35.x86_64.xml index 0ec4c570ac..fa86554892 100644 --- a/tests/domaincapsdata/qemu_4.2.0-q35.x86_64.xml +++ b/tests/domaincapsdata/qemu_4.2.0-q35.x86_64.xml @@ -61,58 +61,58 @@ <feature policy='require' name='pschange-mc-no'/> </mode> <mode name='custom' supported='yes'> - <model usable='yes'>qemu64</model> - <model usable='yes'>qemu32</model> - <model usable='no'>phenom</model> - <model usable='yes'>pentium3</model> - <model usable='yes'>pentium2</model> - <model usable='yes'>pentium</model> - <model usable='yes'>n270</model> - <model usable='yes'>kvm64</model> - <model usable='yes'>kvm32</model> - <model usable='yes'>coreduo</model> - <model usable='yes'>core2duo</model> - <model usable='no'>athlon</model> - <model usable='yes'>Westmere-IBRS</model> - <model usable='yes'>Westmere</model> - <model usable='no'>Snowridge</model> - <model usable='no'>Skylake-Server-noTSX-IBRS</model> - <model usable='no'>Skylake-Server-IBRS</model> - <model usable='no'>Skylake-Server</model> - <model usable='yes'>Skylake-Client-noTSX-IBRS</model> - <model usable='yes'>Skylake-Client-IBRS</model> - <model usable='yes'>Skylake-Client</model> - <model usable='yes'>SandyBridge-IBRS</model> - <model usable='yes'>SandyBridge</model> - <model usable='yes'>Penryn</model> - <model usable='no'>Opteron_G5</model> - <model usable='no'>Opteron_G4</model> - <model usable='no'>Opteron_G3</model> - <model usable='yes'>Opteron_G2</model> - <model usable='yes'>Opteron_G1</model> - <model usable='yes'>Nehalem-IBRS</model> - <model usable='yes'>Nehalem</model> - <model usable='yes'>IvyBridge-IBRS</model> - <model usable='yes'>IvyBridge</model> - <model usable='no'>Icelake-Server-noTSX</model> - <model usable='no'>Icelake-Server</model> - <model usable='no'>Icelake-Client-noTSX</model> - <model usable='no'>Icelake-Client</model> - <model usable='yes'>Haswell-noTSX-IBRS</model> - <model usable='yes'>Haswell-noTSX</model> - <model usable='yes'>Haswell-IBRS</model> - <model usable='yes'>Haswell</model> - <model usable='no'>EPYC-IBPB</model> - <model usable='no'>EPYC</model> - <model usable='no'>Dhyana</model> - <model usable='yes'>Conroe</model> - <model usable='no'>Cascadelake-Server-noTSX</model> - <model usable='no'>Cascadelake-Server</model> - <model usable='yes'>Broadwell-noTSX-IBRS</model> - <model usable='yes'>Broadwell-noTSX</model> - <model usable='yes'>Broadwell-IBRS</model> - <model usable='yes'>Broadwell</model> - <model usable='yes'>486</model> + <model usable='yes' vendor='unknown'>qemu64</model> + <model usable='yes' vendor='unknown'>qemu32</model> + <model usable='no' vendor='unknown'>phenom</model> + <model usable='yes' vendor='unknown'>pentium3</model> + <model usable='yes' vendor='unknown'>pentium2</model> + <model usable='yes' vendor='unknown'>pentium</model> + <model usable='yes' vendor='unknown'>n270</model> + <model usable='yes' vendor='unknown'>kvm64</model> + <model usable='yes' vendor='unknown'>kvm32</model> + <model usable='yes' vendor='unknown'>coreduo</model> + <model usable='yes' vendor='unknown'>core2duo</model> + <model usable='no' vendor='unknown'>athlon</model> + <model usable='yes' vendor='unknown'>Westmere-IBRS</model> + <model usable='yes' vendor='unknown'>Westmere</model> + <model usable='no' vendor='unknown'>Snowridge</model> + <model usable='no' vendor='unknown'>Skylake-Server-noTSX-IBRS</model> + <model usable='no' vendor='unknown'>Skylake-Server-IBRS</model> + <model usable='no' vendor='unknown'>Skylake-Server</model> + <model usable='yes' vendor='unknown'>Skylake-Client-noTSX-IBRS</model> + <model usable='yes' vendor='unknown'>Skylake-Client-IBRS</model> + <model usable='yes' vendor='unknown'>Skylake-Client</model> + <model usable='yes' vendor='unknown'>SandyBridge-IBRS</model> + <model usable='yes' vendor='unknown'>SandyBridge</model> + <model usable='yes' vendor='unknown'>Penryn</model> + <model usable='no' vendor='unknown'>Opteron_G5</model> + <model usable='no' vendor='unknown'>Opteron_G4</model> + <model usable='no' vendor='unknown'>Opteron_G3</model> + <model usable='yes' vendor='unknown'>Opteron_G2</model> + <model usable='yes' vendor='unknown'>Opteron_G1</model> + <model usable='yes' vendor='unknown'>Nehalem-IBRS</model> + <model usable='yes' vendor='unknown'>Nehalem</model> + <model usable='yes' vendor='unknown'>IvyBridge-IBRS</model> + <model usable='yes' vendor='unknown'>IvyBridge</model> + <model usable='no' vendor='unknown'>Icelake-Server-noTSX</model> + <model usable='no' vendor='unknown'>Icelake-Server</model> + <model usable='no' vendor='unknown'>Icelake-Client-noTSX</model> + <model usable='no' vendor='unknown'>Icelake-Client</model> + <model usable='yes' vendor='unknown'>Haswell-noTSX-IBRS</model> + <model usable='yes' vendor='unknown'>Haswell-noTSX</model> + <model usable='yes' vendor='unknown'>Haswell-IBRS</model> + <model usable='yes' vendor='unknown'>Haswell</model> + <model usable='no' vendor='unknown'>EPYC-IBPB</model> + <model usable='no' vendor='unknown'>EPYC</model> + <model usable='no' vendor='unknown'>Dhyana</model> + <model usable='yes' vendor='unknown'>Conroe</model> + <model usable='no' vendor='unknown'>Cascadelake-Server-noTSX</model> + <model usable='no' vendor='unknown'>Cascadelake-Server</model> + <model usable='yes' vendor='unknown'>Broadwell-noTSX-IBRS</model> + <model usable='yes' vendor='unknown'>Broadwell-noTSX</model> + <model usable='yes' vendor='unknown'>Broadwell-IBRS</model> + <model usable='yes' vendor='unknown'>Broadwell</model> + <model usable='yes' vendor='unknown'>486</model> </mode> </cpu> <memoryBacking supported='yes'> ... -- 2.38.0

So far QEMU driver does not get CPU model vendor from QEMU directly and it has to ask the CPU driver for the info stored in CPU map. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com> --- Notes: Version 2: - no change src/cpu/cpu.c | 25 +++++++++++++++++++++++++ src/cpu/cpu.h | 8 ++++++++ src/libvirt_private.syms | 1 + src/qemu/qemu_capabilities.c | 18 +++++++++++++----- 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index d97ef5e873..7f3caf7a27 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -923,6 +923,31 @@ virCPUGetModels(virArch arch, char ***models) } +/** virCPUGetVendorForModel: + * + * @arch: CPU architecture + * @model: CPU model to be checked + * + * Returns @model's vendor or NULL if the vendor is unknown. + */ +const char * +virCPUGetVendorForModel(virArch arch, + const char *model) +{ + struct cpuArchDriver *driver; + + VIR_DEBUG("arch=%s", virArchToString(arch)); + + if (!(driver = cpuGetSubDriver(arch))) + return NULL; + + if (!driver->getVendorForModel) + return NULL; + + return driver->getVendorForModel(model); +} + + /** * virCPUTranslate: * diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 41a62ce486..a4cdb37f03 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -105,6 +105,9 @@ typedef virCPUData * typedef int (*virCPUArchGetModels)(char ***models); +typedef const char * +(*virCPUArchGetVendorForModel)(const char *model); + typedef int (*virCPUArchTranslate)(virCPUDef *cpu, virDomainCapsCPUModels *models); @@ -150,6 +153,7 @@ struct cpuArchDriver { virCPUArchDataFormat dataFormat; virCPUArchDataParse dataParse; virCPUArchGetModels getModels; + virCPUArchGetVendorForModel getVendorForModel; virCPUArchTranslate translate; virCPUArchConvertLegacy convertLegacy; virCPUArchExpandFeatures expandFeatures; @@ -262,6 +266,10 @@ virCPUModelIsAllowed(const char *model, int virCPUGetModels(virArch arch, char ***models); +const char * +virCPUGetVendorForModel(virArch arch, + const char *model); + int virCPUTranslate(virArch arch, virCPUDef *cpu, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 00cb07709d..9cf5c0de7c 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1500,6 +1500,7 @@ virCPUExpandFeatures; virCPUGetHost; virCPUGetHostIsSupported; virCPUGetModels; +virCPUGetVendorForModel; virCPUProbeHost; virCPUTranslate; virCPUUpdate; diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 5af5de8fc5..ccd274b80d 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -2175,9 +2175,11 @@ virQEMUCapsAddCPUDefinitions(virQEMUCaps *qemuCaps, static virDomainCapsCPUModels * -virQEMUCapsCPUDefsToModels(qemuMonitorCPUDefs *defs, +virQEMUCapsCPUDefsToModels(virArch arch, + qemuMonitorCPUDefs *defs, const char **modelAllowed, - const char **modelForbidden) + const char **modelForbidden, + bool vendors) { virDomainCapsCPUModels *cpuModels = NULL; size_t i; @@ -2187,6 +2189,7 @@ virQEMUCapsCPUDefsToModels(qemuMonitorCPUDefs *defs, for (i = 0; i < defs->ncpus; i++) { qemuMonitorCPUDefInfo *cpu = defs->cpus + i; + char *vendor = NULL; if (modelAllowed && !g_strv_contains(modelAllowed, cpu->name)) continue; @@ -2194,8 +2197,11 @@ virQEMUCapsCPUDefsToModels(qemuMonitorCPUDefs *defs, if (modelForbidden && g_strv_contains(modelForbidden, cpu->name)) continue; + if (vendors) + vendor = g_strdup(virCPUGetVendorForModel(arch, cpu->name)); + virDomainCapsCPUModelsAdd(cpuModels, cpu->name, cpu->usable, - cpu->blockers, cpu->deprecated, NULL); + cpu->blockers, cpu->deprecated, vendor); } return cpuModels; @@ -2213,7 +2219,8 @@ virQEMUCapsGetCPUModels(virQEMUCaps *qemuCaps, if (!(defs = virQEMUCapsGetAccel(qemuCaps, type)->cpuModels)) return NULL; - return virQEMUCapsCPUDefsToModels(defs, modelAllowed, modelForbidden); + return virQEMUCapsCPUDefsToModels(qemuCaps->arch, defs, + modelAllowed, modelForbidden, true); } @@ -2946,7 +2953,8 @@ virQEMUCapsFetchCPUModels(qemuMonitor *mon, if (virQEMUCapsFetchCPUDefinitions(mon, arch, &defs) < 0) return -1; - if (defs && !(*cpuModels = virQEMUCapsCPUDefsToModels(defs, NULL, NULL))) + if (defs && + !(*cpuModels = virQEMUCapsCPUDefsToModels(arch, defs, NULL, NULL, false))) return -1; return 0; -- 2.38.0

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com> --- Notes: Version 2: - no change src/cpu/cpu_x86.c | 19 ++++ .../domaincapsdata/qemu_4.2.0-q35.x86_64.xml | 88 ++++++++--------- .../domaincapsdata/qemu_4.2.0-tcg.x86_64.xml | 88 ++++++++--------- tests/domaincapsdata/qemu_4.2.0.x86_64.xml | 88 ++++++++--------- .../domaincapsdata/qemu_5.0.0-q35.x86_64.xml | 92 +++++++++--------- .../domaincapsdata/qemu_5.0.0-tcg.x86_64.xml | 92 +++++++++--------- tests/domaincapsdata/qemu_5.0.0.x86_64.xml | 92 +++++++++--------- .../domaincapsdata/qemu_5.1.0-q35.x86_64.xml | 92 +++++++++--------- .../domaincapsdata/qemu_5.1.0-tcg.x86_64.xml | 92 +++++++++--------- tests/domaincapsdata/qemu_5.1.0.x86_64.xml | 92 +++++++++--------- .../domaincapsdata/qemu_5.2.0-q35.x86_64.xml | 92 +++++++++--------- .../domaincapsdata/qemu_5.2.0-tcg.x86_64.xml | 92 +++++++++--------- tests/domaincapsdata/qemu_5.2.0.x86_64.xml | 92 +++++++++--------- .../domaincapsdata/qemu_6.0.0-q35.x86_64.xml | 94 +++++++++---------- .../domaincapsdata/qemu_6.0.0-tcg.x86_64.xml | 94 +++++++++---------- tests/domaincapsdata/qemu_6.0.0.x86_64.xml | 94 +++++++++---------- .../domaincapsdata/qemu_6.1.0-q35.x86_64.xml | 94 +++++++++---------- .../domaincapsdata/qemu_6.1.0-tcg.x86_64.xml | 94 +++++++++---------- tests/domaincapsdata/qemu_6.1.0.x86_64.xml | 94 +++++++++---------- .../domaincapsdata/qemu_6.2.0-q35.x86_64.xml | 94 +++++++++---------- .../domaincapsdata/qemu_6.2.0-tcg.x86_64.xml | 94 +++++++++---------- tests/domaincapsdata/qemu_6.2.0.x86_64.xml | 94 +++++++++---------- .../domaincapsdata/qemu_7.0.0-q35.x86_64.xml | 94 +++++++++---------- .../domaincapsdata/qemu_7.0.0-tcg.x86_64.xml | 94 +++++++++---------- tests/domaincapsdata/qemu_7.0.0.x86_64.xml | 94 +++++++++---------- .../domaincapsdata/qemu_7.1.0-q35.x86_64.xml | 90 +++++++++--------- .../domaincapsdata/qemu_7.1.0-tcg.x86_64.xml | 90 +++++++++--------- tests/domaincapsdata/qemu_7.1.0.x86_64.xml | 90 +++++++++--------- 28 files changed, 1264 insertions(+), 1245 deletions(-) diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index 9fcd6b8add..4d2379803c 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -3137,6 +3137,24 @@ virCPUx86GetModels(char ***models) } +static const char * +virCPUx86GetVendorForModel(const char *modelName) +{ + virCPUx86Map *map; + virCPUx86Model *model; + + if (!(map = virCPUx86GetMap())) + return NULL; + + model = x86ModelFind(map, modelName); + + if (!model || !model->vendor) + return NULL; + + return model->vendor->name; +} + + static int virCPUx86Translate(virCPUDef *cpu, virDomainCapsCPUModels *models) @@ -3539,6 +3557,7 @@ struct cpuArchDriver cpuDriverX86 = { .dataFormat = virCPUx86DataFormat, .dataParse = virCPUx86DataParse, .getModels = virCPUx86GetModels, + .getVendorForModel = virCPUx86GetVendorForModel, .translate = virCPUx86Translate, .expandFeatures = virCPUx86ExpandFeatures, .copyMigratable = virCPUx86CopyMigratable, diff --git a/tests/domaincapsdata/qemu_4.2.0-q35.x86_64.xml b/tests/domaincapsdata/qemu_4.2.0-q35.x86_64.xml index fa86554892..dab12e5888 100644 --- a/tests/domaincapsdata/qemu_4.2.0-q35.x86_64.xml +++ b/tests/domaincapsdata/qemu_4.2.0-q35.x86_64.xml @@ -63,55 +63,55 @@ <mode name='custom' supported='yes'> <model usable='yes' vendor='unknown'>qemu64</model> <model usable='yes' vendor='unknown'>qemu32</model> - <model usable='no' vendor='unknown'>phenom</model> + <model usable='no' vendor='AMD'>phenom</model> <model usable='yes' vendor='unknown'>pentium3</model> <model usable='yes' vendor='unknown'>pentium2</model> <model usable='yes' vendor='unknown'>pentium</model> - <model usable='yes' vendor='unknown'>n270</model> + <model usable='yes' vendor='Intel'>n270</model> <model usable='yes' vendor='unknown'>kvm64</model> <model usable='yes' vendor='unknown'>kvm32</model> - <model usable='yes' vendor='unknown'>coreduo</model> - <model usable='yes' vendor='unknown'>core2duo</model> - <model usable='no' vendor='unknown'>athlon</model> - <model usable='yes' vendor='unknown'>Westmere-IBRS</model> - <model usable='yes' vendor='unknown'>Westmere</model> - <model usable='no' vendor='unknown'>Snowridge</model> - <model usable='no' vendor='unknown'>Skylake-Server-noTSX-IBRS</model> - <model usable='no' vendor='unknown'>Skylake-Server-IBRS</model> - <model usable='no' vendor='unknown'>Skylake-Server</model> - <model usable='yes' vendor='unknown'>Skylake-Client-noTSX-IBRS</model> - <model usable='yes' vendor='unknown'>Skylake-Client-IBRS</model> - <model usable='yes' vendor='unknown'>Skylake-Client</model> - <model usable='yes' vendor='unknown'>SandyBridge-IBRS</model> - <model usable='yes' vendor='unknown'>SandyBridge</model> - <model usable='yes' vendor='unknown'>Penryn</model> - <model usable='no' vendor='unknown'>Opteron_G5</model> - <model usable='no' vendor='unknown'>Opteron_G4</model> - <model usable='no' vendor='unknown'>Opteron_G3</model> - <model usable='yes' vendor='unknown'>Opteron_G2</model> - <model usable='yes' vendor='unknown'>Opteron_G1</model> - <model usable='yes' vendor='unknown'>Nehalem-IBRS</model> - <model usable='yes' vendor='unknown'>Nehalem</model> - <model usable='yes' vendor='unknown'>IvyBridge-IBRS</model> - <model usable='yes' vendor='unknown'>IvyBridge</model> - <model usable='no' vendor='unknown'>Icelake-Server-noTSX</model> - <model usable='no' vendor='unknown'>Icelake-Server</model> - <model usable='no' vendor='unknown'>Icelake-Client-noTSX</model> - <model usable='no' vendor='unknown'>Icelake-Client</model> - <model usable='yes' vendor='unknown'>Haswell-noTSX-IBRS</model> - <model usable='yes' vendor='unknown'>Haswell-noTSX</model> - <model usable='yes' vendor='unknown'>Haswell-IBRS</model> - <model usable='yes' vendor='unknown'>Haswell</model> - <model usable='no' vendor='unknown'>EPYC-IBPB</model> - <model usable='no' vendor='unknown'>EPYC</model> - <model usable='no' vendor='unknown'>Dhyana</model> - <model usable='yes' vendor='unknown'>Conroe</model> - <model usable='no' vendor='unknown'>Cascadelake-Server-noTSX</model> - <model usable='no' vendor='unknown'>Cascadelake-Server</model> - <model usable='yes' vendor='unknown'>Broadwell-noTSX-IBRS</model> - <model usable='yes' vendor='unknown'>Broadwell-noTSX</model> - <model usable='yes' vendor='unknown'>Broadwell-IBRS</model> - <model usable='yes' vendor='unknown'>Broadwell</model> + <model usable='yes' vendor='Intel'>coreduo</model> + <model usable='yes' vendor='Intel'>core2duo</model> + <model usable='no' vendor='AMD'>athlon</model> + <model usable='yes' vendor='Intel'>Westmere-IBRS</model> + <model usable='yes' vendor='Intel'>Westmere</model> + <model usable='no' vendor='Intel'>Snowridge</model> + <model usable='no' vendor='Intel'>Skylake-Server-noTSX-IBRS</model> + <model usable='no' vendor='Intel'>Skylake-Server-IBRS</model> + <model usable='no' vendor='Intel'>Skylake-Server</model> + <model usable='yes' vendor='Intel'>Skylake-Client-noTSX-IBRS</model> + <model usable='yes' vendor='Intel'>Skylake-Client-IBRS</model> + <model usable='yes' vendor='Intel'>Skylake-Client</model> + <model usable='yes' vendor='Intel'>SandyBridge-IBRS</model> + <model usable='yes' vendor='Intel'>SandyBridge</model> + <model usable='yes' vendor='Intel'>Penryn</model> + <model usable='no' vendor='AMD'>Opteron_G5</model> + <model usable='no' vendor='AMD'>Opteron_G4</model> + <model usable='no' vendor='AMD'>Opteron_G3</model> + <model usable='yes' vendor='AMD'>Opteron_G2</model> + <model usable='yes' vendor='AMD'>Opteron_G1</model> + <model usable='yes' vendor='Intel'>Nehalem-IBRS</model> + <model usable='yes' vendor='Intel'>Nehalem</model> + <model usable='yes' vendor='Intel'>IvyBridge-IBRS</model> + <model usable='yes' vendor='Intel'>IvyBridge</model> + <model usable='no' vendor='Intel'>Icelake-Server-noTSX</model> + <model usable='no' vendor='Intel'>Icelake-Server</model> + <model usable='no' vendor='Intel'>Icelake-Client-noTSX</model> + <model usable='no' vendor='Intel'>Icelake-Client</model> + <model usable='yes' vendor='Intel'>Haswell-noTSX-IBRS</model> + <model usable='yes' vendor='Intel'>Haswell-noTSX</model> + <model usable='yes' vendor='Intel'>Haswell-IBRS</model> + <model usable='yes' vendor='Intel'>Haswell</model> + <model usable='no' vendor='AMD'>EPYC-IBPB</model> + <model usable='no' vendor='AMD'>EPYC</model> + <model usable='no' vendor='Hygon'>Dhyana</model> + <model usable='yes' vendor='Intel'>Conroe</model> + <model usable='no' vendor='Intel'>Cascadelake-Server-noTSX</model> + <model usable='no' vendor='Intel'>Cascadelake-Server</model> + <model usable='yes' vendor='Intel'>Broadwell-noTSX-IBRS</model> + <model usable='yes' vendor='Intel'>Broadwell-noTSX</model> + <model usable='yes' vendor='Intel'>Broadwell-IBRS</model> + <model usable='yes' vendor='Intel'>Broadwell</model> <model usable='yes' vendor='unknown'>486</model> </mode> </cpu> ... -- 2.38.0

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com> --- Notes: Version 2: - no change src/cpu/cpu_ppc64.c | 20 ++++++++++++++++++++ tests/domaincapsdata/qemu_4.2.0.ppc64.xml | 6 +++--- tests/domaincapsdata/qemu_5.0.0.ppc64.xml | 8 ++++---- tests/domaincapsdata/qemu_5.2.0.ppc64.xml | 8 ++++---- tests/domaincapsdata/qemu_6.2.0.ppc64.xml | 8 ++++---- tests/domaincapsdata/qemu_7.0.0.ppc64.xml | 8 ++++---- 6 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/cpu/cpu_ppc64.c b/src/cpu/cpu_ppc64.c index 9997e14a89..7da67ec94a 100644 --- a/src/cpu/cpu_ppc64.c +++ b/src/cpu/cpu_ppc64.c @@ -780,6 +780,25 @@ virCPUppc64DriverGetModels(char ***models) return map->nmodels; } + +static const char * +virCPUppc64GetVendorForModel(const char *modelName) +{ + virCPUppc64Map *map = NULL; + virCPUppc64Model *model; + + if (!(map = virCPUppc64GetMap())) + return NULL; + + model = ppc64ModelFind(map, modelName); + + if (!model || !model->vendor) + return NULL; + + return model->vendor->name; +} + + struct cpuArchDriver cpuDriverPPC64 = { .name = "ppc64", .arch = archs, @@ -793,6 +812,7 @@ struct cpuArchDriver cpuDriverPPC64 = { .baseline = virCPUppc64Baseline, .update = virCPUppc64Update, .getModels = virCPUppc64DriverGetModels, + .getVendorForModel = virCPUppc64GetVendorForModel, .convertLegacy = virCPUppc64ConvertLegacy, .dataIsIdentical = virCPUppc64DataIsIdentical, }; diff --git a/tests/domaincapsdata/qemu_4.2.0.ppc64.xml b/tests/domaincapsdata/qemu_4.2.0.ppc64.xml index 6d09c5ae4e..7093c35355 100644 --- a/tests/domaincapsdata/qemu_4.2.0.ppc64.xml +++ b/tests/domaincapsdata/qemu_4.2.0.ppc64.xml @@ -40,9 +40,9 @@ <model fallback='allow'>POWER8</model> </mode> <mode name='custom' supported='yes'> - <model usable='unknown' vendor='unknown'>POWER9</model> - <model usable='unknown' vendor='unknown'>POWER8</model> - <model usable='unknown' vendor='unknown'>POWER7</model> + <model usable='unknown' vendor='IBM'>POWER9</model> + <model usable='unknown' vendor='IBM'>POWER8</model> + <model usable='unknown' vendor='IBM'>POWER7</model> </mode> </cpu> <memoryBacking supported='yes'> diff --git a/tests/domaincapsdata/qemu_5.0.0.ppc64.xml b/tests/domaincapsdata/qemu_5.0.0.ppc64.xml index 032a4f4e19..b944723885 100644 --- a/tests/domaincapsdata/qemu_5.0.0.ppc64.xml +++ b/tests/domaincapsdata/qemu_5.0.0.ppc64.xml @@ -40,10 +40,10 @@ <model fallback='allow'>POWER8</model> </mode> <mode name='custom' supported='yes'> - <model usable='unknown' vendor='unknown'>POWER10</model> - <model usable='unknown' vendor='unknown'>POWER9</model> - <model usable='unknown' vendor='unknown'>POWER8</model> - <model usable='unknown' vendor='unknown'>POWER7</model> + <model usable='unknown' vendor='IBM'>POWER10</model> + <model usable='unknown' vendor='IBM'>POWER9</model> + <model usable='unknown' vendor='IBM'>POWER8</model> + <model usable='unknown' vendor='IBM'>POWER7</model> </mode> </cpu> <memoryBacking supported='yes'> diff --git a/tests/domaincapsdata/qemu_5.2.0.ppc64.xml b/tests/domaincapsdata/qemu_5.2.0.ppc64.xml index 570d88235b..71f47c8748 100644 --- a/tests/domaincapsdata/qemu_5.2.0.ppc64.xml +++ b/tests/domaincapsdata/qemu_5.2.0.ppc64.xml @@ -40,10 +40,10 @@ <model fallback='allow'>POWER8</model> </mode> <mode name='custom' supported='yes'> - <model usable='unknown' vendor='unknown'>POWER10</model> - <model usable='unknown' vendor='unknown'>POWER9</model> - <model usable='unknown' vendor='unknown'>POWER8</model> - <model usable='unknown' vendor='unknown'>POWER7</model> + <model usable='unknown' vendor='IBM'>POWER10</model> + <model usable='unknown' vendor='IBM'>POWER9</model> + <model usable='unknown' vendor='IBM'>POWER8</model> + <model usable='unknown' vendor='IBM'>POWER7</model> </mode> </cpu> <memoryBacking supported='yes'> diff --git a/tests/domaincapsdata/qemu_6.2.0.ppc64.xml b/tests/domaincapsdata/qemu_6.2.0.ppc64.xml index c2fe03d227..bf2c679c51 100644 --- a/tests/domaincapsdata/qemu_6.2.0.ppc64.xml +++ b/tests/domaincapsdata/qemu_6.2.0.ppc64.xml @@ -40,10 +40,10 @@ <model fallback='allow'>POWER8</model> </mode> <mode name='custom' supported='yes'> - <model usable='unknown' vendor='unknown'>POWER10</model> - <model usable='unknown' vendor='unknown'>POWER9</model> - <model usable='unknown' vendor='unknown'>POWER8</model> - <model usable='unknown' vendor='unknown'>POWER7</model> + <model usable='unknown' vendor='IBM'>POWER10</model> + <model usable='unknown' vendor='IBM'>POWER9</model> + <model usable='unknown' vendor='IBM'>POWER8</model> + <model usable='unknown' vendor='IBM'>POWER7</model> </mode> </cpu> <memoryBacking supported='yes'> diff --git a/tests/domaincapsdata/qemu_7.0.0.ppc64.xml b/tests/domaincapsdata/qemu_7.0.0.ppc64.xml index 06e713373e..8f6f9f57e1 100644 --- a/tests/domaincapsdata/qemu_7.0.0.ppc64.xml +++ b/tests/domaincapsdata/qemu_7.0.0.ppc64.xml @@ -40,10 +40,10 @@ <model fallback='allow'>POWER8</model> </mode> <mode name='custom' supported='yes'> - <model usable='unknown' vendor='unknown'>POWER10</model> - <model usable='unknown' vendor='unknown'>POWER9</model> - <model usable='unknown' vendor='unknown'>POWER8</model> - <model usable='unknown' vendor='unknown'>POWER7</model> + <model usable='unknown' vendor='IBM'>POWER10</model> + <model usable='unknown' vendor='IBM'>POWER9</model> + <model usable='unknown' vendor='IBM'>POWER8</model> + <model usable='unknown' vendor='IBM'>POWER7</model> </mode> </cpu> <memoryBacking supported='yes'> -- 2.38.0

This patch is effectively a no-op, but I wanted to initialize .getVendorForModel explicitly as implementing this function does not even make sense on ARM. The CPU models in our CPU map are only used for describing host CPU in capabilities XML and cannot be used for guest CPU definition in domain XML anyway. The CPU models listed as supported in domain capabilities XML are just passed through from QEMU. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com> --- Notes: Version 2: - no change src/cpu/cpu_arm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index 599bb836ed..409b397155 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -714,6 +714,7 @@ struct cpuArchDriver cpuDriverArm = { #endif .decode = NULL, .encode = NULL, + .getVendorForModel = NULL, .dataCopyNew = virCPUarmDataCopyNew, .dataFree = virCPUarmDataFree, .baseline = virCPUarmBaseline, -- 2.38.0

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - new patch docs/formatdomaincaps.rst | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/docs/formatdomaincaps.rst b/docs/formatdomaincaps.rst index 6ce780fb69..afade16bc0 100644 --- a/docs/formatdomaincaps.rst +++ b/docs/formatdomaincaps.rst @@ -222,10 +222,20 @@ more details about it: ``custom`` The ``mode`` element contains a list of supported CPU models, each described by a dedicated ``model`` element. The ``usable`` attribute specifies whether - the model can be used directly on the host. When usable='no' the - corresponding model cannot be used without disabling some features that the - CPU of such model is expected to have. A special value ``unknown`` indicates - libvirt does not have enough information to provide the usability data. The + the model can be used directly on the host. A special value ``unknown`` + indicates libvirt does not have enough information to provide the usability + data. When ``usable='no'`` the corresponding model cannot be used without + disabling some features that the CPU of such model is expected to have. The + list of features blocking usability of a particular CPU model is returned + as disabled features in the result of ``virConnectBaselineHypervisorCPU`` + API (or ``virsh hypervisor-cpu-baseline``) when called on a CPU definition + using the CPU model and no additional feature elements. Models marked as + usable (``usable='yes'``) can be safely used in domain XMLs with + ``check='none'`` as the hypervisor guarantees the model can be used on the + current host and additional checks done by libvirt are redundant. In fact, + disabling libvirt checks via ``check='none'`` for such models is recommended + to avoid needless issues with starting domains when libvirt's definition of + a particular model differs from hypervisor's definition. The ``deprecated`` attribute reflects the hypervisor's policy on usage of this model :since:`(since 7.1.0)`. The ``vendor`` attribute :since:`(since 8.9.0)` contains the vendor of the CPU model for users who want to use CPU models -- 2.38.0

On a Friday in 2022, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> ---
Notes: Version 2: - new patch
docs/formatdomaincaps.rst | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

The API can be used to get usability blockers for an unusable CPU model, which is not obvious. Let's explicitly document this behavior as it is now mentioned in the documentation of domain capabilities XML. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - new patch src/libvirt-host.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/libvirt-host.c b/src/libvirt-host.c index 2ee6370bce..c02222346c 100644 --- a/src/libvirt-host.c +++ b/src/libvirt-host.c @@ -1319,6 +1319,15 @@ virConnectBaselineCPU(virConnectPtr conn, * This is different from virConnectBaselineCPU() which doesn't consider any * hypervisor abilities when computing the best CPU. * + * If @ncpus == 1, the result will be the first (and only) CPU in @xmlCPUs + * tailored to what the hypervisor can support on the current host. + * Specifically if this single CPU definition contains no feature elements and + * a CPU model listed as usable='no' in domain capabilities XML, the result + * will contain a list usability blockers, i.e., a list of features that would + * need to be disabled to for the model to be usable on this host. This list + * may contain more features than what the hypervisor reports as blockers in + * case the CPU model definition in libvirt differs from QEMU definition. + * * If @flags includes VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES then libvirt * will explicitly list all CPU features that are part of the computed CPU, * without this flag features that are part of the CPU model will not be -- 2.38.0

On a Friday in 2022, Jiri Denemark wrote:
The API can be used to get usability blockers for an unusable CPU model, which is not obvious. Let's explicitly document this behavior as it is now mentioned in the documentation of domain capabilities XML.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> ---
Notes: Version 2: - new patch
src/libvirt-host.c | 9 +++++++++ 1 file changed, 9 insertions(+)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

Since commit "cpu_x86: Disable blockers from unusable CPU models" (v3.8.0-99-g9c9620af1d) we explicitly disable CPU features reported by QEMU as usability blockers for a particular CPU model when creating baseline or host-model CPU definition. When QEMU changed canonical names for some features (mostly those with '_' in their names), we forgot to translate the blocker lists to names used by libvirt and the renamed features would no longer be explicitly disabled in the created CPU model even if they were reported as blockers by QEMU. For example, on a host where EPYC CPU model has the following blockers <blocker name='sha-ni'/> <blocker name='mmxext'/> <blocker name='fxsr-opt'/> <blocker name='cr8legacy'/> <blocker name='sse4a'/> <blocker name='misalignsse'/> <blocker name='osvw'/> we would fail to disable 'fxsr-opt': <cpu mode='custom' match='exact'> <model fallback='forbid'>EPYC</model> <feature policy='disable' name='sha-ni'/> <feature policy='disable' name='mmxext'/> <feature policy='disable' name='cr8legacy'/> <feature policy='disable' name='sse4a'/> <feature policy='disable' name='misalignsse'/> <feature policy='disable' name='osvw'/> <feature policy='disable' name='monitor'/> </cpu> The 'monitor' feature is disabled even though it is not reported as a blocker by QEMU because libvirt's definition of EPYC includes the feature while it is missing in EPYC definition in QEMU. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - also translate blockers when fetching them from QEMU (in virQEMUCapsFetchCPUDefinitions) - rewritten commit message src/qemu/qemu_capabilities.c | 42 ++++++++++++++++++++++++++++++------ src/qemu/qemu_capabilities.h | 4 ++++ 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index ccd274b80d..6f3ff7f43f 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -2936,6 +2936,17 @@ virQEMUCapsFetchCPUDefinitions(qemuMonitor *mon, } } + for (i = 0; i < defs->ncpus; i++) { + qemuMonitorCPUDefInfo *cpu = &defs->cpus[i]; + char **blocker; + + if (!cpu->blockers) + continue; + + for (blocker = cpu->blockers; *blocker; blocker++) + virQEMUCapsCPUFeatureFromQEMUInPlace(arch, blocker); + } + *cpuDefs = g_steal_pointer(&defs); return 0; } @@ -3483,6 +3494,19 @@ virQEMUCapsCPUFeatureFromQEMU(virArch arch, } +void +virQEMUCapsCPUFeatureFromQEMUInPlace(virArch arch, + char **feature) +{ + const char *tmp = virQEMUCapsCPUFeatureFromQEMU(arch, *feature); + + if (tmp != *feature) { + VIR_FREE(*feature); + *feature = g_strdup(tmp); + } +} + + /** * Returns 0 when host CPU model provided by QEMU was filled in qemuCaps, * 1 when the caller should fall back to using virCaps *->host.cpu, @@ -3907,7 +3931,8 @@ virQEMUCapsLoadHostCPUModelInfo(virQEMUCapsAccel *caps, static int -virQEMUCapsLoadCPUModels(virQEMUCapsAccel *caps, +virQEMUCapsLoadCPUModels(virArch arch, + virQEMUCapsAccel *caps, xmlXPathContextPtr ctxt, const char *typeStr) { @@ -3978,6 +4003,8 @@ virQEMUCapsLoadCPUModels(virQEMUCapsAccel *caps, "capabilities cache")); return -1; } + + virQEMUCapsCPUFeatureFromQEMUInPlace(arch, &cpu->blockers[j]); } } @@ -4072,7 +4099,7 @@ virQEMUCapsLoadAccel(virQEMUCaps *qemuCaps, if (virQEMUCapsLoadHostCPUModelInfo(caps, ctxt, typeStr) < 0) return -1; - if (virQEMUCapsLoadCPUModels(caps, ctxt, typeStr) < 0) + if (virQEMUCapsLoadCPUModels(qemuCaps->arch, caps, ctxt, typeStr) < 0) return -1; if (virQEMUCapsLoadMachines(caps, ctxt, typeStr) < 0) @@ -4534,7 +4561,8 @@ virQEMUCapsFormatHostCPUModelInfo(virQEMUCapsAccel *caps, static void -virQEMUCapsFormatCPUModels(virQEMUCapsAccel *caps, +virQEMUCapsFormatCPUModels(virArch arch, + virQEMUCapsAccel *caps, virBuffer *buf, const char *typeStr) { @@ -4563,8 +4591,10 @@ virQEMUCapsFormatCPUModels(virQEMUCapsAccel *caps, virBufferAddLit(buf, ">\n"); virBufferAdjustIndent(buf, 2); - for (j = 0; cpu->blockers[j]; j++) - virBufferAsprintf(buf, "<blocker name='%s'/>\n", cpu->blockers[j]); + for (j = 0; cpu->blockers[j]; j++) { + virBufferAsprintf(buf, "<blocker name='%s'/>\n", + virQEMUCapsCPUFeatureToQEMU(arch, cpu->blockers[j])); + } virBufferAdjustIndent(buf, -2); virBufferAddLit(buf, "</cpu>\n"); @@ -4616,7 +4646,7 @@ virQEMUCapsFormatAccel(virQEMUCaps *qemuCaps, const char *typeStr = virQEMUCapsAccelStr(type); virQEMUCapsFormatHostCPUModelInfo(caps, buf, typeStr); - virQEMUCapsFormatCPUModels(caps, buf, typeStr); + virQEMUCapsFormatCPUModels(qemuCaps->arch, caps, buf, typeStr); virQEMUCapsFormatMachines(caps, buf, typeStr); } diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 904ee54f60..4b2782c462 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -845,6 +845,10 @@ const char * virQEMUCapsCPUFeatureFromQEMU(virArch arch, const char *feature); +void +virQEMUCapsCPUFeatureFromQEMUInPlace(virArch arch, + char **feature); + virSEVCapability * virQEMUCapsGetSEVCapabilities(virQEMUCaps *qemuCaps); -- 2.38.0

On a Friday in 2022, Jiri Denemark wrote:
Since commit "cpu_x86: Disable blockers from unusable CPU models" (v3.8.0-99-g9c9620af1d) we explicitly disable CPU features reported by QEMU as usability blockers for a particular CPU model when creating baseline or host-model CPU definition. When QEMU changed canonical names for some features (mostly those with '_' in their names), we forgot to translate the blocker lists to names used by libvirt and the renamed features would no longer be explicitly disabled in the created CPU model even if they were reported as blockers by QEMU.
For example, on a host where EPYC CPU model has the following blockers
<blocker name='sha-ni'/> <blocker name='mmxext'/> <blocker name='fxsr-opt'/> <blocker name='cr8legacy'/> <blocker name='sse4a'/> <blocker name='misalignsse'/> <blocker name='osvw'/>
we would fail to disable 'fxsr-opt':
<cpu mode='custom' match='exact'> <model fallback='forbid'>EPYC</model> <feature policy='disable' name='sha-ni'/> <feature policy='disable' name='mmxext'/> <feature policy='disable' name='cr8legacy'/> <feature policy='disable' name='sse4a'/> <feature policy='disable' name='misalignsse'/> <feature policy='disable' name='osvw'/> <feature policy='disable' name='monitor'/> </cpu>
The 'monitor' feature is disabled even though it is not reported as a blocker by QEMU because libvirt's definition of EPYC includes the feature while it is missing in EPYC definition in QEMU.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> ---
Notes: Version 2: - also translate blockers when fetching them from QEMU (in virQEMUCapsFetchCPUDefinitions) - rewritten commit message
src/qemu/qemu_capabilities.c | 42 ++++++++++++++++++++++++++++++------ src/qemu/qemu_capabilities.h | 4 ++++ 2 files changed, 40 insertions(+), 6 deletions(-)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

This option can be used as a shortcut for creating a single XML with just a CPU model name and no features: $ virsh hypervisor-cpu-baseline --model Skylake-Server <cpu mode='custom' match='exact'> <model fallback='forbid'>Skylake-Server</model> <feature policy='disable' name='avx512f'/> <feature policy='disable' name='avx512dq'/> <feature policy='disable' name='clwb'/> <feature policy='disable' name='avx512cd'/> <feature policy='disable' name='avx512bw'/> <feature policy='disable' name='avx512vl'/> <feature policy='disable' name='pku'/> </cpu> Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - new patch docs/manpages/virsh.rst | 14 +++++++++++--- tools/virsh-host.c | 23 +++++++++++++++++++---- tools/virsh.h | 7 +++++-- tools/vsh.h | 27 +++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 9 deletions(-) diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst index 5d11c48803..61fcb2e9ca 100644 --- a/docs/manpages/virsh.rst +++ b/docs/manpages/virsh.rst @@ -962,13 +962,18 @@ hypervisor-cpu-baseline :: - hypervisor-cpu-baseline FILE [virttype] [emulator] [arch] [machine] [--features] [--migratable] + hypervisor-cpu-baseline [FILE] [virttype] [emulator] [arch] [machine] + [--features] [--migratable] [model] Compute a baseline CPU which will be compatible with all CPUs defined in an XML *file* and with the CPU the hypervisor is able to provide on the host. (This is different from ``cpu-baseline`` which does not consider any hypervisor abilities when computing the baseline CPU.) +As an alternative for *FILE* in case the XML would only contain a CPU model +with no additional features the CPU model name itself can be passed as *model*. +Exactly one of *FILE* and *model* must be used. + The XML *FILE* may contain either host or guest CPU definitions describing the host CPU model. The host CPU definition is the <cpu> element and its contents as printed by ``capabilities`` command. The guest CPU definition may be created @@ -981,10 +986,13 @@ fail or provide unexpected results. When *FILE* contains only a single CPU definition, the command will print the same CPU with restrictions imposed by the capabilities of the hypervisor. -Specifically, running th ``virsh hypervisor-cpu-baseline`` command with no +Specifically, running the ``virsh hypervisor-cpu-baseline`` command with no additional options on the result of ``virsh domcapabilities`` will transform the host CPU model from domain capabilities XML to a form directly usable in domain -XML. +XML. Running the command with *model* (or *FILE* containing just a single CPU +definition with model and no feature elements) which is marked as unusable in +``virsh domcapabilities`` will provide a list of features that block this CPU +model from being usable. The *virttype* option specifies the virtualization type (usable in the 'type' attribute of the <domain> top level element from the domain XML). *emulator* diff --git a/tools/virsh-host.c b/tools/virsh-host.c index ead966b500..16c3585a1a 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -1689,7 +1689,8 @@ static const vshCmdInfo info_hypervisor_cpu_baseline[] = { }; static const vshCmdOptDef opts_hypervisor_cpu_baseline[] = { - VIRSH_COMMON_OPT_FILE(N_("file containing XML CPU descriptions")), + VIRSH_COMMON_OPT_FILE_FULL(N_("file containing XML CPU descriptions"), + false), {.name = "virttype", .type = VSH_OT_STRING, .completer = virshDomainVirtTypeCompleter, @@ -1716,6 +1717,11 @@ static const vshCmdOptDef opts_hypervisor_cpu_baseline[] = { .type = VSH_OT_BOOL, .help = N_("Do not include features that block migration") }, + {.name = "model", + .type = VSH_OT_STRING, + .help = N_("Shortcut for calling the command with a single CPU model " + "and no additional features") + }, {.name = NULL} }; @@ -1728,6 +1734,7 @@ cmdHypervisorCPUBaseline(vshControl *ctl, const char *emulator = NULL; const char *arch = NULL; const char *machine = NULL; + const char *model = NULL; bool ret = false; g_autofree char *result = NULL; g_auto(GStrv) list = NULL; @@ -1743,11 +1750,19 @@ cmdHypervisorCPUBaseline(vshControl *ctl, vshCommandOptStringReq(ctl, cmd, "virttype", &virttype) < 0 || vshCommandOptStringReq(ctl, cmd, "emulator", &emulator) < 0 || vshCommandOptStringReq(ctl, cmd, "arch", &arch) < 0 || - vshCommandOptStringReq(ctl, cmd, "machine", &machine) < 0) + vshCommandOptStringReq(ctl, cmd, "machine", &machine) < 0 || + vshCommandOptStringReq(ctl, cmd, "model", &model) < 0) return false; - if (!(list = vshExtractCPUDefXMLs(ctl, from))) - return false; + VSH_ALTERNATIVE_OPTIONS_EXPR("file", from, "model", model); + + if (from) { + if (!(list = vshExtractCPUDefXMLs(ctl, from))) + return false; + } else { + list = g_new0(char *, 2); + list[0] = g_strdup_printf("<cpu><model>%s</model></cpu>", model); + } result = virConnectBaselineHypervisorCPU(priv->conn, emulator, arch, machine, virttype, diff --git a/tools/virsh.h b/tools/virsh.h index f9841c8da2..6acefa7f9d 100644 --- a/tools/virsh.h +++ b/tools/virsh.h @@ -96,9 +96,12 @@ /* Use this only for files which are existing and used locally by virsh */ #define VIRSH_COMMON_OPT_FILE(_helpstr) \ + VIRSH_COMMON_OPT_FILE_FULL(_helpstr, true) + +#define VIRSH_COMMON_OPT_FILE_FULL(_helpstr, required) \ {.name = "file", \ - .type = VSH_OT_DATA, \ - .flags = VSH_OFLAG_REQ, \ + .type = required ? VSH_OT_DATA : VSH_OT_STRING, \ + .flags = required ? VSH_OFLAG_REQ : VSH_OFLAG_NONE, \ .completer = virshCompletePathLocalExisting, \ .help = _helpstr \ } diff --git a/tools/vsh.h b/tools/vsh.h index a43660b63d..657a1e7a93 100644 --- a/tools/vsh.h +++ b/tools/vsh.h @@ -520,6 +520,33 @@ void vshReadlineHistoryAdd(const char *cmd); #define VSH_EXCLUSIVE_OPTIONS_VAR(VARNAME1, VARNAME2) \ VSH_EXCLUSIVE_OPTIONS_EXPR(#VARNAME1, VARNAME1, #VARNAME2, VARNAME2) +/* Macros to help dealing with alternative mutually exclusive options. */ + +/* VSH_ALTERNATIVE_OPTIONS_EXPR: + * + * @NAME1: String containing the name of the option. + * @EXPR1: Expression to validate the variable (must evaluate to bool). + * @NAME2: String containing the name of the option. + * @EXPR2: Expression to validate the variable (must evaluate to bool). + * + * Require exactly one of the command options in virsh. Use the provided + * expression to check the variables. + * + * This helper does an early return and therefore it has to be called + * before anything that would require cleanup. + */ +#define VSH_ALTERNATIVE_OPTIONS_EXPR(NAME1, EXPR1, NAME2, EXPR2) \ + do { \ + bool _expr1 = EXPR1; \ + bool _expr2 = EXPR2; \ + VSH_EXCLUSIVE_OPTIONS_EXPR(NAME1, _expr1, NAME2, _expr2); \ + if (!_expr1 && !_expr2) { \ + vshError(ctl, _("Either --%s or --%s must be provided"), \ + NAME1, NAME2); \ + return false; \ + } \ + } while (0) + /* Macros to help dealing with required options. */ /* VSH_REQUIRE_OPTION_EXPR: -- 2.38.0

On a Friday in 2022, Jiri Denemark wrote:
This option can be used as a shortcut for creating a single XML with just a CPU model name and no features:
$ virsh hypervisor-cpu-baseline --model Skylake-Server <cpu mode='custom' match='exact'> <model fallback='forbid'>Skylake-Server</model> <feature policy='disable' name='avx512f'/> <feature policy='disable' name='avx512dq'/> <feature policy='disable' name='clwb'/> <feature policy='disable' name='avx512cd'/> <feature policy='disable' name='avx512bw'/> <feature policy='disable' name='avx512vl'/> <feature policy='disable' name='pku'/> </cpu>
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> ---
Notes: Version 2: - new patch
docs/manpages/virsh.rst | 14 +++++++++++--- tools/virsh-host.c | 23 +++++++++++++++++++---- tools/virsh.h | 7 +++++-- tools/vsh.h | 27 +++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 9 deletions(-)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - new patch tools/virsh-completer-host.c | 50 ++++++++++++++++++++++++++++++++++++ tools/virsh-completer-host.h | 5 ++++ tools/virsh-host.c | 1 + 3 files changed, 56 insertions(+) diff --git a/tools/virsh-completer-host.c b/tools/virsh-completer-host.c index 05a84a43bb..93b633eb64 100644 --- a/tools/virsh-completer-host.c +++ b/tools/virsh-completer-host.c @@ -205,3 +205,53 @@ virshArchCompleter(vshControl *ctl G_GNUC_UNUSED, return virshEnumComplete(VIR_ARCH_LAST, (const char *(*)(int))virArchToString); } + + +char ** +virshCPUModelCompleter(vshControl *ctl, + const vshCmd *cmd, + unsigned int flags) +{ + virshControl *priv = ctl->privData; + const char *virttype = NULL; + const char *emulator = NULL; + const char *arch = NULL; + const char *machine = NULL; + g_autofree char *domcaps = NULL; + g_autoptr(xmlDoc) xml = NULL; + g_autoptr(xmlXPathContext) ctxt = NULL; + g_autofree xmlNodePtr *nodes = NULL; + g_auto(GStrv) models = NULL; + int nmodels = 0; + size_t i; + + virCheckFlags(0, NULL); + + if (vshCommandOptStringReq(ctl, cmd, "virttype", &virttype) < 0 || + vshCommandOptStringReq(ctl, cmd, "emulator", &emulator) < 0 || + vshCommandOptStringReq(ctl, cmd, "arch", &arch) < 0 || + vshCommandOptStringReq(ctl, cmd, "machine", &machine) < 0) + return NULL; + + if (!priv->conn || virConnectIsAlive(priv->conn) <= 0) + return NULL; + + if (!(domcaps = virConnectGetDomainCapabilities(priv->conn, emulator, arch, + machine, virttype, 0))) + return NULL; + + if (!(xml = virXMLParseStringCtxt(domcaps, _("domain capabilities"), &ctxt))) + return NULL; + + nmodels = virXPathNodeSet("/domainCapabilities/cpu/mode[@name='custom']/model", + ctxt, &nodes); + if (nmodels <= 0) + return NULL; + + models = g_new0(char *, nmodels + 1); + + for (i = 0; i < nmodels; i++) + models[i] = virXMLNodeContentString(nodes[i]); + + return g_steal_pointer(&models); +} diff --git a/tools/virsh-completer-host.h b/tools/virsh-completer-host.h index b182661cde..608ae9e3e7 100644 --- a/tools/virsh-completer-host.h +++ b/tools/virsh-completer-host.h @@ -51,3 +51,8 @@ char ** virshArchCompleter(vshControl *ctl, const vshCmd *cmd, unsigned int flags); + +char ** +virshCPUModelCompleter(vshControl *ctl, + const vshCmd *cmd, + unsigned int flags); diff --git a/tools/virsh-host.c b/tools/virsh-host.c index 16c3585a1a..21d479fd01 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -1719,6 +1719,7 @@ static const vshCmdOptDef opts_hypervisor_cpu_baseline[] = { }, {.name = "model", .type = VSH_OT_STRING, + .completer = virshCPUModelCompleter, .help = N_("Shortcut for calling the command with a single CPU model " "and no additional features") }, -- 2.38.0

On a Friday in 2022, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> ---
Notes: Version 2: - new patch
tools/virsh-completer-host.c | 50 ++++++++++++++++++++++++++++++++++++ tools/virsh-completer-host.h | 5 ++++ tools/virsh-host.c | 1 + 3 files changed, 56 insertions(+)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - patch 10/11 from v1 and the corresponding section in NEWS dropped - mention --model for virsh hypervisor-cpu-baseline - mention CPU blockers translation bug - mention docs improvements NEWS.rst | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/NEWS.rst b/NEWS.rst index 3049aa83f9..b6bcb5524d 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -19,8 +19,30 @@ v8.9.0 (unreleased) * **Improvements** + * Add ``vendor`` attribute for CPU models in domain capabilities + + Users can now see the vendor of each CPU model in domain capabilities and + use it, e.g., for filtering usable CPU models based on host CPU vendor. + + * virsh: Add ``--model`` option for ``hypervisor-cpu-baseline`` + + This is a shortcut for calling ``hypervisor-cpu-baseline`` with a single + CPU model and no additional features. It can be used for determining which + features block a particular CPU model from being usable. + + * Improved documentation of CPU ``usable`` attribute in domain capabilities + * **Bug fixes** + * qemu: Disable all blocker features in CPU baseline + + Three years ago QEMU renamed some CPU features (mostly those containing + an underscore). When such renamed feature was reported by QEMU as blocking + usability of a CPU model, we would fail to explicitly disable it when + creating a baseline CPU definition using this model. This bug did not have + any functional impact when the default ``check='partial'`` attribute was + used for guest CPU definition in domain XML, but it could have caused + failures to start a domain with ``check='full'`` in some cases. v8.8.0 (2022-10-03) =================== -- 2.38.0

On a Friday in 2022, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> ---
Notes: Version 2: - patch 10/11 from v1 and the corresponding section in NEWS dropped - mention --model for virsh hypervisor-cpu-baseline - mention CPU blockers translation bug - mention docs improvements
NEWS.rst | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano
participants (2)
-
Jiri Denemark
-
Ján Tomko