[libvirt] [PATCH v3 0/8] CPU Model Baseline and Comparison for s390x

Changelog: v2 - numerous cleanups - removed "policy fix function" and now properly check for policy == -1 in the CPUDef -> JSON parser - resolved some memory leaks - added string arg to qemuMonitorJSONParseCPUModelData for error message to print out proper command name v1 - introduce baseline - split patches into small chunks - free'd lingering qemuMonitorCPUModelInfo pointer - when converting from virCPUDef -> virJSON, consider feature policy FORCED for enabled ___ To run these patches, execute the virsh hypervisor-cpu-compare or hypervisor-cpu-baseline commands and pass an XML file describing one or more CPU definition. You can use the definition from virsh domcapabilities or from a guest XML. There is no need extract it from the file and place it a new one, as the XML parser will look specifically for the CPU tags. ___ These patches hookup the virsh hypervisor-cpu-compare/baseline commands for the s390x architecture. They take an XML file describing some CPU definitions and passes the data to QEMU, where the actual CPU model comparison / baseline calculation is handled (available since QEMU 2.8.5). These calculations are compared against / baselined with the hypervisor CPU model, which can be observed via the virsh domcapabilities command for s390x. When baselining CPU models and the user appends the --features argument to the command, s390x will only report back features that supersede the base model definition. **NOTE** if the --features flag is intended to expand ALL features available to a CPU model (such as the huge list of features reported by a full CPU model expansion), please let me know and I can resolve this. The first patch pulls some code out of the CPU Model Expansion JSON function so that it can be later used for the Comparison and Baseline JSON functions. The rest of the patches follow this sequence: - introduce JSON monitor functions - introduce capability and update test files - hook up monitor functions to virsh command Patch 7 pulls out some code from the CPUDef XML parser to be reused in the comparison hookup. Thanks. x86 and Power review by Daniel Henrique Barboza (thanks!) Collin Walling (8): qemu_monitor: helper functions for CPU models qemu_monitor: implement query-cpu-model-baseline qemu_capabilities: introduce QEMU_CAPS_QUERY_CPU_MODEL_BASELINE qemu_driver: hook up query-cpu-model-baseline qemu_monitor: implement query-cpu-model-comparison qemu_capabilities: introduce QEMU_CAPS_QUERY_CPU_MODEL_COMPARISON cpu_conf: xml to cpu definition parse helper qemu_driver: hook up query-cpu-model-comparison src/conf/cpu_conf.c | 30 +++ src/conf/cpu_conf.h | 6 + src/cpu/cpu.c | 14 +- src/libvirt_private.syms | 1 + src/qemu/qemu_capabilities.c | 138 +++++++++++ src/qemu/qemu_capabilities.h | 20 ++ src/qemu/qemu_driver.c | 38 +++ src/qemu/qemu_monitor.c | 44 ++++ src/qemu/qemu_monitor.h | 18 ++ src/qemu/qemu_monitor_json.c | 297 ++++++++++++++++++++--- src/qemu/qemu_monitor_json.h | 20 ++ tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml | 2 + tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml | 2 + tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml | 2 + tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml | 2 + tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml | 2 + tests/qemucapabilitiesdata/caps_3.0.0.s390x.xml | 2 + tests/qemucapabilitiesdata/caps_4.0.0.s390x.xml | 2 + 18 files changed, 591 insertions(+), 49 deletions(-) -- 2.7.4

