[libvirt] [PATCH RFC 0/4] Expose Expose IOMMU and VFIO host capabilities

*** NOT FOR UPSTREAM MERGE *** This is pure RFC, that's why it contains just code without any documentation, RNG schemas, tests, ..., with sparse commit messages. I just want to make sure I'm on the right track this time. BTW: The ACL issue on the command is still not resolved and honestly, I've no solution. Long story short, with this API I'm introducing users with RO connection can execute arbitrary files on the host. Isn't that just nice? So, what you should see after these patches are applied? Something like this: virsh # domcapabilities /usr/bin/qemu-system-x86_64 kvm <emulatorCapabilities> <path>/usr/bin/qemu-system-x86_64</path> <domain>kvm</domain> <machine>pc-i440fx-2.1</machine> <arch>x86_64</arch> <vcpu>255</vcpu> <devices> <disk supported='yes'> <enum name='diskDevice'> <value>disk</value> <value>cdrom</value> <value>floppy</value> <value>lun</value> </enum> <enum name='bus'> <value>ide</value> <value>fdc</value> <value>scsi</value> <value>virtio</value> <value>xen</value> <value>usb</value> <value>sd</value> </enum> </disk> <hostdev supported='yes'> <enum name='mode'/> <enum name='startupPolicy'> <value>default</value> <value>mandatory</value> <value>requisite</value> <value>optional</value> </enum> <enum name='subsysType'> <value>usb</value> <value>pci</value> <value>scsi</value> </enum> <enum name='capsType'/> <enum name='pciBackend'> <value>default</value> <value>kvm</value> <value>vfio</value> </enum> </hostdev> </devices> </emulatorCapabilities> Michal Privoznik (4): Introduce domain_capabilities Introduce virConnectGetDomainCapabilities virsh: expose virConnectGetDomainCapabilities qemu: Implement virConnectGetDomainCapabilities include/libvirt/libvirt.h.in | 7 ++ src/Makefile.am | 1 + src/conf/domain_capabilities.c | 217 +++++++++++++++++++++++++++++++++++++++++ src/conf/domain_capabilities.h | 89 +++++++++++++++++ src/driver.h | 9 ++ src/libvirt.c | 52 ++++++++++ src/libvirt_private.syms | 6 ++ src/libvirt_public.syms | 1 + src/qemu/qemu_capabilities.c | 82 ++++++++++++++++ src/qemu/qemu_capabilities.h | 4 + src/qemu/qemu_driver.c | 102 +++++++++++++++++++ src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 20 +++- src/remote_protocol-structs | 11 +++ tools/virsh-host.c | 84 ++++++++++++++++ 15 files changed, 685 insertions(+), 1 deletion(-) create mode 100644 src/conf/domain_capabilities.c create mode 100644 src/conf/domain_capabilities.h -- 1.8.5.5

Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/Makefile.am | 1 + src/conf/domain_capabilities.c | 217 +++++++++++++++++++++++++++++++++++++++++ src/conf/domain_capabilities.h | 89 +++++++++++++++++ src/libvirt_private.syms | 5 + 4 files changed, 312 insertions(+) create mode 100644 src/conf/domain_capabilities.c create mode 100644 src/conf/domain_capabilities.h diff --git a/src/Makefile.am b/src/Makefile.am index 2b9ac61..e81af0c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -248,6 +248,7 @@ NETDEV_CONF_SOURCES = \ DOMAIN_CONF_SOURCES = \ conf/capabilities.c conf/capabilities.h \ conf/domain_addr.c conf/domain_addr.h \ + conf/domain_capabilities.c conf/domain_capabilities.h \ conf/domain_conf.c conf/domain_conf.h \ conf/domain_audit.c conf/domain_audit.h \ conf/domain_nwfilter.c conf/domain_nwfilter.h \ diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c new file mode 100644 index 0000000..896aba9 --- /dev/null +++ b/src/conf/domain_capabilities.c @@ -0,0 +1,217 @@ +/* + * domain_capabilities.c: domain capabilities XML processing + * + * Copyright (C) 2014 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Michal Privoznik <mprivozn@redhat.com> + */ + +#include <config.h> + +#include "domain_capabilities.h" +#include "domain_conf.h" +#include "viralloc.h" +#include "virstring.h" + +#define VIR_FROM_THIS VIR_FROM_CAPABILITIES + +static virClassPtr virDomainCapsClass; + +static void virDomainCapsDispose(void *obj); + +static int virDomainCapsOnceInit(void) +{ + if (!(virDomainCapsClass = virClassNew(virClassForObjectLockable(), + "virDomainCapsClass", + sizeof(virDomainCaps), + virDomainCapsDispose))) + return -1; + return 0; +} + + +VIR_ONCE_GLOBAL_INIT(virDomainCaps) + + +static void +virDomainCapsDispose(void *obj) +{ + virDomainCapsPtr caps = obj; + + VIR_FREE(caps->path); + VIR_FREE(caps->machine); +} + + +virDomainCapsPtr +virDomainCapsNew(const char *path, + const char *machine, + virArch arch, + virDomainVirtType virttype) +{ + virDomainCapsPtr caps = NULL; + + if (virDomainCapsInitialize() < 0) + return NULL; + + if (!(caps = virObjectLockableNew(virDomainCapsClass))) + return NULL; + + if (VIR_STRDUP(caps->path, path) < 0 || + VIR_STRDUP(caps->machine, machine) < 0) + goto error; + caps->arch = arch; + caps->virttype = virttype; + + return caps; + error: + virObjectUnref(caps); + return NULL; +} + + +#define FORMAT_PROLOGUE(item) \ + do { \ + virBufferAsprintf(buf, "<" #item " supported='%s'%s\n", \ + item->device.supported ? "yes" : "no", \ + item->device.supported ? ">" : "/>"); \ + if (!item->device.supported) \ + return; \ + virBufferAdjustIndent(buf, 2); \ + } while (0) + +#define FORMAT_EPILOGUE(item) \ + do { \ + virBufferAdjustIndent(buf, -2); \ + virBufferAddLit(buf, "</" #item ">\n"); \ + } while (0) + +static int +virDomainCapsEnumFormat(virBufferPtr buf, + virDomainCapsEnumPtr capsEnum, + const char *capsEnumName, + virDomainCapsValToStr valToStr) +{ + int ret = -1; + size_t i; + + virBufferAsprintf(buf, "<enum name='%s'", capsEnumName); + if (!capsEnum->values) { + virBufferAddLit(buf, "/>\n"); + ret = 0; + goto cleanup; + } + virBufferAddLit(buf, ">\n"); + virBufferAdjustIndent(buf, 2); + + for (i = 0; i < sizeof(capsEnum->values) * CHAR_BIT; i++) { + const char *val; + + if (!(capsEnum->values & (1 << i))) + continue; + + val = (valToStr)(i); + virBufferAsprintf(buf, "<value>%s</value>\n", val); + } + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</enum>\n"); + + ret = 0; + cleanup: + return ret; +} + +#define ENUM_PROCESS(master, capsEnum, valToStr) \ + do { \ + virDomainCapsEnumFormat(buf, &master->capsEnum, \ + #capsEnum, valToStr); \ + } while (0) + +static void +virDomainCapsDeviceDiskFormat(virBufferPtr buf, + virDomainCapsDeviceDiskPtr const disk) +{ + FORMAT_PROLOGUE(disk); + + ENUM_PROCESS(disk, diskDevice, virDomainDiskDeviceTypeToString); + ENUM_PROCESS(disk, bus, virDomainDiskBusTypeToString); + + FORMAT_EPILOGUE(disk); +} + + +static void +virDomainCapsDeviceHostdevFormat(virBufferPtr buf, + virDomainCapsDeviceHostdevPtr const hostdev) +{ + FORMAT_PROLOGUE(hostdev); + + ENUM_PROCESS(hostdev, mode, virDomainHostdevModeTypeToString); + ENUM_PROCESS(hostdev, startupPolicy, virDomainStartupPolicyTypeToString); + ENUM_PROCESS(hostdev, subsysType, virDomainHostdevSubsysTypeToString); + ENUM_PROCESS(hostdev, capsType, virDomainHostdevCapsTypeToString); + ENUM_PROCESS(hostdev, pciBackend, virDomainHostdevSubsysPCIBackendTypeToString); + + FORMAT_EPILOGUE(hostdev); +} + + +static int +virDomainCapsFormatInternal(virBufferPtr buf, + virDomainCapsPtr const caps) +{ + const char *virttype_str = virDomainVirtTypeToString(caps->virttype); + const char *arch_str = virArchToString(caps->arch); + + virBufferAddLit(buf, "<emulatorCapabilities>\n"); + virBufferAdjustIndent(buf, 2); + + virBufferAsprintf(buf, "<path>%s</path>\n", caps->path); + virBufferAsprintf(buf, "<domain>%s</domain>\n", virttype_str); + virBufferAsprintf(buf, "<machine>%s</machine>\n", caps->machine); + virBufferAsprintf(buf, "<arch>%s</arch>\n", arch_str); + + if (caps->maxvcpus) + virBufferAsprintf(buf, "<vcpu>%d</vcpu>\n", caps->maxvcpus); + + virBufferAddLit(buf, "<devices>\n"); + virBufferAdjustIndent(buf, 2); + + virDomainCapsDeviceDiskFormat(buf, &caps->disk); + virDomainCapsDeviceHostdevFormat(buf, &caps->hostdev); + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</devices>\n"); + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</emulatorCapabilities>\n"); + return 0; +} + + +char * +virDomainCapsFormat(virDomainCapsPtr const caps) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (virDomainCapsFormatInternal(&buf, caps) < 0) { + virBufferFreeAndReset(&buf); + return NULL; + } + + return virBufferContentAndReset(&buf); +} diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h new file mode 100644 index 0000000..b42d11f --- /dev/null +++ b/src/conf/domain_capabilities.h @@ -0,0 +1,89 @@ +/* + * domain_capabilities.h: domain capabilities XML processing + * + * Copyright (C) 2014 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Michal Privoznik <mprivozn@redhat.com> + */ + +#ifndef __DOMAIN_CAPABILITIES_H__ +# define __DOMAIN_CAPABILITIES_H__ + +# include "internal.h" +# include "domain_conf.h" + +typedef const char * (*virDomainCapsValToStr)(int value); + +typedef struct _virDomainCaps virDomainCaps; +typedef virDomainCaps *virDomainCapsPtr; + +typedef struct _virDomainCapsEnum virDomainCapsEnum; +typedef virDomainCapsEnum *virDomainCapsEnumPtr; +struct _virDomainCapsEnum { + unsigned int values; /* Bitmask of values supported in the corresponding enum */ +}; + +typedef struct _virDomainCapsDevice virDomainCapsDevice; +typedef virDomainCapsDevice *virDomainCapsDevicePtr; +struct _virDomainCapsDevice { + bool supported; /* true if <devtype> is supported by hypervisor */ +}; + +typedef struct _virDomainCapsDeviceDisk virDomainCapsDeviceDisk; +typedef virDomainCapsDeviceDisk *virDomainCapsDeviceDiskPtr; +struct _virDomainCapsDeviceDisk { + virDomainCapsDevice device; + virDomainCapsEnum diskDevice; /* Info about virDomainDiskDevice enum values */ + virDomainCapsEnum bus; /* Info about virDomainDiskBus enum values */ + /* add new fields here */ +}; + +typedef struct _virDomainCapsDeviceHostdev virDomainCapsDeviceHostdev; +typedef virDomainCapsDeviceHostdev *virDomainCapsDeviceHostdevPtr; +struct _virDomainCapsDeviceHostdev { + virDomainCapsDevice device; + virDomainCapsEnum mode; /* Info about virDomainHostdevMode */ + virDomainCapsEnum startupPolicy; /* Info about virDomainStartupPolicy */ + virDomainCapsEnum subsysType; /* Info about virDomainHostdevSubsysType */ + virDomainCapsEnum capsType; /* Info about virDomainHostdevCapsType */ + virDomainCapsEnum pciBackend; /* Info about virDomainHostdevSubsysPCIBackendType */ + /* add new fields here */ +}; + +struct _virDomainCaps { + virObjectLockable parent; + + char *path; /* path to emulator binary */ + virDomainVirtType virttype; /* virtualization type */ + char *machine; /* machine type */ + virArch arch; /* domain architecture */ + + /* Some machine specific info */ + int maxvcpus; + + virDomainCapsDeviceDisk disk; + virDomainCapsDeviceHostdev hostdev; + /* add new domain devices here */ +}; + +virDomainCapsPtr virDomainCapsNew(const char *path, + const char *machine, + virArch arch, + virDomainVirtType virttype); + +char * virDomainCapsFormat(virDomainCapsPtr const caps); +#endif /* __DOMAIN_CAPABILITIES_H__ */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 1e1dd84..6c583b0 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -130,6 +130,11 @@ virDomainAuditStop; virDomainAuditVcpu; +# conf/domain_capabilities.h +virDomainCapsFormat; +virDomainCapsNew; + + # conf/domain_conf.h virBlkioDeviceArrayClear; virDiskNameToBusDeviceIndex; -- 1.8.5.5

