[libvirt] [PATCH 00/22] New CPU related APIs

The current virConnectCompareCPU and virConnectBaselineCPU APIs are not very useful because they ignore what a hypervisor can do on the current host. This series adds two new APIs which are designed to work with capabilities of a specific hypervisor to provide usable results. The third CPU related API virConnectGetCPUModelNames is pretty useless too, but no new API with similar functionality is needed because domain capabilities XML already contains the relevant data. Jiri Denemark (22): virsh: Move cpu-{baseline,compare} commands virsh: Extract common code from cmdCPU{Compare,Baseline} virsh: Enhance documentation of cpu-compare command virsh: Enhance documentation of cpu-models command Improve documentation of virConnectGetCPUModelNames vshExtractCPUDefXML: Accept domain capabilities XML qemu_capabilities: Introduce virQEMUCapsCacheLookupDefault Introduce virConnectCompareHypervisorCPU public API remote: Implement virConnectCompareHypervisorCPU virsh: Introduce new hypervisor-cpu-compare command qemu: Implement virConnectCompareHypervisorCPU Introduce virConnectBaselineHypervisorCPU public API remote: Implement virConnectBaselineHypervisorCPU virsh: Introduce new hypervisor-cpu-baseline command cpu: Rename cpuBaseline as virCPUBaseline cpu_x86: Add support for passing guest CPUs to virCPUx86Baseline cpu: Add explicit arch parameter for virCPUBaseline cpu: Update style in virCPUBaseline cpu: Add optional list of allowed features to virCPUBaseline qemu_capabilities: Introduce virQEMUCapsGetCPUFeatures qemu: Implement virConnectBaselineHypervisorCPU news: Mention new CPU related APIs docs/news.xml | 9 + include/libvirt/libvirt-host.h | 15 ++ src/bhyve/bhyve_driver.c | 4 +- src/cpu/cpu.c | 34 ++- src/cpu/cpu.h | 21 +- src/cpu/cpu_arm.c | 11 +- src/cpu/cpu_ppc64.c | 5 +- src/cpu/cpu_x86.c | 35 ++- src/driver-hypervisor.h | 20 ++ src/libvirt-host.c | 161 +++++++++++- src/libvirt_private.syms | 2 +- src/libvirt_public.syms | 6 + src/libxl/libxl_driver.c | 4 +- src/qemu/qemu_capabilities.c | 170 +++++++++++++ src/qemu/qemu_capabilities.h | 12 + src/qemu/qemu_driver.c | 241 ++++++++++++------ src/remote/remote_driver.c | 4 +- src/remote/remote_protocol.x | 40 ++- src/remote_protocol-structs | 27 ++ src/test/test_driver.c | 2 +- src/vz/vz_driver.c | 2 +- tests/cputest.c | 6 +- tools/virsh-domain.c | 223 ----------------- tools/virsh-host.c | 441 +++++++++++++++++++++++++++++++++ tools/virsh.pod | 90 ++++++- 25 files changed, 1223 insertions(+), 362 deletions(-) -- 2.17.0

Similarly to cpu-models these two commands do not operate on a domain and should be listed in the "Host and Hypervisor" commands section. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh-domain.c | 223 ------------------------------------------ tools/virsh-host.c | 224 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 224 insertions(+), 223 deletions(-) diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 30da953446..3bb894a425 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -7672,217 +7672,6 @@ cmdIOThreadDel(vshControl *ctl, const vshCmd *cmd) return ret; } -/* - * "cpu-compare" command - */ -static const vshCmdInfo info_cpu_compare[] = { - {.name = "help", - .data = N_("compare host CPU with a CPU described by an XML file") - }, - {.name = "desc", - .data = N_("compare CPU with host CPU") - }, - {.name = NULL} -}; - -static const vshCmdOptDef opts_cpu_compare[] = { - VIRSH_COMMON_OPT_FILE(N_("file containing an XML CPU description")), - {.name = "error", - .type = VSH_OT_BOOL, - .help = N_("report error if CPUs are incompatible") - }, - {.name = NULL} -}; - -static bool -cmdCPUCompare(vshControl *ctl, const vshCmd *cmd) -{ - const char *from = NULL; - bool ret = false; - char *buffer; - int result; - char *snippet = NULL; - unsigned int flags = 0; - xmlDocPtr xml = NULL; - xmlXPathContextPtr ctxt = NULL; - xmlNodePtr node; - virshControlPtr priv = ctl->privData; - - if (vshCommandOptBool(cmd, "error")) - flags |= VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE; - - if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0) - return false; - - if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0) - return false; - - /* try to extract the CPU element from as it would appear in a domain XML*/ - if (!(xml = virXMLParseStringCtxt(buffer, from, &ctxt))) - goto cleanup; - - if ((node = virXPathNode("/cpu|" - "/domain/cpu|" - "/capabilities/host/cpu", ctxt))) { - if (!(snippet = virXMLNodeToString(xml, node))) { - vshSaveLibvirtError(); - goto cleanup; - } - } else { - vshError(ctl, _("File '%s' does not contain a <cpu> element or is not " - "a valid domain or capabilities XML"), from); - goto cleanup; - } - - result = virConnectCompareCPU(priv->conn, snippet, flags); - - switch (result) { - case VIR_CPU_COMPARE_INCOMPATIBLE: - vshPrint(ctl, _("CPU described in %s is incompatible with host CPU\n"), - from); - goto cleanup; - break; - - case VIR_CPU_COMPARE_IDENTICAL: - vshPrint(ctl, _("CPU described in %s is identical to host CPU\n"), - from); - break; - - case VIR_CPU_COMPARE_SUPERSET: - vshPrint(ctl, _("Host CPU is a superset of CPU described in %s\n"), - from); - break; - - case VIR_CPU_COMPARE_ERROR: - default: - vshError(ctl, _("Failed to compare host CPU with %s"), from); - goto cleanup; - } - - ret = true; - - cleanup: - VIR_FREE(buffer); - VIR_FREE(snippet); - xmlXPathFreeContext(ctxt); - xmlFreeDoc(xml); - - return ret; -} - -/* - * "cpu-baseline" command - */ -static const vshCmdInfo info_cpu_baseline[] = { - {.name = "help", - .data = N_("compute baseline CPU") - }, - {.name = "desc", - .data = N_("Compute baseline CPU for a set of given CPUs.") - }, - {.name = NULL} -}; - -static const vshCmdOptDef opts_cpu_baseline[] = { - VIRSH_COMMON_OPT_FILE(N_("file containing XML CPU descriptions")), - {.name = "features", - .type = VSH_OT_BOOL, - .help = N_("Show features that are part of the CPU model type") - }, - {.name = "migratable", - .type = VSH_OT_BOOL, - .help = N_("Do not include features that block migration") - }, - {.name = NULL} -}; - -static bool -cmdCPUBaseline(vshControl *ctl, const vshCmd *cmd) -{ - const char *from = NULL; - bool ret = false; - char *buffer; - char *result = NULL; - char **list = NULL; - unsigned int flags = 0; - int count = 0; - - xmlDocPtr xml = NULL; - xmlNodePtr *node_list = NULL; - xmlXPathContextPtr ctxt = NULL; - virBuffer buf = VIR_BUFFER_INITIALIZER; - size_t i; - virshControlPtr priv = ctl->privData; - - if (vshCommandOptBool(cmd, "features")) - flags |= VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES; - if (vshCommandOptBool(cmd, "migratable")) - flags |= VIR_CONNECT_BASELINE_CPU_MIGRATABLE; - - if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0) - return false; - - if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0) - return false; - - /* add a separate container around the xml */ - virBufferStrcat(&buf, "<container>", buffer, "</container>", NULL); - if (virBufferError(&buf)) - goto no_memory; - - VIR_FREE(buffer); - buffer = virBufferContentAndReset(&buf); - - - if (!(xml = virXMLParseStringCtxt(buffer, from, &ctxt))) - goto cleanup; - - if ((count = virXPathNodeSet("//cpu[not(ancestor::cpus)]", - ctxt, &node_list)) == -1) - goto cleanup; - - if (count == 0) { - vshError(ctl, _("No host CPU specified in '%s'"), from); - goto cleanup; - } - - list = vshCalloc(ctl, count, sizeof(const char *)); - - for (i = 0; i < count; i++) { - if (!(list[i] = virXMLNodeToString(xml, node_list[i]))) { - vshSaveLibvirtError(); - goto cleanup; - } - } - - result = virConnectBaselineCPU(priv->conn, - (const char **)list, count, flags); - - if (result) { - vshPrint(ctl, "%s", result); - ret = true; - } - - cleanup: - xmlXPathFreeContext(ctxt); - xmlFreeDoc(xml); - VIR_FREE(result); - if (list != NULL && count > 0) { - for (i = 0; i < count; i++) - VIR_FREE(list[i]); - } - VIR_FREE(list); - VIR_FREE(buffer); - VIR_FREE(node_list); - - return ret; - - no_memory: - vshError(ctl, "%s", _("Out of memory")); - ret = false; - goto cleanup; -} - /* * "cpu-stats" command */ @@ -13942,18 +13731,6 @@ const vshCmdDef domManagementCmds[] = { .flags = 0 }, #endif - {.name = "cpu-baseline", - .handler = cmdCPUBaseline, - .opts = opts_cpu_baseline, - .info = info_cpu_baseline, - .flags = 0 - }, - {.name = "cpu-compare", - .handler = cmdCPUCompare, - .opts = opts_cpu_compare, - .info = info_cpu_compare, - .flags = 0 - }, {.name = "cpu-stats", .handler = cmdCPUStats, .opts = opts_cpu_stats, diff --git a/tools/virsh-host.c b/tools/virsh-host.c index ecaf830e35..6d6e3cfc85 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -38,6 +38,7 @@ #include "virxml.h" #include "virtypedparam.h" #include "virstring.h" +#include "virfile.h" /* * "capabilities" command @@ -1105,6 +1106,217 @@ cmdURI(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) return true; } +/* + * "cpu-compare" command + */ +static const vshCmdInfo info_cpu_compare[] = { + {.name = "help", + .data = N_("compare host CPU with a CPU described by an XML file") + }, + {.name = "desc", + .data = N_("compare CPU with host CPU") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_cpu_compare[] = { + VIRSH_COMMON_OPT_FILE(N_("file containing an XML CPU description")), + {.name = "error", + .type = VSH_OT_BOOL, + .help = N_("report error if CPUs are incompatible") + }, + {.name = NULL} +}; + +static bool +cmdCPUCompare(vshControl *ctl, const vshCmd *cmd) +{ + const char *from = NULL; + bool ret = false; + char *buffer; + int result; + char *snippet = NULL; + unsigned int flags = 0; + xmlDocPtr xml = NULL; + xmlXPathContextPtr ctxt = NULL; + xmlNodePtr node; + virshControlPtr priv = ctl->privData; + + if (vshCommandOptBool(cmd, "error")) + flags |= VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE; + + if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0) + return false; + + if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0) + return false; + + /* try to extract the CPU element from as it would appear in a domain XML*/ + if (!(xml = virXMLParseStringCtxt(buffer, from, &ctxt))) + goto cleanup; + + if ((node = virXPathNode("/cpu|" + "/domain/cpu|" + "/capabilities/host/cpu", ctxt))) { + if (!(snippet = virXMLNodeToString(xml, node))) { + vshSaveLibvirtError(); + goto cleanup; + } + } else { + vshError(ctl, _("File '%s' does not contain a <cpu> element or is not " + "a valid domain or capabilities XML"), from); + goto cleanup; + } + + result = virConnectCompareCPU(priv->conn, snippet, flags); + + switch (result) { + case VIR_CPU_COMPARE_INCOMPATIBLE: + vshPrint(ctl, _("CPU described in %s is incompatible with host CPU\n"), + from); + goto cleanup; + break; + + case VIR_CPU_COMPARE_IDENTICAL: + vshPrint(ctl, _("CPU described in %s is identical to host CPU\n"), + from); + break; + + case VIR_CPU_COMPARE_SUPERSET: + vshPrint(ctl, _("Host CPU is a superset of CPU described in %s\n"), + from); + break; + + case VIR_CPU_COMPARE_ERROR: + default: + vshError(ctl, _("Failed to compare host CPU with %s"), from); + goto cleanup; + } + + ret = true; + + cleanup: + VIR_FREE(buffer); + VIR_FREE(snippet); + xmlXPathFreeContext(ctxt); + xmlFreeDoc(xml); + + return ret; +} + +/* + * "cpu-baseline" command + */ +static const vshCmdInfo info_cpu_baseline[] = { + {.name = "help", + .data = N_("compute baseline CPU") + }, + {.name = "desc", + .data = N_("Compute baseline CPU for a set of given CPUs.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_cpu_baseline[] = { + VIRSH_COMMON_OPT_FILE(N_("file containing XML CPU descriptions")), + {.name = "features", + .type = VSH_OT_BOOL, + .help = N_("Show features that are part of the CPU model type") + }, + {.name = "migratable", + .type = VSH_OT_BOOL, + .help = N_("Do not include features that block migration") + }, + {.name = NULL} +}; + +static bool +cmdCPUBaseline(vshControl *ctl, const vshCmd *cmd) +{ + const char *from = NULL; + bool ret = false; + char *buffer; + char *result = NULL; + char **list = NULL; + unsigned int flags = 0; + int count = 0; + + xmlDocPtr xml = NULL; + xmlNodePtr *node_list = NULL; + xmlXPathContextPtr ctxt = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + size_t i; + virshControlPtr priv = ctl->privData; + + if (vshCommandOptBool(cmd, "features")) + flags |= VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES; + if (vshCommandOptBool(cmd, "migratable")) + flags |= VIR_CONNECT_BASELINE_CPU_MIGRATABLE; + + if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0) + return false; + + if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0) + return false; + + /* add a separate container around the xml */ + virBufferStrcat(&buf, "<container>", buffer, "</container>", NULL); + if (virBufferError(&buf)) + goto no_memory; + + VIR_FREE(buffer); + buffer = virBufferContentAndReset(&buf); + + + if (!(xml = virXMLParseStringCtxt(buffer, from, &ctxt))) + goto cleanup; + + if ((count = virXPathNodeSet("//cpu[not(ancestor::cpus)]", + ctxt, &node_list)) == -1) + goto cleanup; + + if (count == 0) { + vshError(ctl, _("No host CPU specified in '%s'"), from); + goto cleanup; + } + + list = vshCalloc(ctl, count, sizeof(const char *)); + + for (i = 0; i < count; i++) { + if (!(list[i] = virXMLNodeToString(xml, node_list[i]))) { + vshSaveLibvirtError(); + goto cleanup; + } + } + + result = virConnectBaselineCPU(priv->conn, + (const char **)list, count, flags); + + if (result) { + vshPrint(ctl, "%s", result); + ret = true; + } + + cleanup: + xmlXPathFreeContext(ctxt); + xmlFreeDoc(xml); + VIR_FREE(result); + if (list != NULL && count > 0) { + for (i = 0; i < count; i++) + VIR_FREE(list[i]); + } + VIR_FREE(list); + VIR_FREE(buffer); + VIR_FREE(node_list); + + return ret; + + no_memory: + vshError(ctl, "%s", _("Out of memory")); + ret = false; + goto cleanup; +} + /* * "cpu-models" command */ @@ -1388,6 +1600,18 @@ const vshCmdDef hostAndHypervisorCmds[] = { .info = info_capabilities, .flags = 0 }, + {.name = "cpu-baseline", + .handler = cmdCPUBaseline, + .opts = opts_cpu_baseline, + .info = info_cpu_baseline, + .flags = 0 + }, + {.name = "cpu-compare", + .handler = cmdCPUCompare, + .opts = opts_cpu_compare, + .info = info_cpu_compare, + .flags = 0 + }, {.name = "cpu-models", .handler = cmdCPUModelNames, .opts = opts_cpu_models, -- 2.17.0

On 05/16/2018 04:39 AM, Jiri Denemark wrote:
Similarly to cpu-models these two commands do not operate on a domain and should be listed in the "Host and Hypervisor" commands section.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh-domain.c | 223 ------------------------------------------ tools/virsh-host.c | 224 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 224 insertions(+), 223 deletions(-)
Makes sense to me. Reviewed-by: Collin Walling <walling@linux.ibm.com> -- Respectfully, - Collin Walling

On Wed, May 16, 2018 at 10:39:20AM +0200, Jiri Denemark wrote:
Similarly to cpu-models these two commands do not operate on a domain and should be listed in the "Host and Hypervisor" commands section.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh-domain.c | 223 ------------------------------------------ tools/virsh-host.c | 224 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 224 insertions(+), 223 deletions(-)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

Both cpu-compare and cpu-baseline commands accept more that just CPU definition XML(s). For users' convenience they are able to extract the CPU definition(s) even from domain XML or capabilities XML. The main differences between the two commands is in the number of CPU definitions they expect: cpu-compare wants only one CPU definition while cpu-baseline expects one or more CPUs. The extracted code forms a new vshExtractCPUDefXML function. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh-host.c | 160 +++++++++++++++++++++------------------------ 1 file changed, 75 insertions(+), 85 deletions(-) diff --git a/tools/virsh-host.c b/tools/virsh-host.c index 6d6e3cfc85..51497db385 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -1106,6 +1106,72 @@ cmdURI(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) return true; } + +/* Extracts the CPU definition XML strings from a file which may contain either + * - just the CPU definitions, + * - domain XMLs, or + * - capabilities XMLs. + * + * Returns NULL terminated string list. + */ +static char ** +vshExtractCPUDefXMLs(vshControl *ctl, + const char *xmlFile) +{ + char **cpus = NULL; + char *buffer = NULL; + char *xmlStr = NULL; + xmlDocPtr xml = NULL; + xmlXPathContextPtr ctxt = NULL; + xmlNodePtr *nodes = NULL; + size_t i; + int n; + + if (virFileReadAll(xmlFile, VSH_MAX_XML_FILE, &buffer) < 0) + goto error; + + if (virAsprintf(&xmlStr, "<container>%s</container>", buffer) < 0) + goto error; + + if (!(xml = virXMLParseStringCtxt(xmlStr, xmlFile, &ctxt))) + goto error; + + n = virXPathNodeSet("/container/cpu|" + "/container/domain/cpu|" + "/container/capabilities/host/cpu", + ctxt, &nodes); + if (n < 0) + goto error; + + if (n == 0) { + vshError(ctl, _("File '%s' does not contain any <cpu> element or " + "valid domain or capabilities XML"), xmlFile); + goto error; + } + + cpus = vshCalloc(ctl, n + 1, sizeof(const char *)); + + for (i = 0; i < n; i++) { + if (!(cpus[i] = virXMLNodeToString(xml, nodes[i]))) { + vshSaveLibvirtError(); + goto error; + } + } + + cleanup: + VIR_FREE(buffer); + VIR_FREE(xmlStr); + xmlFreeDoc(xml); + xmlXPathFreeContext(ctxt); + VIR_FREE(nodes); + return cpus; + + error: + virStringListFree(cpus); + goto cleanup; +} + + /* * "cpu-compare" command */ @@ -1133,13 +1199,9 @@ cmdCPUCompare(vshControl *ctl, const vshCmd *cmd) { const char *from = NULL; bool ret = false; - char *buffer; int result; - char *snippet = NULL; + char **cpus = NULL; unsigned int flags = 0; - xmlDocPtr xml = NULL; - xmlXPathContextPtr ctxt = NULL; - xmlNodePtr node; virshControlPtr priv = ctl->privData; if (vshCommandOptBool(cmd, "error")) @@ -1148,27 +1210,10 @@ cmdCPUCompare(vshControl *ctl, const vshCmd *cmd) if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0) return false; - if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0) + if (!(cpus = vshExtractCPUDefXMLs(ctl, from))) return false; - /* try to extract the CPU element from as it would appear in a domain XML*/ - if (!(xml = virXMLParseStringCtxt(buffer, from, &ctxt))) - goto cleanup; - - if ((node = virXPathNode("/cpu|" - "/domain/cpu|" - "/capabilities/host/cpu", ctxt))) { - if (!(snippet = virXMLNodeToString(xml, node))) { - vshSaveLibvirtError(); - goto cleanup; - } - } else { - vshError(ctl, _("File '%s' does not contain a <cpu> element or is not " - "a valid domain or capabilities XML"), from); - goto cleanup; - } - - result = virConnectCompareCPU(priv->conn, snippet, flags); + result = virConnectCompareCPU(priv->conn, cpus[0], flags); switch (result) { case VIR_CPU_COMPARE_INCOMPATIBLE: @@ -1196,10 +1241,7 @@ cmdCPUCompare(vshControl *ctl, const vshCmd *cmd) ret = true; cleanup: - VIR_FREE(buffer); - VIR_FREE(snippet); - xmlXPathFreeContext(ctxt); - xmlFreeDoc(xml); + virStringListFree(cpus); return ret; } @@ -1235,17 +1277,9 @@ cmdCPUBaseline(vshControl *ctl, const vshCmd *cmd) { const char *from = NULL; bool ret = false; - char *buffer; char *result = NULL; char **list = NULL; unsigned int flags = 0; - int count = 0; - - xmlDocPtr xml = NULL; - xmlNodePtr *node_list = NULL; - xmlXPathContextPtr ctxt = NULL; - virBuffer buf = VIR_BUFFER_INITIALIZER; - size_t i; virshControlPtr priv = ctl->privData; if (vshCommandOptBool(cmd, "features")) @@ -1256,65 +1290,21 @@ cmdCPUBaseline(vshControl *ctl, const vshCmd *cmd) if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0) return false; - if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0) + if (!(list = vshExtractCPUDefXMLs(ctl, from))) return false; - /* add a separate container around the xml */ - virBufferStrcat(&buf, "<container>", buffer, "</container>", NULL); - if (virBufferError(&buf)) - goto no_memory; - - VIR_FREE(buffer); - buffer = virBufferContentAndReset(&buf); - - - if (!(xml = virXMLParseStringCtxt(buffer, from, &ctxt))) - goto cleanup; - - if ((count = virXPathNodeSet("//cpu[not(ancestor::cpus)]", - ctxt, &node_list)) == -1) - goto cleanup; - - if (count == 0) { - vshError(ctl, _("No host CPU specified in '%s'"), from); - goto cleanup; - } - - list = vshCalloc(ctl, count, sizeof(const char *)); - - for (i = 0; i < count; i++) { - if (!(list[i] = virXMLNodeToString(xml, node_list[i]))) { - vshSaveLibvirtError(); - goto cleanup; - } - } - - result = virConnectBaselineCPU(priv->conn, - (const char **)list, count, flags); + result = virConnectBaselineCPU(priv->conn, (const char **)list, + virStringListLength((const char **)list), + flags); if (result) { vshPrint(ctl, "%s", result); ret = true; } - cleanup: - xmlXPathFreeContext(ctxt); - xmlFreeDoc(xml); VIR_FREE(result); - if (list != NULL && count > 0) { - for (i = 0; i < count; i++) - VIR_FREE(list[i]); - } - VIR_FREE(list); - VIR_FREE(buffer); - VIR_FREE(node_list); - + virStringListFree(list); return ret; - - no_memory: - vshError(ctl, "%s", _("Out of memory")); - ret = false; - goto cleanup; } /* -- 2.17.0