Refactor some code in qemuMonitorJSONGetCPUModelExpansion to be later used for the comparison and baseline functions. This does not alter any functionality. Signed-off-by: Collin Walling <walling@linux.ibm.com> Reviewed-by: Bjoern Walk <bwalk@linux.ibm.com> --- src/qemu/qemu_monitor_json.c | 173 ++++++++++++++++++++++++++++++------------- 1 file changed, 121 insertions(+), 52 deletions(-) diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 53a7de8..08c734c 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -5503,6 +5503,120 @@ qemuMonitorJSONParseCPUModelProperty(const char *key, return 0; } + +static virJSONValuePtr +qemuMonitorJSONMakeCPUModel(const char *model_name, + size_t nprops, + virCPUFeatureDefPtr props, + bool migratable) +{ + virJSONValuePtr value; + virJSONValuePtr feats = NULL; + size_t i; + + if (!(value = virJSONValueNewObject())) + goto cleanup; + + if (virJSONValueObjectAppendString(value, "name", model_name) < 0) + goto cleanup; + + if (nprops || !migratable) { + if (!(feats = virJSONValueNewObject())) + goto cleanup; + + for (i = 0; i < nprops; i++) { + char *name = props[i].name; + bool enabled = false; + + /* policy may be reported as -1 if the CPU def is a host model */ + if (props[i].policy == VIR_CPU_FEATURE_REQUIRE || + props[i].policy == VIR_CPU_FEATURE_FORCE || + props[i].policy == -1) + enabled = true; + + if (virJSONValueObjectAppendBoolean(feats, name, enabled) < 0) + goto cleanup; + } + + if (!migratable && + virJSONValueObjectAppendBoolean(feats, "migratable", false) < 0) { + goto cleanup; + } + + if (virJSONValueObjectAppend(value, "props", feats) < 0) + goto cleanup; + } + + return value; + + cleanup: + virJSONValueFree(value); + virJSONValueFree(feats); + return NULL; +} + + +static int +qemuMonitorJSONParseCPUModelData(virJSONValuePtr data, + virJSONValuePtr *cpu_model, + virJSONValuePtr *cpu_props, + const char **cpu_name, + const char *cmd_name) +{ + if (!(*cpu_model = virJSONValueObjectGetObject(data, "model"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s reply data was missing 'model'"), cmd_name); + return -1; + } + + if (!(*cpu_name = virJSONValueObjectGetString(*cpu_model, "name"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s reply data was missing 'name'"), cmd_name); + return -1; + } + + /* Some older CPU models do not report properties */ + *cpu_props = virJSONValueObjectGetObject(*cpu_model, "props"); + + return 0; +} + + +static int +qemuMonitorJSONParseCPUModel(const char *cpu_name, + virJSONValuePtr cpu_props, + qemuMonitorCPUModelInfoPtr *model_info) +{ + qemuMonitorCPUModelInfoPtr machine_model = NULL; + int ret = -1; + + if (VIR_ALLOC(machine_model) < 0) + goto cleanup; + + if (VIR_STRDUP(machine_model->name, cpu_name) < 0) + goto cleanup; + + if (cpu_props) { + size_t nprops = virJSONValueObjectKeysNumber(cpu_props); + + if (VIR_ALLOC_N(machine_model->props, nprops) < 0) + goto cleanup; + + if (virJSONValueObjectForeachKeyValue(cpu_props, + qemuMonitorJSONParseCPUModelProperty, + machine_model) < 0) + goto cleanup; + } + + VIR_STEAL_PTR(*model_info, machine_model); + ret = 0; + + cleanup: + qemuMonitorCPUModelInfoFree(machine_model); + return ret; +} + + int qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon, qemuMonitorCPUModelExpansionType type, @@ -5511,33 +5625,20 @@ qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon, qemuMonitorCPUModelInfoPtr *model_info) { int ret = -1; - virJSONValuePtr model = NULL; - virJSONValuePtr props = NULL; + virJSONValuePtr model; virJSONValuePtr cmd = NULL; virJSONValuePtr reply = NULL; virJSONValuePtr data; virJSONValuePtr cpu_model; - virJSONValuePtr cpu_props; - qemuMonitorCPUModelInfoPtr machine_model = NULL; - char const *cpu_name; + virJSONValuePtr cpu_props = NULL; + const char *cpu_name = ""; const char *typeStr = ""; *model_info = NULL; - if (!(model = virJSONValueNewObject())) + if (!(model = qemuMonitorJSONMakeCPUModel(model_name, 0, NULL, migratable))) goto cleanup; - if (virJSONValueObjectAppendString(model, "name", model_name) < 0) - goto cleanup; - - if (!migratable) { - if (!(props = virJSONValueNewObject()) || - virJSONValueObjectAppendBoolean(props, "migratable", false) < 0 || - virJSONValueObjectAppend(model, "props", props) < 0) - goto cleanup; - props = NULL; - } - retry: switch (type) { case QEMU_MONITOR_CPU_MODEL_EXPANSION_STATIC: @@ -5573,11 +5674,9 @@ qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon, data = virJSONValueObjectGetObject(reply, "return"); - if (!(cpu_model = virJSONValueObjectGetObject(data, "model"))) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("query-cpu-model-expansion reply data was missing 'model'")); + if (qemuMonitorJSONParseCPUModelData(data, &cpu_model, &cpu_props, &cpu_name, + "query-cpu-model-expansion") < 0) goto cleanup; - } /* QEMU_MONITOR_CPU_MODEL_EXPANSION_STATIC_FULL requests "full" expansion * on the result of the initial "static" expansion. @@ -5592,42 +5691,12 @@ qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon, goto retry; } - if (!(cpu_name = virJSONValueObjectGetString(cpu_model, "name"))) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("query-cpu-model-expansion reply data was missing 'name'")); - goto cleanup; - } - - if (!(cpu_props = virJSONValueObjectGetObject(cpu_model, "props"))) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("query-cpu-model-expansion reply data was missing 'props'")); - goto cleanup; - } - - if (VIR_ALLOC(machine_model) < 0) - goto cleanup; - - if (VIR_STRDUP(machine_model->name, cpu_name) < 0) - goto cleanup; - - if (VIR_ALLOC_N(machine_model->props, virJSONValueObjectKeysNumber(cpu_props)) < 0) - goto cleanup; - - if (virJSONValueObjectForeachKeyValue(cpu_props, - qemuMonitorJSONParseCPUModelProperty, - machine_model) < 0) - goto cleanup; - - ret = 0; - *model_info = machine_model; - machine_model = NULL; + ret = qemuMonitorJSONParseCPUModel(cpu_name, cpu_props, model_info); cleanup: - qemuMonitorCPUModelInfoFree(machine_model); virJSONValueFree(cmd); virJSONValueFree(reply); virJSONValueFree(model); - virJSONValueFree(props); return ret; } -- 2.7.4

On 5/30/19 11:23 AM, Collin Walling wrote:
Refactor some code in qemuMonitorJSONGetCPUModelExpansion to be later used for the comparison and baseline functions.
This does not alter any functionality.
Signed-off-by: Collin Walling <walling@linux.ibm.com> Reviewed-by: Bjoern Walk <bwalk@linux.ibm.com> ---
Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com>
src/qemu/qemu_monitor_json.c | 173 ++++++++++++++++++++++++++++++------------- 1 file changed, 121 insertions(+), 52 deletions(-)
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 53a7de8..08c734c 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -5503,6 +5503,120 @@ qemuMonitorJSONParseCPUModelProperty(const char *key, return 0; }
+ +static virJSONValuePtr +qemuMonitorJSONMakeCPUModel(const char *model_name, + size_t nprops, + virCPUFeatureDefPtr props, + bool migratable) +{ + virJSONValuePtr value; + virJSONValuePtr feats = NULL; + size_t i; + + if (!(value = virJSONValueNewObject())) + goto cleanup; + + if (virJSONValueObjectAppendString(value, "name", model_name) < 0) + goto cleanup; + + if (nprops || !migratable) { + if (!(feats = virJSONValueNewObject())) + goto cleanup; + + for (i = 0; i < nprops; i++) { + char *name = props[i].name; + bool enabled = false; + + /* policy may be reported as -1 if the CPU def is a host model */ + if (props[i].policy == VIR_CPU_FEATURE_REQUIRE || + props[i].policy == VIR_CPU_FEATURE_FORCE || + props[i].policy == -1) + enabled = true; + + if (virJSONValueObjectAppendBoolean(feats, name, enabled) < 0) + goto cleanup; + } + + if (!migratable && + virJSONValueObjectAppendBoolean(feats, "migratable", false) < 0) { + goto cleanup; + } + + if (virJSONValueObjectAppend(value, "props", feats) < 0) + goto cleanup; + } + + return value; + + cleanup: + virJSONValueFree(value); + virJSONValueFree(feats); + return NULL; +} + + +static int +qemuMonitorJSONParseCPUModelData(virJSONValuePtr data, + virJSONValuePtr *cpu_model, + virJSONValuePtr *cpu_props, + const char **cpu_name, + const char *cmd_name) +{ + if (!(*cpu_model = virJSONValueObjectGetObject(data, "model"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s reply data was missing 'model'"), cmd_name); + return -1; + } + + if (!(*cpu_name = virJSONValueObjectGetString(*cpu_model, "name"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s reply data was missing 'name'"), cmd_name); + return -1; + } + + /* Some older CPU models do not report properties */ + *cpu_props = virJSONValueObjectGetObject(*cpu_model, "props"); + + return 0; +} + + +static int +qemuMonitorJSONParseCPUModel(const char *cpu_name, + virJSONValuePtr cpu_props, + qemuMonitorCPUModelInfoPtr *model_info) +{ + qemuMonitorCPUModelInfoPtr machine_model = NULL; + int ret = -1; + + if (VIR_ALLOC(machine_model) < 0) + goto cleanup; + + if (VIR_STRDUP(machine_model->name, cpu_name) < 0) + goto cleanup; + + if (cpu_props) { + size_t nprops = virJSONValueObjectKeysNumber(cpu_props); + + if (VIR_ALLOC_N(machine_model->props, nprops) < 0) + goto cleanup; + + if (virJSONValueObjectForeachKeyValue(cpu_props, + qemuMonitorJSONParseCPUModelProperty, + machine_model) < 0) + goto cleanup; + } + + VIR_STEAL_PTR(*model_info, machine_model); + ret = 0; + + cleanup: + qemuMonitorCPUModelInfoFree(machine_model); + return ret; +} + + int qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon, qemuMonitorCPUModelExpansionType type, @@ -5511,33 +5625,20 @@ qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon, qemuMonitorCPUModelInfoPtr *model_info) { int ret = -1; - virJSONValuePtr model = NULL; - virJSONValuePtr props = NULL; + virJSONValuePtr model; virJSONValuePtr cmd = NULL; virJSONValuePtr reply = NULL; virJSONValuePtr data; virJSONValuePtr cpu_model; - virJSONValuePtr cpu_props; - qemuMonitorCPUModelInfoPtr machine_model = NULL; - char const *cpu_name; + virJSONValuePtr cpu_props = NULL; + const char *cpu_name = ""; const char *typeStr = "";
*model_info = NULL;
- if (!(model = virJSONValueNewObject())) + if (!(model = qemuMonitorJSONMakeCPUModel(model_name, 0, NULL, migratable))) goto cleanup;
- if (virJSONValueObjectAppendString(model, "name", model_name) < 0) - goto cleanup; - - if (!migratable) { - if (!(props = virJSONValueNewObject()) || - virJSONValueObjectAppendBoolean(props, "migratable", false) < 0 || - virJSONValueObjectAppend(model, "props", props) < 0) - goto cleanup; - props = NULL; - } - retry: switch (type) { case QEMU_MONITOR_CPU_MODEL_EXPANSION_STATIC: @@ -5573,11 +5674,9 @@ qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon,
data = virJSONValueObjectGetObject(reply, "return");
- if (!(cpu_model = virJSONValueObjectGetObject(data, "model"))) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("query-cpu-model-expansion reply data was missing 'model'")); + if (qemuMonitorJSONParseCPUModelData(data, &cpu_model, &cpu_props, &cpu_name, + "query-cpu-model-expansion") < 0) goto cleanup; - }
/* QEMU_MONITOR_CPU_MODEL_EXPANSION_STATIC_FULL requests "full" expansion * on the result of the initial "static" expansion. @@ -5592,42 +5691,12 @@ qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon, goto retry; }
- if (!(cpu_name = virJSONValueObjectGetString(cpu_model, "name"))) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("query-cpu-model-expansion reply data was missing 'name'")); - goto cleanup; - } - - if (!(cpu_props = virJSONValueObjectGetObject(cpu_model, "props"))) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("query-cpu-model-expansion reply data was missing 'props'")); - goto cleanup; - } - - if (VIR_ALLOC(machine_model) < 0) - goto cleanup; - - if (VIR_STRDUP(machine_model->name, cpu_name) < 0) - goto cleanup; - - if (VIR_ALLOC_N(machine_model->props, virJSONValueObjectKeysNumber(cpu_props)) < 0) - goto cleanup; - - if (virJSONValueObjectForeachKeyValue(cpu_props, - qemuMonitorJSONParseCPUModelProperty, - machine_model) < 0) - goto cleanup; - - ret = 0; - *model_info = machine_model; - machine_model = NULL; + ret = qemuMonitorJSONParseCPUModel(cpu_name, cpu_props, model_info);
cleanup: - qemuMonitorCPUModelInfoFree(machine_model); virJSONValueFree(cmd); virJSONValueFree(reply); virJSONValueFree(model); - virJSONValueFree(props); return ret; }

Interfaces with QEMU to baseline CPU models. The command takes two CPU models, A and B, that are given a model name and an optional list of CPU features. Through the query-cpu-model-baseline command issued via QMP, a result is produced that contains a new baselined CPU model that is guaranteed to run on both A and B. Signed-off-by: Collin Walling <walling@linux.ibm.com> Reviewed-by: Daniel Henrique Barboza <danielh413@gmail.com> --- src/qemu/qemu_monitor.c | 22 ++++++++++++++++ src/qemu/qemu_monitor.h | 9 +++++++ src/qemu/qemu_monitor_json.c | 61 ++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 10 ++++++++ 4 files changed, 102 insertions(+) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 6b731cd..13ec623 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -3685,6 +3685,28 @@ qemuMonitorGetCPUModelExpansion(qemuMonitorPtr mon, } +int +qemuMonitorGetCPUModelBaseline(qemuMonitorPtr mon, + const char *model_a_name, + int model_a_nprops, + virCPUFeatureDefPtr model_a_props, + const char *model_b_name, + int model_b_nprops, + virCPUFeatureDefPtr model_b_props, + qemuMonitorCPUModelInfoPtr *model_result) +{ + VIR_DEBUG("model_a_name=%s model_a_nprops=%d model_b_name=%s model_b_nprops=%d", + model_a_name, model_a_nprops, model_b_name, model_b_nprops); + + QEMU_CHECK_MONITOR(mon); + + return qemuMonitorJSONGetCPUModelBaseline(mon, model_a_name, model_a_nprops, + model_a_props, model_b_name, + model_b_nprops, model_b_props, + model_result); +} + + void qemuMonitorCPUModelInfoFree(qemuMonitorCPUModelInfoPtr model_info) { diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index dee594f..6ab28c3 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1067,6 +1067,15 @@ int qemuMonitorGetCPUModelExpansion(qemuMonitorPtr mon, void qemuMonitorCPUModelInfoFree(qemuMonitorCPUModelInfoPtr model_info); +int qemuMonitorGetCPUModelBaseline(qemuMonitorPtr mon, + const char *model_a_name, + int model_a_nprops, + virCPUFeatureDefPtr model_a_props, + const char *model_b_name, + int model_b_nprops, + virCPUFeatureDefPtr model_b_props, + qemuMonitorCPUModelInfoPtr *model_result); + qemuMonitorCPUModelInfoPtr qemuMonitorCPUModelInfoCopy(const qemuMonitorCPUModelInfo *orig); diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 08c734c..a75646c 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -5701,6 +5701,67 @@ qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon, } +int +qemuMonitorJSONGetCPUModelBaseline(qemuMonitorPtr mon, + const char *model_a_name, + int model_a_nprops, + virCPUFeatureDefPtr model_a_props, + const char *model_b_name, + int model_b_nprops, + virCPUFeatureDefPtr model_b_props, + qemuMonitorCPUModelInfoPtr *model_result) +{ + int ret = -1; + virJSONValuePtr model_a; + virJSONValuePtr model_b = NULL; + virJSONValuePtr cmd = NULL; + virJSONValuePtr reply = NULL; + virJSONValuePtr data; + virJSONValuePtr cpu_model; + virJSONValuePtr cpu_props = NULL; + const char *cpu_name = ""; + qemuMonitorCPUModelInfoPtr baseline = NULL; + + if (!(model_a = qemuMonitorJSONMakeCPUModel(model_a_name, model_a_nprops, + model_a_props, true)) || + !(model_b = qemuMonitorJSONMakeCPUModel(model_b_name, model_b_nprops, + model_b_props, true))) + goto cleanup; + + if (!(cmd = qemuMonitorJSONMakeCommand("query-cpu-model-baseline", + "a:modela", &model_a, + "a:modelb", &model_b, + NULL))) + goto cleanup; + + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) + goto cleanup; + + if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_OBJECT) < 0) + goto cleanup; + + data = virJSONValueObjectGetObject(reply, "return"); + + if (qemuMonitorJSONParseCPUModelData(data, &cpu_model, &cpu_props, &cpu_name, + "query-cpu-model-baseline") < 0) + goto cleanup; + + if (qemuMonitorJSONParseCPUModel(cpu_name, cpu_props, &baseline) < 0) + goto cleanup; + + VIR_STEAL_PTR(*model_result, baseline); + ret = 0; + + cleanup: + qemuMonitorCPUModelInfoFree(baseline); + virJSONValueFree(cmd); + virJSONValueFree(reply); + virJSONValueFree(model_a); + virJSONValueFree(model_b); + return ret; +} + + int qemuMonitorJSONGetCommands(qemuMonitorPtr mon, char ***commands) { diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index acef1a0..5bd7275 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -368,6 +368,16 @@ int qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon, qemuMonitorCPUModelInfoPtr *model_info) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(5); +int qemuMonitorJSONGetCPUModelBaseline(qemuMonitorPtr mon, + const char *model_a_name, + int model_a_nprops, + virCPUFeatureDefPtr model_a_props, + const char *model_b_name, + int model_b_nprops, + virCPUFeatureDefPtr model_b_props, + qemuMonitorCPUModelInfoPtr *model_result) + ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(5) ATTRIBUTE_NONNULL(8); + int qemuMonitorJSONGetCommands(qemuMonitorPtr mon, char ***commands) ATTRIBUTE_NONNULL(2); -- 2.7.4

This capability enables CPU model baselining between two CPU definitions via QMP. Signed-off-by: Collin Walling <walling@linux.ibm.com> Reviewed-by: Daniel Henrique Barboza <danielh413@gmail.com> --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_3.0.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_4.0.0.s390x.xml | 1 + 9 files changed, 10 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index a827bd2..5cbcf64 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -525,6 +525,7 @@ VIR_ENUM_IMPL(virQEMUCaps, "virtio-pci-non-transitional", "overcommit", "query-current-machine", + "query-cpu-model-baseline", ); @@ -971,6 +972,7 @@ struct virQEMUCapsStringFlags virQEMUCapsCommands[] = { { "qom-list-properties", QEMU_CAPS_QOM_LIST_PROPERTIES }, { "blockdev-del", QEMU_CAPS_BLOCKDEV_DEL }, { "query-current-machine", QEMU_CAPS_QUERY_CURRENT_MACHINE }, + { "query-cpu-model-baseline", QEMU_CAPS_QUERY_CPU_MODEL_BASELINE }, }; struct virQEMUCapsStringFlags virQEMUCapsMigration[] = { diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 67c8e80..102f259 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -507,6 +507,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ QEMU_CAPS_VIRTIO_PCI_TRANSITIONAL, /* virtio *-pci-{non-}transitional devices */ QEMU_CAPS_OVERCOMMIT, /* -overcommit */ QEMU_CAPS_QUERY_CURRENT_MACHINE, /* query-current-machine command */ + QEMU_CAPS_QUERY_CPU_MODEL_BASELINE, /* qmp query-cpu-model-baseline */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; diff --git a/tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml index 21b918f..e6f7e28 100644 --- a/tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml @@ -103,6 +103,7 @@ <flag name='egl-headless'/> <flag name='zpci'/> <flag name='iothread.poll-max-ns'/> + <flag name='query-cpu-model-baseline'/> <version>2010000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>39100805</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml index 6cb997d..48d7742 100644 --- a/tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml @@ -110,6 +110,7 @@ <flag name='egl-headless'/> <flag name='zpci'/> <flag name='iothread.poll-max-ns'/> + <flag name='query-cpu-model-baseline'/> <version>2011000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>39100806</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml index 2930381..381abd5 100644 --- a/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml @@ -121,6 +121,7 @@ <flag name='memory-backend-memfd.hugetlb'/> <flag name='iothread.poll-max-ns'/> <flag name='memory-backend-file.align'/> + <flag name='query-cpu-model-baseline'/> <version>2012000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>39100807</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml index 5a2b740..9516a3b 100644 --- a/tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml @@ -92,6 +92,7 @@ <flag name='sdl-gl'/> <flag name='vhost-vsock'/> <flag name='zpci'/> + <flag name='query-cpu-model-baseline'/> <version>2007093</version> <kvmVersion>0</kvmVersion> <microcodeVersion>39100764</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml index 72ae100..cf8bbb2 100644 --- a/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml @@ -97,6 +97,7 @@ <flag name='vhost-vsock'/> <flag name='zpci'/> <flag name='iothread.poll-max-ns'/> + <flag name='query-cpu-model-baseline'/> <version>2009000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>39100765</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_3.0.0.s390x.xml b/tests/qemucapabilitiesdata/caps_3.0.0.s390x.xml index d511377..40b4a2b 100644 --- a/tests/qemucapabilitiesdata/caps_3.0.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_3.0.0.s390x.xml @@ -123,6 +123,7 @@ <flag name='memory-backend-memfd.hugetlb'/> <flag name='iothread.poll-max-ns'/> <flag name='memory-backend-file.align'/> + <flag name='query-cpu-model-baseline'/> <version>3000000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>39100757</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_4.0.0.s390x.xml b/tests/qemucapabilitiesdata/caps_4.0.0.s390x.xml index 8cb537e..e37c2f3 100644 --- a/tests/qemucapabilitiesdata/caps_4.0.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_4.0.0.s390x.xml @@ -129,6 +129,7 @@ <flag name='virtio-pci-non-transitional'/> <flag name='overcommit'/> <flag name='query-current-machine'/> + <flag name='query-cpu-model-baseline'/> <version>4000000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>39100758</microcodeVersion> -- 2.7.4