On Thu, Jun 26, 2014 at 12:18:25PM +0200, Michal Privoznik wrote:
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/Makefile.am | 1 + src/conf/domain_capabilities.c | 217 +++++++++++++++++++++++++++++++++++++++++ src/conf/domain_capabilities.h | 89 +++++++++++++++++ src/libvirt_private.syms | 5 + 4 files changed, 312 insertions(+) create mode 100644 src/conf/domain_capabilities.c create mode 100644 src/conf/domain_capabilities.h +static int +virDomainCapsFormatInternal(virBufferPtr buf, + virDomainCapsPtr const caps) +{ + const char *virttype_str = virDomainVirtTypeToString(caps->virttype); + const char *arch_str = virArchToString(caps->arch); + + virBufferAddLit(buf, "<emulatorCapabilities>\n");
s/emulator/domain/
+ virBufferAdjustIndent(buf, 2); + + virBufferAsprintf(buf, "<path>%s</path>\n", caps->path); + virBufferAsprintf(buf, "<domain>%s</domain>\n", virttype_str); + virBufferAsprintf(buf, "<machine>%s</machine>\n", caps->machine); + virBufferAsprintf(buf, "<arch>%s</arch>\n", arch_str); + + if (caps->maxvcpus) + virBufferAsprintf(buf, "<vcpu>%d</vcpu>\n", caps->maxvcpus);
I might suggest using max='%d' so if we need to expose more info about vcpus in future we can still have child elements
+ + virBufferAddLit(buf, "<devices>\n"); + virBufferAdjustIndent(buf, 2); + + virDomainCapsDeviceDiskFormat(buf, &caps->disk); + virDomainCapsDeviceHostdevFormat(buf, &caps->hostdev); + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</devices>\n"); + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</emulatorCapabilities>\n"); + return 0; +}
Basically this looks sane to me. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- include/libvirt/libvirt.h.in | 7 ++++++ src/driver.h | 9 ++++++++ src/libvirt.c | 52 ++++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 20 ++++++++++++++++- src/remote_protocol-structs | 11 ++++++++++ 7 files changed, 100 insertions(+), 1 deletion(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 594521e..de2d606 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1585,6 +1585,13 @@ int virNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info); char * virConnectGetCapabilities (virConnectPtr conn); +char * virConnectGetDomainCapabilities(virConnectPtr conn, + const char *emulatorbin, + const char *arch, + const char *machine, + const char *virttype, + unsigned int flags); + int virNodeGetCPUStats (virConnectPtr conn, int cpuNum, virNodeCPUStatsPtr params, diff --git a/src/driver.h b/src/driver.h index 6e72e92..1fbea1b 100644 --- a/src/driver.h +++ b/src/driver.h @@ -126,6 +126,14 @@ typedef int typedef char * (*virDrvConnectGetCapabilities)(virConnectPtr conn); +typedef char * +(*virDrvConnectGetDomainCapabilities)(virConnectPtr conn, + const char *emulatorbin, + const char *arch, + const char *machine, + const char *virttype, + unsigned int flags); + typedef int (*virDrvConnectListDomains)(virConnectPtr conn, int *ids, @@ -1412,6 +1420,7 @@ struct _virDriver { virDrvDomainGetTime domainGetTime; virDrvDomainSetTime domainSetTime; virDrvNodeGetFreePages nodeGetFreePages; + virDrvConnectGetDomainCapabilities connectGetDomainCapabilities; }; diff --git a/src/libvirt.c b/src/libvirt.c index 566f984..fa4b9de 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -21189,3 +21189,55 @@ virNetworkDHCPLeaseFree(virNetworkDHCPLeasePtr lease) VIR_FREE(lease->clientid); VIR_FREE(lease); } + +/** + * virConnectGetDomainCapabilities: + * @conn: pointer to the hypervisor connection + * @emulatorbin: path to emulator + * @arch: domain architecture + * @machine: machine type + * @virttype: virtualization type + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Prior creating a domain (for instance via virDomainCreateXML + * or virDomainDefineXML) it may be suitable to know what the + * underlying emulator and/or libvirt is capable of. For + * instance, if host, libvirt and qemu is capable of VFIO + * passthrough and so on. + * + * Returns NULL in case of error, or an XML string + * defining the capabilities. + */ +char * +virConnectGetDomainCapabilities(virConnectPtr conn, + const char *emulatorbin, + const char *arch, + const char *machine, + const char *virttype, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, emulatorbin=%s, arch=%s, " + "machine=%s, virttype=%s, flags=%x", + conn, emulatorbin, arch, machine, virttype, flags); + + virResetLastError(); + + virCheckConnectReturn(conn, NULL); + + if (conn->driver->connectGetDomainCapabilities) { + char *ret; + ret = conn->driver->connectGetDomainCapabilities(conn, emulatorbin, + arch, machine, + virttype, flags); + if (!ret) + goto error; + VIR_DEBUG("conn=%p, ret=%s", conn, ret); + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(conn); + return NULL; +} diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index f64462e..3088ee8 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -664,6 +664,7 @@ LIBVIRT_1.2.6 { virNetworkDHCPLeaseFree; virNetworkGetDHCPLeases; virNetworkGetDHCPLeasesForMAC; + virConnectGetDomainCapabilities; } LIBVIRT_1.2.5; # .... define new API here using predicted next version number .... diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 76ce4a9..549c238 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -8070,6 +8070,7 @@ static virDriver remote_driver = { .domainGetTime = remoteDomainGetTime, /* 1.2.5 */ .domainSetTime = remoteDomainSetTime, /* 1.2.5 */ .nodeGetFreePages = remoteNodeGetFreePages, /* 1.2.6 */ + .connectGetDomainCapabilities = remoteConnectGetDomainCapabilities, /* 1.2.6 */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 4b75bdb..9d141e9 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -478,6 +478,18 @@ struct remote_connect_get_capabilities_ret { remote_nonnull_string capabilities; }; +struct remote_connect_get_domain_capabilities_args { + remote_string emulatorbin; + remote_string arch; + remote_string machine; + remote_string virttype; + unsigned int flags; +}; + +struct remote_connect_get_domain_capabilities_ret { + remote_nonnull_string capabilities; +}; + struct remote_node_get_cpu_stats_args { int cpuNum; int nparams; @@ -5419,5 +5431,11 @@ enum remote_procedure { * @generate: none * @acl: network:read */ - REMOTE_PROC_NETWORK_GET_DHCP_LEASES_FOR_MAC = 342 + REMOTE_PROC_NETWORK_GET_DHCP_LEASES_FOR_MAC = 342, + + /** + * @generate: both + * @acl: connect:read + */ + REMOTE_PROC_CONNECT_GET_DOMAIN_CAPABILITIES = 343 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 222f125..d926cc6 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -148,6 +148,16 @@ struct remote_node_get_info_ret { struct remote_connect_get_capabilities_ret { remote_nonnull_string capabilities; }; +struct remote_connect_get_domain_capabilities_args { + remote_string emulatorbin; + remote_string arch; + remote_string machine; + remote_string virttype; + u_int flags; +}; +struct remote_connect_get_domain_capabilities_ret { + remote_nonnull_string capabilities; +}; struct remote_node_get_cpu_stats_args { int cpuNum; int nparams; @@ -2864,4 +2874,5 @@ enum remote_procedure { REMOTE_PROC_NODE_GET_FREE_PAGES = 340, REMOTE_PROC_NETWORK_GET_DHCP_LEASES = 341, REMOTE_PROC_NETWORK_GET_DHCP_LEASES_FOR_MAC = 342, + REMOTE_PROC_CONNECT_GET_DOMAIN_CAPABILITIES = 343, }; -- 1.8.5.5

On Thu, Jun 26, 2014 at 12:18:26PM +0200, Michal Privoznik wrote:
static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 4b75bdb..9d141e9 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x
@@ -5419,5 +5431,11 @@ enum remote_procedure { * @generate: none * @acl: network:read */ - REMOTE_PROC_NETWORK_GET_DHCP_LEASES_FOR_MAC = 342 + REMOTE_PROC_NETWORK_GET_DHCP_LEASES_FOR_MAC = 342, + + /** + * @generate: both + * @acl: connect:read
As mentioned against cover letter we'll need 'connect:write' here I think. Perhaps we could allow for 'connect:read' if-and-only-if emulatorbin is NULL. ie we'd use the combination of arch + machine + virttype to lookup the binary in the primary capabilities when emulatorbin is NULL. That would avoid any risk of running arbitrary user provided paths, and so we safe to allow connect:read there. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- tools/virsh-host.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/tools/virsh-host.c b/tools/virsh-host.c index 734f1a8..2f926d6 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -69,6 +69,84 @@ cmdCapabilities(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) } /* + * "domcapabilities" command + */ +static const vshCmdInfo info_domcapabilities[] = { + {.name = "help", + .data = N_("domain capabilities") + }, + {.name = "desc", + .data = N_("Returns capabilities of emulator with respect to host and libvirt.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_domcapabilities[] = { + {.name = "emulatorbin", + .type = VSH_OT_STRING, + .help = N_("path to emulator binary"), + }, + {.name = "virttype", + .type = VSH_OT_STRING, + .help = N_("virtualization type (/domain/@type)"), + }, + {.name = "machine", + .type = VSH_OT_STRING, + .help = N_("machine type (/domain/os/type/@machine)"), + }, + {.name = "arch", + .type = VSH_OT_STRING, + .help = N_("domain architecture (/domain/os/type/@arch)"), + }, + {.name = NULL} +}; + +static bool +cmdDomCapabilities(vshControl *ctl, const vshCmd *cmd) +{ + bool ret = false; + char *caps; + const char *emulatorbin = NULL; + const char *machine = NULL; + const char *virttype = NULL; + const char *arch = NULL; + const unsigned int flags = 0; /* No flags so far */ + + if (vshCommandOptString(cmd, "emulatorbin", &emulatorbin) < 0) { + vshError(ctl, "%s", _("ble")); + goto cleanup; + } + + if (vshCommandOptString(cmd, "virttype", &virttype) < 0) { + vshError(ctl, "%s", _("ble")); + goto cleanup; + } + + if (vshCommandOptString(cmd, "machine", &machine) < 0) { + vshError(ctl, "%s", _("ble")); + goto cleanup; + } + + if (vshCommandOptString(cmd, "arch", &arch) < 0) { + vshError(ctl, "%s", _("ble")); + goto cleanup; + } + + caps = virConnectGetDomainCapabilities(ctl->conn, emulatorbin, + arch, machine, virttype, flags); + if (!caps) { + vshError(ctl, "%s", _("failed to get emulator capabilities")); + goto cleanup; + } + + vshPrint(ctl, "%s\n", caps); + ret = true; + cleanup: + VIR_FREE(caps); + return ret; +} + +/* * "freecell" command */ static const vshCmdInfo info_freecell[] = { @@ -1131,6 +1209,12 @@ const vshCmdDef hostAndHypervisorCmds[] = { .info = info_cpu_models, .flags = 0 }, + {.name = "domcapabilities", + .handler = cmdDomCapabilities, + .opts = opts_domcapabilities, + .info = info_domcapabilities, + .flags = 0 + }, {.name = "freecell", .handler = cmdFreecell, .opts = opts_freecell, -- 1.8.5.5

Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/libvirt_private.syms | 1 + src/qemu/qemu_capabilities.c | 82 ++++++++++++++++++++++++++++++++++ src/qemu/qemu_capabilities.h | 4 ++ src/qemu/qemu_driver.c | 102 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 189 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 6c583b0..4bf57a4 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -437,6 +437,7 @@ virDomainVideoTypeFromString; virDomainVideoTypeToString; virDomainVirtioEventIdxTypeFromString; virDomainVirtioEventIdxTypeToString; +virDomainVirtTypeFromString; virDomainVirtTypeToString; virDomainWatchdogActionTypeFromString; virDomainWatchdogActionTypeToString; diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 8e0a550..0a1f6fc 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -39,6 +39,7 @@ #include "virnodesuspend.h" #include "qemu_monitor.h" #include "virstring.h" +#include "qemu_hostdev.h" #include <fcntl.h> #include <sys/stat.h> @@ -3509,3 +3510,84 @@ virQEMUCapsSupportsChardev(virDomainDefPtr def, (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE && chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO)); } + + +static void +virQEMUCapsFillDomainDeviceDiskCaps(virQEMUCapsPtr qemuCaps, + virDomainCapsDeviceDiskPtr disk) +{ + disk->device.supported = true; + /* QEMU supports all of these */ + disk->diskDevice.values = (1 << VIR_DOMAIN_DISK_DEVICE_DISK) | + (1 << VIR_DOMAIN_DISK_DEVICE_CDROM) | + (1 << VIR_DOMAIN_DISK_DEVICE_FLOPPY) | + (1 << VIR_DOMAIN_DISK_DEVICE_LUN); + + disk->bus.values = (1 << VIR_DOMAIN_DISK_BUS_IDE) | + (1 << VIR_DOMAIN_DISK_BUS_FDC) | + (1 << VIR_DOMAIN_DISK_BUS_SCSI) | + (1 << VIR_DOMAIN_DISK_BUS_VIRTIO) | + (1 << VIR_DOMAIN_DISK_BUS_XEN) | + (1 << VIR_DOMAIN_DISK_BUS_SD); + + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_USB_STORAGE)) + disk->bus.values |= (1 << VIR_DOMAIN_DISK_BUS_USB); +} + + +static void +virQEMUCapsFillDomainDeviceHostdevCaps(virQEMUCapsPtr qemuCaps, + virDomainCapsDeviceHostdevPtr hostdev) +{ + bool supportsPassthroughKVM = qemuHostdevHostSupportsPassthroughLegacy(); + bool supportsPassthroughVFIO = qemuHostdevHostSupportsPassthroughVFIO(); + + hostdev->device.supported = true; + /* VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES is for containers only */ + hostdev->subsysType.values = (1 << VIR_DOMAIN_HOSTDEV_MODE_SUBSYS); + + hostdev->startupPolicy.values = (1 << VIR_DOMAIN_STARTUP_POLICY_DEFAULT) | + (1 << VIR_DOMAIN_STARTUP_POLICY_MANDATORY) | + (1 << VIR_DOMAIN_STARTUP_POLICY_REQUISITE) | + (1 << VIR_DOMAIN_STARTUP_POLICY_OPTIONAL); + + hostdev->subsysType.values = (1 << VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) | + (1 << VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI); + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE) && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE) && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_SCSI_GENERIC)) + hostdev->subsysType.values |= 1 << VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI; + + /* No virDomainHostdevCapsType for QEMU */ + hostdev->capsType.values = 0; + + hostdev->pciBackend.values = 0; + if (supportsPassthroughVFIO && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VFIO_PCI)) { + hostdev->pciBackend.values |= (1 << VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT) | + (1 << VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO); + + } + + if (supportsPassthroughKVM && + (virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCIDEVICE) || + virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE))) { + hostdev->pciBackend.values |= (1 << VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT) | + (1 << VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM); + } +} + + +void +virQEMUCapsFillDomainCaps(virQEMUCapsPtr qemuCaps, + virDomainCapsPtr domCaps) +{ + virDomainCapsDeviceDiskPtr disk = &domCaps->disk; + virDomainCapsDeviceHostdevPtr hostdev = &domCaps->hostdev; + int maxvcpus = virQEMUCapsGetMachineMaxCpus(qemuCaps, domCaps->machine); + + domCaps->maxvcpus = maxvcpus; + + virQEMUCapsFillDomainDeviceDiskCaps(qemuCaps, disk); + virQEMUCapsFillDomainDeviceHostdevCaps(qemuCaps, hostdev); +} diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 53ebe90..bb59172 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -28,6 +28,7 @@ # include "capabilities.h" # include "vircommand.h" # include "qemu_monitor.h" +# include "domain_capabilities.h" /* Internal flags to keep track of qemu command line capabilities */ typedef enum { @@ -307,4 +308,7 @@ int virQEMUCapsInitGuestFromBinary(virCapsPtr caps, virQEMUCapsPtr kvmbinCaps, virArch guestarch); +void virQEMUCapsFillDomainCaps(virQEMUCapsPtr qemuCaps, + virDomainCapsPtr domCaps); + #endif /* __QEMU_CAPABILITIES_H__*/ diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index d34da6f..96a9f13 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -95,6 +95,7 @@ #include "viraccessapicheckqemu.h" #include "storage/storage_driver.h" #include "virhostdev.h" +#include "domain_capabilities.h" #define VIR_FROM_THIS VIR_FROM_QEMU @@ -16902,6 +16903,106 @@ qemuNodeGetFreePages(virConnectPtr conn, } +static char * +qemuConnectGetDomainCapabilities(virConnectPtr conn, + const char *emulatorbin, + const char *arch_str, + const char *machine, + const char *virttype_str, + unsigned int flags) +{ + char *ret = NULL; + virQEMUDriverPtr driver = conn->privateData; + virQEMUCapsPtr qemuCaps = NULL; + int virttype; /* virDomainVirtType */ + size_t ncanonicalMachine, i; + const char **canonicalMachine; + virDomainCapsPtr domCaps = NULL; + int arch; /* virArch */ + + virCheckFlags(0, ret); + virCheckNonNullArgReturn(emulatorbin, ret); + virCheckNonNullArgReturn(virttype_str, ret); + + if (virConnectGetDomainCapabilitiesEnsureACL(conn) < 0) + return ret; + + if ((virttype = virDomainVirtTypeFromString(virttype_str)) < 0) { + virReportError(VIR_ERR_INVALID_ARG, + _("unknown virttype: %s"), virttype_str); + goto cleanup; + } + + if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, + emulatorbin))) + goto cleanup; + + if (machine) { + const char *machine_tmp; + + if (!(machine_tmp = virQEMUCapsGetCanonicalMachine(qemuCaps, + machine))) { + /* This should never ever happen (TM) */ + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("an error that should never " + "ever happen just occurred")); + goto cleanup; + } + machine = machine_tmp; + } + + /* The virQEMUCapsGetMachineTypes expects char *** but we want to stress + * the fact that we are not going to change machine types array, so we are + * using const char *** */ + if (!(ncanonicalMachine = virQEMUCapsGetMachineTypes(qemuCaps, + (char ***) &canonicalMachine))) { + virReportError(VIR_ERR_INVALID_ARG, + _(" emulator doesn't support any machines: %s"), + emulatorbin); + goto cleanup; + } + + if (machine) { + for (i = 0; i < ncanonicalMachine; i++) { + if (STREQ(machine, canonicalMachine[i])) + break; + } + + if (i == ncanonicalMachine) { + virReportError(VIR_ERR_INVALID_ARG, + _("the machine '%s' is not supported by emulator '%s'"), + machine, emulatorbin); + goto cleanup; + } + } else { + /* The default machine type is at the first position */ + machine = canonicalMachine[0]; + } + + if (arch_str) { + if ((arch = virArchFromString(arch_str)) == VIR_ARCH_NONE) { + virReportError(VIR_ERR_INVALID_ARG, + _("unknown architecture: %s"), + arch_str); + goto cleanup; + } + } else { + arch = virQEMUCapsGetArch(qemuCaps); + } + + if (!(domCaps = virDomainCapsNew(emulatorbin, machine, arch, virttype))) + goto cleanup; + + virQEMUCapsFillDomainCaps(qemuCaps, domCaps); + + ret = virDomainCapsFormat(domCaps); + cleanup: + virObjectUnref(domCaps); + virObjectUnref(qemuCaps); + return ret; +} + + static virDriver qemuDriver = { .no = VIR_DRV_QEMU, .name = QEMU_DRIVER_NAME, @@ -17097,6 +17198,7 @@ static virDriver qemuDriver = { .domainGetTime = qemuDomainGetTime, /* 1.2.5 */ .domainSetTime = qemuDomainSetTime, /* 1.2.5 */ .nodeGetFreePages = qemuNodeGetFreePages, /* 1.2.6 */ + .connectGetDomainCapabilities = qemuConnectGetDomainCapabilities, /* 1.2.6 */ }; -- 1.8.5.5

On Thu, Jun 26, 2014 at 12:18:28PM +0200, Michal Privoznik wrote:
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/libvirt_private.syms | 1 + src/qemu/qemu_capabilities.c | 82 ++++++++++++++++++++++++++++++++++ src/qemu/qemu_capabilities.h | 4 ++ src/qemu/qemu_driver.c | 102 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 189 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 6c583b0..4bf57a4 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -437,6 +437,7 @@ virDomainVideoTypeFromString; virDomainVideoTypeToString; virDomainVirtioEventIdxTypeFromString; virDomainVirtioEventIdxTypeToString; +virDomainVirtTypeFromString; virDomainVirtTypeToString; virDomainWatchdogActionTypeFromString; virDomainWatchdogActionTypeToString; diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 8e0a550..0a1f6fc 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -39,6 +39,7 @@ #include "virnodesuspend.h" #include "qemu_monitor.h" #include "virstring.h" +#include "qemu_hostdev.h"
#include <fcntl.h> #include <sys/stat.h> @@ -3509,3 +3510,84 @@ virQEMUCapsSupportsChardev(virDomainDefPtr def, (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE && chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO)); } + + +static void +virQEMUCapsFillDomainDeviceDiskCaps(virQEMUCapsPtr qemuCaps, + virDomainCapsDeviceDiskPtr disk) +{ + disk->device.supported = true; + /* QEMU supports all of these */ + disk->diskDevice.values = (1 << VIR_DOMAIN_DISK_DEVICE_DISK) | + (1 << VIR_DOMAIN_DISK_DEVICE_CDROM) | + (1 << VIR_DOMAIN_DISK_DEVICE_FLOPPY) | + (1 << VIR_DOMAIN_DISK_DEVICE_LUN);
IIRC, LUN required a specific version of QEMU, but can't remember which.
+ + disk->bus.values = (1 << VIR_DOMAIN_DISK_BUS_IDE) | + (1 << VIR_DOMAIN_DISK_BUS_FDC) | + (1 << VIR_DOMAIN_DISK_BUS_SCSI) | + (1 << VIR_DOMAIN_DISK_BUS_VIRTIO) | + (1 << VIR_DOMAIN_DISK_BUS_XEN) | + (1 << VIR_DOMAIN_DISK_BUS_SD);
I think 'SD' requires a particular QEMU version. Also, don't think we support 'XEN' any more actually - that was probably left over from the Xenner support we ripped out a while ago.
+ + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_USB_STORAGE)) + disk->bus.values |= (1 << VIR_DOMAIN_DISK_BUS_USB); +} + + +static void +virQEMUCapsFillDomainDeviceHostdevCaps(virQEMUCapsPtr qemuCaps, + virDomainCapsDeviceHostdevPtr hostdev) +{ + bool supportsPassthroughKVM = qemuHostdevHostSupportsPassthroughLegacy(); + bool supportsPassthroughVFIO = qemuHostdevHostSupportsPassthroughVFIO(); + + hostdev->device.supported = true; + /* VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES is for containers only */ + hostdev->subsysType.values = (1 << VIR_DOMAIN_HOSTDEV_MODE_SUBSYS); + + hostdev->startupPolicy.values = (1 << VIR_DOMAIN_STARTUP_POLICY_DEFAULT) | + (1 << VIR_DOMAIN_STARTUP_POLICY_MANDATORY) | + (1 << VIR_DOMAIN_STARTUP_POLICY_REQUISITE) | + (1 << VIR_DOMAIN_STARTUP_POLICY_OPTIONAL); + + hostdev->subsysType.values = (1 << VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) | + (1 << VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI); + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE) && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE) && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_SCSI_GENERIC)) + hostdev->subsysType.values |= 1 << VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI; + + /* No virDomainHostdevCapsType for QEMU */ + hostdev->capsType.values = 0; + + hostdev->pciBackend.values = 0; + if (supportsPassthroughVFIO && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VFIO_PCI)) { + hostdev->pciBackend.values |= (1 << VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT) | + (1 << VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO); + + } + + if (supportsPassthroughKVM && + (virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCIDEVICE) || + virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE))) { + hostdev->pciBackend.values |= (1 << VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT) | + (1 << VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM); + } +}
+static char * +qemuConnectGetDomainCapabilities(virConnectPtr conn, + const char *emulatorbin, + const char *arch_str, + const char *machine, + const char *virttype_str, + unsigned int flags) +{ + char *ret = NULL; + virQEMUDriverPtr driver = conn->privateData; + virQEMUCapsPtr qemuCaps = NULL; + int virttype; /* virDomainVirtType */ + size_t ncanonicalMachine, i; + const char **canonicalMachine; + virDomainCapsPtr domCaps = NULL; + int arch; /* virArch */ + + virCheckFlags(0, ret); + virCheckNonNullArgReturn(emulatorbin, ret); + virCheckNonNullArgReturn(virttype_str, ret);
I think virttype is the only thing we must have as mandatory. At least one of emulator or arch must be given. eg given one we can lookup the other. Machine we can pick the default if NULL so that's fine.
+ + if (virConnectGetDomainCapabilitiesEnsureACL(conn) < 0) + return ret; + + if ((virttype = virDomainVirtTypeFromString(virttype_str)) < 0) { + virReportError(VIR_ERR_INVALID_ARG, + _("unknown virttype: %s"), virttype_str); + goto cleanup; + } + + if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, + emulatorbin))) + goto cleanup; + + if (machine) { + const char *machine_tmp; + + if (!(machine_tmp = virQEMUCapsGetCanonicalMachine(qemuCaps, + machine))) { + /* This should never ever happen (TM) */ + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("an error that should never " + "ever happen just occurred")); + goto cleanup; + } + machine = machine_tmp; + } + + /* The virQEMUCapsGetMachineTypes expects char *** but we want to stress + * the fact that we are not going to change machine types array, so we are + * using const char *** */ + if (!(ncanonicalMachine = virQEMUCapsGetMachineTypes(qemuCaps, + (char ***) &canonicalMachine))) { + virReportError(VIR_ERR_INVALID_ARG, + _(" emulator doesn't support any machines: %s"), + emulatorbin); + goto cleanup; + } + + if (machine) { + for (i = 0; i < ncanonicalMachine; i++) { + if (STREQ(machine, canonicalMachine[i])) + break; + } + + if (i == ncanonicalMachine) { + virReportError(VIR_ERR_INVALID_ARG, + _("the machine '%s' is not supported by emulator '%s'"), + machine, emulatorbin); + goto cleanup; + } + } else { + /* The default machine type is at the first position */ + machine = canonicalMachine[0]; + }
Probably worth defining a 'virQEMUCapsIsMachineSupported" method and a virQEMUCapsGetDefaultMachine method Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Thu, Jun 26, 2014 at 12:18:24PM +0200, Michal Privoznik wrote:
*** NOT FOR UPSTREAM MERGE ***
This is pure RFC, that's why it contains just code without any documentation, RNG schemas, tests, ..., with sparse commit messages. I just want to make sure I'm on the right track this time.
BTW: The ACL issue on the command is still not resolved and honestly, I've no solution. Long story short, with this API I'm introducing users with RO connection can execute arbitrary files on the host. Isn't that just nice?
Yes, that's the same scenario as the XMLToNative / NativeToXML APIs. In that case we set connect:write as the permission and I think that's probably reasonable here too. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Thu, Jun 26, 2014 at 12:18:24PM +0200, Michal Privoznik wrote: [...]
<enum name='bus'> <value>ide</value> <value>fdc</value> <value>scsi</value> <value>virtio</value> <value>xen</value> <value>usb</value> <value>sd</value> </enum>
Libguestfs could certainly use this ^. Also we could use the features outlined in this bug: https://bugzilla.redhat.com/show_bug.cgi?id=1107842#c0 - If this works: <bios useserial=yes> (ie. sgabios) - If this works: <cpu mode=host-passthrough> - Whether the hpet timer needs to be disabled (see also bug 1066145) - Whether guests need a <dtb/> element I wonder if we should or should not expose the version number of qemu too? Although it would tempt API users to key features based on the version of qemu, which is wrong, it's useful for debugging. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-df lists disk usage of guests without needing to install any software inside the virtual machine. Supports Linux and Windows. http://people.redhat.com/~rjones/virt-df/