On 05/16/2018 04:39 AM, Jiri Denemark wrote:
Both cpu-compare and cpu-baseline commands accept more that just CPU definition XML(s). For users' convenience they are able to extract the CPU definition(s) even from domain XML or capabilities XML. The main differences between the two commands is in the number of CPU definitions they expect: cpu-compare wants only one CPU definition while cpu-baseline expects one or more CPUs.
The extracted code forms a new vshExtractCPUDefXML function.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh-host.c | 160 +++++++++++++++++++++------------------------ 1 file changed, 75 insertions(+), 85 deletions(-)
diff --git a/tools/virsh-host.c b/tools/virsh-host.c index 6d6e3cfc85..51497db385 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -1106,6 +1106,72 @@ cmdURI(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) return true; }
+ +/* Extracts the CPU definition XML strings from a file which may contain either + * - just the CPU definitions, + * - domain XMLs, or + * - capabilities XMLs. + * + * Returns NULL terminated string list. + */ +static char ** +vshExtractCPUDefXMLs(vshControl *ctl, + const char *xmlFile) +{ + char **cpus = NULL; + char *buffer = NULL; + char *xmlStr = NULL; + xmlDocPtr xml = NULL; + xmlXPathContextPtr ctxt = NULL; + xmlNodePtr *nodes = NULL; + size_t i; + int n; + + if (virFileReadAll(xmlFile, VSH_MAX_XML_FILE, &buffer) < 0) + goto error; + + if (virAsprintf(&xmlStr, "<container>%s</container>", buffer) < 0) + goto error; +
Why wrap the xml in the <container> tags?
+ if (!(xml = virXMLParseStringCtxt(xmlStr, xmlFile, &ctxt))) + goto error; + + n = virXPathNodeSet("/container/cpu|" + "/container/domain/cpu|" + "/container/capabilities/host/cpu", + ctxt, &nodes); + if (n < 0) + goto error; + + if (n == 0) { + vshError(ctl, _("File '%s' does not contain any <cpu> element or " + "valid domain or capabilities XML"), xmlFile); + goto error; + } + + cpus = vshCalloc(ctl, n + 1, sizeof(const char *)); + + for (i = 0; i < n; i++) { + if (!(cpus[i] = virXMLNodeToString(xml, nodes[i]))) { + vshSaveLibvirtError(); + goto error; + } + } + + cleanup: + VIR_FREE(buffer); + VIR_FREE(xmlStr); + xmlFreeDoc(xml); + xmlXPathFreeContext(ctxt); + VIR_FREE(nodes); + return cpus; + + error: + virStringListFree(cpus); + goto cleanup; +} + + /* * "cpu-compare" command */ @@ -1133,13 +1199,9 @@ cmdCPUCompare(vshControl *ctl, const vshCmd *cmd) { const char *from = NULL; bool ret = false; - char *buffer; int result; - char *snippet = NULL; + char **cpus = NULL; unsigned int flags = 0; - xmlDocPtr xml = NULL; - xmlXPathContextPtr ctxt = NULL; - xmlNodePtr node; virshControlPtr priv = ctl->privData;
if (vshCommandOptBool(cmd, "error")) @@ -1148,27 +1210,10 @@ cmdCPUCompare(vshControl *ctl, const vshCmd *cmd) if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0) return false;
- if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0) + if (!(cpus = vshExtractCPUDefXMLs(ctl, from))) return false;
- /* try to extract the CPU element from as it would appear in a domain XML*/ - if (!(xml = virXMLParseStringCtxt(buffer, from, &ctxt))) - goto cleanup; - - if ((node = virXPathNode("/cpu|" - "/domain/cpu|" - "/capabilities/host/cpu", ctxt))) { - if (!(snippet = virXMLNodeToString(xml, node))) { - vshSaveLibvirtError(); - goto cleanup; - } - } else { - vshError(ctl, _("File '%s' does not contain a <cpu> element or is not " - "a valid domain or capabilities XML"), from); - goto cleanup; - } - - result = virConnectCompareCPU(priv->conn, snippet, flags); + result = virConnectCompareCPU(priv->conn, cpus[0], flags);
I wonder if it's worth commenting here or adding to the cpu compare docs that comparison only compares the host CPU with the _first_ cpu found in the XML file?
switch (result) { case VIR_CPU_COMPARE_INCOMPATIBLE: @@ -1196,10 +1241,7 @@ cmdCPUCompare(vshControl *ctl, const vshCmd *cmd) ret = true;
cleanup: - VIR_FREE(buffer); - VIR_FREE(snippet); - xmlXPathFreeContext(ctxt); - xmlFreeDoc(xml); + virStringListFree(cpus);
return ret; }
[...] The rest of this patch looks good... I'd like to take another look tomorrow in case I missed anything subtle. -- Respectfully, - Collin Walling

On Tue, May 22, 2018 at 17:33:14 -0400, Collin Walling wrote:
On 05/16/2018 04:39 AM, Jiri Denemark wrote:
Both cpu-compare and cpu-baseline commands accept more that just CPU definition XML(s). For users' convenience they are able to extract the CPU definition(s) even from domain XML or capabilities XML. The main differences between the two commands is in the number of CPU definitions they expect: cpu-compare wants only one CPU definition while cpu-baseline expects one or more CPUs.
The extracted code forms a new vshExtractCPUDefXML function.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh-host.c | 160 +++++++++++++++++++++------------------------ 1 file changed, 75 insertions(+), 85 deletions(-)
diff --git a/tools/virsh-host.c b/tools/virsh-host.c index 6d6e3cfc85..51497db385 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -1106,6 +1106,72 @@ cmdURI(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) return true; }
+ +/* Extracts the CPU definition XML strings from a file which may contain either + * - just the CPU definitions, + * - domain XMLs, or + * - capabilities XMLs. + * + * Returns NULL terminated string list. + */ +static char ** +vshExtractCPUDefXMLs(vshControl *ctl, + const char *xmlFile) +{ + char **cpus = NULL; + char *buffer = NULL; + char *xmlStr = NULL; + xmlDocPtr xml = NULL; + xmlXPathContextPtr ctxt = NULL; + xmlNodePtr *nodes = NULL; + size_t i; + int n; + + if (virFileReadAll(xmlFile, VSH_MAX_XML_FILE, &buffer) < 0) + goto error; + + if (virAsprintf(&xmlStr, "<container>%s</container>", buffer) < 0) + goto error; +
Why wrap the xml in the <container> tags?
Because you can only have one root element in an XML document. Thus to be able to parse a file with several root elements, we need to encapsulate the content into a container.
+ if (!(xml = virXMLParseStringCtxt(xmlStr, xmlFile, &ctxt))) + goto error; + + n = virXPathNodeSet("/container/cpu|" + "/container/domain/cpu|" + "/container/capabilities/host/cpu", + ctxt, &nodes); + if (n < 0) + goto error; + + if (n == 0) { + vshError(ctl, _("File '%s' does not contain any <cpu> element or " + "valid domain or capabilities XML"), xmlFile); + goto error; + } + + cpus = vshCalloc(ctl, n + 1, sizeof(const char *)); + + for (i = 0; i < n; i++) { + if (!(cpus[i] = virXMLNodeToString(xml, nodes[i]))) { + vshSaveLibvirtError(); + goto error; + } + } + + cleanup: + VIR_FREE(buffer); + VIR_FREE(xmlStr); + xmlFreeDoc(xml); + xmlXPathFreeContext(ctxt); + VIR_FREE(nodes); + return cpus; + + error: + virStringListFree(cpus); + goto cleanup; +} + + /* * "cpu-compare" command */ @@ -1133,13 +1199,9 @@ cmdCPUCompare(vshControl *ctl, const vshCmd *cmd) { const char *from = NULL; bool ret = false; - char *buffer; int result; - char *snippet = NULL; + char **cpus = NULL; unsigned int flags = 0; - xmlDocPtr xml = NULL; - xmlXPathContextPtr ctxt = NULL; - xmlNodePtr node; virshControlPtr priv = ctl->privData;
if (vshCommandOptBool(cmd, "error")) @@ -1148,27 +1210,10 @@ cmdCPUCompare(vshControl *ctl, const vshCmd *cmd) if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0) return false;
- if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0) + if (!(cpus = vshExtractCPUDefXMLs(ctl, from))) return false;
- /* try to extract the CPU element from as it would appear in a domain XML*/ - if (!(xml = virXMLParseStringCtxt(buffer, from, &ctxt))) - goto cleanup; - - if ((node = virXPathNode("/cpu|" - "/domain/cpu|" - "/capabilities/host/cpu", ctxt))) { - if (!(snippet = virXMLNodeToString(xml, node))) { - vshSaveLibvirtError(); - goto cleanup; - } - } else { - vshError(ctl, _("File '%s' does not contain a <cpu> element or is not " - "a valid domain or capabilities XML"), from); - goto cleanup; - } - - result = virConnectCompareCPU(priv->conn, snippet, flags); + result = virConnectCompareCPU(priv->conn, cpus[0], flags);
I wonder if it's worth commenting here or adding to the cpu compare docs that comparison only compares the host CPU with the _first_ cpu found in the XML file?
The cpu-compare command is already documented this way. It accepts a CPU definition and compares it to host CPU, while cpu-baseline accepts a set of CPU definitions. Jirka

On Wed, May 16, 2018 at 10:39:21AM +0200, Jiri Denemark wrote:
Both cpu-compare and cpu-baseline commands accept more that just CPU definition XML(s). For users' convenience they are able to extract the CPU definition(s) even from domain XML or capabilities XML. The main differences between the two commands is in the number of CPU definitions they expect: cpu-compare wants only one CPU definition while cpu-baseline expects one or more CPUs.
The extracted code forms a new vshExtractCPUDefXML function.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh-host.c | 160 +++++++++++++++++++++------------------------ 1 file changed, 75 insertions(+), 85 deletions(-)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh.pod | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/virsh.pod b/tools/virsh.pod index 929958a953..5f72e11dec 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -589,7 +589,9 @@ Compare CPU definition from XML <file> with host CPU. The XML <file> may contain either host or guest CPU definition. The host CPU definition is the <cpu> element and its contents as printed by B<capabilities> command. The guest CPU definition is the <cpu> element and its contents from domain XML -definition. For more information on guest CPU definition see: +definition. In addition to the <cpu> element itself, this command accepts +full domain or capabilities XML containing the <cpu> element. For more +information on guest CPU definition see: L<https://libvirt.org/formatdomain.html#elementsCPU>. If I<--error> is specified, the command will return an error when the given CPU is incompatible with host CPU and a message providing more details about the -- 2.17.0

On 05/16/2018 04:39 AM, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh.pod | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/tools/virsh.pod b/tools/virsh.pod index 929958a953..5f72e11dec 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -589,7 +589,9 @@ Compare CPU definition from XML <file> with host CPU. The XML <file> may contain either host or guest CPU definition. The host CPU definition is the <cpu> element and its contents as printed by B<capabilities> command. The guest CPU definition is the <cpu> element and its contents from domain XML -definition. For more information on guest CPU definition see: +definition. In addition to the <cpu> element itself, this command accepts +full domain or capabilities XML containing the <cpu> element. For more +information on guest CPU definition see: L<https://libvirt.org/formatdomain.html#elementsCPU>. If I<--error> is specified, the command will return an error when the given CPU is incompatible with host CPU and a message providing more details about the
Reviewed-by: Collin Walling <walling@linux.ibm.com> -- Respectfully, - Collin Walling

On Wed, May 16, 2018 at 10:39:22AM +0200, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh.pod | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/tools/virsh.pod b/tools/virsh.pod index 929958a953..5f72e11dec 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -589,7 +589,9 @@ Compare CPU definition from XML <file> with host CPU. The XML <file> may contain either host or guest CPU definition. The host CPU definition is the <cpu> element and its contents as printed by B<capabilities> command. The guest CPU definition is the <cpu> element and its contents from domain XML -definition. For more information on guest CPU definition see: +definition. In addition to the <cpu> element itself, this command accepts +full domain or capabilities XML containing the <cpu> element. For more +information on guest CPU definition see: L<https://libvirt.org/formatdomain.html#elementsCPU>. If I<--error> is specified, the command will return an error when the given CPU is incompatible with host CPU and a message providing more details about the
Reviewed-by: Kashyap Chamarthy <kchamart@redhat.com> -- /kashyap

On Wed, May 16, 2018 at 10:39:22AM +0200, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh.pod | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh.pod | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/virsh.pod b/tools/virsh.pod index 5f72e11dec..5fc8201893 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -599,7 +599,13 @@ incompatibility will be printed out. =item B<cpu-models> I<arch> -Print the list of CPU models known for the specified architecture. +Print the list of CPU models known by libvirt for the specified architecture. +Whether a specific hypervisor is able to create a domain which uses any of +the printed CPU models is a separate question which can be answered by +looking the domain capabilities XML returned by B<domcapabilities> command. +Moreover, for some architectures libvirt does not know any CPU models and +the usable CPU models are only limited by the hypervisor. This command will +print that all CPU models are accepted for these architectures. =item B<echo> [I<--shell>] [I<--xml>] [I<arg>...] -- 2.17.0

On 05/16/2018 04:39 AM, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh.pod | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/tools/virsh.pod b/tools/virsh.pod index 5f72e11dec..5fc8201893 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -599,7 +599,13 @@ incompatibility will be printed out.
=item B<cpu-models> I<arch>
-Print the list of CPU models known for the specified architecture. +Print the list of CPU models known by libvirt for the specified architecture. +Whether a specific hypervisor is able to create a domain which uses any of +the printed CPU models is a separate question which can be answered by +looking the domain capabilities XML returned by B<domcapabilities> command. +Moreover, for some architectures libvirt does not know any CPU models and +the usable CPU models are only limited by the hypervisor. This command will +print that all CPU models are accepted for these architectures.
=item B<echo> [I<--shell>] [I<--xml>] [I<arg>...]
Reviewed-by: Collin Walling <walling@linux.ibm.com> -- Respectfully, - Collin Walling

On Wed, May 16, 2018 at 10:39:23AM +0200, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh.pod | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/tools/virsh.pod b/tools/virsh.pod index 5f72e11dec..5fc8201893 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -599,7 +599,13 @@ incompatibility will be printed out.
=item B<cpu-models> I<arch>
-Print the list of CPU models known for the specified architecture. +Print the list of CPU models known by libvirt for the specified architecture. +Whether a specific hypervisor is able to create a domain which uses any of +the printed CPU models is a separate question which can be answered by +looking the domain capabilities XML returned by B<domcapabilities> command.
s/looking the/looking at the/
+Moreover, for some architectures libvirt does not know any CPU models and +the usable CPU models are only limited by the hypervisor.
Wonder if it is worth adding a small example for the above.
This command will +print that all CPU models are accepted for these architectures.
s/CPU models are accepted/CPU models that are accepted/
=item B<echo> [I<--shell>] [I<--xml>] [I<arg>...]
With the nits addresed: Reviewed-by: Kashyap Chamarthy <kchamart@redhat.com> -- /kashyap

On Wed, May 23, 2018 at 13:08:51 +0200, Kashyap Chamarthy wrote:
On Wed, May 16, 2018 at 10:39:23AM +0200, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh.pod | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/tools/virsh.pod b/tools/virsh.pod index 5f72e11dec..5fc8201893 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -599,7 +599,13 @@ incompatibility will be printed out.
=item B<cpu-models> I<arch>
-Print the list of CPU models known for the specified architecture. +Print the list of CPU models known by libvirt for the specified architecture. +Whether a specific hypervisor is able to create a domain which uses any of +the printed CPU models is a separate question which can be answered by +looking the domain capabilities XML returned by B<domcapabilities> command.
s/looking the/looking at the/
Oops.
+Moreover, for some architectures libvirt does not know any CPU models and +the usable CPU models are only limited by the hypervisor.
Wonder if it is worth adding a small example for the above.
An example for what exactly?
This command will +print that all CPU models are accepted for these architectures.
s/CPU models are accepted/CPU models that are accepted/
It's certainly possible my wording was not perfect, but this change would make it wrong. Jirka

On Wed, May 23, 2018 at 02:43:23PM +0200, Jiri Denemark wrote:
On Wed, May 23, 2018 at 13:08:51 +0200, Kashyap Chamarthy wrote:
On Wed, May 16, 2018 at 10:39:23AM +0200, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh.pod | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
[...]
+Moreover, for some architectures libvirt does not know any CPU models and +the usable CPU models are only limited by the hypervisor.
Wonder if it is worth adding a small example for the above.
An example for what exactly?
I meant an example of a usable CPU model that libvirt doesn't know for the said architecture(s). Maybe it's not worth it; not quite sure.
This command will +print that all CPU models are accepted for these architectures.
s/CPU models are accepted/CPU models that are accepted/
It's certainly possible my wording was not perfect, but this change would make it wrong.
Err, sorry, I misread that sentence; please disregard the above. [...] -- /kashyap

On Wed, May 23, 2018 at 16:53:37 +0200, Kashyap Chamarthy wrote:
On Wed, May 23, 2018 at 02:43:23PM +0200, Jiri Denemark wrote:
On Wed, May 23, 2018 at 13:08:51 +0200, Kashyap Chamarthy wrote:
On Wed, May 16, 2018 at 10:39:23AM +0200, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh.pod | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
[...]
+Moreover, for some architectures libvirt does not know any CPU models and +the usable CPU models are only limited by the hypervisor.
Wonder if it is worth adding a small example for the above.
An example for what exactly?
I meant an example of a usable CPU model that libvirt doesn't know for the said architecture(s). Maybe it's not worth it; not quite sure.
The usable models are all models accepted by hypervisor for that architecture. So, e.g., libvirt won't list any CPU model for aarch64 when you call "virsh cpu-models aarch64", it will just print "all CPU models are accepted" and "virsh domcapabilities --arch aarch64" will show a very long list of CPU models libvirt would actually accept. Similarly for s390x. Jirka

On Wed, May 23, 2018 at 09:09:28PM +0200, Jiri Denemark wrote:
On Wed, May 23, 2018 at 16:53:37 +0200, Kashyap Chamarthy wrote:
On Wed, May 23, 2018 at 02:43:23PM +0200, Jiri Denemark wrote:
On Wed, May 23, 2018 at 13:08:51 +0200, Kashyap Chamarthy wrote:
On Wed, May 16, 2018 at 10:39:23AM +0200, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh.pod | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
[...]
+Moreover, for some architectures libvirt does not know any CPU models and +the usable CPU models are only limited by the hypervisor.
Wonder if it is worth adding a small example for the above.
An example for what exactly?
I meant an example of a usable CPU model that libvirt doesn't know for the said architecture(s). Maybe it's not worth it; not quite sure.
The usable models are all models accepted by hypervisor for that architecture. So, e.g., libvirt won't list any CPU model for aarch64 when you call "virsh cpu-models aarch64", it will just print "all CPU models are accepted" and "virsh domcapabilities --arch aarch64" will show a very long list of CPU models libvirt would actually accept. Similarly for s390x.
Ah, that is clearer; thank you. So if you think it is worth it, maybe adjust your doc patch to a variant of the following: Moreover, for some architectures libvirt does not know any CPU models and the usable CPU models are only limited by the hypervisor (e.g. to enumerate a list of acceptable CPU models for AArch64, use `virsh domcapabilities --arch aarch64`; likewise for 's390x'). -- /kashyap

On Thu, May 24, 2018 at 11:05:08 +0200, Kashyap Chamarthy wrote:
On Wed, May 23, 2018 at 09:09:28PM +0200, Jiri Denemark wrote:
On Wed, May 23, 2018 at 16:53:37 +0200, Kashyap Chamarthy wrote:
On Wed, May 23, 2018 at 02:43:23PM +0200, Jiri Denemark wrote:
On Wed, May 23, 2018 at 13:08:51 +0200, Kashyap Chamarthy wrote:
On Wed, May 16, 2018 at 10:39:23AM +0200, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh.pod | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
[...]
+Moreover, for some architectures libvirt does not know any CPU models and +the usable CPU models are only limited by the hypervisor.
Wonder if it is worth adding a small example for the above.
An example for what exactly?
I meant an example of a usable CPU model that libvirt doesn't know for the said architecture(s). Maybe it's not worth it; not quite sure.
The usable models are all models accepted by hypervisor for that architecture. So, e.g., libvirt won't list any CPU model for aarch64 when you call "virsh cpu-models aarch64", it will just print "all CPU models are accepted" and "virsh domcapabilities --arch aarch64" will show a very long list of CPU models libvirt would actually accept. Similarly for s390x.
Ah, that is clearer; thank you. So if you think it is worth it, maybe adjust your doc patch to a variant of the following:
Moreover, for some architectures libvirt does not know any CPU models and the usable CPU models are only limited by the hypervisor (e.g. to enumerate a list of acceptable CPU models for AArch64, use `virsh domcapabilities --arch aarch64`; likewise for 's390x').
So how about Print the list of CPU models known by libvirt for the specified architecture. Whether a specific hypervisor is able to create a domain which uses any of the printed CPU models is a separate question which can be answered by looking at the domain capabilities XML returned by B<domcapabilities> command. Moreover, for some architectures libvirt does not know any CPU models and the usable CPU models are only limited by the hypervisor. This command will print that all CPU models are accepted for these architectures and the actual list of supported CPU models can be checked in the domain capabilities XML. Jirka

On Fri, May 25, 2018 at 11:36:21AM +0200, Jiri Denemark wrote:
On Thu, May 24, 2018 at 11:05:08 +0200, Kashyap Chamarthy wrote:
[...]
Ah, that is clearer; thank you. So if you think it is worth it, maybe adjust your doc patch to a variant of the following:
Moreover, for some architectures libvirt does not know any CPU models and the usable CPU models are only limited by the hypervisor (e.g. to enumerate a list of acceptable CPU models for AArch64, use `virsh domcapabilities --arch aarch64`; likewise for 's390x').
So how about
Print the list of CPU models known by libvirt for the specified architecture. Whether a specific hypervisor is able to create a domain which uses any of the printed CPU models is a separate question which can be answered by looking at the domain capabilities XML returned by B<domcapabilities> command. Moreover, for some architectures libvirt does not know any CPU models and the usable CPU models are only limited by the hypervisor. This command will print that all CPU models are accepted for these architectures and the actual list of supported CPU models can be checked in the domain capabilities XML.
Yep, clear and to the point. Thanks. Reviewed-by: Kashyap Chamarthy <kchamart@redhat.com> -- /kashyap