This command is hooked into the virsh hypervisor-cpu-baseline command. As such, the CPU models provided in the XML sent to the command will be baselined with the CPU contained in the QEMU capabilities file for the appropriate QEMU binary (for s390x, this CPU definition can be observed via virsh domcapabilities). Signed-off-by: Collin Walling <walling@linux.ibm.com> Reviewed-by: Daniel Henrique Barboza <danielh413@gmail.com> --- src/qemu/qemu_capabilities.c | 84 ++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_capabilities.h | 7 ++++ src/qemu/qemu_driver.c | 27 ++++++++++++++ 3 files changed, 118 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 5cbcf64..71f4f4e 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -5446,3 +5446,87 @@ virQEMUCapsStripMachineAliases(virQEMUCapsPtr qemuCaps) for (i = 0; i < qemuCaps->nmachineTypes; i++) VIR_FREE(qemuCaps->machineTypes[i].alias); } + + +static int +virQEMUCapsStealCPUModelFromInfo(virCPUDefPtr dst, + qemuMonitorCPUModelInfoPtr *src) +{ + qemuMonitorCPUModelInfoPtr info = *src; + size_t i; + + virCPUDefFreeModel(dst); + + VIR_STEAL_PTR(dst->model, info->name); + + for (i = 0; i < info->nprops; i++) { + char *name = info->props[i].name; + int policy = VIR_CPU_FEATURE_REQUIRE; + + if (info->props[i].type == QEMU_MONITOR_CPU_PROPERTY_BOOLEAN && + !info->props[i].value.boolean) + policy = VIR_CPU_FEATURE_DISABLE; + + if (virCPUDefAddFeature(dst, name, policy) < 0) + goto error; + } + + qemuMonitorCPUModelInfoFree(info); + *src = NULL; + return 0; + + error: + virCPUDefFree(dst); + return -1; +} + + +virCPUDefPtr +virQEMUCapsCPUModelBaseline(virQEMUCapsPtr qemuCaps, + const char *libDir, + uid_t runUid, + gid_t runGid, + int ncpus, + virCPUDefPtr *cpus) +{ + qemuMonitorCPUModelInfoPtr result = NULL; + qemuProcessQMPPtr proc = NULL; + virCPUDefPtr cpu = NULL; + virCPUDefPtr baseline = NULL; + size_t i; + + if (VIR_ALLOC(cpu) < 0) + goto cleanup; + + if (virCPUDefCopyModel(cpu, cpus[0], false)) + goto cleanup; + + if (!(proc = qemuProcessQMPNew(qemuCaps->binary, libDir, + runUid, runGid, false))) + goto cleanup; + + if (qemuProcessQMPStart(proc) < 0) + goto cleanup; + + for (i = 1; i < ncpus; i++) { + if (qemuMonitorGetCPUModelBaseline(proc->mon, cpu->model, + cpu->nfeatures, cpu->features, + cpus[i]->model, cpus[i]->nfeatures, + cpus[i]->features, &result) < 0) + goto cleanup; + + if (virQEMUCapsStealCPUModelFromInfo(cpu, &result) < 0) + goto cleanup; + } + + VIR_STEAL_PTR(baseline, cpu); + + cleanup: + if (!baseline) + virQEMUCapsLogProbeFailure(qemuCaps->binary); + + qemuMonitorCPUModelInfoFree(result); + qemuProcessQMPFree(proc); + virCPUDefFree(cpu); + return baseline; +} diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 102f259..08fd555 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -648,4 +648,11 @@ virQEMUCapsGetSEVCapabilities(virQEMUCapsPtr qemuCaps); virArch virQEMUCapsArchFromString(const char *arch); const char *virQEMUCapsArchToString(virArch arch); +virCPUDefPtr virQEMUCapsCPUModelBaseline(virQEMUCapsPtr qemuCaps, + const char *libDir, + uid_t runUid, + gid_t runGid, + int ncpus, + virCPUDefPtr *cpus); + #endif /* LIBVIRT_QEMU_CAPABILITIES_H */ diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 42b1ce2..9750962 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -13573,6 +13573,7 @@ qemuConnectBaselineHypervisorCPU(virConnectPtr conn, unsigned int flags) { virQEMUDriverPtr driver = conn->privateData; + virQEMUDriverConfigPtr config = driver->config; virCPUDefPtr *cpus = NULL; virQEMUCapsPtr qemuCaps = NULL; virArch arch; @@ -13627,6 +13628,32 @@ qemuConnectBaselineHypervisorCPU(virConnectPtr conn, if (!(cpu = virCPUBaseline(arch, cpus, ncpus, cpuModels, (const char **)features, migratable))) goto cleanup; + } else if (ARCH_IS_S390(arch) && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_QUERY_CPU_MODEL_BASELINE)) { + /* Add a copy of the hypervisor CPU to the list */ + virCPUDefPtr hvCPU, tmp; + size_t allocated = ncpus + 1; + + hvCPU = virQEMUCapsGetHostModel(qemuCaps, virttype, + VIR_QEMU_CAPS_HOST_CPU_REPORTED); + if (VIR_ALLOC(tmp) < 0) + goto cleanup; + + if (virCPUDefCopyModel(tmp, hvCPU, false)) + goto cleanup; + + if (VIR_INSERT_ELEMENT(cpus, ncpus, allocated, tmp) < 0) + goto cleanup; + + ncpus++; + + if (!(cpu = virQEMUCapsCPUModelBaseline(qemuCaps, config->libDir, + config->user, config->group, + ncpus, cpus))) + goto cleanup; + + if (!(flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES)) + virCPUDefFreeFeatures(cpu); } else { virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("computing baseline hypervisor CPU is not supported " -- 2.7.4

