The new function virConnectGetCPUModelNames allows to retrieve the list of CPU models known by the hypervisor for a specific architecture. Signed-off-by: Giuseppe Scrivano <gscrivan@xxxxxxxxxx> --- I have collected your comments on my RFC patch into this new version. I've replaced "virConnectGetCPUMapDesc" with "virConnectGetCPUModelNames". The new function signature is: int virConnectGetCPUModelNames(virConnectPtr conn, const char *arch, char **models, unsigned int flags); It returns (in MODELS) the list of CPU models formatted as an XML document, like: <models> <arch name='x86'> <model name='486'/> <model name='pentium'/> <model name='pentium2'/> <model name='pentium3'/> <model name='pentiumpro'/> <model name='coreduo'/> ... </arch> </models> The FLAGS attribute is not used for now. daemon/remote.c | 36 +++++++++++++++++++++++++++ include/libvirt/libvirt.h.in | 18 ++++++++++++++ python/generator.py | 1 + python/libvirt-override-api.xml | 7 ++++++ python/libvirt-override.c | 28 +++++++++++++++++++++ python/libvirt-override.py | 11 +++++++++ src/cpu/cpu.c | 55 +++++++++++++++++++++++++++++++++++++++++ src/cpu/cpu.h | 3 +++ src/driver.h | 7 ++++++ src/libvirt.c | 42 +++++++++++++++++++++++++++++++ src/libvirt_private.syms | 1 + src/libvirt_public.syms | 5 ++++ src/qemu/qemu_driver.c | 14 +++++++++++ src/remote/remote_driver.c | 40 ++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 22 ++++++++++++++++- src/remote_protocol-structs | 8 ++++++ src/test/test_driver.c | 17 +++++++++++++ tools/virsh-host.c | 45 +++++++++++++++++++++++++++++++++ tools/virsh.pod | 5 ++++ 19 files changed, 364 insertions(+), 1 deletion(-) diff --git a/daemon/remote.c b/daemon/remote.c index 03d5557..6fc2d78 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -4923,6 +4923,42 @@ cleanup: } +static int +remoteDispatchConnectGetCPUModelNames( + virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client ATTRIBUTE_UNUSED, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_connect_get_cpu_model_names_args *args, + remote_connect_get_cpu_model_names_ret *ret) +{ + virDomainPtr dom = NULL; + int rv = -1; + char *models = NULL; + struct daemonClientPrivate *priv = + virNetServerClientGetPrivateData(client); + + if (!priv->conn) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + if (virConnectGetCPUModelNames(priv->conn, args->arch, &models, + args->flags) < 0) + goto cleanup; + + ret->models = models; + rv = 0; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + if (dom) + virDomainFree(dom); + return rv; +} + + static int remoteDispatchDomainCreateXMLWithFiles( virNetServerPtr server ATTRIBUTE_UNUSED, virNetServerClientPtr client, diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index a47e33c..3819606 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -4006,6 +4006,24 @@ int virConnectCompareCPU(virConnectPtr conn, const char *xmlDesc, unsigned int flags); +/** + * virConnectGetCPUModelNames: + * + * @conn: virConnect connection + * @arch: Architecture + * @models: XML description containing the CPU models. The string is allocated + * by virConnectGetCPUModelNames and needs to be released using free() by the + * caller. + * @flags: extra flags; not used yet, so callers should always pass 0. + * + * Get the list of supported CPU models for a specific architecture. + * + * Returns -1 on error, 0 on success. + */ +int virConnectGetCPUModelNames(virConnectPtr conn, + const char *arch, + char **models, + unsigned int flags); /** * virConnectBaselineCPUFlags diff --git a/python/generator.py b/python/generator.py index 427cebc..10d4a49 100755 --- a/python/generator.py +++ b/python/generator.py @@ -250,6 +250,7 @@ lxc_functions_failed = [] qemu_functions_failed = [] functions_skipped = [ "virConnectListDomains", + "virConnectGetCPUModelNames", ] lxc_functions_skipped = [] qemu_functions_skipped = [] diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index 9a88215..1bceb05 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -476,6 +476,13 @@ <arg name='xmlCPUs' type='const char **' info='array of XML descriptions of host CPUs'/> <arg name='flags' type='unsigned int' info='fine-tuning flags, currently unused, pass 0.'/> </function> + <function name='virConnectGetCPUModelNames' file='python'> + <info>Get the list of supported CPU models.</info> + <return type='char *' info='list of supported CPU models'/> + <arg name='conn' type='virConnectPtr' info='virConnect connection'/> + <arg name='arch' type='const char *' info='arch'/> + <arg name='flags' type='unsigned int' info='fine-tuning flags, currently unused, pass 0.'/> + </function> <function name='virDomainSnapshotListNames' file='python'> <info>collect the list of snapshot names for the given domain</info> <arg name='dom' type='virDomainPtr' info='pointer to the domain'/> diff --git a/python/libvirt-override.c b/python/libvirt-override.c index d16b9a2..7537cf5 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -2276,6 +2276,34 @@ libvirt_virConnectGetVersion(PyObject *self ATTRIBUTE_UNUSED, return PyInt_FromLong(hvVersion); } +PyObject * +libvirt_virConnectGetCPUModelNames(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{ + int c_retval; + virConnectPtr conn; + PyObject *pyobj_conn; + char *models; + int flags = 0; + const char *arch = NULL; + + if (!PyArg_ParseTuple(args, (char *)"Osi:virConnectGetCPUModelNames", + &pyobj_conn, &arch, &flags)) + return NULL; + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + + LIBVIRT_BEGIN_ALLOW_THREADS; + + c_retval = virConnectGetCPUModelNames(conn, arch, &models, flags); + + LIBVIRT_END_ALLOW_THREADS; + + if (c_retval == -1) + return VIR_PY_INT_FAIL; + + return PyString_FromString(models); +} + static PyObject * libvirt_virConnectGetLibVersion(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) diff --git a/python/libvirt-override.py b/python/libvirt-override.py index ccfec48..3471a43 100644 --- a/python/libvirt-override.py +++ b/python/libvirt-override.py @@ -207,3 +207,14 @@ def virEventAddTimeout(timeout, cb, opaque): ret = libvirtmod.virEventAddTimeout(timeout, cbData) if ret == -1: raise libvirtError ('virEventAddTimeout() failed') return ret + +def getCPUModelNames(conn, arch, flags=0): + """ + get the list of supported CPU models. + @conn: virConnect connection + @arch: Architecture + @flags: extra flags; not used yet, so callers should always pass 0. + """ + ret = libvirtmod.virConnectGetCPUModelNames(conn._o, arch, flags) + if ret == None: raise libvirtError ('virConnectGetCPUModelNames() failed', conn=self) + return ret diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 023ce26..5d05951 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -27,6 +27,7 @@ #include "viralloc.h" #include "virxml.h" #include "cpu.h" +#include "cpu_map.h" #include "cpu_x86.h" #include "cpu_powerpc.h" #include "cpu_s390.h" @@ -456,3 +457,57 @@ cpuModelIsAllowed(const char *model, } return false; } + +static int +cpuGetArchModelsCb(enum cpuMapElement element, + xmlXPathContextPtr ctxt, + void *data) +{ + virBufferPtr buf = (virBufferPtr) data; + if (element == CPU_MAP_ELEMENT_MODEL) { + const char *name = virXPathString("string(@name)", ctxt); + virBufferStrcat(buf, " <model name='", name, "'/>\n", NULL); + VIR_FREE(name); + return virBufferError(buf) ? -1 : 0; + } + return 0; +} + + +static int +cpuGetArchModels(virBufferPtr buf, const char *arch) +{ + return cpuMapLoad(arch, cpuGetArchModelsCb, buf); +} + + +int +cpuGetModels(const char *arch, char **models) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + + virBufferAddLit(&buf, "<models>\n"); + if (virBufferError(&buf)) + goto no_memory; + + virBufferStrcat(&buf, " <arch name='", arch, "'>\n", NULL); + if (virBufferError(&buf)) + goto no_memory; + + if (cpuGetArchModels(&buf, arch) < 0) + goto error; + + virBufferAddLit(&buf, " </arch>\n</models>\n"); + if (virBufferError(&buf)) + goto no_memory; + + *models = virBufferContentAndReset(&buf); + return 0; + +no_memory: + virReportOOMError(); + +error: + virBufferFreeAndReset(&buf); + return -1; +} diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 7f1d4bd..3e123b2 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -175,4 +175,7 @@ cpuModelIsAllowed(const char *model, const char **models, unsigned int nmodels); +extern int +cpuGetModels(const char *arch, char **models); + #endif /* __VIR_CPU_H__ */ diff --git a/src/driver.h b/src/driver.h index be64333..9cf74f5 100644 --- a/src/driver.h +++ b/src/driver.h @@ -682,6 +682,12 @@ typedef char * unsigned int flags); typedef int +(*virDrvConnectGetCPUModelNames)(virConnectPtr conn, + const char *args, + char **models, + unsigned int flags); + +typedef int (*virDrvDomainGetJobInfo)(virDomainPtr domain, virDomainJobInfoPtr info); @@ -1332,6 +1338,7 @@ struct _virDriver { virDrvDomainMigratePerform3Params domainMigratePerform3Params; virDrvDomainMigrateFinish3Params domainMigrateFinish3Params; virDrvDomainMigrateConfirm3Params domainMigrateConfirm3Params; + virDrvConnectGetCPUModelNames connectGetCPUModelNames; }; diff --git a/src/libvirt.c b/src/libvirt.c index 07a3fd5..56d6d1b 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -18519,6 +18519,48 @@ error: /** + * virConnectGetCPUModelNames: + * + * @conn: virConnect connection + * @arch: Architecture + * @models: XML description containing the CPU models. The string is allocated + * by virConnectGetCPUModelNames and needs to be released using free() by the + * caller. + * @flags: extra flags; not used yet, so callers should always pass 0. + * + * Get the list of supported CPU models for a specific architecture. + * + * Returns -1 on error, 0 on success. + */ +int +virConnectGetCPUModelNames(virConnectPtr conn, const char *arch, char **models, + unsigned int flags) +{ + VIR_DEBUG("conn=%p", conn); + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + if (conn->driver->connectGetCPUModelNames) { + if (conn->driver->connectGetCPUModelNames(conn, arch, models, flags) < 0) + goto error; + + return 0; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} + + +/** * virConnectBaselineCPU: * * @conn: virConnect connection diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index c25a61f..e485bd2 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -717,6 +717,7 @@ cpuCompareXML; cpuDataFree; cpuDecode; cpuEncode; +cpuGetModels; cpuGuestData; cpuHasFeature; cpuMapOverride; diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index bbdf78a..547b3ea 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -634,4 +634,9 @@ LIBVIRT_1.1.1 { virDomainSetMemoryStatsPeriod; } LIBVIRT_1.1.0; +LIBVIRT_1.1.2 { + global: + virConnectGetCPUModelNames; +} LIBVIRT_1.1.1; + # .... define new API here using predicted next version number .... diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 2ad236e..c212b76 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -16033,6 +16033,19 @@ qemuNodeSuspendForDuration(virConnectPtr conn, return nodeSuspendForDuration(target, duration, flags); } +static int +qemuConnectGetCPUModelNames(virConnectPtr conn, + const char *arch, + char **models, + unsigned int flags) +{ + virCheckFlags(0, -1); + if (virConnectGetCPUModelNamesEnsureACL(conn) < 0) + return -1; + + return cpuGetModels(arch, models); +} + static virDriver qemuDriver = { .no = VIR_DRV_QEMU, @@ -16220,6 +16233,7 @@ static virDriver qemuDriver = { .domainMigratePerform3Params = qemuDomainMigratePerform3Params, /* 1.1.0 */ .domainMigrateFinish3Params = qemuDomainMigrateFinish3Params, /* 1.1.0 */ .domainMigrateConfirm3Params = qemuDomainMigrateConfirm3Params, /* 1.1.0 */ + .connectGetCPUModelNames = qemuConnectGetCPUModelNames, /* 1.1.2 */ }; diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 71d0034..ebbcc48 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -5485,6 +5485,45 @@ done: static int +remoteConnectGetCPUModelNames(virConnectPtr conn, + const char *arch, + char **models, + unsigned int flags) +{ + int rv = -1; + remote_connect_get_cpu_model_names_args args; + remote_connect_get_cpu_model_names_ret ret; + struct private_data *priv = conn->privateData; + + remoteDriverLock(priv); + + memset(&args, 0, sizeof(args)); + memset(&ret, 0, sizeof(ret)); + + args.arch = (char *) arch; + args.flags = flags; + + if (call(conn, priv, 0, REMOTE_PROC_CONNECT_GET_CPU_MODEL_NAMES, + (xdrproc_t) xdr_remote_connect_get_cpu_model_names_args, (char *) &args, + (xdrproc_t) xdr_remote_connect_get_cpu_model_names_ret, (char *) &ret) < 0) + goto error; + + *models = ret.models; /* Caller frees. */ + + rv = 0; + +done: + remoteDriverUnlock(priv); + return rv; + +error: + rv = -1; + VIR_FREE(ret.models); + goto done; +} + + +static int remoteDomainOpenGraphics(virDomainPtr dom, unsigned int idx, int fd, @@ -6811,6 +6850,7 @@ static virDriver remote_driver = { .domainMigratePerform3Params = remoteDomainMigratePerform3Params, /* 1.1.0 */ .domainMigrateFinish3Params = remoteDomainMigrateFinish3Params, /* 1.1.0 */ .domainMigrateConfirm3Params = remoteDomainMigrateConfirm3Params, /* 1.1.0 */ + .connectGetCPUModelNames = remoteConnectGetCPUModelNames, /* 1.1.2 */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 7cfebdf..7ef6c61 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -234,6 +234,11 @@ const REMOTE_DOMAIN_DISK_ERRORS_MAX = 256; */ const REMOTE_NODE_MEMORY_PARAMETERS_MAX = 64; +/* + * Upper limit on lists of CPU models + */ +const REMOTE_INTERFACE_CPU_MODELS_MAX = 16384; + /* UUID. VIR_UUID_BUFLEN definition comes from libvirt.h */ typedef opaque remote_uuid[VIR_UUID_BUFLEN]; @@ -2837,6 +2842,15 @@ struct remote_domain_event_device_removed_msg { remote_nonnull_string devAlias; }; +struct remote_connect_get_cpu_model_names_args { + remote_nonnull_string arch; + unsigned int flags; +}; + +struct remote_connect_get_cpu_model_names_ret { + remote_nonnull_string models; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -5000,5 +5014,11 @@ enum remote_procedure { * @generate: both * @acl: none */ - REMOTE_PROC_DOMAIN_EVENT_DEVICE_REMOVED = 311 + REMOTE_PROC_DOMAIN_EVENT_DEVICE_REMOVED = 311, + + /** + * @generate: none + * @acl: connect:read + */ + REMOTE_PROC_CONNECT_GET_CPU_MODEL_NAMES = 312 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 4e27aae..a2c3b14 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -2316,6 +2316,13 @@ struct remote_domain_event_device_removed_msg { remote_nonnull_domain dom; remote_nonnull_string devAlias; }; +struct remote_connect_get_cpu_model_names_args { + remote_nonnull_string arch; + u_int flags; +}; +struct remote_connect_get_cpu_model_names_ret { + remote_nonnull_string models; +}; enum remote_procedure { REMOTE_PROC_CONNECT_OPEN = 1, REMOTE_PROC_CONNECT_CLOSE = 2, @@ -2628,4 +2635,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_CREATE_XML_WITH_FILES = 309, REMOTE_PROC_DOMAIN_CREATE_WITH_FILES = 310, REMOTE_PROC_DOMAIN_EVENT_DEVICE_REMOVED = 311, + REMOTE_PROC_CONNECT_GET_CPU_MODEL_NAMES = 312, }; diff --git a/src/test/test_driver.c b/src/test/test_driver.c index d7b2e40..51baf18 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -5801,6 +5801,22 @@ testDomainScreenshot(virDomainPtr dom ATTRIBUTE_UNUSED, return ret; } +static int +testConnectGetCPUModelNames(virConnectPtr conn ATTRIBUTE_UNUSED, + const char *arch, + char **models, + unsigned int flags) +{ + char *ret; + virCheckFlags(0, -1); + if (virAsprintf(&ret, "<models>\n" + " <arch name='%s'/>\n" + "</models>\n", arch) < 0) + return -1; + + *models = ret; + return 0; +} static virDriver testDriver = { .no = VIR_DRV_TEST, @@ -5872,6 +5888,7 @@ static virDriver testDriver = { .connectIsAlive = testConnectIsAlive, /* 0.9.8 */ .nodeGetCPUMap = testNodeGetCPUMap, /* 1.0.0 */ .domainScreenshot = testDomainScreenshot, /* 1.0.5 */ + .connectGetCPUModelNames = testConnectGetCPUModelNames, /* 1.1.2 */ }; static virNetworkDriver testNetworkDriver = { diff --git a/tools/virsh-host.c b/tools/virsh-host.c index 880ae4b..cc210b4 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -92,6 +92,25 @@ static const vshCmdOptDef opts_freecell[] = { {.name = NULL} }; +static const vshCmdInfo info_cpu_models[] = { + {.name = "help", + .data = N_("CPU models.") + }, + {.name = "desc", + .data = N_("Get the CPU models for an arch.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_cpu_models[] = { + {.name = "arch", + .type = VSH_OT_DATA, + .flags = VSH_OFLAG_REQ, + .help = N_("architecture") + }, + {.name = NULL} +}; + static bool cmdFreecell(vshControl *ctl, const vshCmd *cmd) { @@ -626,6 +645,26 @@ cmdURI(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) return true; } +static bool +cmdCPUModelNames(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + char *models; + const char *arch = NULL; + + if (vshCommandOptStringReq(ctl, cmd, "arch", &arch) < 0) + return false; + + if (virConnectGetCPUModelNames(ctl->conn, arch, &models, 0) < 0) { + vshError(ctl, "%s", _("failed to get CPU Models Names")); + return false; + } + + vshPrint(ctl, "%s\n", models); + VIR_FREE(models); + + return true; +} + /* * "version" command */ @@ -851,6 +890,12 @@ const vshCmdDef hostAndHypervisorCmds[] = { .info = info_capabilities, .flags = 0 }, + {.name = "cpu-models", + .handler = cmdCPUModelNames, + .opts = opts_cpu_models, + .info = info_cpu_models, + .flags = 0 + }, {.name = "freecell", .handler = cmdFreecell, .opts = opts_freecell, diff --git a/tools/virsh.pod b/tools/virsh.pod index 0ae5178..72555e7 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -163,6 +163,7 @@ group as an option. For example: Host and Hypervisor (help keyword 'host'): capabilities capabilities + cpu-models show the CPU models for an architecture connect (re)connect to hypervisor freecell NUMA free memory hostname print the hypervisor hostname @@ -358,6 +359,10 @@ current domain is in. =over 4 +=item B<cpu-models> I<arch> + +Print the list of CPU models known for the specified architecture. + =item B<running> The domain is currently running on a CPU -- 1.8.3.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list