On 27.06.2014 12:54, Richard W.M. Jones wrote:
On Thu, Jun 26, 2014 at 12:18:24PM +0200, Michal Privoznik wrote: [...]
<enum name='bus'> <value>ide</value> <value>fdc</value> <value>scsi</value> <value>virtio</value> <value>xen</value> <value>usb</value> <value>sd</value> </enum>
Libguestfs could certainly use this ^.
Also we could use the features outlined in this bug:
https://bugzilla.redhat.com/show_bug.cgi?id=1107842#c0
- If this works: <bios useserial=yes> (ie. sgabios)
- If this works: <cpu mode=host-passthrough>
- Whether the hpet timer needs to be disabled (see also bug 1066145)
- Whether guests need a <dtb/> element
Sure, but I'd rather focus on getting in the API (even if in its minimalistic reporting capabilities) and save your requests for a follow up patch. Michal

On Fri, Jun 27, 2014 at 01:41:50PM +0200, Michal Privoznik wrote:
Sure, but I'd rather focus on getting in the API (even if in its minimalistic reporting capabilities) and save your requests for a follow up patch.
In that case, concentrating on the proposed API: + * virConnectGetDomainCapabilities: + * @conn: pointer to the hypervisor connection + * @emulatorbin: path to emulator + * @arch: domain architecture + * @machine: machine type + * @virttype: virtualization type + * @flags: extra flags; not used yet, so callers should always pass 0 It looks fine and is something we could use in libguestfs. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com libguestfs lets you edit virtual machines. Supports shell scripting, bindings from many languages. http://libguestfs.org
participants (3)
-
Daniel P. Berrange
-
Michal Privoznik
-
Richard W.M. Jones