On Wed, May 16, 2018 at 10:39:23AM +0200, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh.pod | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/tools/virsh.pod b/tools/virsh.pod index 5f72e11dec..5fc8201893 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -599,7 +599,13 @@ incompatibility will be printed out.
=item B<cpu-models> I<arch>
-Print the list of CPU models known for the specified architecture. +Print the list of CPU models known by libvirt for the specified architecture. +Whether a specific hypervisor is able to create a domain which uses any of +the printed CPU models is a separate question which can be answered by +looking the domain capabilities XML returned by B<domcapabilities> command. +Moreover, for some architectures libvirt does not know any CPU models and +the usable CPU models are only limited by the hypervisor. This command will +print that all CPU models are accepted for these architectures.
=item B<echo> [I<--shell>] [I<--xml>] [I<arg>...]
with the 'at' added: Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/libvirt-host.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libvirt-host.c b/src/libvirt-host.c index 76087badd8..ed689b9ec2 100644 --- a/src/libvirt-host.c +++ b/src/libvirt-host.c @@ -1003,7 +1003,13 @@ virConnectCompareCPU(virConnectPtr conn, * NULL if only the list length is needed. * @flags: extra flags; not used yet, so callers should always pass 0. * - * Get the list of supported CPU models for a specific architecture. + * Get the list of CPU models supported by libvirt for a specific architecture. + * + * The returned list limits CPU models usable with libvirt (empty list means, + * there's no limit imposed by libvirt) and it does not reflect capabalities of + * any hypervisor. See the XML returned by virConnectGetDomainCapabilities() + * for a list of CPU models supported by libvirt for domains created on a + * specific hypervisor. * * Returns -1 on error, number of elements in @models on success (0 means * libvirt accepts any CPU model). -- 2.17.0

On 05/16/2018 04:39 AM, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/libvirt-host.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/libvirt-host.c b/src/libvirt-host.c index 76087badd8..ed689b9ec2 100644 --- a/src/libvirt-host.c +++ b/src/libvirt-host.c @@ -1003,7 +1003,13 @@ virConnectCompareCPU(virConnectPtr conn, * NULL if only the list length is needed. * @flags: extra flags; not used yet, so callers should always pass 0. * - * Get the list of supported CPU models for a specific architecture. + * Get the list of CPU models supported by libvirt for a specific architecture. + * + * The returned list limits CPU models usable with libvirt (empty list means, + * there's no limit imposed by libvirt) and it does not reflect capabalities of
s/capabalities/capabilities
+ * any hypervisor. See the XML returned by virConnectGetDomainCapabilities() + * for a list of CPU models supported by libvirt for domains created on a + * specific hypervisor. * * Returns -1 on error, number of elements in @models on success (0 means * libvirt accepts any CPU model).
Other than that: Reviewed-by: Collin Walling <walling@linux.ibm.com> -- Respectfully, - Collin Walling

On Wed, May 16, 2018 at 10:39:24AM +0200, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/libvirt-host.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/libvirt-host.c b/src/libvirt-host.c index 76087badd8..ed689b9ec2 100644 --- a/src/libvirt-host.c +++ b/src/libvirt-host.c @@ -1003,7 +1003,13 @@ virConnectCompareCPU(virConnectPtr conn, * NULL if only the list length is needed. * @flags: extra flags; not used yet, so callers should always pass 0. * - * Get the list of supported CPU models for a specific architecture. + * Get the list of CPU models supported by libvirt for a specific architecture. + * + * The returned list limits CPU models usable with libvirt (empty list means, + * there's no limit imposed by libvirt) and it does not reflect capabalities of + * any hypervisor.
s/any hypervisor/any particular hypervisor/
See the XML returned by virConnectGetDomainCapabilities() + * for a list of CPU models supported by libvirt for domains created on a + * specific hypervisor. * * Returns -1 on error, number of elements in @models on success (0 means * libvirt accepts any CPU model).
Reviewed-by: Kashyap Chamarthy <kchamart@redhat.com> -- /kashyap

On Wed, May 16, 2018 at 10:39:24AM +0200, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/libvirt-host.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/libvirt-host.c b/src/libvirt-host.c index 76087badd8..ed689b9ec2 100644 --- a/src/libvirt-host.c +++ b/src/libvirt-host.c @@ -1003,7 +1003,13 @@ virConnectCompareCPU(virConnectPtr conn, * NULL if only the list length is needed. * @flags: extra flags; not used yet, so callers should always pass 0. * - * Get the list of supported CPU models for a specific architecture. + * Get the list of CPU models supported by libvirt for a specific architecture. + * + * The returned list limits CPU models usable with libvirt (empty list means,
Should there be a comma?
+ * there's no limit imposed by libvirt) and it does not reflect capabalities of + * any hypervisor. See the XML returned by virConnectGetDomainCapabilities() + * for a list of CPU models supported by libvirt for domains created on a + * specific hypervisor. *
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

The domain capabilities XML contains host CPU model tailored to a specific hypervisor and since it's enclosed in <mode name='host-model'> element rather then the required <cpu> it's impossible to directly use the host CPU model as an input to, e.g., cpu-compare command. To make this more convenient, vshExtractCPUDefXML now accepts full domain capabilities XML and automatically transforms the host CPU models into the form accepted by libvirt APIs. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh-host.c | 26 ++++++++++++++++++++++---- tools/virsh.pod | 8 +++++--- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/tools/virsh-host.c b/tools/virsh-host.c index 51497db385..ea2c411c02 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -1109,8 +1109,9 @@ cmdURI(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) /* Extracts the CPU definition XML strings from a file which may contain either * - just the CPU definitions, - * - domain XMLs, or - * - capabilities XMLs. + * - domain XMLs, + * - capabilities XMLs, or + * - domain capabilities XMLs. * * Returns NULL terminated string list. */ @@ -1138,20 +1139,37 @@ vshExtractCPUDefXMLs(vshControl *ctl, n = virXPathNodeSet("/container/cpu|" "/container/domain/cpu|" - "/container/capabilities/host/cpu", + "/container/capabilities/host/cpu|" + "/container/domainCapabilities/cpu/" + "mode[@name='host-model' and @supported='yes']", ctxt, &nodes); if (n < 0) goto error; if (n == 0) { vshError(ctl, _("File '%s' does not contain any <cpu> element or " - "valid domain or capabilities XML"), xmlFile); + "valid domain XML, host capabilities XML, or " + "domain capabilities XML"), xmlFile); goto error; } cpus = vshCalloc(ctl, n + 1, sizeof(const char *)); for (i = 0; i < n; i++) { + /* If the user provided domain capabilities XML, we need to replace + * <mode ...> element with <cpu>. */ + if (xmlStrEqual(nodes[i]->name, BAD_CAST "mode")) { + xmlNodeSetName(nodes[i], (const xmlChar *)"cpu"); + while (nodes[i]->properties) { + if (xmlRemoveProp(nodes[i]->properties) < 0) { + vshError(ctl, + _("Cannot extract CPU definition from domain " + "capabilities XML")); + goto error; + } + } + } + if (!(cpus[i] = virXMLNodeToString(xml, nodes[i]))) { vshSaveLibvirtError(); goto error; diff --git a/tools/virsh.pod b/tools/virsh.pod index 5fc8201893..ea10e1ad43 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -589,9 +589,11 @@ Compare CPU definition from XML <file> with host CPU. The XML <file> may contain either host or guest CPU definition. The host CPU definition is the <cpu> element and its contents as printed by B<capabilities> command. The guest CPU definition is the <cpu> element and its contents from domain XML -definition. In addition to the <cpu> element itself, this command accepts -full domain or capabilities XML containing the <cpu> element. For more -information on guest CPU definition see: +definition or the CPU definition created from the host CPU model found in +domain capabilities XML (printed by B<domcapabilities> command). In +addition to the <cpu> element itself, this command accepts +full domain XML, capabilities XML, or domain capabilities XML containing +the CPU definition. For more information on guest CPU definition see: L<https://libvirt.org/formatdomain.html#elementsCPU>. If I<--error> is specified, the command will return an error when the given CPU is incompatible with host CPU and a message providing more details about the -- 2.17.0

On 05/16/2018 04:39 AM, Jiri Denemark wrote:
The domain capabilities XML contains host CPU model tailored to a specific hypervisor and since it's enclosed in <mode name='host-model'> element rather then the required <cpu> it's impossible to directly use the host CPU model as an input to, e.g., cpu-compare command. To make this more convenient, vshExtractCPUDefXML now accepts full domain capabilities XML and automatically transforms the host CPU models into the form accepted by libvirt APIs.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh-host.c | 26 ++++++++++++++++++++++---- tools/virsh.pod | 8 +++++--- 2 files changed, 27 insertions(+), 7 deletions(-)
diff --git a/tools/virsh-host.c b/tools/virsh-host.c index 51497db385..ea2c411c02 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -1109,8 +1109,9 @@ cmdURI(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
/* Extracts the CPU definition XML strings from a file which may contain either * - just the CPU definitions, - * - domain XMLs, or - * - capabilities XMLs. + * - domain XMLs, + * - capabilities XMLs, or + * - domain capabilities XMLs. * * Returns NULL terminated string list. */ @@ -1138,20 +1139,37 @@ vshExtractCPUDefXMLs(vshControl *ctl,
n = virXPathNodeSet("/container/cpu|" "/container/domain/cpu|" - "/container/capabilities/host/cpu", + "/container/capabilities/host/cpu|" + "/container/domainCapabilities/cpu/" + "mode[@name='host-model' and @supported='yes']", ctxt, &nodes); if (n < 0) goto error;
if (n == 0) { vshError(ctl, _("File '%s' does not contain any <cpu> element or " - "valid domain or capabilities XML"), xmlFile); + "valid domain XML, host capabilities XML, or " + "domain capabilities XML"), xmlFile); goto error; }
cpus = vshCalloc(ctl, n + 1, sizeof(const char *));
for (i = 0; i < n; i++) { + /* If the user provided domain capabilities XML, we need to replace + * <mode ...> element with <cpu>. */ + if (xmlStrEqual(nodes[i]->name, BAD_CAST "mode")) { + xmlNodeSetName(nodes[i], (const xmlChar *)"cpu"); + while (nodes[i]->properties) { + if (xmlRemoveProp(nodes[i]->properties) < 0) { + vshError(ctl, + _("Cannot extract CPU definition from domain " + "capabilities XML")); + goto error; + } + } + } + if (!(cpus[i] = virXMLNodeToString(xml, nodes[i]))) { vshSaveLibvirtError(); goto error; diff --git a/tools/virsh.pod b/tools/virsh.pod index 5fc8201893..ea10e1ad43 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -589,9 +589,11 @@ Compare CPU definition from XML <file> with host CPU. The XML <file> may contain either host or guest CPU definition. The host CPU definition is the <cpu> element and its contents as printed by B<capabilities> command. The guest CPU definition is the <cpu> element and its contents from domain XML -definition. In addition to the <cpu> element itself, this command accepts -full domain or capabilities XML containing the <cpu> element. For more -information on guest CPU definition see: +definition or the CPU definition created from the host CPU model found in +domain capabilities XML (printed by B<domcapabilities> command). In +addition to the <cpu> element itself, this command accepts +full domain XML, capabilities XML, or domain capabilities XML containing +the CPU definition. For more information on guest CPU definition see: L<https://libvirt.org/formatdomain.html#elementsCPU>. If I<--error> is specified, the command will return an error when the given CPU is incompatible with host CPU and a message providing more details about the
Reviewed-by: Collin Walling <walling@linux.ibm.com> -- Respectfully, - Collin Walling

On Wed, May 16, 2018 at 10:39:25AM +0200, Jiri Denemark wrote:
The domain capabilities XML contains host CPU model tailored to a specific hypervisor and since it's enclosed in <mode name='host-model'> element rather then the required <cpu> it's impossible to directly use the host CPU model as an input to, e.g., cpu-compare command. To make this more convenient, vshExtractCPUDefXML now accepts full domain capabilities XML and automatically transforms the host CPU models into the form accepted by libvirt APIs.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh-host.c | 26 ++++++++++++++++++++++---- tools/virsh.pod | 8 +++++--- 2 files changed, 27 insertions(+), 7 deletions(-)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

virConnectGetDomainCapabilities needs to lookup QEMU capabilities matching a specified binary, architecture, virt type, and machine type while using default values when any of the parameters are not provided by the user. Let's extract the lookup code into virQEMUCapsCacheLookupDefault to make it reusable. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_capabilities.c | 118 +++++++++++++++++++++++++++++++++++ src/qemu/qemu_capabilities.h | 8 +++ src/qemu/qemu_driver.c | 86 ++++--------------------- 3 files changed, 137 insertions(+), 75 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index a5cb24fec6..77a4b4154e 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -4546,6 +4546,124 @@ virQEMUCapsCacheLookupByArch(virFileCachePtr cache, } +/** + * virQEMUCapsCacheLookupDefault: + * @cache: QEMU capabilities cache + * @binary: optional path to QEMU binary + * @archStr: optional guest architecture + * @virttypeStr: optional virt type + * @machine: optional machine type + * @retArch: if non-NULL, guest architecture will be returned here + * @retVirttype: if non-NULL, domain virt type will be returned here + * @retMachine: if non-NULL, canonical machine type will be returned here + * + * Looks up the QEMU binary specified by @binary and @archStr, checks it can + * provide the required @virttypeStr and @machine and returns its capabilities. + * Sensible defaults are used for any argument which is NULL (the function can + * even be called with all NULL arguments). + * + * Returns QEMU capabilities matching the requirements, NULL on error. + */ +virQEMUCapsPtr +virQEMUCapsCacheLookupDefault(virFileCachePtr cache, + const char *binary, + const char *archStr, + const char *virttypeStr, + const char *machine, + virArch *retArch, + virDomainVirtType *retVirttype, + const char **retMachine) +{ + int virttype = VIR_DOMAIN_VIRT_NONE; + int arch = virArchFromHost(); + virDomainVirtType capsType; + virQEMUCapsPtr qemuCaps = NULL; + virQEMUCapsPtr ret = NULL; + + if (virttypeStr && + (virttype = virDomainVirtTypeFromString(virttypeStr)) < 0) { + virReportError(VIR_ERR_INVALID_ARG, + _("unknown virttype: %s"), virttypeStr); + goto cleanup; + } + + if (archStr && + (arch = virArchFromString(archStr)) == VIR_ARCH_NONE) { + virReportError(VIR_ERR_INVALID_ARG, + _("unknown architecture: %s"), archStr); + goto cleanup; + } + + if (binary) { + virArch arch_from_caps; + + if (!(qemuCaps = virQEMUCapsCacheLookup(cache, binary))) + goto cleanup; + + arch_from_caps = virQEMUCapsGetArch(qemuCaps); + + if (arch_from_caps != arch && + !((ARCH_IS_X86(arch) && ARCH_IS_X86(arch_from_caps)) || + (ARCH_IS_PPC(arch) && ARCH_IS_PPC(arch_from_caps)) || + (ARCH_IS_ARM(arch) && ARCH_IS_ARM(arch_from_caps)) || + (ARCH_IS_S390(arch) && ARCH_IS_S390(arch_from_caps)))) { + virReportError(VIR_ERR_INVALID_ARG, + _("architecture from emulator '%s' doesn't " + "match given architecture '%s'"), + virArchToString(arch_from_caps), + virArchToString(arch)); + goto cleanup; + } + } else { + if (!(qemuCaps = virQEMUCapsCacheLookupByArch(cache, arch))) + goto cleanup; + + binary = virQEMUCapsGetBinary(qemuCaps); + } + + if (machine) { + /* Turn @machine into canonical name */ + machine = virQEMUCapsGetCanonicalMachine(qemuCaps, machine); + + if (!virQEMUCapsIsMachineSupported(qemuCaps, machine)) { + virReportError(VIR_ERR_INVALID_ARG, + _("the machine '%s' is not supported by emulator '%s'"), + machine, binary); + goto cleanup; + } + } else { + machine = virQEMUCapsGetDefaultMachine(qemuCaps); + } + + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) + capsType = VIR_DOMAIN_VIRT_KVM; + else + capsType = VIR_DOMAIN_VIRT_QEMU; + + if (virttype == VIR_DOMAIN_VIRT_NONE) + virttype = capsType; + + if (virttype == VIR_DOMAIN_VIRT_KVM && capsType == VIR_DOMAIN_VIRT_QEMU) { + virReportError(VIR_ERR_INVALID_ARG, + _("KVM is not supported by '%s' on this host"), + binary); + goto cleanup; + } + + if (retArch) + *retArch = arch; + if (retVirttype) + *retVirttype = virttype; + if (retMachine) + *retMachine = machine; + + VIR_STEAL_PTR(ret, qemuCaps); + + cleanup: + virObjectUnref(qemuCaps); + return ret; +} + bool virQEMUCapsSupportsVmport(virQEMUCapsPtr qemuCaps, const virDomainDef *def) diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index d23c34c24d..6f095bfbfe 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -559,6 +559,14 @@ virQEMUCapsPtr virQEMUCapsCacheLookupCopy(virFileCachePtr cache, const char *machineType); virQEMUCapsPtr virQEMUCapsCacheLookupByArch(virFileCachePtr cache, virArch arch); +virQEMUCapsPtr virQEMUCapsCacheLookupDefault(virFileCachePtr cache, + const char *binary, + const char *archStr, + const char *virttypeStr, + const char *machine, + virArch *retArch, + virDomainVirtType *retVirttype, + const char **retMachine); virCapsPtr virQEMUCapsInit(virFileCachePtr cache); diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 9037818e2a..6c086b9ef8 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -19249,10 +19249,9 @@ qemuConnectGetDomainCapabilities(virConnectPtr conn, char *ret = NULL; virQEMUDriverPtr driver = conn->privateData; virQEMUCapsPtr qemuCaps = NULL; - int virttype = VIR_DOMAIN_VIRT_NONE; - virDomainVirtType capsType; + virArch arch; + virDomainVirtType virttype; virDomainCapsPtr domCaps = NULL; - int arch = virArchFromHost(); /* virArch */ virQEMUDriverConfigPtr cfg = NULL; virCapsPtr caps = NULL; @@ -19266,80 +19265,17 @@ qemuConnectGetDomainCapabilities(virConnectPtr conn, if (!(caps = virQEMUDriverGetCapabilities(driver, false))) goto cleanup; - if (virttype_str && - (virttype = virDomainVirtTypeFromString(virttype_str)) < 0) { - virReportError(VIR_ERR_INVALID_ARG, - _("unknown virttype: %s"), - virttype_str); + qemuCaps = virQEMUCapsCacheLookupDefault(driver->qemuCapsCache, + emulatorbin, + arch_str, + virttype_str, + machine, + &arch, &virttype, &machine); + if (!qemuCaps) goto cleanup; - } - if (arch_str && (arch = virArchFromString(arch_str)) == VIR_ARCH_NONE) { - virReportError(VIR_ERR_INVALID_ARG, - _("unknown architecture: %s"), - arch_str); - goto cleanup; - } - - if (emulatorbin) { - virArch arch_from_caps; - - if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, - emulatorbin))) - goto cleanup; - - arch_from_caps = virQEMUCapsGetArch(qemuCaps); - - if (arch_from_caps != arch && - !((ARCH_IS_X86(arch) && ARCH_IS_X86(arch_from_caps)) || - (ARCH_IS_PPC(arch) && ARCH_IS_PPC(arch_from_caps)) || - (ARCH_IS_ARM(arch) && ARCH_IS_ARM(arch_from_caps)) || - (ARCH_IS_S390(arch) && ARCH_IS_S390(arch_from_caps)))) { - virReportError(VIR_ERR_INVALID_ARG, - _("architecture from emulator '%s' doesn't " - "match given architecture '%s'"), - virArchToString(arch_from_caps), - virArchToString(arch)); - goto cleanup; - } - } else { - if (!(qemuCaps = virQEMUCapsCacheLookupByArch(driver->qemuCapsCache, - arch))) - goto cleanup; - - emulatorbin = virQEMUCapsGetBinary(qemuCaps); - } - - if (machine) { - /* Turn @machine into canonical name */ - machine = virQEMUCapsGetCanonicalMachine(qemuCaps, machine); - - if (!virQEMUCapsIsMachineSupported(qemuCaps, machine)) { - virReportError(VIR_ERR_INVALID_ARG, - _("the machine '%s' is not supported by emulator '%s'"), - machine, emulatorbin); - goto cleanup; - } - } else { - machine = virQEMUCapsGetDefaultMachine(qemuCaps); - } - - if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) - capsType = VIR_DOMAIN_VIRT_KVM; - else - capsType = VIR_DOMAIN_VIRT_QEMU; - - if (virttype == VIR_DOMAIN_VIRT_NONE) - virttype = capsType; - - if (virttype == VIR_DOMAIN_VIRT_KVM && capsType == VIR_DOMAIN_VIRT_QEMU) { - virReportError(VIR_ERR_INVALID_ARG, - _("KVM is not supported by '%s' on this host"), - emulatorbin); - goto cleanup; - } - - if (!(domCaps = virDomainCapsNew(emulatorbin, machine, arch, virttype))) + if (!(domCaps = virDomainCapsNew(virQEMUCapsGetBinary(qemuCaps), machine, + arch, virttype))) goto cleanup; if (virQEMUCapsFillDomainCaps(caps, domCaps, qemuCaps, -- 2.17.0

On 05/16/2018 04:39 AM, Jiri Denemark wrote:
virConnectGetDomainCapabilities needs to lookup QEMU capabilities matching a specified binary, architecture, virt type, and machine type while using default values when any of the parameters are not provided by the user. Let's extract the lookup code into virQEMUCapsCacheLookupDefault to make it reusable.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_capabilities.c | 118 +++++++++++++++++++++++++++++++++++ src/qemu/qemu_capabilities.h | 8 +++ src/qemu/qemu_driver.c | 86 ++++--------------------- 3 files changed, 137 insertions(+), 75 deletions(-)
[...]
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 9037818e2a..6c086b9ef8 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -19249,10 +19249,9 @@ qemuConnectGetDomainCapabilities(virConnectPtr conn, char *ret = NULL; virQEMUDriverPtr driver = conn->privateData; virQEMUCapsPtr qemuCaps = NULL; - int virttype = VIR_DOMAIN_VIRT_NONE; - virDomainVirtType capsType; + virArch arch; + virDomainVirtType virttype; virDomainCapsPtr domCaps = NULL; - int arch = virArchFromHost(); /* virArch */ virQEMUDriverConfigPtr cfg = NULL; virCapsPtr caps = NULL;
@@ -19266,80 +19265,17 @@ qemuConnectGetDomainCapabilities(virConnectPtr conn, if (!(caps = virQEMUDriverGetCapabilities(driver, false))) goto cleanup;
- if (virttype_str && - (virttype = virDomainVirtTypeFromString(virttype_str)) < 0) { - virReportError(VIR_ERR_INVALID_ARG, - _("unknown virttype: %s"), - virttype_str); + qemuCaps = virQEMUCapsCacheLookupDefault(driver->qemuCapsCache, + emulatorbin, + arch_str, + virttype_str, + machine, + &arch, &virttype, &machine); + if (!qemuCaps) goto cleanup; - }
- if (arch_str && (arch = virArchFromString(arch_str)) == VIR_ARCH_NONE) { - virReportError(VIR_ERR_INVALID_ARG, - _("unknown architecture: %s"), - arch_str); - goto cleanup; - } - - if (emulatorbin) { - virArch arch_from_caps; - - if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, - emulatorbin))) - goto cleanup; - - arch_from_caps = virQEMUCapsGetArch(qemuCaps); - - if (arch_from_caps != arch && - !((ARCH_IS_X86(arch) && ARCH_IS_X86(arch_from_caps)) || - (ARCH_IS_PPC(arch) && ARCH_IS_PPC(arch_from_caps)) || - (ARCH_IS_ARM(arch) && ARCH_IS_ARM(arch_from_caps)) || - (ARCH_IS_S390(arch) && ARCH_IS_S390(arch_from_caps)))) { - virReportError(VIR_ERR_INVALID_ARG, - _("architecture from emulator '%s' doesn't " - "match given architecture '%s'"), - virArchToString(arch_from_caps), - virArchToString(arch)); - goto cleanup; - }
Are all these checks necessary? Can't you get away with just checking arch_from_caps != arch?
- } else { - if (!(qemuCaps = virQEMUCapsCacheLookupByArch(driver->qemuCapsCache, - arch))) - goto cleanup; - - emulatorbin = virQEMUCapsGetBinary(qemuCaps); - } - - if (machine) { - /* Turn @machine into canonical name */ - machine = virQEMUCapsGetCanonicalMachine(qemuCaps, machine); - - if (!virQEMUCapsIsMachineSupported(qemuCaps, machine)) { - virReportError(VIR_ERR_INVALID_ARG, - _("the machine '%s' is not supported by emulator '%s'"), - machine, emulatorbin); - goto cleanup; - } - } else { - machine = virQEMUCapsGetDefaultMachine(qemuCaps); - } - - if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) - capsType = VIR_DOMAIN_VIRT_KVM; - else - capsType = VIR_DOMAIN_VIRT_QEMU; - - if (virttype == VIR_DOMAIN_VIRT_NONE) - virttype = capsType; - - if (virttype == VIR_DOMAIN_VIRT_KVM && capsType == VIR_DOMAIN_VIRT_QEMU) { - virReportError(VIR_ERR_INVALID_ARG, - _("KVM is not supported by '%s' on this host"), - emulatorbin); - goto cleanup; - } - - if (!(domCaps = virDomainCapsNew(emulatorbin, machine, arch, virttype))) + if (!(domCaps = virDomainCapsNew(virQEMUCapsGetBinary(qemuCaps), machine, + arch, virttype))) goto cleanup;
if (virQEMUCapsFillDomainCaps(caps, domCaps, qemuCaps,
-- Respectfully, - Collin Walling

On Tue, May 22, 2018 at 18:24:57 -0400, Collin Walling wrote:
On 05/16/2018 04:39 AM, Jiri Denemark wrote:
virConnectGetDomainCapabilities needs to lookup QEMU capabilities matching a specified binary, architecture, virt type, and machine type while using default values when any of the parameters are not provided by the user. Let's extract the lookup code into virQEMUCapsCacheLookupDefault to make it reusable.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_capabilities.c | 118 +++++++++++++++++++++++++++++++++++ src/qemu/qemu_capabilities.h | 8 +++ src/qemu/qemu_driver.c | 86 ++++--------------------- 3 files changed, 137 insertions(+), 75 deletions(-)
[...]
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 9037818e2a..6c086b9ef8 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -19249,10 +19249,9 @@ qemuConnectGetDomainCapabilities(virConnectPtr conn, char *ret = NULL; virQEMUDriverPtr driver = conn->privateData; virQEMUCapsPtr qemuCaps = NULL; - int virttype = VIR_DOMAIN_VIRT_NONE; - virDomainVirtType capsType; + virArch arch; + virDomainVirtType virttype; virDomainCapsPtr domCaps = NULL; - int arch = virArchFromHost(); /* virArch */ virQEMUDriverConfigPtr cfg = NULL; virCapsPtr caps = NULL;
@@ -19266,80 +19265,17 @@ qemuConnectGetDomainCapabilities(virConnectPtr conn, if (!(caps = virQEMUDriverGetCapabilities(driver, false))) goto cleanup;
- if (virttype_str && - (virttype = virDomainVirtTypeFromString(virttype_str)) < 0) { - virReportError(VIR_ERR_INVALID_ARG, - _("unknown virttype: %s"), - virttype_str); + qemuCaps = virQEMUCapsCacheLookupDefault(driver->qemuCapsCache, + emulatorbin, + arch_str, + virttype_str, + machine, + &arch, &virttype, &machine); + if (!qemuCaps) goto cleanup; - }
- if (arch_str && (arch = virArchFromString(arch_str)) == VIR_ARCH_NONE) { - virReportError(VIR_ERR_INVALID_ARG, - _("unknown architecture: %s"), - arch_str); - goto cleanup; - } - - if (emulatorbin) { - virArch arch_from_caps; - - if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, - emulatorbin))) - goto cleanup; - - arch_from_caps = virQEMUCapsGetArch(qemuCaps); - - if (arch_from_caps != arch && - !((ARCH_IS_X86(arch) && ARCH_IS_X86(arch_from_caps)) || - (ARCH_IS_PPC(arch) && ARCH_IS_PPC(arch_from_caps)) || - (ARCH_IS_ARM(arch) && ARCH_IS_ARM(arch_from_caps)) || - (ARCH_IS_S390(arch) && ARCH_IS_S390(arch_from_caps)))) { - virReportError(VIR_ERR_INVALID_ARG, - _("architecture from emulator '%s' doesn't " - "match given architecture '%s'"), - virArchToString(arch_from_caps), - virArchToString(arch)); - goto cleanup; - }
Are all these checks necessary? Can't you get away with just checking arch_from_caps != arch?
Yes, because i686 != x86_64, while ARCH_IS_X86(i686) && ARCH_IS_X86(x86_64) is true. Jirka

On Wed, May 16, 2018 at 10:39:26AM +0200, Jiri Denemark wrote:
virConnectGetDomainCapabilities needs to lookup QEMU capabilities matching a specified binary, architecture, virt type, and machine type while using default values when any of the parameters are not provided by the user. Let's extract the lookup code into virQEMUCapsCacheLookupDefault to make it reusable.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_capabilities.c | 118 +++++++++++++++++++++++++++++++++++ src/qemu/qemu_capabilities.h | 8 +++ src/qemu/qemu_driver.c | 86 ++++--------------------- 3 files changed, 137 insertions(+), 75 deletions(-)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

This new API compares the given CPU description with the CPU the specified hypervisor is able to provide on the host. It is a more useful version of virConnectCompareCPU, which compares the CPU definition with the host CPU without considering any specific hypervisor and its abilities. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- include/libvirt/libvirt-host.h | 7 ++++ src/driver-hypervisor.h | 10 +++++ src/libvirt-host.c | 72 +++++++++++++++++++++++++++++++++- src/libvirt_public.syms | 5 +++ 4 files changed, 93 insertions(+), 1 deletion(-) diff --git a/include/libvirt/libvirt-host.h b/include/libvirt/libvirt-host.h index 07b5d15943..e2054baebc 100644 --- a/include/libvirt/libvirt-host.h +++ b/include/libvirt/libvirt-host.h @@ -640,6 +640,13 @@ typedef enum { int virConnectCompareCPU(virConnectPtr conn, const char *xmlDesc, unsigned int flags); +int virConnectCompareHypervisorCPU(virConnectPtr conn, + const char *emulator, + const char *arch, + const char *machine, + const char *virttype, + const char *xmlCPU, + unsigned int flags); int virConnectGetCPUModelNames(virConnectPtr conn, const char *arch, diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h index e71a72a441..d64de2d54c 100644 --- a/src/driver-hypervisor.h +++ b/src/driver-hypervisor.h @@ -673,6 +673,15 @@ typedef int const char *cpu, unsigned int flags); +typedef int +(*virDrvConnectCompareHypervisorCPU)(virConnectPtr conn, + const char *emulator, + const char *arch, + const char *machine, + const char *virttype, + const char *xmlCPU, + unsigned int flags); + typedef char * (*virDrvConnectBaselineCPU)(virConnectPtr conn, const char **xmlCPUs, @@ -1532,6 +1541,7 @@ struct _virHypervisorDriver { virDrvDomainSetVcpu domainSetVcpu; virDrvDomainSetBlockThreshold domainSetBlockThreshold; virDrvDomainSetLifecycleAction domainSetLifecycleAction; + virDrvConnectCompareHypervisorCPU connectCompareHypervisorCPU; }; diff --git a/src/libvirt-host.c b/src/libvirt-host.c index ed689b9ec2..17cf183499 100644 --- a/src/libvirt-host.c +++ b/src/libvirt-host.c @@ -954,7 +954,11 @@ virConnectIsSecure(virConnectPtr conn) * @xmlDesc: XML describing the CPU to compare with host CPU * @flags: bitwise-OR of virConnectCompareCPUFlags * - * Compares the given CPU description with the host CPU + * Compares the given CPU description with the host CPU. + * + * See vitConnectCompareHypervisorCPU() if you want to consider hypervisor + * abilities and compare the CPU to the CPU which a hypervisor is able to + * provide on the host. * * Returns comparison result according to enum virCPUCompareResult. If * VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE is used and @xmlDesc CPU is @@ -992,6 +996,72 @@ virConnectCompareCPU(virConnectPtr conn, } +/** + * virConnectCompareHypervisorCPU: + * @conn: pointer to the hypervisor connection + * @emulator: path to the emulator binary + * @arch: domain architecture + * @machine: machine type + * @virttype: virtualization type + * @xmlCPU: XML describing the CPU to be compared + * @flags: bitwise-OR of virConnectCompareCPUFlags + * + * Compares the given CPU description with the CPU the specified hypervisor is + * able to provide on the host. Any of @emulator, @arch, @machine, and + * @virttype parameters may be NULL; libvirt will choose sensible defaults + * tailored to the host and its current configuration. + * + * This is different from virConnectCompareCPU() which compares the CPU + * definition with the host CPU without considering any specific hypervisor and + * its abilities. + * + * Returns comparison result according to enum virCPUCompareResult. If + * VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE is used and @xmlCPU is + * incompatible with the CPU the specified hypervisor is able to provide on the + * host, this function will return VIR_CPU_COMPARE_ERROR (instead of + * VIR_CPU_COMPARE_INCOMPATIBLE) and the error will use the + * VIR_ERR_CPU_INCOMPATIBLE code with a message providing more details about + * the incompatibility. + */ +int +virConnectCompareHypervisorCPU(virConnectPtr conn, + const char *emulator, + const char *arch, + const char *machine, + const char *virttype, + const char *xmlCPU, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, emulator=%s, arch=%s, machine=%s, " + "virttype=%s, xmlCPU=%s, flags=0x%x", + conn, NULLSTR(emulator), NULLSTR(arch), NULLSTR(machine), + NULLSTR(virttype), NULLSTR(xmlCPU), flags); + + virResetLastError(); + + virCheckConnectReturn(conn, VIR_CPU_COMPARE_ERROR); + virCheckNonNullArgGoto(xmlCPU, error); + + if (conn->driver->connectCompareHypervisorCPU) { + int ret; + + ret = conn->driver->connectCompareHypervisorCPU(conn, emulator, arch, + machine, virttype, + xmlCPU, flags); + if (ret == VIR_CPU_COMPARE_ERROR) + goto error; + + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(conn); + return VIR_CPU_COMPARE_ERROR; +} + + /** * virConnectGetCPUModelNames: * diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 95df3a0dbc..97597d7708 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -785,4 +785,9 @@ LIBVIRT_4.1.0 { virStoragePoolLookupByTargetPath; } LIBVIRT_3.9.0; +LIBVIRT_4.4.0 { + global: + virConnectCompareHypervisorCPU; +} LIBVIRT_4.1.0; + # .... define new API here using predicted next version number .... -- 2.17.0

On 05/16/2018 04:39 AM, Jiri Denemark wrote:
This new API compares the given CPU description with the CPU the specified hypervisor is able to provide on the host. It is a more useful version of virConnectCompareCPU, which compares the CPU definition with the host CPU without considering any specific hypervisor and its abilities.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- include/libvirt/libvirt-host.h | 7 ++++ src/driver-hypervisor.h | 10 +++++ src/libvirt-host.c | 72 +++++++++++++++++++++++++++++++++- src/libvirt_public.syms | 5 +++ 4 files changed, 93 insertions(+), 1 deletion(-)
diff --git a/include/libvirt/libvirt-host.h b/include/libvirt/libvirt-host.h index 07b5d15943..e2054baebc 100644 --- a/include/libvirt/libvirt-host.h +++ b/include/libvirt/libvirt-host.h @@ -640,6 +640,13 @@ typedef enum { int virConnectCompareCPU(virConnectPtr conn, const char *xmlDesc, unsigned int flags); +int virConnectCompareHypervisorCPU(virConnectPtr conn, + const char *emulator, + const char *arch, + const char *machine, + const char *virttype, + const char *xmlCPU, + unsigned int flags);
int virConnectGetCPUModelNames(virConnectPtr conn, const char *arch, diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h index e71a72a441..d64de2d54c 100644 --- a/src/driver-hypervisor.h +++ b/src/driver-hypervisor.h @@ -673,6 +673,15 @@ typedef int const char *cpu, unsigned int flags);
+typedef int +(*virDrvConnectCompareHypervisorCPU)(virConnectPtr conn, + const char *emulator, + const char *arch, + const char *machine, + const char *virttype, + const char *xmlCPU, + unsigned int flags); + typedef char * (*virDrvConnectBaselineCPU)(virConnectPtr conn, const char **xmlCPUs, @@ -1532,6 +1541,7 @@ struct _virHypervisorDriver { virDrvDomainSetVcpu domainSetVcpu; virDrvDomainSetBlockThreshold domainSetBlockThreshold; virDrvDomainSetLifecycleAction domainSetLifecycleAction; + virDrvConnectCompareHypervisorCPU connectCompareHypervisorCPU; };
diff --git a/src/libvirt-host.c b/src/libvirt-host.c index ed689b9ec2..17cf183499 100644 --- a/src/libvirt-host.c +++ b/src/libvirt-host.c @@ -954,7 +954,11 @@ virConnectIsSecure(virConnectPtr conn) * @xmlDesc: XML describing the CPU to compare with host CPU * @flags: bitwise-OR of virConnectCompareCPUFlags * - * Compares the given CPU description with the host CPU + * Compares the given CPU description with the host CPU. + * + * See vitConnectCompareHypervisorCPU() if you want to consider hypervisor + * abilities and compare the CPU to the CPU which a hypervisor is able to + * provide on the host. * * Returns comparison result according to enum virCPUCompareResult. If * VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE is used and @xmlDesc CPU is @@ -992,6 +996,72 @@ virConnectCompareCPU(virConnectPtr conn, }
+/** + * virConnectCompareHypervisorCPU: + * @conn: pointer to the hypervisor connection + * @emulator: path to the emulator binary + * @arch: domain architecture + * @machine: machine type + * @virttype: virtualization type + * @xmlCPU: XML describing the CPU to be compared + * @flags: bitwise-OR of virConnectCompareCPUFlags + * + * Compares the given CPU description with the CPU the specified hypervisor is + * able to provide on the host. Any of @emulator, @arch, @machine, and + * @virttype parameters may be NULL; libvirt will choose sensible defaults + * tailored to the host and its current configuration. + * + * This is different from virConnectCompareCPU() which compares the CPU + * definition with the host CPU without considering any specific hypervisor and + * its abilities. + * + * Returns comparison result according to enum virCPUCompareResult. If + * VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE is used and @xmlCPU is + * incompatible with the CPU the specified hypervisor is able to provide on the + * host, this function will return VIR_CPU_COMPARE_ERROR (instead of + * VIR_CPU_COMPARE_INCOMPATIBLE) and the error will use the + * VIR_ERR_CPU_INCOMPATIBLE code with a message providing more details about + * the incompatibility. + */ +int +virConnectCompareHypervisorCPU(virConnectPtr conn, + const char *emulator, + const char *arch, + const char *machine, + const char *virttype, + const char *xmlCPU, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, emulator=%s, arch=%s, machine=%s, " + "virttype=%s, xmlCPU=%s, flags=0x%x", + conn, NULLSTR(emulator), NULLSTR(arch), NULLSTR(machine), + NULLSTR(virttype), NULLSTR(xmlCPU), flags); + + virResetLastError(); + + virCheckConnectReturn(conn, VIR_CPU_COMPARE_ERROR); + virCheckNonNullArgGoto(xmlCPU, error); + + if (conn->driver->connectCompareHypervisorCPU) { + int ret; + + ret = conn->driver->connectCompareHypervisorCPU(conn, emulator, arch, + machine, virttype, + xmlCPU, flags); + if (ret == VIR_CPU_COMPARE_ERROR) + goto error;
Admittedly I did not look too closely, but will the compareHypervisorCPU functions actually return "VIR_CPU_COMPARE_ERROR" on error? If so, wouldn't it be more sensible to return a "VIR_HYPERVISOR_CPU_COMPARE_ERROR" instead?
+ + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(conn); + return VIR_CPU_COMPARE_ERROR; +} + + /** * virConnectGetCPUModelNames: * diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 95df3a0dbc..97597d7708 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -785,4 +785,9 @@ LIBVIRT_4.1.0 { virStoragePoolLookupByTargetPath; } LIBVIRT_3.9.0;
+LIBVIRT_4.4.0 { + global: + virConnectCompareHypervisorCPU; +} LIBVIRT_4.1.0; + # .... define new API here using predicted next version number ....
-- Respectfully, - Collin Walling

On Tue, May 22, 2018 at 18:27:51 -0400, Collin Walling wrote:
On 05/16/2018 04:39 AM, Jiri Denemark wrote:
This new API compares the given CPU description with the CPU the specified hypervisor is able to provide on the host. It is a more useful version of virConnectCompareCPU, which compares the CPU definition with the host CPU without considering any specific hypervisor and its abilities.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- include/libvirt/libvirt-host.h | 7 ++++ src/driver-hypervisor.h | 10 +++++ src/libvirt-host.c | 72 +++++++++++++++++++++++++++++++++- src/libvirt_public.syms | 5 +++ 4 files changed, 93 insertions(+), 1 deletion(-)
diff --git a/include/libvirt/libvirt-host.h b/include/libvirt/libvirt-host.h index 07b5d15943..e2054baebc 100644 --- a/include/libvirt/libvirt-host.h +++ b/include/libvirt/libvirt-host.h @@ -640,6 +640,13 @@ typedef enum { int virConnectCompareCPU(virConnectPtr conn, const char *xmlDesc, unsigned int flags); +int virConnectCompareHypervisorCPU(virConnectPtr conn, + const char *emulator, + const char *arch, + const char *machine, + const char *virttype, + const char *xmlCPU, + unsigned int flags);
int virConnectGetCPUModelNames(virConnectPtr conn, const char *arch, diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h index e71a72a441..d64de2d54c 100644 --- a/src/driver-hypervisor.h +++ b/src/driver-hypervisor.h @@ -673,6 +673,15 @@ typedef int const char *cpu, unsigned int flags);
+typedef int +(*virDrvConnectCompareHypervisorCPU)(virConnectPtr conn, + const char *emulator, + const char *arch, + const char *machine, + const char *virttype, + const char *xmlCPU, + unsigned int flags); + typedef char * (*virDrvConnectBaselineCPU)(virConnectPtr conn, const char **xmlCPUs, @@ -1532,6 +1541,7 @@ struct _virHypervisorDriver { virDrvDomainSetVcpu domainSetVcpu; virDrvDomainSetBlockThreshold domainSetBlockThreshold; virDrvDomainSetLifecycleAction domainSetLifecycleAction; + virDrvConnectCompareHypervisorCPU connectCompareHypervisorCPU; };
diff --git a/src/libvirt-host.c b/src/libvirt-host.c index ed689b9ec2..17cf183499 100644 --- a/src/libvirt-host.c +++ b/src/libvirt-host.c @@ -954,7 +954,11 @@ virConnectIsSecure(virConnectPtr conn) * @xmlDesc: XML describing the CPU to compare with host CPU * @flags: bitwise-OR of virConnectCompareCPUFlags * - * Compares the given CPU description with the host CPU + * Compares the given CPU description with the host CPU. + * + * See vitConnectCompareHypervisorCPU() if you want to consider hypervisor + * abilities and compare the CPU to the CPU which a hypervisor is able to + * provide on the host. * * Returns comparison result according to enum virCPUCompareResult. If * VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE is used and @xmlDesc CPU is @@ -992,6 +996,72 @@ virConnectCompareCPU(virConnectPtr conn, }
+/** + * virConnectCompareHypervisorCPU: + * @conn: pointer to the hypervisor connection + * @emulator: path to the emulator binary + * @arch: domain architecture + * @machine: machine type + * @virttype: virtualization type + * @xmlCPU: XML describing the CPU to be compared + * @flags: bitwise-OR of virConnectCompareCPUFlags + * + * Compares the given CPU description with the CPU the specified hypervisor is + * able to provide on the host. Any of @emulator, @arch, @machine, and + * @virttype parameters may be NULL; libvirt will choose sensible defaults + * tailored to the host and its current configuration. + * + * This is different from virConnectCompareCPU() which compares the CPU + * definition with the host CPU without considering any specific hypervisor and + * its abilities. + * + * Returns comparison result according to enum virCPUCompareResult. If + * VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE is used and @xmlCPU is + * incompatible with the CPU the specified hypervisor is able to provide on the + * host, this function will return VIR_CPU_COMPARE_ERROR (instead of + * VIR_CPU_COMPARE_INCOMPATIBLE) and the error will use the + * VIR_ERR_CPU_INCOMPATIBLE code with a message providing more details about + * the incompatibility. + */ +int +virConnectCompareHypervisorCPU(virConnectPtr conn, + const char *emulator, + const char *arch, + const char *machine, + const char *virttype, + const char *xmlCPU, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, emulator=%s, arch=%s, machine=%s, " + "virttype=%s, xmlCPU=%s, flags=0x%x", + conn, NULLSTR(emulator), NULLSTR(arch), NULLSTR(machine), + NULLSTR(virttype), NULLSTR(xmlCPU), flags); + + virResetLastError(); + + virCheckConnectReturn(conn, VIR_CPU_COMPARE_ERROR); + virCheckNonNullArgGoto(xmlCPU, error); + + if (conn->driver->connectCompareHypervisorCPU) { + int ret; + + ret = conn->driver->connectCompareHypervisorCPU(conn, emulator, arch, + machine, virttype, + xmlCPU, flags); + if (ret == VIR_CPU_COMPARE_ERROR) + goto error;
Admittedly I did not look too closely, but will the compareHypervisorCPU functions actually return "VIR_CPU_COMPARE_ERROR" on error? If so, wouldn't it be more sensible to return a "VIR_HYPERVISOR_CPU_COMPARE_ERROR" instead?
The function returns a value from enum virCPUCompareResult just like the original connectCompareCPU API. I don't see a reason for introducing a new set of return values for the new connectCompareHypervisorCPU. Jirka

+ if (ret == VIR_CPU_COMPARE_ERROR) + goto error;
Admittedly I did not look too closely, but will the compareHypervisorCPU functions actually return "VIR_CPU_COMPARE_ERROR" on error? If so, wouldn't it be more sensible to return a "VIR_HYPERVISOR_CPU_COMPARE_ERROR" instead?
The function returns a value from enum virCPUCompareResult just like the original connectCompareCPU API. I don't see a reason for introducing a new set of return values for the new connectCompareHypervisorCPU.
Yeah, that makes sense. Reviewed-by: Collin Walling <walling@linux.ibm.com> -- Respectfully, - Collin Walling

On Wed, May 16, 2018 at 10:39:27AM +0200, Jiri Denemark wrote:
This new API compares the given CPU description with the CPU the specified hypervisor is able to provide on the host. It is a more useful version of virConnectCompareCPU, which compares the CPU definition with the host CPU without considering any specific hypervisor and its abilities.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- include/libvirt/libvirt-host.h | 7 ++++ src/driver-hypervisor.h | 10 +++++ src/libvirt-host.c | 72 +++++++++++++++++++++++++++++++++- src/libvirt_public.syms | 5 +++ 4 files changed, 93 insertions(+), 1 deletion(-)
diff --git a/include/libvirt/libvirt-host.h b/include/libvirt/libvirt-host.h index 07b5d15943..e2054baebc 100644 --- a/include/libvirt/libvirt-host.h +++ b/include/libvirt/libvirt-host.h diff --git a/src/libvirt-host.c b/src/libvirt-host.c index ed689b9ec2..17cf183499 100644 --- a/src/libvirt-host.c +++ b/src/libvirt-host.c @@ -954,7 +954,11 @@ virConnectIsSecure(virConnectPtr conn) * @xmlDesc: XML describing the CPU to compare with host CPU * @flags: bitwise-OR of virConnectCompareCPUFlags * - * Compares the given CPU description with the host CPU + * Compares the given CPU description with the host CPU. + * + * See vitConnectCompareHypervisorCPU() if you want to consider hypervisor
s/vit/vir/
+ * abilities and compare the CPU to the CPU which a hypervisor is able to + * provide on the host. * * Returns comparison result according to enum virCPUCompareResult. If * VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE is used and @xmlDesc CPU is
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/remote/remote_driver.c | 3 ++- src/remote/remote_protocol.x | 21 ++++++++++++++++++++- src/remote_protocol-structs | 12 ++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 95437b4365..acefe8c457 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -8448,7 +8448,8 @@ static virHypervisorDriver hypervisor_driver = { .domainSetGuestVcpus = remoteDomainSetGuestVcpus, /* 2.0.0 */ .domainSetVcpu = remoteDomainSetVcpu, /* 3.1.0 */ .domainSetBlockThreshold = remoteDomainSetBlockThreshold, /* 3.2.0 */ - .domainSetLifecycleAction = remoteDomainSetLifecycleAction /* 3.9.0 */ + .domainSetLifecycleAction = remoteDomainSetLifecycleAction, /* 3.9.0 */ + .connectCompareHypervisorCPU = remoteConnectCompareHypervisorCPU, /* 4.4.0 */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 296a087181..0aa123b5ac 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -3448,6 +3448,19 @@ struct remote_domain_set_lifecycle_action_args { unsigned int flags; }; +struct remote_connect_compare_hypervisor_cpu_args { + remote_string emulator; + remote_string arch; + remote_string machine; + remote_string virttype; + remote_nonnull_string xmlCPU; + unsigned int flags; +}; + +struct remote_connect_compare_hypervisor_cpu_ret { + int result; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -6135,5 +6148,11 @@ enum remote_procedure { * @priority: high * @acl: storage_pool:getattr */ - REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_TARGET_PATH = 391 + REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_TARGET_PATH = 391, + + /** + * @generate: both + * @acl: connect:write + */ + REMOTE_PROC_CONNECT_COMPARE_HYPERVISOR_CPU = 392 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index fe163db73f..64e48c52ba 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -2877,6 +2877,17 @@ struct remote_domain_set_lifecycle_action_args { u_int action; u_int flags; }; +struct remote_connect_compare_hypervisor_cpu_args { + remote_string emulator; + remote_string arch; + remote_string machine; + remote_string virttype; + remote_nonnull_string xmlCPU; + u_int flags; +}; +struct remote_connect_compare_hypervisor_cpu_ret { + int result; +}; enum remote_procedure { REMOTE_PROC_CONNECT_OPEN = 1, REMOTE_PROC_CONNECT_CLOSE = 2, @@ -3269,4 +3280,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_MANAGED_SAVE_DEFINE_XML = 389, REMOTE_PROC_DOMAIN_SET_LIFECYCLE_ACTION = 390, REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_TARGET_PATH = 391, + REMOTE_PROC_CONNECT_COMPARE_HYPERVISOR_CPU = 392, }; -- 2.17.0

On Wed, May 16, 2018 at 10:39:28AM +0200, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/remote/remote_driver.c | 3 ++- src/remote/remote_protocol.x | 21 ++++++++++++++++++++- src/remote_protocol-structs | 12 ++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

This command is a virsh wrapper for virConnectCompareHypervisorCPU. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh-host.c | 113 +++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 29 +++++++++++- 2 files changed, 141 insertions(+), 1 deletion(-) diff --git a/tools/virsh-host.c b/tools/virsh-host.c index ea2c411c02..1e7cfcbd5e 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -1595,6 +1595,113 @@ cmdNodeMemoryTune(vshControl *ctl, const vshCmd *cmd) goto cleanup; } + +/* + * "hypervisor-cpu-compare" command + */ +static const vshCmdInfo info_hypervisor_cpu_compare[] = { + {.name = "help", + .data = N_("compare a CPU with the CPU created by a hypervisor on the host") + }, + {.name = "desc", + .data = N_("compare CPU with hypervisor CPU") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_hypervisor_cpu_compare[] = { + VIRSH_COMMON_OPT_FILE(N_("file containing an XML CPU description")), + {.name = "virttype", + .type = VSH_OT_STRING, + .help = N_("virtualization type (/domain/@type)"), + }, + {.name = "emulator", + .type = VSH_OT_STRING, + .help = N_("path to emulator binary (/domain/devices/emulator)"), + }, + {.name = "arch", + .type = VSH_OT_STRING, + .help = N_("domain architecture (/domain/os/type/@arch)"), + }, + {.name = "machine", + .type = VSH_OT_STRING, + .help = N_("machine type (/domain/os/type/@machine)"), + }, + {.name = "error", + .type = VSH_OT_BOOL, + .help = N_("report error if CPUs are incompatible") + }, + {.name = NULL} +}; + +static bool +cmdHypervisorCPUCompare(vshControl *ctl, + const vshCmd *cmd) +{ + const char *from = NULL; + const char *virttype = NULL; + const char *emulator = NULL; + const char *arch = NULL; + const char *machine = NULL; + bool ret = false; + int result; + char **cpus = NULL; + unsigned int flags = 0; + virshControlPtr priv = ctl->privData; + + if (vshCommandOptBool(cmd, "error")) + flags |= VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE; + + if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0 || + 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 false; + + if (!(cpus = vshExtractCPUDefXMLs(ctl, from))) + return false; + + result = virConnectCompareHypervisorCPU(priv->conn, emulator, arch, + machine, virttype, cpus[0], flags); + + switch (result) { + case VIR_CPU_COMPARE_INCOMPATIBLE: + vshPrint(ctl, + _("CPU described in %s is incompatible with the CPU provided " + "by hypervisor on the host\n"), + from); + goto cleanup; + break; + + case VIR_CPU_COMPARE_IDENTICAL: + vshPrint(ctl, + _("CPU described in %s is identical to the CPU provided by " + "hypervisor on the host\n"), + from); + break; + + case VIR_CPU_COMPARE_SUPERSET: + vshPrint(ctl, + _("The CPU provided by hypervisor on the host is a superset " + "of CPU described in %s\n"), + from); + break; + + case VIR_CPU_COMPARE_ERROR: + default: + vshError(ctl, _("Failed to compare hypervisor CPU with %s"), from); + goto cleanup; + } + + ret = true; + + cleanup: + virStringListFree(cpus); + return ret; +} + + const vshCmdDef hostAndHypervisorCmds[] = { {.name = "allocpages", .handler = cmdAllocpages, @@ -1650,6 +1757,12 @@ const vshCmdDef hostAndHypervisorCmds[] = { .info = info_hostname, .flags = 0 }, + {.name = "hypervisor-cpu-compare", + .handler = cmdHypervisorCPUCompare, + .opts = opts_hypervisor_cpu_compare, + .info = info_hypervisor_cpu_compare, + .flags = 0 + }, {.name = "maxvcpus", .handler = cmdMaxvcpus, .opts = opts_maxvcpus, diff --git a/tools/virsh.pod b/tools/virsh.pod index ea10e1ad43..1a55092efd 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -585,7 +585,9 @@ features that block migration will not be included in the resulting CPU. =item B<cpu-compare> I<FILE> [I<--error>] -Compare CPU definition from XML <file> with host CPU. The XML <file> may +Compare CPU definition from XML <file> with host CPU. (See +B<hypervisor-cpu-compare> command for comparing the CPU definition with the CPU +which a specific hypervisor is able to provide on the host.) The XML <file> may contain either host or guest CPU definition. The host CPU definition is the <cpu> element and its contents as printed by B<capabilities> command. The guest CPU definition is the <cpu> element and its contents from domain XML @@ -616,6 +618,31 @@ specified, then the output will be single-quoted where needed, so that it is suitable for reuse in a shell context. If I<--xml> is specified, then the output will be escaped for use in XML. +=item B<hypervisor-cpu-compare> I<FILE> [I<virttype>] [I<emulator>] [I<arch>] +[I<machine>] [I<--error>] + +Compare CPU definition from XML <file> with the CPU the specified hypervisor +is able to provide on the host. (This is different from B<cpu-compare> which +compares the CPU definition with the host CPU without considering any specific +hypervisor and its abilities.) + +The XML I<FILE> may contain either host or guest CPU definition. The host CPU +definition is the <cpu> element and its contents as printed by B<capabilities> +command. The guest CPU definition is the <cpu> element and its contents from +domain XML definition or the CPU definition created from the host CPU model +found in domain capabilities XML (printed by B<domcapabilities> command). In +addition to the <cpu> element itself, this command accepts full domain XML, +capabilities XML, or domain capabilities XML containing the CPU definition. For +more information on guest CPU definition see: +L<https://libvirt.org/formatdomain.html#elementsCPU>. + +The I<virttype> option specifies the virtualization type (usable in the 'type' +attribute of the <domain> top level element from the domain XML). I<emulator> +specifies the path to the emulator, I<arch> specifies the CPU architecture, and +I<machine> specifies the machine type. If I<--error> is specified, the command +will return an error when the given CPU is incompatible with host CPU and a +message providing more details about the incompatibility will be printed out. + =back =head1 DOMAIN COMMANDS -- 2.17.0

I've applied and looked at the patches up to this point. Things are looking good thus far. Will give them another once-over tomorrow and continue with the rest of the patches. -- Respectfully, - Collin Walling

On Wed, May 16, 2018 at 10:39:29AM +0200, Jiri Denemark wrote:
This command is a virsh wrapper for virConnectCompareHypervisorCPU.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh-host.c | 113 +++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 29 +++++++++++- 2 files changed, 141 insertions(+), 1 deletion(-)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

On 05/16/2018 04:39 AM, Jiri Denemark wrote:
This command is a virsh wrapper for virConnectCompareHypervisorCPU.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh-host.c | 113 +++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 29 +++++++++++- 2 files changed, 141 insertions(+), 1 deletion(-)
diff --git a/tools/virsh-host.c b/tools/virsh-host.c index ea2c411c02..1e7cfcbd5e 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -1595,6 +1595,113 @@ cmdNodeMemoryTune(vshControl *ctl, const vshCmd *cmd) goto cleanup; }
+ +/* + * "hypervisor-cpu-compare" command + */
Really just a nit: I'm somewhat torn by the verbose command name. "hypervisor-" is a bit cumbersome, but hy<tab> will auto-complete it for you at this point. Maybe shorten it to hv-cpu-compare?
+static const vshCmdInfo info_hypervisor_cpu_compare[] = { + {.name = "help", + .data = N_("compare a CPU with the CPU created by a hypervisor on the host") + }, + {.name = "desc", + .data = N_("compare CPU with hypervisor CPU") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_hypervisor_cpu_compare[] = { + VIRSH_COMMON_OPT_FILE(N_("file containing an XML CPU description")), + {.name = "virttype", + .type = VSH_OT_STRING, + .help = N_("virtualization type (/domain/@type)"), + }, + {.name = "emulator", + .type = VSH_OT_STRING, + .help = N_("path to emulator binary (/domain/devices/emulator)"), + }, + {.name = "arch", + .type = VSH_OT_STRING, + .help = N_("domain architecture (/domain/os/type/@arch)"), + },
Your documentation states that this option is the "CPU architecture", which I think I like more than "domain architecture".
+ {.name = "machine", + .type = VSH_OT_STRING, + .help = N_("machine type (/domain/os/type/@machine)"), + }, + {.name = "error", + .type = VSH_OT_BOOL, + .help = N_("report error if CPUs are incompatible") + }, + {.name = NULL} +}; + +static bool +cmdHypervisorCPUCompare(vshControl *ctl, + const vshCmd *cmd) +{ + const char *from = NULL; + const char *virttype = NULL; + const char *emulator = NULL; + const char *arch = NULL; + const char *machine = NULL; + bool ret = false; + int result; + char **cpus = NULL; + unsigned int flags = 0; + virshControlPtr priv = ctl->privData; + + if (vshCommandOptBool(cmd, "error")) + flags |= VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE; + + if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0 || + 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 false; + + if (!(cpus = vshExtractCPUDefXMLs(ctl, from))) + return false; + + result = virConnectCompareHypervisorCPU(priv->conn, emulator, arch, + machine, virttype, cpus[0], flags); + + switch (result) { + case VIR_CPU_COMPARE_INCOMPATIBLE: + vshPrint(ctl, + _("CPU described in %s is incompatible with the CPU provided " + "by hypervisor on the host\n"), + from);
How much information regarding a CPU definition does libvirt consider when comparing CPU's for x86 (and for other archs, if you happen to know)? On s390, we only take the cpu model and features into consideration. If the archs other than s390 will only use the cpu model and features as well -- or if this API should explicitly work only with CPU models -- then perhaps it is more accurate for these messages to state "CPU model" instead of "CPU"? This change would also have to be propagated in to the documentation, replacing "CPU definition" with "CPU model".
+ goto cleanup; + break; + + case VIR_CPU_COMPARE_IDENTICAL: + vshPrint(ctl, + _("CPU described in %s is identical to the CPU provided by " + "hypervisor on the host\n"), + from); + break; + + case VIR_CPU_COMPARE_SUPERSET: + vshPrint(ctl, + _("The CPU provided by hypervisor on the host is a superset " + "of CPU described in %s\n"), + from); + break; + + case VIR_CPU_COMPARE_ERROR: + default: + vshError(ctl, _("Failed to compare hypervisor CPU with %s"), from); + goto cleanup; + } + + ret = true; + + cleanup: + virStringListFree(cpus); + return ret; +} + + const vshCmdDef hostAndHypervisorCmds[] = { {.name = "allocpages", .handler = cmdAllocpages, @@ -1650,6 +1757,12 @@ const vshCmdDef hostAndHypervisorCmds[] = { .info = info_hostname, .flags = 0 }, + {.name = "hypervisor-cpu-compare", + .handler = cmdHypervisorCPUCompare, + .opts = opts_hypervisor_cpu_compare, + .info = info_hypervisor_cpu_compare, + .flags = 0 + }, {.name = "maxvcpus", .handler = cmdMaxvcpus, .opts = opts_maxvcpus, diff --git a/tools/virsh.pod b/tools/virsh.pod index ea10e1ad43..1a55092efd 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -585,7 +585,9 @@ features that block migration will not be included in the resulting CPU.
=item B<cpu-compare> I<FILE> [I<--error>]
-Compare CPU definition from XML <file> with host CPU. The XML <file> may +Compare CPU definition from XML <file> with host CPU. (See +B<hypervisor-cpu-compare> command for comparing the CPU definition with the CPU +which a specific hypervisor is able to provide on the host.) The XML <file> may contain either host or guest CPU definition. The host CPU definition is the <cpu> element and its contents as printed by B<capabilities> command. The guest CPU definition is the <cpu> element and its contents from domain XML @@ -616,6 +618,31 @@ specified, then the output will be single-quoted where needed, so that it is suitable for reuse in a shell context. If I<--xml> is specified, then the output will be escaped for use in XML.
+=item B<hypervisor-cpu-compare> I<FILE> [I<virttype>] [I<emulator>] [I<arch>] +[I<machine>] [I<--error>] + +Compare CPU definition from XML <file> with the CPU the specified hypervisor
What is "the specified hypervisor"? To me, this implies that the user would have to provide the other options to specify a hypervisor for the command, but you can simply provide the XML <file> and be done. I think it reads better as: "Compares the CPU definition from an XML <file> with the CPU the hypervisor is able to provide on the host." And then leave it up to your last paragraph (which defines the additional options) to explain how to "specify" a hypervisor.
+is able to provide on the host. (This is different from B<cpu-compare> which +compares the CPU definition with the host CPU without considering any specific +hypervisor and its abilities.) + +The XML I<FILE> may contain either host or guest CPU definition. The host CPU
"either _a_ host or guest CPU definition"
+definition is the <cpu> element and its contents as printed by B<capabilities>
"by _the_ B<capabilities> command"
+command. The guest CPU definition is the <cpu> element and its contents from
"from _the_ domain XML definition"
+domain XML definition or the CPU definition created from the host CPU model +found in domain capabilities XML (printed by B<domcapabilities> command). In
"found in _the_ domain capabilities XML (printed by _the_ B<domcapabilities command)."
+addition to the <cpu> element itself, this command accepts full domain XML, +capabilities XML, or domain capabilities XML containing the CPU definition. For +more information on guest CPU definition see: +L<https://libvirt.org/formatdomain.html#elementsCPU>. + +The I<virttype> option specifies the virtualization type (usable in the 'type' +attribute of the <domain> top level element from the domain XML). I<emulator> +specifies the path to the emulator, I<arch> specifies the CPU architecture, and +I<machine> specifies the machine type. If I<--error> is specified, the command +will return an error when the given CPU is incompatible with host CPU and a
"is incompatible with _the_ host CPU"
+message providing more details about the incompatibility will be printed out. + =back
=head1 DOMAIN COMMANDS
Functionally, everything looks good. -- Respectfully, - Collin Walling

On Thu, May 24, 2018 at 13:24:25 -0400, Collin Walling wrote:
On 05/16/2018 04:39 AM, Jiri Denemark wrote:
This command is a virsh wrapper for virConnectCompareHypervisorCPU.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh-host.c | 113 +++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 29 +++++++++++- 2 files changed, 141 insertions(+), 1 deletion(-)
diff --git a/tools/virsh-host.c b/tools/virsh-host.c index ea2c411c02..1e7cfcbd5e 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -1595,6 +1595,113 @@ cmdNodeMemoryTune(vshControl *ctl, const vshCmd *cmd) goto cleanup; }
+ +/* + * "hypervisor-cpu-compare" command + */
Really just a nit:
I'm somewhat torn by the verbose command name. "hypervisor-" is a bit cumbersome, but hy<tab> will auto-complete it for you at this point. Maybe shorten it to hv-cpu-compare?
Yeah, hv-* is definitely shorter, but I don't know if it's better. What do others think?
+static const vshCmdInfo info_hypervisor_cpu_compare[] = { + {.name = "help", + .data = N_("compare a CPU with the CPU created by a hypervisor on the host") + }, + {.name = "desc", + .data = N_("compare CPU with hypervisor CPU") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_hypervisor_cpu_compare[] = { + VIRSH_COMMON_OPT_FILE(N_("file containing an XML CPU description")), + {.name = "virttype", + .type = VSH_OT_STRING, + .help = N_("virtualization type (/domain/@type)"), + }, + {.name = "emulator", + .type = VSH_OT_STRING, + .help = N_("path to emulator binary (/domain/devices/emulator)"), + }, + {.name = "arch", + .type = VSH_OT_STRING, + .help = N_("domain architecture (/domain/os/type/@arch)"), + },
Your documentation states that this option is the "CPU architecture", which I think I like more than "domain architecture".
Definitely, I forgot to fix it here.
+ {.name = "machine", + .type = VSH_OT_STRING, + .help = N_("machine type (/domain/os/type/@machine)"), + }, + {.name = "error", + .type = VSH_OT_BOOL, + .help = N_("report error if CPUs are incompatible") + }, + {.name = NULL} +}; + +static bool +cmdHypervisorCPUCompare(vshControl *ctl, + const vshCmd *cmd) +{ + const char *from = NULL; + const char *virttype = NULL; + const char *emulator = NULL; + const char *arch = NULL; + const char *machine = NULL; + bool ret = false; + int result; + char **cpus = NULL; + unsigned int flags = 0; + virshControlPtr priv = ctl->privData; + + if (vshCommandOptBool(cmd, "error")) + flags |= VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE; + + if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0 || + 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 false; + + if (!(cpus = vshExtractCPUDefXMLs(ctl, from))) + return false; + + result = virConnectCompareHypervisorCPU(priv->conn, emulator, arch, + machine, virttype, cpus[0], flags); + + switch (result) { + case VIR_CPU_COMPARE_INCOMPATIBLE: + vshPrint(ctl, + _("CPU described in %s is incompatible with the CPU provided " + "by hypervisor on the host\n"), + from);
How much information regarding a CPU definition does libvirt consider when comparing CPU's for x86 (and for other archs, if you happen to know)? On s390, we only take the cpu model and features into consideration.
If the archs other than s390 will only use the cpu model and features as well -- or if this API should explicitly work only with CPU models -- then perhaps it is more accurate for these messages to state "CPU model" instead of "CPU"? This change would also have to be propagated in to the documentation, replacing "CPU definition" with "CPU model".
It doesn't really matter what libvirt currently checks for which architecture. The API takes a CPU definition XML and libvirt will use anything it needs from that. ...
@@ -616,6 +618,31 @@ specified, then the output will be single-quoted where needed, so that it is suitable for reuse in a shell context. If I<--xml> is specified, then the output will be escaped for use in XML.
+=item B<hypervisor-cpu-compare> I<FILE> [I<virttype>] [I<emulator>] [I<arch>] +[I<machine>] [I<--error>] + +Compare CPU definition from XML <file> with the CPU the specified hypervisor
What is "the specified hypervisor"? To me, this implies that the user would have to provide the other options to specify a hypervisor for the command, but you can simply provide the XML <file> and be done.
I think it reads better as:
"Compares the CPU definition from an XML <file> with the CPU the hypervisor is able to provide on the host."
Yeah, your version looks better. Jirka

On Fri, May 25, 2018 at 12:35:09PM +0200, Jiri Denemark wrote:
On Thu, May 24, 2018 at 13:24:25 -0400, Collin Walling wrote:
On 05/16/2018 04:39 AM, Jiri Denemark wrote:
This command is a virsh wrapper for virConnectCompareHypervisorCPU.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh-host.c | 113 +++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 29 +++++++++++- 2 files changed, 141 insertions(+), 1 deletion(-)
diff --git a/tools/virsh-host.c b/tools/virsh-host.c index ea2c411c02..1e7cfcbd5e 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -1595,6 +1595,113 @@ cmdNodeMemoryTune(vshControl *ctl, const vshCmd *cmd) goto cleanup; }
+ +/* + * "hypervisor-cpu-compare" command + */
Really just a nit:
I'm somewhat torn by the verbose command name. "hypervisor-" is a bit cumbersome, but hy<tab> will auto-complete it for you at this point. Maybe shorten it to hv-cpu-compare?
Yeah, hv-* is definitely shorter, but I don't know if it's better. What do others think?
Since you asked (and as a heavy `virsh` user) ... although I like shorter commands, I go by "explicit is better than implicit" (within reason) with written text. FWIW, I lean towards the full spelling 'hypervisor'; one less acronym to auto-expand in your head. [...] -- /kashyap

+ switch (result) { + case VIR_CPU_COMPARE_INCOMPATIBLE: + vshPrint(ctl, + _("CPU described in %s is incompatible with the CPU provided " + "by hypervisor on the host\n"), + from);
How much information regarding a CPU definition does libvirt consider when comparing CPU's for x86 (and for other archs, if you happen to know)? On s390, we only take the cpu model and features into consideration.
If the archs other than s390 will only use the cpu model and features as well -- or if this API should explicitly work only with CPU models -- then perhaps it is more accurate for these messages to state "CPU model" instead of "CPU"? This change would also have to be propagated in to the documentation, replacing "CPU definition" with "CPU model".
It doesn't really matter what libvirt currently checks for which architecture. The API takes a CPU definition XML and libvirt will use anything it needs from that.
I had to bat this around in my head a bit. Truthfully, I think trying to expand on why we got the result might be a little much. Perhaps I should have more faith in the user to understand what is taken into consideration when CPUs are compared :) Reviewed-by: Collin Walling <walling@linux.ibm.com> -- Respectfully, - Collin Walling

On Fri, May 25, 2018 at 15:22:43 -0400, Collin Walling wrote:
+ switch (result) { + case VIR_CPU_COMPARE_INCOMPATIBLE: + vshPrint(ctl, + _("CPU described in %s is incompatible with the CPU provided " + "by hypervisor on the host\n"), + from);
How much information regarding a CPU definition does libvirt consider when comparing CPU's for x86 (and for other archs, if you happen to know)? On s390, we only take the cpu model and features into consideration.
If the archs other than s390 will only use the cpu model and features as well -- or if this API should explicitly work only with CPU models -- then perhaps it is more accurate for these messages to state "CPU model" instead of "CPU"? This change would also have to be propagated in to the documentation, replacing "CPU definition" with "CPU model".
It doesn't really matter what libvirt currently checks for which architecture. The API takes a CPU definition XML and libvirt will use anything it needs from that.
I had to bat this around in my head a bit. Truthfully, I think trying to expand on why we got the result might be a little much.
That's (partially) the reason behind --error option. It will cause the API to return an error (rather than VIR_CPU_COMPARE_INCOMPATIBLE) and you can check the error messages for details about the incompatibility. For example, the x86 CPU driver will list all missing features.
Perhaps I should have more faith in the user to understand what is taken into consideration when CPUs are compared :)
The user should not really need to know what is used for comparison. They would just have a CPU definition they want to use for a guest and this API can be used to check whether such CPU can be run on a given host. For example, oVirt has a set of CPU definitions from which a user can select and calls the compare API to check which hosts can run which CPU so that they can properly schedule where to run individual VMs. Jirka

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_driver.c | 60 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 6c086b9ef8..4b48afdad1 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -13100,6 +13100,65 @@ qemuConnectCompareCPU(virConnectPtr conn, } +static int +qemuConnectCompareHypervisorCPU(virConnectPtr conn, + const char *emulator, + const char *archStr, + const char *machine, + const char *virttypeStr, + const char *xmlCPU, + unsigned int flags) +{ + int ret = VIR_CPU_COMPARE_ERROR; + virQEMUDriverPtr driver = conn->privateData; + virQEMUCapsPtr qemuCaps = NULL; + bool failIncompatible; + virCPUDefPtr hvCPU; + virArch arch; + virDomainVirtType virttype; + + virCheckFlags(VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE, + VIR_CPU_COMPARE_ERROR); + + if (virConnectCompareHypervisorCPUEnsureACL(conn) < 0) + goto cleanup; + + failIncompatible = !!(flags & VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE); + + qemuCaps = virQEMUCapsCacheLookupDefault(driver->qemuCapsCache, + emulator, + archStr, + virttypeStr, + machine, + &arch, &virttype, NULL); + if (!qemuCaps) + goto cleanup; + + hvCPU = virQEMUCapsGetHostModel(qemuCaps, virttype, + VIR_QEMU_CAPS_HOST_CPU_REPORTED); + if (!hvCPU || hvCPU->fallback != VIR_CPU_FALLBACK_FORBID) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("QEMU '%s' does not support reporting CPU model for " + "virttype '%s'"), + virQEMUCapsGetBinary(qemuCaps), + virDomainVirtTypeToString(virttype)); + goto cleanup; + } + + if (ARCH_IS_X86(arch)) { + ret = virCPUCompareXML(arch, hvCPU, xmlCPU, failIncompatible); + } else { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("comparing hypervisor CPUs is not supported for " + "arch %s"), virArchToString(arch)); + } + + cleanup: + virObjectUnref(qemuCaps); + return ret; +} + + static char * qemuConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED, const char **xmlCPUs, @@ -21326,6 +21385,7 @@ static virHypervisorDriver qemuHypervisorDriver = { .domainSetVcpu = qemuDomainSetVcpu, /* 3.1.0 */ .domainSetBlockThreshold = qemuDomainSetBlockThreshold, /* 3.2.0 */ .domainSetLifecycleAction = qemuDomainSetLifecycleAction, /* 3.9.0 */ + .connectCompareHypervisorCPU = qemuConnectCompareHypervisorCPU, /* 4.4.0 */ }; -- 2.17.0

On Wed, May 16, 2018 at 10:39:30AM +0200, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_driver.c | 60 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

Sorry for the delay. I've been experiencing issues with the mail server :( On 05/16/2018 04:39 AM, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_driver.c | 60 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 6c086b9ef8..4b48afdad1 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -13100,6 +13100,65 @@ qemuConnectCompareCPU(virConnectPtr conn, }
+static int +qemuConnectCompareHypervisorCPU(virConnectPtr conn, + const char *emulator, + const char *archStr, + const char *machine, + const char *virttypeStr, + const char *xmlCPU, + unsigned int flags) +{ + int ret = VIR_CPU_COMPARE_ERROR; + virQEMUDriverPtr driver = conn->privateData; + virQEMUCapsPtr qemuCaps = NULL; + bool failIncompatible; + virCPUDefPtr hvCPU; + virArch arch; + virDomainVirtType virttype; + + virCheckFlags(VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE, + VIR_CPU_COMPARE_ERROR); + + if (virConnectCompareHypervisorCPUEnsureACL(conn) < 0) + goto cleanup; + + failIncompatible = !!(flags & VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE); + + qemuCaps = virQEMUCapsCacheLookupDefault(driver->qemuCapsCache, + emulator, + archStr, + virttypeStr, + machine, + &arch, &virttype, NULL); + if (!qemuCaps) + goto cleanup; + + hvCPU = virQEMUCapsGetHostModel(qemuCaps, virttype, + VIR_QEMU_CAPS_HOST_CPU_REPORTED);
nit: add a blank line here
+ if (!hvCPU || hvCPU->fallback != VIR_CPU_FALLBACK_FORBID) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("QEMU '%s' does not support reporting CPU model for " + "virttype '%s'"), + virQEMUCapsGetBinary(qemuCaps), + virDomainVirtTypeToString(virttype)); + goto cleanup; + } + + if (ARCH_IS_X86(arch)) { + ret = virCPUCompareXML(arch, hvCPU, xmlCPU, failIncompatible); + } else { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("comparing hypervisor CPUs is not supported for " + "arch %s"), virArchToString(arch));
At first glance, this message makes me think that this function is for "comparing two hypervisor CPUs". Perhaps the message should say "comparing with the hypervisor CPU is not supported for arch %s" instead? I think that makes it more clear that the other CPU in question is not (necessarily) a hypervisor CPU.
+ } + + cleanup: + virObjectUnref(qemuCaps); + return ret; +} + + static char * qemuConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED, const char **xmlCPUs, @@ -21326,6 +21385,7 @@ static virHypervisorDriver qemuHypervisorDriver = { .domainSetVcpu = qemuDomainSetVcpu, /* 3.1.0 */ .domainSetBlockThreshold = qemuDomainSetBlockThreshold, /* 3.2.0 */ .domainSetLifecycleAction = qemuDomainSetLifecycleAction, /* 3.9.0 */ + .connectCompareHypervisorCPU = qemuConnectCompareHypervisorCPU, /* 4.4.0 */ };
-- Respectfully, - Collin Walling

On Fri, May 25, 2018 at 13:50:19 -0400, Collin Walling wrote:
Sorry for the delay. I've been experiencing issues with the mail server :(
On 05/16/2018 04:39 AM, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_driver.c | 60 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 6c086b9ef8..4b48afdad1 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -13100,6 +13100,65 @@ qemuConnectCompareCPU(virConnectPtr conn, }
+static int +qemuConnectCompareHypervisorCPU(virConnectPtr conn, + const char *emulator, + const char *archStr, + const char *machine, + const char *virttypeStr, + const char *xmlCPU, + unsigned int flags) +{ + int ret = VIR_CPU_COMPARE_ERROR; + virQEMUDriverPtr driver = conn->privateData; + virQEMUCapsPtr qemuCaps = NULL; + bool failIncompatible; + virCPUDefPtr hvCPU; + virArch arch; + virDomainVirtType virttype; + + virCheckFlags(VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE, + VIR_CPU_COMPARE_ERROR); + + if (virConnectCompareHypervisorCPUEnsureACL(conn) < 0) + goto cleanup; + + failIncompatible = !!(flags & VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE); + + qemuCaps = virQEMUCapsCacheLookupDefault(driver->qemuCapsCache, + emulator, + archStr, + virttypeStr, + machine, + &arch, &virttype, NULL); + if (!qemuCaps) + goto cleanup; + + hvCPU = virQEMUCapsGetHostModel(qemuCaps, virttype, + VIR_QEMU_CAPS_HOST_CPU_REPORTED);
nit: add a blank line here
+ if (!hvCPU || hvCPU->fallback != VIR_CPU_FALLBACK_FORBID) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("QEMU '%s' does not support reporting CPU model for " + "virttype '%s'"), + virQEMUCapsGetBinary(qemuCaps), + virDomainVirtTypeToString(virttype)); + goto cleanup; + } + + if (ARCH_IS_X86(arch)) { + ret = virCPUCompareXML(arch, hvCPU, xmlCPU, failIncompatible); + } else { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("comparing hypervisor CPUs is not supported for " + "arch %s"), virArchToString(arch));
At first glance, this message makes me think that this function is for "comparing two hypervisor CPUs". Perhaps the message should say "comparing with the hypervisor CPU is not supported for arch %s" instead? I think that makes it more clear that the other CPU in question is not (necessarily) a hypervisor CPU.
Yeah, that's definitely better. Jirka

CC'ing Chris just in case. -- Respectfully, - Collin Walling

The new API computes the most feature-rich CPU which is compatible with all given CPUs and can be provided by the specified hypervisor. It is a more useful version of vitConnectBaselineCPU, which doesn't consider any hypervisor capabilities when computing the best CPU. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- include/libvirt/libvirt-host.h | 8 ++++ src/driver-hypervisor.h | 10 +++++ src/libvirt-host.c | 81 ++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 4 files changed, 100 insertions(+) diff --git a/include/libvirt/libvirt-host.h b/include/libvirt/libvirt-host.h index e2054baebc..84f4858169 100644 --- a/include/libvirt/libvirt-host.h +++ b/include/libvirt/libvirt-host.h @@ -667,6 +667,14 @@ char *virConnectBaselineCPU(virConnectPtr conn, const char **xmlCPUs, unsigned int ncpus, unsigned int flags); +char *virConnectBaselineHypervisorCPU(virConnectPtr conn, + const char *emulator, + const char *arch, + const char *machine, + const char *virttype, + const char **xmlCPUs, + unsigned int ncpus, + unsigned int flags); int virNodeGetFreePages(virConnectPtr conn, diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h index d64de2d54c..9ce0d7e5de 100644 --- a/src/driver-hypervisor.h +++ b/src/driver-hypervisor.h @@ -687,6 +687,15 @@ typedef char * const char **xmlCPUs, unsigned int ncpus, unsigned int flags); +typedef char * +(*virDrvConnectBaselineHypervisorCPU)(virConnectPtr conn, + const char *emulator, + const char *arch, + const char *machine, + const char *virttype, + const char **xmlCPUs, + unsigned int ncpus, + unsigned int flags); typedef int (*virDrvConnectGetCPUModelNames)(virConnectPtr conn, @@ -1542,6 +1551,7 @@ struct _virHypervisorDriver { virDrvDomainSetBlockThreshold domainSetBlockThreshold; virDrvDomainSetLifecycleAction domainSetLifecycleAction; virDrvConnectCompareHypervisorCPU connectCompareHypervisorCPU; + virDrvConnectBaselineHypervisorCPU connectBaselineHypervisorCPU; }; diff --git a/src/libvirt-host.c b/src/libvirt-host.c index 17cf183499..cdbbe35e5a 100644 --- a/src/libvirt-host.c +++ b/src/libvirt-host.c @@ -1127,6 +1127,9 @@ virConnectGetCPUModelNames(virConnectPtr conn, const char *arch, char ***models, * Computes the most feature-rich CPU which is compatible with all given * host CPUs. * + * See vitConnectBaselineHypervisorCPU() to get a CPU which can be provided + * by a specific hypervisor. + * * If @flags includes VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES then libvirt * will explicitly list all CPU features that are part of the host CPU, * without this flag features that are part of the CPU model will not be @@ -1174,6 +1177,84 @@ virConnectBaselineCPU(virConnectPtr conn, } +/** + * virConnectBaselineHypervisorCPU: + * + * @conn: pointer to the hypervisor connection + * @emulator: path to the emulator binary + * @arch: domain architecture + * @machine: machine type + * @virttype: virtualization type + * @xmlCPUs: array of XML descriptions of CPUs + * @ncpus: number of CPUs in xmlCPUs + * @flags: bitwise-OR of virConnectBaselineCPUFlags + * + * Computes the most feature-rich CPU which is compatible with all given CPUs + * and can be provided by the specified hypervisor. For best results the + * host-model CPUs as advertised by virConnectGetDomainCapabilities() should be + * passed in @xmlCPUs. Any of @emulator, @arch, @machine, and @virttype + * parameters may be NULL; libvirt will choose sensible defaults tailored to + * the host and its current configuration. + * + * This is different from vitConnectBaselineCPU() which doesn't consider any + * hypervisor abilities when computing the best CPU. + * + * 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 + * listed. + * + * If @flags includes VIR_CONNECT_BASELINE_CPU_MIGRATABLE, the resulting + * CPU will not include features that block migration. + * + * Returns XML description of the computed CPU (caller frees) or NULL on error. + */ +char * +virConnectBaselineHypervisorCPU(virConnectPtr conn, + const char *emulator, + const char *arch, + const char *machine, + const char *virttype, + const char **xmlCPUs, + unsigned int ncpus, + unsigned int flags) +{ + size_t i; + + VIR_DEBUG("conn=%p, emulator=%s, arch=%s, machine=%s, " + "virttype=%s, xmlCPUs=%p, ncpus=%u, flags=0x%x", + conn, NULLSTR(emulator), NULLSTR(arch), NULLSTR(machine), + NULLSTR(virttype), xmlCPUs, ncpus, flags); + if (xmlCPUs) { + for (i = 0; i < ncpus; i++) + VIR_DEBUG("xmlCPUs[%zu]=%s", i, NULLSTR(xmlCPUs[i])); + } + + virResetLastError(); + + virCheckConnectReturn(conn, NULL); + virCheckNonNullArgGoto(xmlCPUs, error); + + if (conn->driver->connectBaselineHypervisorCPU) { + char *cpu; + + cpu = conn->driver->connectBaselineHypervisorCPU(conn, emulator, arch, + machine, virttype, + xmlCPUs, ncpus, flags); + if (!cpu) + goto error; + + return cpu; + } + + virReportUnsupportedError(); + + error: + virDispatchError(conn); + return NULL; +} + + /** * virConnectSetKeepAlive: * @conn: pointer to a hypervisor connection diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 97597d7708..05ab077fb4 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -788,6 +788,7 @@ LIBVIRT_4.1.0 { LIBVIRT_4.4.0 { global: virConnectCompareHypervisorCPU; + virConnectBaselineHypervisorCPU; } LIBVIRT_4.1.0; # .... define new API here using predicted next version number .... -- 2.17.0

On Wed, May 16, 2018 at 10:39:31AM +0200, Jiri Denemark wrote:
The new API computes the most feature-rich CPU which is compatible with all given CPUs and can be provided by the specified hypervisor. It is a more useful version of vitConnectBaselineCPU, which doesn't consider any hypervisor capabilities when computing the best CPU.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- include/libvirt/libvirt-host.h | 8 ++++ src/driver-hypervisor.h | 10 +++++ src/libvirt-host.c | 81 ++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 4 files changed, 100 insertions(+)
diff --git a/src/libvirt-host.c b/src/libvirt-host.c index 17cf183499..cdbbe35e5a 100644 --- a/src/libvirt-host.c +++ b/src/libvirt-host.c @@ -1127,6 +1127,9 @@ virConnectGetCPUModelNames(virConnectPtr conn, const char *arch, char ***models, * Computes the most feature-rich CPU which is compatible with all given * host CPUs. * + * See vitConnectBaselineHypervisorCPU() to get a CPU which can be provided
The same rypo.
+ * by a specific hypervisor. + * * If @flags includes VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES then libvirt * will explicitly list all CPU features that are part of the host CPU, * without this flag features that are part of the CPU model will not be
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

On 05/16/2018 04:39 AM, Jiri Denemark wrote:
The new API computes the most feature-rich CPU which is compatible with all given CPUs and can be provided by the specified hypervisor. It is a more useful version of vitConnectBaselineCPU, which doesn't consider any
s/vit/vir
hypervisor capabilities when computing the best CPU.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- include/libvirt/libvirt-host.h | 8 ++++ src/driver-hypervisor.h | 10 +++++ src/libvirt-host.c | 81 ++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 4 files changed, 100 insertions(+)
diff --git a/include/libvirt/libvirt-host.h b/include/libvirt/libvirt-host.h index e2054baebc..84f4858169 100644 --- a/include/libvirt/libvirt-host.h +++ b/include/libvirt/libvirt-host.h @@ -667,6 +667,14 @@ char *virConnectBaselineCPU(virConnectPtr conn, const char **xmlCPUs, unsigned int ncpus, unsigned int flags); +char *virConnectBaselineHypervisorCPU(virConnectPtr conn, + const char *emulator, + const char *arch, + const char *machine, + const char *virttype, + const char **xmlCPUs, + unsigned int ncpus, + unsigned int flags);
int virNodeGetFreePages(virConnectPtr conn, diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h index d64de2d54c..9ce0d7e5de 100644 --- a/src/driver-hypervisor.h +++ b/src/driver-hypervisor.h @@ -687,6 +687,15 @@ typedef char * const char **xmlCPUs, unsigned int ncpus, unsigned int flags); +typedef char * +(*virDrvConnectBaselineHypervisorCPU)(virConnectPtr conn, + const char *emulator, + const char *arch, + const char *machine, + const char *virttype, + const char **xmlCPUs, + unsigned int ncpus, + unsigned int flags);
typedef int (*virDrvConnectGetCPUModelNames)(virConnectPtr conn, @@ -1542,6 +1551,7 @@ struct _virHypervisorDriver { virDrvDomainSetBlockThreshold domainSetBlockThreshold; virDrvDomainSetLifecycleAction domainSetLifecycleAction; virDrvConnectCompareHypervisorCPU connectCompareHypervisorCPU; + virDrvConnectBaselineHypervisorCPU connectBaselineHypervisorCPU; };
diff --git a/src/libvirt-host.c b/src/libvirt-host.c index 17cf183499..cdbbe35e5a 100644 --- a/src/libvirt-host.c +++ b/src/libvirt-host.c @@ -1127,6 +1127,9 @@ virConnectGetCPUModelNames(virConnectPtr conn, const char *arch, char ***models, * Computes the most feature-rich CPU which is compatible with all given * host CPUs. * + * See vitConnectBaselineHypervisorCPU() to get a CPU which can be provided
same here
+ * by a specific hypervisor.
Maybe say "by the hypervisor" here? I don't think it's as important as the change to the documentation as discussed in the previous patch, but it might be good for consistency.
+ * * If @flags includes VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES then libvirt * will explicitly list all CPU features that are part of the host CPU, * without this flag features that are part of the CPU model will not be @@ -1174,6 +1177,84 @@ virConnectBaselineCPU(virConnectPtr conn, }
+/** + * virConnectBaselineHypervisorCPU: + * + * @conn: pointer to the hypervisor connection + * @emulator: path to the emulator binary + * @arch: domain architecture
I'd say "CPU architecture" instead
+ * @machine: machine type + * @virttype: virtualization type + * @xmlCPUs: array of XML descriptions of CPUs + * @ncpus: number of CPUs in xmlCPUs + * @flags: bitwise-OR of virConnectBaselineCPUFlags + * + * Computes the most feature-rich CPU which is compatible with all given CPUs + * and can be provided by the specified hypervisor. For best results the + * host-model CPUs as advertised by virConnectGetDomainCapabilities() should be + * passed in @xmlCPUs. Any of @emulator, @arch, @machine, and @virttype + * parameters may be NULL; libvirt will choose sensible defaults tailored to + * the host and its current configuration. + * + * This is different from vitConnectBaselineCPU() which doesn't consider any
s/vit/vir
+ * hypervisor abilities when computing the best CPU. + * + * 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 + * listed. + * + * If @flags includes VIR_CONNECT_BASELINE_CPU_MIGRATABLE, the resulting + * CPU will not include features that block migration. + * + * Returns XML description of the computed CPU (caller frees) or NULL on error. + */ +char * +virConnectBaselineHypervisorCPU(virConnectPtr conn, + const char *emulator, + const char *arch, + const char *machine, + const char *virttype, + const char **xmlCPUs, + unsigned int ncpus, + unsigned int flags) +{ + size_t i; + + VIR_DEBUG("conn=%p, emulator=%s, arch=%s, machine=%s, " + "virttype=%s, xmlCPUs=%p, ncpus=%u, flags=0x%x", + conn, NULLSTR(emulator), NULLSTR(arch), NULLSTR(machine), + NULLSTR(virttype), xmlCPUs, ncpus, flags); + if (xmlCPUs) { + for (i = 0; i < ncpus; i++) + VIR_DEBUG("xmlCPUs[%zu]=%s", i, NULLSTR(xmlCPUs[i])); + } + + virResetLastError(); + + virCheckConnectReturn(conn, NULL); + virCheckNonNullArgGoto(xmlCPUs, error); + + if (conn->driver->connectBaselineHypervisorCPU) { + char *cpu; + + cpu = conn->driver->connectBaselineHypervisorCPU(conn, emulator, arch, + machine, virttype, + xmlCPUs, ncpus, flags); + if (!cpu) + goto error; + + return cpu; + } + + virReportUnsupportedError(); + + error: + virDispatchError(conn); + return NULL; +} + + /** * virConnectSetKeepAlive: * @conn: pointer to a hypervisor connection diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 97597d7708..05ab077fb4 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -788,6 +788,7 @@ LIBVIRT_4.1.0 { LIBVIRT_4.4.0 { global: virConnectCompareHypervisorCPU; + virConnectBaselineHypervisorCPU; } LIBVIRT_4.1.0;
# .... define new API here using predicted next version number ....
Other than the nits above: Reviewed-by: Collin Walling <walling@linux.ibm.com> -- Respectfully, - Collin Walling

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 21 ++++++++++++++++++++- src/remote_protocol-structs | 15 +++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index acefe8c457..d106a18510 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -8450,6 +8450,7 @@ static virHypervisorDriver hypervisor_driver = { .domainSetBlockThreshold = remoteDomainSetBlockThreshold, /* 3.2.0 */ .domainSetLifecycleAction = remoteDomainSetLifecycleAction, /* 3.9.0 */ .connectCompareHypervisorCPU = remoteConnectCompareHypervisorCPU, /* 4.4.0 */ + .connectBaselineHypervisorCPU = remoteConnectBaselineHypervisorCPU, /* 4.4.0 */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 0aa123b5ac..ff28cec50f 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -3461,6 +3461,19 @@ struct remote_connect_compare_hypervisor_cpu_ret { int result; }; +struct remote_connect_baseline_hypervisor_cpu_args { + remote_string emulator; + remote_string arch; + remote_string machine; + remote_string virttype; + remote_nonnull_string xmlCPUs<REMOTE_CPU_BASELINE_MAX>; /* (const char **) */ + unsigned int flags; +}; + +struct remote_connect_baseline_hypervisor_cpu_ret { + remote_nonnull_string cpu; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -6154,5 +6167,11 @@ enum remote_procedure { * @generate: both * @acl: connect:write */ - REMOTE_PROC_CONNECT_COMPARE_HYPERVISOR_CPU = 392 + REMOTE_PROC_CONNECT_COMPARE_HYPERVISOR_CPU = 392, + + /** + * @generate: both + * @acl: connect:write + */ + REMOTE_PROC_CONNECT_BASELINE_HYPERVISOR_CPU = 393 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 64e48c52ba..99251ac0e8 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -2888,6 +2888,20 @@ struct remote_connect_compare_hypervisor_cpu_args { struct remote_connect_compare_hypervisor_cpu_ret { int result; }; +struct remote_connect_baseline_hypervisor_cpu_args { + remote_string emulator; + remote_string arch; + remote_string machine; + remote_string virttype; + struct { + u_int xmlCPUs_len; + remote_nonnull_string * xmlCPUs_val; + } xmlCPUs; + u_int flags; +}; +struct remote_connect_baseline_hypervisor_cpu_ret { + remote_nonnull_string cpu; +}; enum remote_procedure { REMOTE_PROC_CONNECT_OPEN = 1, REMOTE_PROC_CONNECT_CLOSE = 2, @@ -3281,4 +3295,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_SET_LIFECYCLE_ACTION = 390, REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_TARGET_PATH = 391, REMOTE_PROC_CONNECT_COMPARE_HYPERVISOR_CPU = 392, + REMOTE_PROC_CONNECT_BASELINE_HYPERVISOR_CPU = 393, }; -- 2.17.0

On Wed, May 16, 2018 at 10:39:32AM +0200, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 21 ++++++++++++++++++++- src/remote_protocol-structs | 15 +++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

This command is a virsh wrapper for virConnectBaselineHypervisorCPU. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh-host.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 47 ++++++++++++++++++++--- 2 files changed, 137 insertions(+), 6 deletions(-) diff --git a/tools/virsh-host.c b/tools/virsh-host.c index 1e7cfcbd5e..8fde5da50e 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -1702,6 +1702,96 @@ cmdHypervisorCPUCompare(vshControl *ctl, } +/* + * "hypervisor-cpu-baseline" command + */ +static const vshCmdInfo info_hypervisor_cpu_baseline[] = { + {.name = "help", + .data = N_("compute baseline CPU usable by a specific hypervisor") + }, + {.name = "desc", + .data = N_("Compute baseline CPU for a set of given CPUs. The result " + "will be tailored to the specified hypervisor.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_hypervisor_cpu_baseline[] = { + VIRSH_COMMON_OPT_FILE(N_("file containing XML CPU descriptions")), + {.name = "virttype", + .type = VSH_OT_STRING, + .help = N_("virtualization type (/domain/@type)"), + }, + {.name = "emulator", + .type = VSH_OT_STRING, + .help = N_("path to emulator binary (/domain/devices/emulator)"), + }, + {.name = "arch", + .type = VSH_OT_STRING, + .help = N_("domain architecture (/domain/os/type/@arch)"), + }, + {.name = "machine", + .type = VSH_OT_STRING, + .help = N_("machine type (/domain/os/type/@machine)"), + }, + {.name = "features", + .type = VSH_OT_BOOL, + .help = N_("Show features that are part of the CPU model type") + }, + {.name = "migratable", + .type = VSH_OT_BOOL, + .help = N_("Do not include features that block migration") + }, + {.name = NULL} +}; + +static bool +cmdHypervisorCPUBaseline(vshControl *ctl, + const vshCmd *cmd) +{ + const char *from = NULL; + const char *virttype = NULL; + const char *emulator = NULL; + const char *arch = NULL; + const char *machine = NULL; + bool ret = false; + char *result = NULL; + char **list = NULL; + unsigned int flags = 0; + virshControlPtr priv = ctl->privData; + + if (vshCommandOptBool(cmd, "features")) + flags |= VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES; + if (vshCommandOptBool(cmd, "migratable")) + flags |= VIR_CONNECT_BASELINE_CPU_MIGRATABLE; + + if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0 || + 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 false; + + if (!(list = vshExtractCPUDefXMLs(ctl, from))) + return false; + + result = virConnectBaselineHypervisorCPU(priv->conn, emulator, arch, + machine, virttype, + (const char **)list, + virStringListLength((const char **)list), + flags); + + if (result) { + vshPrint(ctl, "%s", result); + ret = true; + } + + VIR_FREE(result); + virStringListFree(list); + return ret; +} + + const vshCmdDef hostAndHypervisorCmds[] = { {.name = "allocpages", .handler = cmdAllocpages, @@ -1757,6 +1847,12 @@ const vshCmdDef hostAndHypervisorCmds[] = { .info = info_hostname, .flags = 0 }, + {.name = "hypervisor-cpu-baseline", + .handler = cmdHypervisorCPUBaseline, + .opts = opts_hypervisor_cpu_baseline, + .info = info_hypervisor_cpu_baseline, + .flags = 0 + }, {.name = "hypervisor-cpu-compare", .handler = cmdHypervisorCPUCompare, .opts = opts_hypervisor_cpu_compare, diff --git a/tools/virsh.pod b/tools/virsh.pod index 1a55092efd..d57ebadee6 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -574,12 +574,13 @@ I<--all> which executes the modification on all NUMA cells. =item B<cpu-baseline> I<FILE> [I<--features>] [I<--migratable>] Compute baseline CPU which will be supported by all host CPUs given in <file>. -The list of host CPUs is built by extracting all <cpu> elements from the -<file>. Thus, the <file> can contain either a set of <cpu> elements separated -by new lines or even a set of complete <capabilities> elements printed by -B<capabilities> command. If I<--features> is specified then the -resulting XML description will explicitly include all features that make -up the CPU, without this option features that are part of the CPU model +(See B<hypervisor-cpu-baseline> command to get a CPU which can be provided by a +specific hypervisor.) The list of host CPUs is built by extracting all <cpu> +elements from the <file>. Thus, the <file> can contain either a set of <cpu> +elements separated by new lines or even a set of complete <capabilities> +elements printed by B<capabilities> command. If I<--features> is specified +then the resulting XML description will explicitly include all features that +make up the CPU, without this option features that are part of the CPU model will not be listed in the XML description. If I<--migratable> is specified, features that block migration will not be included in the resulting CPU. @@ -643,6 +644,40 @@ I<machine> specifies the machine type. If I<--error> is specified, the command will return an error when the given CPU is incompatible with host CPU and a message providing more details about the incompatibility will be printed out. +=item B<hypervisor-cpu-baseline> I<FILE> [I<virttype>] [I<emulator>] [I<arch>] +[I<machine>] [I<--features>] [I<--migratable>] + +Compute baseline CPU which will be compatible with all CPUs given in I<FILE> +and can be provided by the specified hypervisor. (This is different from +B<cpu-baseline> which does not consider any hypervisor abilities when computing +the baseline CPU.) + +The XML I<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 B<capabilities> command. The guest CPU definition may be created +from the host CPU model found in domain capabilities XML (printed by +B<domcapabilities> command). In addition to the <cpu> elements, this command +accepts full capabilities XMLs, or domain capabilities XMLs containing the CPU +definitions. For best results, use only the CPU definitions from domain +capabilities. + +When I<FILE> contains only a single CPU definition, the command will print the +same CPU updated according to additional options and restricted to the +capabilities of the specified hypervisor. Specifically, running +B<virsh hypervisor-cpu-baseline> command with no additional options on the +result of B<virsh domcapabilities> will return transform the host CPU model +from domain capabilities XML to the form directly usable in domain XML. + +The I<virttype> option specifies the virtualization type (usable in the 'type' +attribute of the <domain> top level element from the domain XML). I<emulator> +specifies the path to the emulator, I<arch> specifies the CPU architecture, and +I<machine> specifies the machine type. If I<--features> is specified then the +resulting XML description will explicitly include all features that make up the +CPU, without this option features that are part of the CPU model will not be +listed in the XML description. If I<--migratable> is specified, features that +block migration will not be included in the resulting CPU. + + =back =head1 DOMAIN COMMANDS -- 2.17.0

On Wed, May 16, 2018 at 10:39:33AM +0200, Jiri Denemark wrote:
This command is a virsh wrapper for virConnectBaselineHypervisorCPU.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh-host.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 47 ++++++++++++++++++++--- 2 files changed, 137 insertions(+), 6 deletions(-)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

On 05/16/2018 04:39 AM, Jiri Denemark wrote:
This command is a virsh wrapper for virConnectBaselineHypervisorCPU.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh-host.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 47 ++++++++++++++++++++--- 2 files changed, 137 insertions(+), 6 deletions(-)
diff --git a/tools/virsh-host.c b/tools/virsh-host.c index 1e7cfcbd5e..8fde5da50e 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -1702,6 +1702,96 @@ cmdHypervisorCPUCompare(vshControl *ctl, }
[...]
+ +static const vshCmdOptDef opts_hypervisor_cpu_baseline[] = { + VIRSH_COMMON_OPT_FILE(N_("file containing XML CPU descriptions")), + {.name = "virttype", + .type = VSH_OT_STRING, + .help = N_("virtualization type (/domain/@type)"), + }, + {.name = "emulator", + .type = VSH_OT_STRING, + .help = N_("path to emulator binary (/domain/devices/emulator)"), + }, + {.name = "arch", + .type = VSH_OT_STRING, + .help = N_("domain architecture (/domain/os/type/@arch)"),
"CPU architecture" again :) [...]
diff --git a/tools/virsh.pod b/tools/virsh.pod index 1a55092efd..d57ebadee6 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -574,12 +574,13 @@ I<--all> which executes the modification on all NUMA cells. =item B<cpu-baseline> I<FILE> [I<--features>] [I<--migratable>]
Compute baseline CPU which will be supported by all host CPUs given in <file>.
-The list of host CPUs is built by extracting all <cpu> elements from the -<file>. Thus, the <file> can contain either a set of <cpu> elements separated -by new lines or even a set of complete <capabilities> elements printed by -B<capabilities> command. If I<--features> is specified then the -resulting XML description will explicitly include all features that make -up the CPU, without this option features that are part of the CPU model
+(See B<hypervisor-cpu-baseline> command to get a CPU which can be provided by a +specific hypervisor.) The list of host CPUs is built by extracting all <cpu> +elements from the <file>. Thus, the <file> can contain either a set of <cpu> +elements separated by new lines or even a set of complete <capabilities> +elements printed by B<capabilities> command. If I<--features> is specified
comma after "specified"
+then the resulting XML description will explicitly include all features that +make up the CPU, without this option features that are part of the CPU model will not be listed in the XML description. If I<--migratable> is specified, features that block migration will not be included in the resulting CPU.
@@ -643,6 +644,40 @@ I<machine> specifies the machine type. If I<--error> is specified, the command will return an error when the given CPU is incompatible with host CPU and a message providing more details about the incompatibility will be printed out.
+=item B<hypervisor-cpu-baseline> I<FILE> [I<virttype>] [I<emulator>] [I<arch>] +[I<machine>] [I<--features>] [I<--migratable>] + +Compute baseline CPU which will be compatible with all CPUs given in I<FILE> +and can be provided by the specified hypervisor. (This is different from
Borrowing some ideas from your documentation on comparison: "Compute a baseline CPU which will be compatible with all CPUs defined in an XML I<file> and with the CPU the hypervisor is able to provide on the host. (This is different from"
+B<cpu-baseline> which does not consider any hypervisor abilities when computing +the baseline CPU.) + +The XML I<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 B<capabilities> command. The guest CPU definition may be created +from the host CPU model found in domain capabilities XML (printed by +B<domcapabilities> command). In addition to the <cpu> elements, this command +accepts full capabilities XMLs, or domain capabilities XMLs containing the CPU +definitions. For best results, use only the CPU definitions from domain +capabilities. + +When I<FILE> contains only a single CPU definition, the command will print the +same CPU updated according to additional options and restricted to the +capabilities of the specified hypervisor. Specifically, running
My head got wrapped around trying to understand what this sentence, specifically what is meant by "additional options". I assume you're referring to the --features and --migratable options? How about something like this: "When I<FILE> contains only a single CPU definition, the command will print the same CPU with restrictions imposed by the capabilities of the hypervisor." and then leave it up to your description of the additional options in your last paragraph to explain how to print the features? "Specifically, running the"
+B<virsh hypervisor-cpu-baseline> command with no additional options on the +result of B<virsh domcapabilities> will return transform the host CPU model
I would remove "return" from this sentence.
+from domain capabilities XML to the form directly usable in domain XML.
"from domain capabilities XML to _a_ form directly usable in the domain XML."
+ +The I<virttype> option specifies the virtualization type (usable in the 'type' +attribute of the <domain> top level element from the domain XML). I<emulator> +specifies the path to the emulator, I<arch> specifies the CPU architecture, and +I<machine> specifies the machine type. If I<--features> is specified then the +resulting XML description will explicitly include all features that make up the +CPU, without this option features that are part of the CPU model will not be +listed in the XML description. If I<--migratable> is specified, features that +block migration will not be included in the resulting CPU. + + =back
=head1 DOMAIN COMMANDS
-- Respectfully, - Collin Walling

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/bhyve/bhyve_driver.c | 4 ++-- src/cpu/cpu.c | 10 +++++----- src/cpu/cpu.h | 18 +++++++++--------- src/cpu/cpu_arm.c | 10 +++++----- src/cpu/cpu_ppc64.c | 4 ++-- src/cpu/cpu_x86.c | 10 +++++----- src/libvirt_private.syms | 2 +- src/libxl/libxl_driver.c | 4 ++-- src/qemu/qemu_driver.c | 4 ++-- src/test/test_driver.c | 2 +- src/vz/vz_driver.c | 2 +- tests/cputest.c | 6 +++--- 12 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c index d2a538337f..72c51434c7 100644 --- a/src/bhyve/bhyve_driver.c +++ b/src/bhyve/bhyve_driver.c @@ -1398,8 +1398,8 @@ bhyveConnectBaselineCPU(virConnectPtr conn, if (!(cpus = virCPUDefListParse(xmlCPUs, ncpus, VIR_CPU_TYPE_HOST))) goto cleanup; - if (!(cpu = cpuBaseline(cpus, ncpus, NULL, - !!(flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE)))) + if (!(cpu = virCPUBaseline(cpus, ncpus, NULL, + !!(flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE)))) goto cleanup; if ((flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES) && diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 047e3b1112..81b93a991b 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -479,7 +479,7 @@ virCPUProbeHost(virArch arch) /** - * cpuBaseline: + * virCPUBaseline: * * @cpus: list of host CPU definitions * @ncpus: number of CPUs in @cpus @@ -494,10 +494,10 @@ virCPUProbeHost(virArch arch) * Returns baseline CPU definition or NULL on error. */ virCPUDefPtr -cpuBaseline(virCPUDefPtr *cpus, - unsigned int ncpus, - virDomainCapsCPUModelsPtr models, - bool migratable) +virCPUBaseline(virCPUDefPtr *cpus, + unsigned int ncpus, + virDomainCapsCPUModelsPtr models, + bool migratable) { struct cpuArchDriver *driver; size_t i; diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 83d5bcb63f..529068a618 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -73,10 +73,10 @@ typedef int virDomainCapsCPUModelsPtr models); typedef virCPUDefPtr -(*cpuArchBaseline) (virCPUDefPtr *cpus, - unsigned int ncpus, - virDomainCapsCPUModelsPtr models, - bool migratable); +(*virCPUArchBaseline)(virCPUDefPtr *cpus, + unsigned int ncpus, + virDomainCapsCPUModelsPtr models, + bool migratable); typedef int (*virCPUArchUpdate)(virCPUDefPtr guest, @@ -129,7 +129,7 @@ struct cpuArchDriver { cpuArchEncode encode; cpuArchDataFree dataFree; virCPUArchGetHost getHost; - cpuArchBaseline baseline; + virCPUArchBaseline baseline; virCPUArchUpdate update; virCPUArchUpdateLive updateLive; virCPUArchCheckFeature checkFeature; @@ -194,10 +194,10 @@ virCPUDefPtr virCPUProbeHost(virArch arch); virCPUDefPtr -cpuBaseline (virCPUDefPtr *cpus, - unsigned int ncpus, - virDomainCapsCPUModelsPtr models, - bool migratable); +virCPUBaseline(virCPUDefPtr *cpus, + unsigned int ncpus, + virDomainCapsCPUModelsPtr models, + bool migratable); int virCPUUpdate(virArch arch, diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index 44cb4fea68..a9aa065f9f 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -73,10 +73,10 @@ virCPUarmUpdate(virCPUDefPtr guest, static virCPUDefPtr -armBaseline(virCPUDefPtr *cpus, - unsigned int ncpus ATTRIBUTE_UNUSED, - virDomainCapsCPUModelsPtr models ATTRIBUTE_UNUSED, - bool migratable ATTRIBUTE_UNUSED) +virCPUarmBaseline(virCPUDefPtr *cpus, + unsigned int ncpus ATTRIBUTE_UNUSED, + virDomainCapsCPUModelsPtr models ATTRIBUTE_UNUSED, + bool migratable ATTRIBUTE_UNUSED) { virCPUDefPtr cpu = NULL; @@ -107,6 +107,6 @@ struct cpuArchDriver cpuDriverArm = { .compare = virCPUarmCompare, .decode = NULL, .encode = NULL, - .baseline = armBaseline, + .baseline = virCPUarmBaseline, .update = virCPUarmUpdate, }; diff --git a/src/cpu/cpu_ppc64.c b/src/cpu/cpu_ppc64.c index 76582d4083..c213245fc9 100644 --- a/src/cpu/cpu_ppc64.c +++ b/src/cpu/cpu_ppc64.c @@ -767,7 +767,7 @@ virCPUppc64Update(virCPUDefPtr guest, } static virCPUDefPtr -ppc64DriverBaseline(virCPUDefPtr *cpus, +virCPUppc64Baseline(virCPUDefPtr *cpus, unsigned int ncpus, virDomainCapsCPUModelsPtr models ATTRIBUTE_UNUSED, bool migratable ATTRIBUTE_UNUSED) @@ -901,7 +901,7 @@ struct cpuArchDriver cpuDriverPPC64 = { .encode = NULL, .dataFree = virCPUppc64DataFree, .getHost = virCPUppc64GetHost, - .baseline = ppc64DriverBaseline, + .baseline = virCPUppc64Baseline, .update = virCPUppc64Update, .getModels = virCPUppc64DriverGetModels, .convertLegacy = virCPUppc64ConvertLegacy, diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index b2398c5ad2..188d1eba75 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -2464,10 +2464,10 @@ virCPUx86GetHost(virCPUDefPtr cpu, static virCPUDefPtr -x86Baseline(virCPUDefPtr *cpus, - unsigned int ncpus, - virDomainCapsCPUModelsPtr models, - bool migratable) +virCPUx86Baseline(virCPUDefPtr *cpus, + unsigned int ncpus, + virDomainCapsCPUModelsPtr models, + bool migratable) { virCPUx86MapPtr map = NULL; virCPUx86ModelPtr base_model = NULL; @@ -3050,7 +3050,7 @@ struct cpuArchDriver cpuDriverX86 = { #if defined(__i386__) || defined(__x86_64__) .getHost = virCPUx86GetHost, #endif - .baseline = x86Baseline, + .baseline = virCPUx86Baseline, .update = virCPUx86Update, .updateLive = virCPUx86UpdateLive, .checkFeature = virCPUx86CheckFeature, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 3dece252df..912676ec7a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1139,9 +1139,9 @@ virStoragePoolObjVolumeListExport; # cpu/cpu.h -cpuBaseline; cpuDecode; cpuEncode; +virCPUBaseline; virCPUCheckFeature; virCPUCompare; virCPUCompareXML; diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index df53dead0a..e11969dca7 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -6349,8 +6349,8 @@ libxlConnectBaselineCPU(virConnectPtr conn, if (!(cpus = virCPUDefListParse(xmlCPUs, ncpus, VIR_CPU_TYPE_HOST))) goto cleanup; - if (!(cpu = cpuBaseline(cpus, ncpus, NULL, - !!(flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE)))) + if (!(cpu = virCPUBaseline(cpus, ncpus, NULL, + !!(flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE)))) goto cleanup; if ((flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES) && diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 4b48afdad1..17167129da 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -13179,8 +13179,8 @@ qemuConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED, if (!(cpus = virCPUDefListParse(xmlCPUs, ncpus, VIR_CPU_TYPE_HOST))) goto cleanup; - if (!(baseline = cpuBaseline(cpus, ncpus, NULL, - !!(flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE)))) + if (!(baseline = virCPUBaseline(cpus, ncpus, NULL, + !!(flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE)))) goto cleanup; if (!(cpu = virCPUDefCopyWithoutModel(baseline))) diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 467587b19f..abb856a5b2 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -1536,7 +1536,7 @@ testConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED, if (!(cpus = virCPUDefListParse(xmlCPUs, ncpus, VIR_CPU_TYPE_HOST))) goto cleanup; - if (!(cpu = cpuBaseline(cpus, ncpus, NULL, false))) + if (!(cpu = virCPUBaseline(cpus, ncpus, NULL, false))) goto cleanup; if ((flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES) && diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c index 48a9a866d9..d4cf2d5f62 100644 --- a/src/vz/vz_driver.c +++ b/src/vz/vz_driver.c @@ -934,7 +934,7 @@ vzConnectBaselineCPU(virConnectPtr conn, if (!(cpus = virCPUDefListParse(xmlCPUs, ncpus, VIR_CPU_TYPE_HOST))) goto cleanup; - if (!(cpu = cpuBaseline(cpus, ncpus, NULL, false))) + if (!(cpu = virCPUBaseline(cpus, ncpus, NULL, false))) goto cleanup; if ((flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES) && diff --git a/tests/cputest.c b/tests/cputest.c index e86cd0b9bc..beb9afabdf 100644 --- a/tests/cputest.c +++ b/tests/cputest.c @@ -321,8 +321,8 @@ cpuTestBaseline(const void *arg) if (!(cpus = cpuTestLoadMultiXML(data->arch, data->name, &ncpus))) goto cleanup; - baseline = cpuBaseline(cpus, ncpus, NULL, - !!(data->flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE)); + baseline = virCPUBaseline(cpus, ncpus, NULL, + !!(data->flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE)); if (baseline && (data->flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES) && @@ -337,7 +337,7 @@ cpuTestBaseline(const void *arg) ret = 0; } else { VIR_TEST_VERBOSE("\n%-70s... ", - "cpuBaseline was expected to fail but it succeeded"); + "virCPUBaseline was expected to fail but it succeeded"); } goto cleanup; } -- 2.17.0

On Wed, May 16, 2018 at 10:39:34AM +0200, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/bhyve/bhyve_driver.c | 4 ++-- src/cpu/cpu.c | 10 +++++----- src/cpu/cpu.h | 18 +++++++++--------- src/cpu/cpu_arm.c | 10 +++++----- src/cpu/cpu_ppc64.c | 4 ++-- src/cpu/cpu_x86.c | 10 +++++----- src/libvirt_private.syms | 2 +- src/libxl/libxl_driver.c | 4 ++-- src/qemu/qemu_driver.c | 4 ++-- src/test/test_driver.c | 2 +- src/vz/vz_driver.c | 2 +- tests/cputest.c | 6 +++--- 12 files changed, 38 insertions(+), 38 deletions(-)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

Modern host CPU models from domain capabilities XMLs are reported as guest CPU definitions with feature policies. This patch updates virCPUx86Baseline to properly handle such CPU models. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/cpu/cpu_x86.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index 188d1eba75..6bef4089e9 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -2482,13 +2482,12 @@ virCPUx86Baseline(virCPUDefPtr *cpus, if (!(map = virCPUx86GetMap())) goto error; - if (!(base_model = x86ModelFromCPU(cpus[0], map, VIR_CPU_FEATURE_REQUIRE))) + if (!(base_model = x86ModelFromCPU(cpus[0], map, -1))) goto error; if (VIR_ALLOC(cpu) < 0) goto error; - cpu->arch = cpus[0]->arch; cpu->type = VIR_CPU_TYPE_GUEST; cpu->match = VIR_CPU_MATCH_EXACT; @@ -2513,7 +2512,7 @@ virCPUx86Baseline(virCPUDefPtr *cpus, } } - if (!(model = x86ModelFromCPU(cpus[i], map, VIR_CPU_FEATURE_REQUIRE))) + if (!(model = x86ModelFromCPU(cpus[i], map, -1))) goto error; if (cpus[i]->vendor && model->vendor && @@ -2570,8 +2569,6 @@ virCPUx86Baseline(virCPUDefPtr *cpus, if (!outputVendor) VIR_FREE(cpu->vendor); - cpu->arch = VIR_ARCH_NONE; - cleanup: x86ModelFree(base_model); -- 2.17.0

On Wed, May 16, 2018 at 10:39:35AM +0200, Jiri Denemark wrote:
Modern host CPU models from domain capabilities XMLs are reported as guest CPU definitions with feature policies. This patch updates virCPUx86Baseline to properly handle such CPU models.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/cpu/cpu_x86.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

This is required for virCPUBaseline to accept a list of guest CPU definitions since they do not have arch set. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/bhyve/bhyve_driver.c | 2 +- src/cpu/cpu.c | 16 +++++++++++----- src/cpu/cpu.h | 3 ++- src/libxl/libxl_driver.c | 2 +- src/qemu/qemu_driver.c | 2 +- src/test/test_driver.c | 2 +- src/vz/vz_driver.c | 2 +- tests/cputest.c | 2 +- 8 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c index 72c51434c7..26047d31e2 100644 --- a/src/bhyve/bhyve_driver.c +++ b/src/bhyve/bhyve_driver.c @@ -1398,7 +1398,7 @@ bhyveConnectBaselineCPU(virConnectPtr conn, if (!(cpus = virCPUDefListParse(xmlCPUs, ncpus, VIR_CPU_TYPE_HOST))) goto cleanup; - if (!(cpu = virCPUBaseline(cpus, ncpus, NULL, + if (!(cpu = virCPUBaseline(VIR_ARCH_NONE, cpus, ncpus, NULL, !!(flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE)))) goto cleanup; diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 81b93a991b..2c60d27b17 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -481,20 +481,22 @@ virCPUProbeHost(virArch arch) /** * virCPUBaseline: * + * @arch: CPU architecture, use VIR_ARCH_NONE to autodetect from @cpus * @cpus: list of host CPU definitions * @ncpus: number of CPUs in @cpus * @models: list of CPU models that can be considered for the baseline CPU * @migratable: requests non-migratable features to be removed from the result * * Computes the most feature-rich CPU which is compatible with all given - * host CPUs. If @models is NULL, all models supported by libvirt will + * CPUs. If @models is NULL, all models supported by libvirt will * be considered when computing the baseline CPU model, otherwise the baseline * CPU model will be one of the provided CPU @models. * * Returns baseline CPU definition or NULL on error. */ virCPUDefPtr -virCPUBaseline(virCPUDefPtr *cpus, +virCPUBaseline(virArch arch, + virCPUDefPtr *cpus, unsigned int ncpus, virDomainCapsCPUModelsPtr models, bool migratable) @@ -502,7 +504,8 @@ virCPUBaseline(virCPUDefPtr *cpus, struct cpuArchDriver *driver; size_t i; - VIR_DEBUG("ncpus=%u, models=%p, migratable=%d", ncpus, models, migratable); + VIR_DEBUG("arch=%s, ncpus=%u, models=%p, migratable=%d", + virArchToString(arch), ncpus, models, migratable); if (cpus) { for (i = 0; i < ncpus; i++) VIR_DEBUG("cpus[%zu]=%p", i, cpus[i]); @@ -536,13 +539,16 @@ virCPUBaseline(virCPUDefPtr *cpus, } } - if ((driver = cpuGetSubDriver(cpus[0]->arch)) == NULL) + if (arch == VIR_ARCH_NONE) + arch = cpus[0]->arch; + + if ((driver = cpuGetSubDriver(arch)) == NULL) return NULL; if (driver->baseline == NULL) { virReportError(VIR_ERR_NO_SUPPORT, _("cannot compute baseline CPU of %s architecture"), - virArchToString(cpus[0]->arch)); + virArchToString(arch)); return NULL; } diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 529068a618..8c45bf8b31 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -194,7 +194,8 @@ virCPUDefPtr virCPUProbeHost(virArch arch); virCPUDefPtr -virCPUBaseline(virCPUDefPtr *cpus, +virCPUBaseline(virArch arch, + virCPUDefPtr *cpus, unsigned int ncpus, virDomainCapsCPUModelsPtr models, bool migratable); diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index e11969dca7..a85ce84404 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -6349,7 +6349,7 @@ libxlConnectBaselineCPU(virConnectPtr conn, if (!(cpus = virCPUDefListParse(xmlCPUs, ncpus, VIR_CPU_TYPE_HOST))) goto cleanup; - if (!(cpu = virCPUBaseline(cpus, ncpus, NULL, + if (!(cpu = virCPUBaseline(VIR_ARCH_NONE, cpus, ncpus, NULL, !!(flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE)))) goto cleanup; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 17167129da..b95e1f5296 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -13179,7 +13179,7 @@ qemuConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED, if (!(cpus = virCPUDefListParse(xmlCPUs, ncpus, VIR_CPU_TYPE_HOST))) goto cleanup; - if (!(baseline = virCPUBaseline(cpus, ncpus, NULL, + if (!(baseline = virCPUBaseline(VIR_ARCH_NONE, cpus, ncpus, NULL, !!(flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE)))) goto cleanup; diff --git a/src/test/test_driver.c b/src/test/test_driver.c index abb856a5b2..3b4acaf7fe 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -1536,7 +1536,7 @@ testConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED, if (!(cpus = virCPUDefListParse(xmlCPUs, ncpus, VIR_CPU_TYPE_HOST))) goto cleanup; - if (!(cpu = virCPUBaseline(cpus, ncpus, NULL, false))) + if (!(cpu = virCPUBaseline(VIR_ARCH_NONE, cpus, ncpus, NULL, false))) goto cleanup; if ((flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES) && diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c index d4cf2d5f62..50cd0acfdf 100644 --- a/src/vz/vz_driver.c +++ b/src/vz/vz_driver.c @@ -934,7 +934,7 @@ vzConnectBaselineCPU(virConnectPtr conn, if (!(cpus = virCPUDefListParse(xmlCPUs, ncpus, VIR_CPU_TYPE_HOST))) goto cleanup; - if (!(cpu = virCPUBaseline(cpus, ncpus, NULL, false))) + if (!(cpu = virCPUBaseline(VIR_ARCH_NONE, cpus, ncpus, NULL, false))) goto cleanup; if ((flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES) && diff --git a/tests/cputest.c b/tests/cputest.c index beb9afabdf..9b84ffea86 100644 --- a/tests/cputest.c +++ b/tests/cputest.c @@ -321,7 +321,7 @@ cpuTestBaseline(const void *arg) if (!(cpus = cpuTestLoadMultiXML(data->arch, data->name, &ncpus))) goto cleanup; - baseline = virCPUBaseline(cpus, ncpus, NULL, + baseline = virCPUBaseline(data->arch, cpus, ncpus, NULL, !!(data->flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE)); if (baseline && -- 2.17.0

On Wed, May 16, 2018 at 10:39:36AM +0200, Jiri Denemark wrote:
This is required for virCPUBaseline to accept a list of guest CPU definitions since they do not have arch set.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/bhyve/bhyve_driver.c | 2 +- src/cpu/cpu.c | 16 +++++++++++----- src/cpu/cpu.h | 3 ++- src/libxl/libxl_driver.c | 2 +- src/qemu/qemu_driver.c | 2 +- src/test/test_driver.c | 2 +- src/vz/vz_driver.c | 2 +- tests/cputest.c | 2 +- 8 files changed, 19 insertions(+), 12 deletions(-)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

On 05/16/2018 04:39 AM, Jiri Denemark wrote:
This is required for virCPUBaseline to accept a list of guest CPU definitions since they do not have arch set.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/bhyve/bhyve_driver.c | 2 +- src/cpu/cpu.c | 16 +++++++++++----- src/cpu/cpu.h | 3 ++- src/libxl/libxl_driver.c | 2 +- src/qemu/qemu_driver.c | 2 +- src/test/test_driver.c | 2 +- src/vz/vz_driver.c | 2 +- tests/cputest.c | 2 +- 8 files changed, 19 insertions(+), 12 deletions(-)
Reviewed-by: Collin Walling <walling@linux.ibm.com> -- Respectfully, - Collin Walling

To make it more consistent with the rest of the CPU driver code. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/cpu/cpu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 2c60d27b17..b6c1695f2a 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -515,14 +515,14 @@ virCPUBaseline(virArch arch, VIR_DEBUG("models[%zu]=%s", i, models->models[i].name); } - if (cpus == NULL && ncpus != 0) { + if (!cpus && ncpus != 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nonzero ncpus doesn't match with NULL cpus")); return NULL; } if (ncpus < 1) { - virReportError(VIR_ERR_INVALID_ARG, "%s", _("No CPUs given")); + virReportError(VIR_ERR_INVALID_ARG, "%s", _("no CPUs given")); return NULL; } @@ -542,10 +542,10 @@ virCPUBaseline(virArch arch, if (arch == VIR_ARCH_NONE) arch = cpus[0]->arch; - if ((driver = cpuGetSubDriver(arch)) == NULL) + if (!(driver = cpuGetSubDriver(arch))) return NULL; - if (driver->baseline == NULL) { + if (!driver->baseline) { virReportError(VIR_ERR_NO_SUPPORT, _("cannot compute baseline CPU of %s architecture"), virArchToString(arch)); -- 2.17.0

On Wed, May 16, 2018 at 10:39:37AM +0200, Jiri Denemark wrote:
To make it more consistent with the rest of the CPU driver code.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/cpu/cpu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

On 05/16/2018 04:39 AM, Jiri Denemark wrote:
To make it more consistent with the rest of the CPU driver code.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/cpu/cpu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
Reviewed-by: Collin Walling <walling@linux.ibm.com> -- Respectfully, - Collin Walling

When computing a baseline CPU for a specific hypervisor we have to make sure to include only CPU features supported by the hypervisor. Otherwise the computed CPU could not be used for starting a new domain. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/bhyve/bhyve_driver.c | 2 +- src/cpu/cpu.c | 8 +++++--- src/cpu/cpu.h | 2 ++ src/cpu/cpu_arm.c | 1 + src/cpu/cpu_ppc64.c | 1 + src/cpu/cpu_x86.c | 18 ++++++++++++++++++ src/libxl/libxl_driver.c | 2 +- src/qemu/qemu_driver.c | 2 +- src/test/test_driver.c | 2 +- src/vz/vz_driver.c | 2 +- tests/cputest.c | 2 +- 11 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c index 26047d31e2..97e8d4eb37 100644 --- a/src/bhyve/bhyve_driver.c +++ b/src/bhyve/bhyve_driver.c @@ -1398,7 +1398,7 @@ bhyveConnectBaselineCPU(virConnectPtr conn, if (!(cpus = virCPUDefListParse(xmlCPUs, ncpus, VIR_CPU_TYPE_HOST))) goto cleanup; - if (!(cpu = virCPUBaseline(VIR_ARCH_NONE, cpus, ncpus, NULL, + if (!(cpu = virCPUBaseline(VIR_ARCH_NONE, cpus, ncpus, NULL, NULL, !!(flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE)))) goto cleanup; diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index b6c1695f2a..cc93c49418 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -485,6 +485,7 @@ virCPUProbeHost(virArch arch) * @cpus: list of host CPU definitions * @ncpus: number of CPUs in @cpus * @models: list of CPU models that can be considered for the baseline CPU + * @features: optional NULL terminated list of allowed features * @migratable: requests non-migratable features to be removed from the result * * Computes the most feature-rich CPU which is compatible with all given @@ -499,13 +500,14 @@ virCPUBaseline(virArch arch, virCPUDefPtr *cpus, unsigned int ncpus, virDomainCapsCPUModelsPtr models, + const char **features, bool migratable) { struct cpuArchDriver *driver; size_t i; - VIR_DEBUG("arch=%s, ncpus=%u, models=%p, migratable=%d", - virArchToString(arch), ncpus, models, migratable); + VIR_DEBUG("arch=%s, ncpus=%u, models=%p, features=%p, migratable=%d", + virArchToString(arch), ncpus, models, features, migratable); if (cpus) { for (i = 0; i < ncpus; i++) VIR_DEBUG("cpus[%zu]=%p", i, cpus[i]); @@ -552,7 +554,7 @@ virCPUBaseline(virArch arch, return NULL; } - return driver->baseline(cpus, ncpus, models, migratable); + return driver->baseline(cpus, ncpus, models, features, migratable); } diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 8c45bf8b31..81119b6aeb 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -76,6 +76,7 @@ typedef virCPUDefPtr (*virCPUArchBaseline)(virCPUDefPtr *cpus, unsigned int ncpus, virDomainCapsCPUModelsPtr models, + const char **features, bool migratable); typedef int @@ -198,6 +199,7 @@ virCPUBaseline(virArch arch, virCPUDefPtr *cpus, unsigned int ncpus, virDomainCapsCPUModelsPtr models, + const char **features, bool migratable); int diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index a9aa065f9f..cc7da44ac4 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -76,6 +76,7 @@ static virCPUDefPtr virCPUarmBaseline(virCPUDefPtr *cpus, unsigned int ncpus ATTRIBUTE_UNUSED, virDomainCapsCPUModelsPtr models ATTRIBUTE_UNUSED, + const char **features ATTRIBUTE_UNUSED, bool migratable ATTRIBUTE_UNUSED) { virCPUDefPtr cpu = NULL; diff --git a/src/cpu/cpu_ppc64.c b/src/cpu/cpu_ppc64.c index c213245fc9..d562677fa3 100644 --- a/src/cpu/cpu_ppc64.c +++ b/src/cpu/cpu_ppc64.c @@ -770,6 +770,7 @@ static virCPUDefPtr virCPUppc64Baseline(virCPUDefPtr *cpus, unsigned int ncpus, virDomainCapsCPUModelsPtr models ATTRIBUTE_UNUSED, + const char **features ATTRIBUTE_UNUSED, bool migratable ATTRIBUTE_UNUSED) { struct ppc64_map *map; diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index 6bef4089e9..809da94117 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -2467,6 +2467,7 @@ static virCPUDefPtr virCPUx86Baseline(virCPUDefPtr *cpus, unsigned int ncpus, virDomainCapsCPUModelsPtr models, + const char **features, bool migratable) { virCPUx86MapPtr map = NULL; @@ -2478,6 +2479,7 @@ virCPUx86Baseline(virCPUDefPtr *cpus, bool outputVendor = true; const char *modelName; bool matchingNames = true; + virCPUDataPtr featData = NULL; if (!(map = virCPUx86GetMap())) goto error; @@ -2550,6 +2552,21 @@ virCPUx86Baseline(virCPUDefPtr *cpus, model = NULL; } + if (features) { + virCPUx86FeaturePtr feat; + + if (!(featData = virCPUDataNew(archs[0]))) + goto cleanup; + + for (i = 0; features[i]; i++) { + if ((feat = x86FeatureFind(map, features[i])) && + x86DataAdd(&featData->data.x86, &feat->data) < 0) + goto cleanup; + } + + x86DataIntersect(&base_model->data, &featData->data.x86); + } + if (x86DataIsEmpty(&base_model->data)) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("CPUs are incompatible")); @@ -2571,6 +2588,7 @@ virCPUx86Baseline(virCPUDefPtr *cpus, cleanup: x86ModelFree(base_model); + virCPUx86DataFree(featData); return cpu; diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index a85ce84404..8c40661e5a 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -6349,7 +6349,7 @@ libxlConnectBaselineCPU(virConnectPtr conn, if (!(cpus = virCPUDefListParse(xmlCPUs, ncpus, VIR_CPU_TYPE_HOST))) goto cleanup; - if (!(cpu = virCPUBaseline(VIR_ARCH_NONE, cpus, ncpus, NULL, + if (!(cpu = virCPUBaseline(VIR_ARCH_NONE, cpus, ncpus, NULL, NULL, !!(flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE)))) goto cleanup; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index b95e1f5296..e036764f92 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -13179,7 +13179,7 @@ qemuConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED, if (!(cpus = virCPUDefListParse(xmlCPUs, ncpus, VIR_CPU_TYPE_HOST))) goto cleanup; - if (!(baseline = virCPUBaseline(VIR_ARCH_NONE, cpus, ncpus, NULL, + if (!(baseline = virCPUBaseline(VIR_ARCH_NONE, cpus, ncpus, NULL, NULL, !!(flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE)))) goto cleanup; diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 3b4acaf7fe..09f17bc8f9 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -1536,7 +1536,7 @@ testConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED, if (!(cpus = virCPUDefListParse(xmlCPUs, ncpus, VIR_CPU_TYPE_HOST))) goto cleanup; - if (!(cpu = virCPUBaseline(VIR_ARCH_NONE, cpus, ncpus, NULL, false))) + if (!(cpu = virCPUBaseline(VIR_ARCH_NONE, cpus, ncpus, NULL, NULL, false))) goto cleanup; if ((flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES) && diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c index 50cd0acfdf..c9520d4a58 100644 --- a/src/vz/vz_driver.c +++ b/src/vz/vz_driver.c @@ -934,7 +934,7 @@ vzConnectBaselineCPU(virConnectPtr conn, if (!(cpus = virCPUDefListParse(xmlCPUs, ncpus, VIR_CPU_TYPE_HOST))) goto cleanup; - if (!(cpu = virCPUBaseline(VIR_ARCH_NONE, cpus, ncpus, NULL, false))) + if (!(cpu = virCPUBaseline(VIR_ARCH_NONE, cpus, ncpus, NULL, NULL, false))) goto cleanup; if ((flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES) && diff --git a/tests/cputest.c b/tests/cputest.c index 9b84ffea86..baf2b3c648 100644 --- a/tests/cputest.c +++ b/tests/cputest.c @@ -321,7 +321,7 @@ cpuTestBaseline(const void *arg) if (!(cpus = cpuTestLoadMultiXML(data->arch, data->name, &ncpus))) goto cleanup; - baseline = virCPUBaseline(data->arch, cpus, ncpus, NULL, + baseline = virCPUBaseline(data->arch, cpus, ncpus, NULL, NULL, !!(data->flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE)); if (baseline && -- 2.17.0

On Wed, May 16, 2018 at 10:39:38AM +0200, Jiri Denemark wrote:
When computing a baseline CPU for a specific hypervisor we have to make sure to include only CPU features supported by the hypervisor. Otherwise the computed CPU could not be used for starting a new domain.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/bhyve/bhyve_driver.c | 2 +- src/cpu/cpu.c | 8 +++++--- src/cpu/cpu.h | 2 ++ src/cpu/cpu_arm.c | 1 + src/cpu/cpu_ppc64.c | 1 + src/cpu/cpu_x86.c | 18 ++++++++++++++++++ src/libxl/libxl_driver.c | 2 +- src/qemu/qemu_driver.c | 2 +- src/test/test_driver.c | 2 +- src/vz/vz_driver.c | 2 +- tests/cputest.c | 2 +- 11 files changed, 33 insertions(+), 9 deletions(-)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

On 05/16/2018 04:39 AM, Jiri Denemark wrote:
When computing a baseline CPU for a specific hypervisor we have to make sure to include only CPU features supported by the hypervisor. Otherwise the computed CPU could not be used for starting a new domain.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/bhyve/bhyve_driver.c | 2 +- src/cpu/cpu.c | 8 +++++--- src/cpu/cpu.h | 2 ++ src/cpu/cpu_arm.c | 1 + src/cpu/cpu_ppc64.c | 1 + src/cpu/cpu_x86.c | 18 ++++++++++++++++++ src/libxl/libxl_driver.c | 2 +- src/qemu/qemu_driver.c | 2 +- src/test/test_driver.c | 2 +- src/vz/vz_driver.c | 2 +- tests/cputest.c | 2 +- 11 files changed, 33 insertions(+), 9 deletions(-)
Reviewed-by: Collin Walling <walling@linux.ibm.com> -- Respectfully, - Collin Walling

The function creates a lost of all (or migratable only) CPU features supported by QEMU. It works by looking at the CPU model info returned by query-cpu-model-expansion QMP command. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_capabilities.c | 52 ++++++++++++++++++++++++++++++++++++ src/qemu/qemu_capabilities.h | 4 +++ 2 files changed, 56 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 77a4b4154e..e8c5940210 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -2367,6 +2367,58 @@ virQEMUCapsProbeQMPHostCPU(virQEMUCapsPtr qemuCaps, return ret; } + +/** + * Get NULL terminated list of features supported by QEMU. + * + * Returns -1 on error, + * 0 on success (@features will be NULL if QEMU does not support this), + * 1 when @features is filled in, but migratability info is not available. + */ +int +virQEMUCapsGetCPUFeatures(virQEMUCapsPtr qemuCaps, + virDomainVirtType virtType, + bool migratable, + char ***features) +{ + virQEMUCapsHostCPUDataPtr data; + char **list; + size_t i; + size_t n; + int ret = -1; + + *features = NULL; + data = virQEMUCapsGetHostCPUData(qemuCaps, virtType); + + if (!data->info) + return 0; + + if (VIR_ALLOC_N(list, data->info->nprops + 1) < 0) + return -1; + + n = 0; + for (i = 0; i < data->info->nprops; i++) { + qemuMonitorCPUPropertyPtr prop = data->info->props + i; + + if (migratable && prop->migratable == VIR_TRISTATE_BOOL_NO) + continue; + + if (VIR_STRDUP(list[n++], prop->name) < 0) + goto cleanup; + } + + VIR_STEAL_PTR(*features, list); + if (migratable && !data->info->migratability) + ret = 1; + else + ret = 0; + + cleanup: + virStringListFree(list); + return ret; +} + + struct tpmTypeToCaps { int type; virQEMUCapsFlags caps; diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 6f095bfbfe..eee989559e 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -529,6 +529,10 @@ typedef enum { virCPUDefPtr virQEMUCapsGetHostModel(virQEMUCapsPtr qemuCaps, virDomainVirtType type, virQEMUCapsHostCPUType cpuType); +int virQEMUCapsGetCPUFeatures(virQEMUCapsPtr qemuCaps, + virDomainVirtType virtType, + bool migratable, + char ***features); bool virQEMUCapsIsCPUModeSupported(virQEMUCapsPtr qemuCaps, virCapsPtr caps, -- 2.17.0

On Wed, May 16, 2018 at 10:39:39AM +0200, Jiri Denemark wrote:
The function creates a lost of all (or migratable only) CPU features
s/lost/list/
supported by QEMU. It works by looking at the CPU model info returned by query-cpu-model-expansion QMP command.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_capabilities.c | 52 ++++++++++++++++++++++++++++++++++++ src/qemu/qemu_capabilities.h | 4 +++ 2 files changed, 56 insertions(+)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

On 05/16/2018 04:39 AM, Jiri Denemark wrote:
The function creates a lost of all (or migratable only) CPU features supported by QEMU. It works by looking at the CPU model info returned by query-cpu-model-expansion QMP command.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_capabilities.c | 52 ++++++++++++++++++++++++++++++++++++ src/qemu/qemu_capabilities.h | 4 +++ 2 files changed, 56 insertions(+)
Reviewed-by: Collin Walling <walling@linux.ibm.com> -- Respectfully, - Collin Walling

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_driver.c | 91 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index e036764f92..d702e8a8ff 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -13206,6 +13206,96 @@ qemuConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED, } +static char * +qemuConnectBaselineHypervisorCPU(virConnectPtr conn, + const char *emulator, + const char *archStr, + const char *machine, + const char *virttypeStr, + const char **xmlCPUs, + unsigned int ncpus, + unsigned int flags) +{ + virQEMUDriverPtr driver = conn->privateData; + virCPUDefPtr *cpus = NULL; + virQEMUCapsPtr qemuCaps = NULL; + virArch arch; + virDomainVirtType virttype; + virDomainCapsCPUModelsPtr cpuModels; + bool migratable; + virCPUDefPtr cpu = NULL; + char *cpustr = NULL; + char **features = NULL; + + virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES | + VIR_CONNECT_BASELINE_CPU_MIGRATABLE, NULL); + + if (virConnectBaselineHypervisorCPUEnsureACL(conn) < 0) + goto cleanup; + + migratable = !!(flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE); + + if (!(cpus = virCPUDefListParse(xmlCPUs, ncpus, VIR_CPU_TYPE_AUTO))) + goto cleanup; + + qemuCaps = virQEMUCapsCacheLookupDefault(driver->qemuCapsCache, + emulator, + archStr, + virttypeStr, + machine, + &arch, &virttype, NULL); + if (!qemuCaps) + goto cleanup; + + if (!(cpuModels = virQEMUCapsGetCPUDefinitions(qemuCaps, virttype)) || + cpuModels->nmodels == 0) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("QEMU '%s' does not support any CPU models for " + "virttype '%s'"), + virQEMUCapsGetBinary(qemuCaps), + virDomainVirtTypeToString(virttype)); + goto cleanup; + } + + if (ARCH_IS_X86(arch)) { + int rc = virQEMUCapsGetCPUFeatures(qemuCaps, virttype, + migratable, &features); + if (rc < 0) + goto cleanup; + if (features && rc == 0) { + /* We got only migratable features from QEMU if we asked for them, + * no further filtering in virCPUBaseline is desired. */ + migratable = false; + } + + if (!(cpu = virCPUBaseline(arch, cpus, ncpus, cpuModels, + (const char **)features, migratable))) + goto cleanup; + } else { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("computing baseline hypervisor CPU is not supported " + "for arch %s"), virArchToString(arch)); + goto cleanup; + } + + cpu->fallback = VIR_CPU_FALLBACK_FORBID; + + if ((flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES) && + virCPUExpandFeatures(arch, cpu) < 0) + goto cleanup; + + cpustr = virCPUDefFormat(cpu, NULL); + + cleanup: + virCPUDefListFree(cpus); + virCPUDefFree(cpu); + virObjectUnref(qemuCaps); + virStringListFree(features); + + return cpustr; +} + + static int qemuDomainGetJobInfoMigrationStats(virQEMUDriverPtr driver, virDomainObjPtr vm, @@ -21386,6 +21476,7 @@ static virHypervisorDriver qemuHypervisorDriver = { .domainSetBlockThreshold = qemuDomainSetBlockThreshold, /* 3.2.0 */ .domainSetLifecycleAction = qemuDomainSetLifecycleAction, /* 3.9.0 */ .connectCompareHypervisorCPU = qemuConnectCompareHypervisorCPU, /* 4.4.0 */ + .connectBaselineHypervisorCPU = qemuConnectBaselineHypervisorCPU, /* 4.4.0 */ }; -- 2.17.0

On Wed, May 16, 2018 at 10:39:40AM +0200, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_driver.c | 91 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

On 05/16/2018 04:39 AM, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_driver.c | 91 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+)
Reviewed-by: Collin Walling <walling@linux.ibm.com> -- Respectfully, - Collin Walling

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- docs/news.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/news.xml b/docs/news.xml index 7d40e85b9a..bd7885e91a 100644 --- a/docs/news.xml +++ b/docs/news.xml @@ -54,6 +54,15 @@ a QEMU virtual machine. </description> </change> + <change> + <summary> + Introduce new virConnectBaselineHypervisorCPU and virConnectBaselineHypervisorCPU APIs + </summary> + <description> + Unlike the old virConnectBaselineCPU and virConnectBaselineCPU APIs, + both new APIs consider capabilities of a specific hypervisor. + </description> + </change> </section> <section title="Improvements"> <change> -- 2.17.0

On Wed, May 16, 2018 at 10:39:41AM +0200, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- docs/news.xml | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/docs/news.xml b/docs/news.xml index 7d40e85b9a..bd7885e91a 100644 --- a/docs/news.xml +++ b/docs/news.xml @@ -54,6 +54,15 @@ a QEMU virtual machine. </description> </change> + <change> + <summary> + Introduce new virConnectBaselineHypervisorCPU and virConnectBaselineHypervisorCPU APIs
Duplicate: s/virConnectBaselineHypervisorCPU/virConnectCompareHypervisorCPU/
+ </summary> + <description> + Unlike the old virConnectBaselineCPU and virConnectBaselineCPU APIs,
Here too: s/virConnectBaselineCPU/virConnectCompareCPU/
+ both new APIs consider capabilities of a specific hypervisor.
If it in scope of the 'news.xml' file, a one-sentence description of each of the two APIs would be useful. It's just a nice to have, so feel free to disregard this. FWIW, I will aim to try out these two new APIs this week / next week.
+ </description> + </change> </section> <section title="Improvements"> <change> -- 2.17.0
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
-- /kashyap

On Wed, May 16, 2018 at 10:39:41AM +0200, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- docs/news.xml | 9 +++++++++ 1 file changed, 9 insertions(+)
With the copy & paste errors fixed: Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

On Wed, May 16, 2018 at 10:39:19 +0200, Jiri Denemark wrote:
The current virConnectCompareCPU and virConnectBaselineCPU APIs are not very useful because they ignore what a hypervisor can do on the current host. This series adds two new APIs which are designed to work with capabilities of a specific hypervisor to provide usable results.
The third CPU related API virConnectGetCPUModelNames is pretty useless too, but no new API with similar functionality is needed because domain capabilities XML already contains the relevant data.
Any comments? I'd like to have these new APIs in the upcoming 4.4 release. Jirka

On 05/22/2018 05:33 AM, Jiri Denemark wrote:
On Wed, May 16, 2018 at 10:39:19 +0200, Jiri Denemark wrote:
The current virConnectCompareCPU and virConnectBaselineCPU APIs are not very useful because they ignore what a hypervisor can do on the current host. This series adds two new APIs which are designed to work with capabilities of a specific hypervisor to provide usable results.
The third CPU related API virConnectGetCPUModelNames is pretty useless too, but no new API with similar functionality is needed because domain capabilities XML already contains the relevant data.
Any comments? I'd like to have these new APIs in the upcoming 4.4 release.
Jirka
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
This is on top of my todo for today. -- Respectfully, - Collin Walling

Code-wise, these patches look good. I'd like to take the time next week to hook up my comparison patches and test them out properly (unless Chris gets to it first, then I'll just apply his patches and run some tests) On 05/16/2018 04:39 AM, Jiri Denemark wrote:
The current virConnectCompareCPU and virConnectBaselineCPU APIs are not very useful because they ignore what a hypervisor can do on the current host. This series adds two new APIs which are designed to work with capabilities of a specific hypervisor to provide usable results.
The third CPU related API virConnectGetCPUModelNames is pretty useless too, but no new API with similar functionality is needed because domain capabilities XML already contains the relevant data.
-- Respectfully, - Collin Walling

On Wed, May 16, 2018 at 10:39:19 +0200, Jiri Denemark wrote:
The current virConnectCompareCPU and virConnectBaselineCPU APIs are not very useful because they ignore what a hypervisor can do on the current host. This series adds two new APIs which are designed to work with capabilities of a specific hypervisor to provide usable results.
The third CPU related API virConnectGetCPUModelNames is pretty useless too, but no new API with similar functionality is needed because domain capabilities XML already contains the relevant data.
I made the suggested changes and pushed the series. Thanks for the reviews. Jirka

Quoting Jiri Denemark (2018-05-28 09:19:51)
On Wed, May 16, 2018 at 10:39:19 +0200, Jiri Denemark wrote:
The current virConnectCompareCPU and virConnectBaselineCPU APIs are not very useful because they ignore what a hypervisor can do on the current host. This series adds two new APIs which are designed to work with capabilities of a specific hypervisor to provide usable results.
The third CPU related API virConnectGetCPUModelNames is pretty useless too, but no new API with similar functionality is needed because domain capabilities XML already contains the relevant data.
I made the suggested changes and pushed the series. Thanks for the reviews.
Jirka
Hi Jirka, FYI I reviewed your patches too and everthing I found that was not already identified was nitpick stuff but I do have a something I am wondering about... The new hypervisor specific compare and baseline commands seem to depend on qemuCaps being pre-populated with model data that is specific to a hypervisor instance. How do we make sure the qemuCaps are pre-populated with cpu model data for any arbitrary hypervisor (with a different exec path, arch, etc) that we can issue the hypervisor compare or baseline commands against? Is it a case of executing a virsh command to populate qemuCaps for a non-default hypervisor prior to issuing the hypervisor compare or baseline commands? Sorry if a complete noob question or I missed the answer in previous mails. Chris
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On 05/28/2018 03:44 PM, Chris Venteicher wrote:
Quoting Jiri Denemark (2018-05-28 09:19:51)
On Wed, May 16, 2018 at 10:39:19 +0200, Jiri Denemark wrote:
The current virConnectCompareCPU and virConnectBaselineCPU APIs are not very useful because they ignore what a hypervisor can do on the current host. This series adds two new APIs which are designed to work with capabilities of a specific hypervisor to provide usable results.
The third CPU related API virConnectGetCPUModelNames is pretty useless too, but no new API with similar functionality is needed because domain capabilities XML already contains the relevant data.
I made the suggested changes and pushed the series. Thanks for the reviews.
Jirka
Hi Jirka,
FYI I reviewed your patches too and everthing I found that was not already identified was nitpick stuff but I do have a something I am wondering about...
The new hypervisor specific compare and baseline commands seem to depend on qemuCaps being pre-populated with model data that is specific to a hypervisor instance.
How do we make sure the qemuCaps are pre-populated with cpu model data for any arbitrary hypervisor (with a different exec path, arch, etc) that we can issue the hypervisor compare or baseline commands against?
Is it a case of executing a virsh command to populate qemuCaps for a non-default hypervisor prior to issuing the hypervisor compare or baseline commands?
Sorry if a complete noob question or I missed the answer in previous mails.
Chris
The qemuCaps are generated for each qemu binary upon startup of libvirt and are stored in /var/cache/libvirt/qemu/capabilities/ If you take a look at virQEMUCapsInitQMPMonitor in file qemu_capabilities, you'll see a bunch of functions with monitor calls that will probe qemu for its capabilities. Since there can be a lot of different qemu caps that can exist on one system (due to different archs, different virttypes, etc), Jiri adds the ability to add parameters to specify which qemu capabilities file we want to pull data from.
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
-- Respectfully, - Collin Walling

Hi Chris,
The new hypervisor specific compare and baseline commands seem to depend on qemuCaps being pre-populated with model data that is specific to a hypervisor instance.
How do we make sure the qemuCaps are pre-populated with cpu model data for any arbitrary hypervisor (with a different exec path, arch, etc) that we can issue the hypervisor compare or baseline commands against?
The cache lookup functions automatically generate qemuCaps if they don't exist (i.e., someone asked for an emulator binary which is not known to libvirt yet) or if they need to be refreshed (e.g., the QEMU binary changed in the meantime). It's a bit hidden behind the generic virFileCache object which uses the following callbacks to handle QEMU caps cache: virFileCacheHandlers qemuCapsCacheHandlers = { .isValid = virQEMUCapsIsValid, .newData = virQEMUCapsNewData, .loadFile = virQEMUCapsLoadFile, .saveFile = virQEMUCapsSaveFile, .privFree = virQEMUCapsCachePrivFree, }; Jirka

Quoting Jiri Denemark (2018-05-29 09:34:02)
Hi Chris,
The new hypervisor specific compare and baseline commands seem to depend on qemuCaps being pre-populated with model data that is specific to a hypervisor instance.
How do we make sure the qemuCaps are pre-populated with cpu model data for any arbitrary hypervisor (with a different exec path, arch, etc) that we can issue the hypervisor compare or baseline commands against?
The cache lookup functions automatically generate qemuCaps if they don't exist (i.e., someone asked for an emulator binary which is not known to libvirt yet) or if they need to be refreshed (e.g., the QEMU binary changed in the meantime). It's a bit hidden behind the generic virFileCache object which uses the following callbacks to handle QEMU caps cache:
virFileCacheHandlers qemuCapsCacheHandlers = { .isValid = virQEMUCapsIsValid, .newData = virQEMUCapsNewData, .loadFile = virQEMUCapsLoadFile, .saveFile = virQEMUCapsSaveFile, .privFree = virQEMUCapsCachePrivFree, };
Jirka
Got it. Read through cache of sorts. Thanks Jirka and Collin. Chris.
participants (5)
-
Chris Venteicher
-
Collin Walling
-
Jiri Denemark
-
Ján Tomko
-
Kashyap Chamarthy