Interfaces with QEMU to compare CPU models. The command takes two CPU models, A and B, that are given a model name and an optional list of CPU features. Through the query-cpu-model-comparison command issued via QMP, a result is produced that contains the comparison evaluation string (identical, superset, subset, incompatible) as well as a list of properties (aka CPU features) responsible for the subset or superset result. Signed-off-by: Collin Walling <walling@linux.ibm.com> Reviewed-by: Daniel Henrique Barboza <danielh413@gmail.com> --- src/qemu/qemu_monitor.c | 22 ++++++++++ src/qemu/qemu_monitor.h | 9 +++++ src/qemu/qemu_monitor_json.c | 95 ++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 10 +++++ 4 files changed, 136 insertions(+) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 13ec623..68ac0c8 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -3707,6 +3707,28 @@ qemuMonitorGetCPUModelBaseline(qemuMonitorPtr mon, } +int +qemuMonitorGetCPUModelComparison(qemuMonitorPtr mon, + const char *model_a_name, + int model_a_nprops, + virCPUFeatureDefPtr model_a_props, + const char *model_b_name, + int model_b_nprops, + virCPUFeatureDefPtr model_b_props, + qemuMonitorCPUModelInfoPtr *model_result) +{ + VIR_DEBUG("model_a_name=%s model_a_nprops=%d model_b_name=%s model_b_nprops=%d", + model_a_name, model_a_nprops, model_b_name, model_b_nprops); + + QEMU_CHECK_MONITOR(mon); + + return qemuMonitorJSONGetCPUModelComparison(mon, model_a_name, model_a_nprops, + model_a_props, model_b_name, + model_b_nprops, model_b_props, + model_result); +} + + void qemuMonitorCPUModelInfoFree(qemuMonitorCPUModelInfoPtr model_info) { diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 6ab28c3..891476a 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1076,6 +1076,15 @@ int qemuMonitorGetCPUModelBaseline(qemuMonitorPtr mon, virCPUFeatureDefPtr model_b_props, qemuMonitorCPUModelInfoPtr *model_result); +int qemuMonitorGetCPUModelComparison(qemuMonitorPtr mon, + const char *model_a_name, + int model_a_nprops, + virCPUFeatureDefPtr model_a_props, + const char *model_b_name, + int model_b_nprops, + virCPUFeatureDefPtr model_b_props, + qemuMonitorCPUModelInfoPtr *model_result); + qemuMonitorCPUModelInfoPtr qemuMonitorCPUModelInfoCopy(const qemuMonitorCPUModelInfo *orig); diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index a75646c..36fe7fb 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -5762,6 +5762,101 @@ qemuMonitorJSONGetCPUModelBaseline(qemuMonitorPtr mon, } +static int +qemuMonitorJSONParseCPUModelPropName(size_t pos ATTRIBUTE_UNUSED, + virJSONValuePtr item, + void *opaque) +{ + if (!qemuMonitorJSONParseCPUModelProperty(virJSONValueGetString(item), + item, opaque)) + return -1; + + virJSONValueFree(item); + return 0; +} + + +int +qemuMonitorJSONGetCPUModelComparison(qemuMonitorPtr mon, + const char *model_a_name, + int model_a_nprops, + virCPUFeatureDefPtr model_a_props, + const char *model_b_name, + int model_b_nprops, + virCPUFeatureDefPtr model_b_props, + qemuMonitorCPUModelInfoPtr *model_result) +{ + int ret = -1; + virJSONValuePtr model_a; + virJSONValuePtr model_b = NULL; + virJSONValuePtr cmd = NULL; + virJSONValuePtr reply = NULL; + virJSONValuePtr data; + const char *result_name; + virJSONValuePtr props; + qemuMonitorCPUModelInfoPtr compare = NULL; + + if (!(model_a = qemuMonitorJSONMakeCPUModel(model_a_name, model_a_nprops, + model_a_props, true)) || + !(model_b = qemuMonitorJSONMakeCPUModel(model_b_name, model_b_nprops, + model_b_props, true))) + goto cleanup; + + if (!(cmd = qemuMonitorJSONMakeCommand("query-cpu-model-comparison", + "a:modela", &model_a, + "a:modelb", &model_b, + NULL))) + goto cleanup; + + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) + goto cleanup; + + if (qemuMonitorJSONCheckError(cmd, reply) < 0) + goto cleanup; + + data = virJSONValueObjectGetObject(reply, "return"); + + if (!(result_name = virJSONValueObjectGetString(data, "result"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-cpu-model-comparison reply data was missing " + "'result'")); + goto cleanup; + } + + if (!(props = virJSONValueObjectGetArray(data, "responsible-properties"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-cpu-model-comparison reply data was missing " + "'responsible-properties'")); + goto cleanup; + } + + if (VIR_ALLOC(compare) < 0) + goto cleanup; + + if (VIR_STRDUP(compare->name, result_name) < 0) + goto cleanup; + + if (VIR_ALLOC_N(compare->props, virJSONValueArraySize(props)) < 0) + goto cleanup; + + if (virJSONValueArrayForeachSteal(props, + qemuMonitorJSONParseCPUModelPropName, + compare) < 0) + goto cleanup; + + VIR_STEAL_PTR(*model_result, compare); + ret = 0; + + cleanup: + qemuMonitorCPUModelInfoFree(compare); + virJSONValueFree(cmd); + virJSONValueFree(reply); + virJSONValueFree(model_a); + virJSONValueFree(model_b); + return ret; +} + + int qemuMonitorJSONGetCommands(qemuMonitorPtr mon, char ***commands) { diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 5bd7275..1877598 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -378,6 +378,16 @@ int qemuMonitorJSONGetCPUModelBaseline(qemuMonitorPtr mon, qemuMonitorCPUModelInfoPtr *model_result) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(5) ATTRIBUTE_NONNULL(8); +int qemuMonitorJSONGetCPUModelComparison(qemuMonitorPtr mon, + const char *model_a_name, + int model_a_nprops, + virCPUFeatureDefPtr model_a_props, + const char *model_b_name, + int model_b_nprops, + virCPUFeatureDefPtr model_b_props, + qemuMonitorCPUModelInfoPtr *model_result) + ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(5) ATTRIBUTE_NONNULL(8); + int qemuMonitorJSONGetCommands(qemuMonitorPtr mon, char ***commands) ATTRIBUTE_NONNULL(2); -- 2.7.4

This capability enables CPU model comparison between two CPU definitions via QMP. Signed-off-by: Collin Walling <walling@linux.ibm.com> Reviewed-by: Daniel Henrique Barboza <danielh413@gmail.com> --- src/qemu/qemu_capabilities.c | 4 ++++ src/qemu/qemu_capabilities.h | 3 +++ tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_3.0.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_4.0.0.s390x.xml | 1 + 9 files changed, 14 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 71f4f4e..8efc6d6 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -526,6 +526,9 @@ VIR_ENUM_IMPL(virQEMUCaps, "overcommit", "query-current-machine", "query-cpu-model-baseline", + + /* 330 */ + "query-cpu-model-comparison", ); @@ -973,6 +976,7 @@ struct virQEMUCapsStringFlags virQEMUCapsCommands[] = { { "blockdev-del", QEMU_CAPS_BLOCKDEV_DEL }, { "query-current-machine", QEMU_CAPS_QUERY_CURRENT_MACHINE }, { "query-cpu-model-baseline", QEMU_CAPS_QUERY_CPU_MODEL_BASELINE }, + { "query-cpu-model-comparison", QEMU_CAPS_QUERY_CPU_MODEL_COMPARISON }, }; struct virQEMUCapsStringFlags virQEMUCapsMigration[] = { diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 08fd555..47612e9 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -509,6 +509,9 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ QEMU_CAPS_QUERY_CURRENT_MACHINE, /* query-current-machine command */ QEMU_CAPS_QUERY_CPU_MODEL_BASELINE, /* qmp query-cpu-model-baseline */ + /* 330 */ + QEMU_CAPS_QUERY_CPU_MODEL_COMPARISON, /* qmp query-cpu-model-comparison */ + QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; diff --git a/tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml index e6f7e28..058eb32 100644 --- a/tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml @@ -104,6 +104,7 @@ <flag name='zpci'/> <flag name='iothread.poll-max-ns'/> <flag name='query-cpu-model-baseline'/> + <flag name='query-cpu-model-comparison'/> <version>2010000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>39100805</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml index 48d7742..4256131 100644 --- a/tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml @@ -111,6 +111,7 @@ <flag name='zpci'/> <flag name='iothread.poll-max-ns'/> <flag name='query-cpu-model-baseline'/> + <flag name='query-cpu-model-comparison'/> <version>2011000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>39100806</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml index 381abd5..48be96d 100644 --- a/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml @@ -122,6 +122,7 @@ <flag name='iothread.poll-max-ns'/> <flag name='memory-backend-file.align'/> <flag name='query-cpu-model-baseline'/> + <flag name='query-cpu-model-comparison'/> <version>2012000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>39100807</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml index 9516a3b..5b04416 100644 --- a/tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml @@ -93,6 +93,7 @@ <flag name='vhost-vsock'/> <flag name='zpci'/> <flag name='query-cpu-model-baseline'/> + <flag name='query-cpu-model-comparison'/> <version>2007093</version> <kvmVersion>0</kvmVersion> <microcodeVersion>39100764</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml index cf8bbb2..d5feb7b 100644 --- a/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml @@ -98,6 +98,7 @@ <flag name='zpci'/> <flag name='iothread.poll-max-ns'/> <flag name='query-cpu-model-baseline'/> + <flag name='query-cpu-model-comparison'/> <version>2009000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>39100765</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_3.0.0.s390x.xml b/tests/qemucapabilitiesdata/caps_3.0.0.s390x.xml index 40b4a2b..27befc4 100644 --- a/tests/qemucapabilitiesdata/caps_3.0.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_3.0.0.s390x.xml @@ -124,6 +124,7 @@ <flag name='iothread.poll-max-ns'/> <flag name='memory-backend-file.align'/> <flag name='query-cpu-model-baseline'/> + <flag name='query-cpu-model-comparison'/> <version>3000000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>39100757</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_4.0.0.s390x.xml b/tests/qemucapabilitiesdata/caps_4.0.0.s390x.xml index e37c2f3..b5ec1a4 100644 --- a/tests/qemucapabilitiesdata/caps_4.0.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_4.0.0.s390x.xml @@ -130,6 +130,7 @@ <flag name='overcommit'/> <flag name='query-current-machine'/> <flag name='query-cpu-model-baseline'/> + <flag name='query-cpu-model-comparison'/> <version>4000000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>39100758</microcodeVersion> -- 2.7.4

Implement an XML to virCPUDefPtr helper that handles the ctxt prerequisite for virCPUDefParseXML. This does not alter any functionality. Signed-off-by: Collin Walling <walling@linux.ibm.com> Reviewed-by: Bjoern Walk <bwalk@linux.ibm.com> Reviewed-by: Daniel Henrique Barboza <danielh413@gmail.com> --- src/conf/cpu_conf.c | 30 ++++++++++++++++++++++++++++++ src/conf/cpu_conf.h | 6 ++++++ src/cpu/cpu.c | 14 +------------- src/libvirt_private.syms | 1 + 4 files changed, 38 insertions(+), 13 deletions(-) diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c index bd2beab..d5f6fa1 100644 --- a/src/conf/cpu_conf.c +++ b/src/conf/cpu_conf.c @@ -260,6 +260,36 @@ virCPUDefCopy(const virCPUDef *cpu) } +int +virCPUDefParseXMLHelper(const char *xml, + const char *xpath, + virCPUType type, + virCPUDefPtr *cpu) +{ + xmlDocPtr doc = NULL; + xmlXPathContextPtr ctxt = NULL; + int ret = -1; + + if (!xml) { + virReportError(VIR_ERR_INVALID_ARG, "%s", _("missing CPU definition")); + goto cleanup; + } + + if (!(doc = virXMLParseStringCtxt(xml, _("(CPU_definition)"), &ctxt))) + goto cleanup; + + if (virCPUDefParseXML(ctxt, xpath, type, cpu) < 0) + goto cleanup; + + ret = 0; + + cleanup: + xmlFreeDoc(doc); + xmlXPathFreeContext(ctxt); + return ret; +} + + /* * Parses CPU definition XML from a node pointed to by @xpath. If @xpath is * NULL, the current node of @ctxt is used (i.e., it is a shortcut to "."). diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h index c98db65..8d06b6f 100644 --- a/src/conf/cpu_conf.h +++ b/src/conf/cpu_conf.h @@ -182,6 +182,12 @@ virCPUDefPtr virCPUDefCopyWithoutModel(const virCPUDef *cpu); int +virCPUDefParseXMLHelper(const char *xml, + const char *xpath, + virCPUType type, + virCPUDefPtr *cpu); + +int virCPUDefParseXML(xmlXPathContextPtr ctxt, const char *xpath, virCPUType mode, diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index a223ff0..6eca956 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -111,31 +111,19 @@ virCPUCompareXML(virArch arch, const char *xml, bool failIncompatible) { - xmlDocPtr doc = NULL; - xmlXPathContextPtr ctxt = NULL; virCPUDefPtr cpu = NULL; virCPUCompareResult ret = VIR_CPU_COMPARE_ERROR; VIR_DEBUG("arch=%s, host=%p, xml=%s", virArchToString(arch), host, NULLSTR(xml)); - if (!xml) { - virReportError(VIR_ERR_INVALID_ARG, "%s", _("missing CPU definition")); - goto cleanup; - } - - if (!(doc = virXMLParseStringCtxt(xml, _("(CPU_definition)"), &ctxt))) - goto cleanup; - - if (virCPUDefParseXML(ctxt, NULL, VIR_CPU_TYPE_AUTO, &cpu) < 0) + if (virCPUDefParseXMLHelper(xml, NULL, VIR_CPU_TYPE_AUTO, &cpu) < 0) goto cleanup; ret = virCPUCompare(arch, host, cpu, failIncompatible); cleanup: virCPUDefFree(cpu); - xmlXPathFreeContext(ctxt); - xmlFreeDoc(doc); return ret; } diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 9099757..1d149b9 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -88,6 +88,7 @@ virCPUDefIsEqual; virCPUDefListFree; virCPUDefListParse; virCPUDefParseXML; +virCPUDefParseXMLHelper; virCPUDefStealModel; virCPUDefUpdateFeature; virCPUModeTypeToString; -- 2.7.4

This command is hooked into the virsh hypervisor-cpu-compare command. As such, the CPU model XML provided to the command will be compared to the hypervisor CPU contained in the QEMU capabilities file for the appropriate QEMU binary (for s390x, this CPU definition can be observed via virsh domcapabilities). s390x can report that the first model (A) is a subset of the second (B). If A is the hypervisor CPU and a subset of B (the CPU contained in the XML), then B would not be able to run on this machine and thus we will report that CPU model B is incompatible. Signed-off-by: Collin Walling <walling@linux.ibm.com> Reviewed-by: Daniel Henrique Barboza <danielh413@gmail.com> --- src/qemu/qemu_capabilities.c | 48 ++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_capabilities.h | 9 +++++++++ src/qemu/qemu_driver.c | 11 ++++++++++ 3 files changed, 68 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 8efc6d6..4970a1e 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -5534,3 +5534,51 @@ virQEMUCapsCPUModelBaseline(virQEMUCapsPtr qemuCaps, virCPUDefFree(cpu); return baseline; } + +virCPUCompareResult +virQEMUCapsCPUModelComparison(virQEMUCapsPtr qemuCaps, + const char *libDir, + uid_t runUid, + gid_t runGid, + virCPUDefPtr cpu_a, + virCPUDefPtr cpu_b, + bool failIncompatible) +{ + qemuProcessQMPPtr proc = NULL; + qemuMonitorCPUModelInfoPtr result = NULL; + int ret = -1; + + if (!(proc = qemuProcessQMPNew(qemuCaps->binary, libDir, + runUid, runGid, false))) + goto cleanup; + + if (qemuProcessQMPStart(proc) < 0) + goto cleanup; + + if (qemuMonitorGetCPUModelComparison(proc->mon, cpu_a->model, + cpu_a->nfeatures, cpu_a->features, + cpu_b->model, cpu_b->nfeatures, + cpu_b->features, &result) < 0) + goto cleanup; + + if (STREQ(result->name, "incompatible") || + STREQ(result->name, "subset")) + ret = VIR_CPU_COMPARE_INCOMPATIBLE; + else if (STREQ(result->name, "identical")) + ret = VIR_CPU_COMPARE_IDENTICAL; + else if (STREQ(result->name, "superset")) + ret = VIR_CPU_COMPARE_SUPERSET; + + if (failIncompatible && ret == VIR_CPU_COMPARE_INCOMPATIBLE) { + ret = VIR_CPU_COMPARE_ERROR; + virReportError(VIR_ERR_CPU_INCOMPATIBLE, NULL); + } + + cleanup: + if (ret < 0) + virQEMUCapsLogProbeFailure(qemuCaps->binary); + + qemuMonitorCPUModelInfoFree(result); + qemuProcessQMPFree(proc); + return ret; +} diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 47612e9..01aecc0 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -658,4 +658,13 @@ virCPUDefPtr virQEMUCapsCPUModelBaseline(virQEMUCapsPtr qemuCaps, int ncpus, virCPUDefPtr *cpus); +virCPUCompareResult +virQEMUCapsCPUModelComparison(virQEMUCapsPtr qemuCaps, + const char *libDir, + uid_t runUid, + gid_t runGid, + virCPUDefPtr cpu_a, + virCPUDefPtr cpu_b, + bool failIncompatible); + #endif /* LIBVIRT_QEMU_CAPABILITIES_H */ diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 9750962..a33648f 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -13466,9 +13466,11 @@ qemuConnectCompareHypervisorCPU(virConnectPtr conn, { int ret = VIR_CPU_COMPARE_ERROR; virQEMUDriverPtr driver = conn->privateData; + virQEMUDriverConfigPtr config = driver->config; virQEMUCapsPtr qemuCaps = NULL; bool failIncompatible; virCPUDefPtr hvCPU; + virCPUDefPtr cpu; virArch arch; virDomainVirtType virttype; @@ -13503,6 +13505,14 @@ qemuConnectCompareHypervisorCPU(virConnectPtr conn, if (ARCH_IS_X86(arch)) { ret = virCPUCompareXML(arch, hvCPU, xmlCPU, failIncompatible); + } else if (ARCH_IS_S390(arch) && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_QUERY_CPU_MODEL_COMPARISON)) { + if (virCPUDefParseXMLHelper(xmlCPU, NULL, VIR_CPU_TYPE_AUTO, &cpu) < 0) + goto cleanup; + + ret = virQEMUCapsCPUModelComparison(qemuCaps, config->libDir, + config->user, config->group, + hvCPU, cpu, failIncompatible); } else { virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("comparing with the hypervisor CPU is not supported " @@ -13510,6 +13520,7 @@ qemuConnectCompareHypervisorCPU(virConnectPtr conn, } cleanup: + virCPUDefFree(cpu); virObjectUnref(qemuCaps); return ret; } -- 2.7.4

Polite ping. I'd like to at least make sure these patches are on the right track with what libvirt expects for these commands. :) On 5/30/19 10:23 AM, Collin Walling wrote:
Changelog:
v2 - numerous cleanups - removed "policy fix function" and now properly check for policy == -1 in the CPUDef -> JSON parser - resolved some memory leaks
- added string arg to qemuMonitorJSONParseCPUModelData for error message to print out proper command name
v1 - introduce baseline - split patches into small chunks - free'd lingering qemuMonitorCPUModelInfo pointer - when converting from virCPUDef -> virJSON, consider feature policy FORCED for enabled
___
To run these patches, execute the virsh hypervisor-cpu-compare or hypervisor-cpu-baseline commands and pass an XML file describing one or more CPU definition. You can use the definition from virsh domcapabilities or from a guest XML. There is no need extract it from the file and place it a new one, as the XML parser will look specifically for the CPU tags.
___
These patches hookup the virsh hypervisor-cpu-compare/baseline commands for the s390x architecture. They take an XML file describing some CPU definitions and passes the data to QEMU, where the actual CPU model comparison / baseline calculation is handled (available since QEMU 2.8.5). These calculations are compared against / baselined with the hypervisor CPU model, which can be observed via the virsh domcapabilities command for s390x.
When baselining CPU models and the user appends the --features argument to the command, s390x will only report back features that supersede the base model definition.
**NOTE** if the --features flag is intended to expand ALL features available to a CPU model (such as the huge list of features reported by a full CPU model expansion), please let me know and I can resolve this.
The first patch pulls some code out of the CPU Model Expansion JSON function so that it can be later used for the Comparison and Baseline JSON functions.
The rest of the patches follow this sequence: - introduce JSON monitor functions - introduce capability and update test files - hook up monitor functions to virsh command
Patch 7 pulls out some code from the CPUDef XML parser to be reused in the comparison hookup.
Thanks.
x86 and Power review by Daniel Henrique Barboza (thanks!)
Collin Walling (8): qemu_monitor: helper functions for CPU models qemu_monitor: implement query-cpu-model-baseline qemu_capabilities: introduce QEMU_CAPS_QUERY_CPU_MODEL_BASELINE qemu_driver: hook up query-cpu-model-baseline qemu_monitor: implement query-cpu-model-comparison qemu_capabilities: introduce QEMU_CAPS_QUERY_CPU_MODEL_COMPARISON cpu_conf: xml to cpu definition parse helper qemu_driver: hook up query-cpu-model-comparison
src/conf/cpu_conf.c | 30 +++ src/conf/cpu_conf.h | 6 + src/cpu/cpu.c | 14 +- src/libvirt_private.syms | 1 + src/qemu/qemu_capabilities.c | 138 +++++++++++ src/qemu/qemu_capabilities.h | 20 ++ src/qemu/qemu_driver.c | 38 +++ src/qemu/qemu_monitor.c | 44 ++++ src/qemu/qemu_monitor.h | 18 ++ src/qemu/qemu_monitor_json.c | 297 ++++++++++++++++++++--- src/qemu/qemu_monitor_json.h | 20 ++ tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml | 2 + tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml | 2 + tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml | 2 + tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml | 2 + tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml | 2 + tests/qemucapabilitiesdata/caps_3.0.0.s390x.xml | 2 + tests/qemucapabilitiesdata/caps_4.0.0.s390x.xml | 2 + 18 files changed, 591 insertions(+), 49 deletions(-)
participants (2)
-
Collin Walling
-
Daniel Henrique Barboza