Fixed since v1: - avoid setup/restore security contexts - some hotplug code improvements, although the lack of dynamic chardev limits the utility of this code for now --- docs/formatdomain.html.in | 15 ++++- docs/schemas/domain.rng | 66 ++++++++++++-------- src/conf/domain_conf.c | 63 ++++++++++++++++--- src/conf/domain_conf.h | 2 + src/qemu/qemu_cgroup.c | 3 +- src/qemu/qemu_command.c | 36 +++++++++-- src/qemu/qemu_hostdev.c | 2 + src/qemu/qemu_hotplug.c | 54 +++++++++++++++- src/qemu/qemu_hotplug.h | 3 + src/security/security_dac.c | 6 ++ src/security/security_selinux.c | 6 ++ tests/qemuxml2argvdata/qemuxml2argv-usb-redir.args | 8 +++ tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml | 33 ++++++++++ tests/qemuxml2argvtest.c | 4 + 14 files changed, 255 insertions(+), 46 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-redir.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index e35b76b..0ab08de 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -1314,6 +1314,12 @@ 0.4.4 for USB and 0.6.0 for PCI (KVM only)</span>: </p> + <p> + Device redirection through a character device is + supported <span class="since">since after 0.9.5 for USB (KVM + only)</span>: + </p> + <pre> ... <devices> @@ -1348,14 +1354,19 @@ "subsystem" and <code>type</code> is "usb" for a USB device and "pci" for a PCI device. When <code>managed</code> is "yes" for a PCI device, it is detached from the host before being passed on to - the guest.</dd> + the guest. Redirection through a character device is enable by + specifying the <code>redirection</code> character device + type.</dd> <dt><code>source</code></dt> <dd>The source element describes the device as seen from the host. The USB device can either be addressed by vendor / product id using the <code>vendor</code> and <code>product</code> elements or by the device's address on the hosts using the <code>address</code> element. PCI devices on the other hand can only be described by their - <code>address</code></dd> + <code>address</code> + In case of device redirection, the source element describes the + character device to redirect from. + </dd> <dt><code>vendor</code>, <code>product</code></dt> <dd>The <code>vendor</code> and <code>product</code> elements each have an <code>id</code> attribute that specifies the USB vendor and product id. diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index b496a32..9b790f6 100644 --- a/docs/schemas/domain.rng +++ b/docs/schemas/domain.rng @@ -1723,21 +1723,25 @@ </element> </define> + <define name="qemucdevSrcTypeChoice"> + <choice> + <value>dev</value> + <value>file</value> + <value>pipe</value> + <value>unix</value> + <value>tcp</value> + <value>udp</value> + <value>null</value> + <value>stdio</value> + <value>vc</value> + <value>pty</value> + <value>spicevmc</value> + </choice> + </define> + <define name="qemucdevSrcType"> <attribute name="type"> - <choice> - <value>dev</value> - <value>file</value> - <value>pipe</value> - <value>unix</value> - <value>tcp</value> - <value>udp</value> - <value>null</value> - <value>stdio</value> - <value>vc</value> - <value>pty</value> - <value>spicevmc</value> - </choice> + <ref name="qemucdevSrcTypeChoice"/> </attribute> </define> <define name="qemucdevSrcDef"> @@ -1998,21 +2002,29 @@ </choice> </attribute> </optional> + <optional> + <attribute name="redirection"> + <ref name="qemucdevSrcTypeChoice"/> + </attribute> + </optional> <group> - <element name="source"> - <choice> - <group> - <ref name="usbproduct"/> - <optional> - <ref name="usbaddress"/> - </optional> - </group> - <ref name="usbaddress"/> - <element name="address"> - <ref name="pciaddress"/> - </element> - </choice> - </element> + <choice> + <ref name="qemucdevSrcDef"/> + <element name="source"> + <choice> + <group> + <ref name="usbproduct"/> + <optional> + <ref name="usbaddress"/> + </optional> + </group> + <ref name="usbaddress"/> + <element name="address"> + <ref name="pciaddress"/> + </element> + </choice> + </element> + </choice> </group> <optional> <ref name="deviceBoot"/> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 80fe2a0..31330a5 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -5165,18 +5165,26 @@ error: static int virDomainHostdevSubsysUsbDefParseXML(const xmlNodePtr node, - virDomainHostdevDefPtr def) + virDomainHostdevDefPtr def, + unsigned int flags) { int ret = -1; int got_product, got_vendor; xmlNodePtr cur; + int remaining; /* Product can validly be 0, so we need some extra help to determine * if it is uninitialized*/ got_product = 0; got_vendor = 0; + if (def->redirection) { + remaining = virDomainChrSourceDefParseXML(&def->source.subsys.u.chr, node, flags); + if (remaining < 0) + goto out; + } + cur = node->children; while (cur != NULL) { if (cur->type == XML_ELEMENT_NODE) { @@ -5341,7 +5349,7 @@ virDomainHostdevDefParseXML(const xmlNodePtr node, xmlNodePtr cur; virDomainHostdevDefPtr def; - char *mode, *type = NULL, *managed = NULL; + char *mode, *type = NULL, *managed = NULL, *redirection = NULL; if (VIR_ALLOC(def) < 0) { virReportOOMError(); @@ -5379,14 +5387,30 @@ virDomainHostdevDefParseXML(const xmlNodePtr node, VIR_FREE(managed); } + redirection = virXMLPropString(node, "redirection"); + if (redirection != NULL) { + def->redirection = 1; + if ((def->source.subsys.u.chr.type = virDomainChrTypeFromString(redirection)) < 0) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown redirection character device type '%s'"), + redirection); + goto error; + } + if (def->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("only usb redirection is supported")); + goto error; + } + } + cur = node->children; while (cur != NULL) { if (cur->type == XML_ELEMENT_NODE) { if (xmlStrEqual(cur->name, BAD_CAST "source")) { if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) { - if (virDomainHostdevSubsysUsbDefParseXML(cur, def) < 0) - goto error; + if (virDomainHostdevSubsysUsbDefParseXML(cur, def, flags) < 0) + goto error; } if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) { @@ -10105,6 +10129,7 @@ virDomainHostdevDefFormat(virBufferPtr buf, { const char *mode = virDomainHostdevModeTypeToString(def->mode); const char *type; + const char *redirection = NULL; if (!mode || def->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) { virDomainReportError(VIR_ERR_INTERNAL_ERROR, @@ -10120,11 +10145,32 @@ virDomainHostdevDefFormat(virBufferPtr buf, return -1; } - virBufferAsprintf(buf, " <hostdev mode='%s' type='%s' managed='%s'>\n", + if (def->redirection) { + redirection = virDomainChrTypeToString(def->source.subsys.u.chr.type); + if (!redirection) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected redirection type %d"), + def->source.subsys.u.chr.type); + return -1; + } + } + + virBufferAsprintf(buf, " <hostdev mode='%s' type='%s' managed='%s'", mode, type, def->managed ? "yes" : "no"); - virBufferAddLit(buf, " <source>\n"); + if (redirection != NULL) { + virBufferAsprintf(buf, " redirection='%s'", redirection); + } + virBufferAddLit(buf, ">\n"); + virBufferAddLit(buf, " <source"); + if (def->redirection) { + virBufferAsprintf(buf, " mode='connect' host='%s' service='%s'/", + def->source.subsys.u.chr.data.tcp.host, + def->source.subsys.u.chr.data.tcp.service); + } + virBufferAddLit(buf, ">\n"); - if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) { + if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB && + redirection == NULL) { if (def->source.subsys.u.usb.vendor) { virBufferAsprintf(buf, " <vendor id='0x%.4x'/>\n", def->source.subsys.u.usb.vendor); @@ -10144,7 +10190,8 @@ virDomainHostdevDefFormat(virBufferPtr buf, def->source.subsys.u.pci.function); } - virBufferAddLit(buf, " </source>\n"); + if (!def->redirection) + virBufferAddLit(buf, " </source>\n"); if (def->bootIndex) virBufferAsprintf(buf, " <boot order='%d'/>\n", def->bootIndex); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 4b48efc..ff25743 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -914,6 +914,7 @@ typedef virDomainHostdevDef *virDomainHostdevDefPtr; struct _virDomainHostdevDef { int mode; /* enum virDomainHostdevMode */ unsigned int managed : 1; + unsigned int redirection : 1; union { struct { int type; /* enum virDomainHostdevBusType */ @@ -926,6 +927,7 @@ struct _virDomainHostdevDef { unsigned product; } usb; virDomainDevicePCIAddress pci; /* host address */ + virDomainChrSourceDef chr; } u; } subsys; struct { diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c index 2a10bd2..ca9c86f 100644 --- a/src/qemu/qemu_cgroup.c +++ b/src/qemu/qemu_cgroup.c @@ -284,9 +284,10 @@ int qemuSetupCgroup(struct qemud_driver *driver, if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) continue; + if (hostdev->redirection) + continue; if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) continue; - if ((usb = usbGetDevice(hostdev->source.subsys.u.usb.bus, hostdev->source.subsys.u.usb.device)) == NULL) goto cleanup; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index f50d927..aaaad87 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -590,12 +590,14 @@ qemuAssignDeviceNetAlias(virDomainDefPtr def, virDomainNetDefPtr net, int idx) int qemuAssignDeviceHostdevAlias(virDomainDefPtr def, virDomainHostdevDefPtr hostdev, int idx) { + const char *prefix = hostdev->redirection ? "usbredir" : "hostdev"; + if (idx == -1) { int i; idx = 0; for (i = 0 ; i < def->nhostdevs ; i++) { int thisidx; - if ((thisidx = qemuDomainDeviceAliasIndex(&def->hostdevs[i]->info, "hostdev")) < 0) { + if ((thisidx = qemuDomainDeviceAliasIndex(&def->hostdevs[i]->info, prefix)) < 0) { qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to determine device index for hostdev device")); return -1; @@ -605,7 +607,7 @@ qemuAssignDeviceHostdevAlias(virDomainDefPtr def, virDomainHostdevDefPtr hostdev } } - if (virAsprintf(&hostdev->info.alias, "hostdev%d", idx) < 0) { + if (virAsprintf(&hostdev->info.alias, "%s%d", prefix, idx) < 0) { virReportOOMError(); return -1; } @@ -2352,10 +2354,16 @@ qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev, return NULL; } - virBufferAsprintf(&buf, "usb-host,hostbus=%d,hostaddr=%d,id=%s", - dev->source.subsys.u.usb.bus, - dev->source.subsys.u.usb.device, - dev->info.alias); + if (dev->redirection) { + virBufferAsprintf(&buf, "usb-redir,chardev=char%s,id=%s", + dev->info.alias, + dev->info.alias); + } else { + virBufferAsprintf(&buf, "usb-host,hostbus=%d,hostaddr=%d,id=%s", + dev->source.subsys.u.usb.bus, + dev->source.subsys.u.usb.device, + dev->info.alias); + } if (qemuBuildDeviceAddressStr(&buf, &dev->info, qemuCaps) < 0) goto error; @@ -4854,6 +4862,22 @@ qemuBuildCommandLine(virConnectPtr conn, if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) { + if (hostdev->redirection) { + if (!qemuCapsGet(qemuCaps, QEMU_CAPS_USB_REDIR)) { + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("USB redirection is not supported " + "by this version of QEMU")); + goto error; + } + virCommandAddArg(cmd, "-chardev"); + if (!(devstr = qemuBuildChrChardevStr(&hostdev->source.subsys.u.chr, + hostdev->info.alias, + qemuCaps))) { + goto error; + } + virCommandAddArg(cmd, devstr); + } + if (qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { virCommandAddArg(cmd, "-device"); if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev, qemuCaps))) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 7f5ad51..357fc94 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -200,6 +200,8 @@ qemuPrepareHostUSBDevices(struct qemud_driver *driver ATTRIBUTE_UNUSED, continue; if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) continue; + if (hostdev->redirection) + continue; /* Resolve a vendor/product to bus/device */ if (hostdev->source.subsys.u.usb.vendor) { diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 60cd241..42bffa8 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -911,6 +911,49 @@ error: } +int qemuDomainAttachUsbRedirDevice(struct qemud_driver *driver, + virDomainObjPtr vm, + virDomainHostdevDefPtr hostdev) +{ + int ret; + qemuDomainObjPrivatePtr priv = vm->privateData; + char *devstr = NULL; + + if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) { + if (qemuAssignDeviceHostdevAlias(vm->def, hostdev, -1) < 0) + goto error; + if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev, priv->qemuCaps))) + goto error; + } + + if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0) { + virReportOOMError(); + goto error; + } + + qemuDomainObjEnterMonitorWithDriver(driver, vm); + if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) + ret = qemuMonitorAddDevice(priv->mon, devstr); + else + goto error; + + qemuDomainObjExitMonitorWithDriver(driver, vm); + virDomainAuditHostdev(vm, hostdev, "attach", ret == 0); + if (ret < 0) + goto error; + + vm->def->hostdevs[vm->def->nhostdevs++] = hostdev; + + VIR_FREE(devstr); + + return 0; + +error: + VIR_FREE(devstr); + return -1; + +} + int qemuDomainAttachHostUsbDevice(struct qemud_driver *driver, virDomainObjPtr vm, virDomainHostdevDefPtr hostdev) @@ -960,6 +1003,7 @@ int qemuDomainAttachHostUsbDevice(struct qemud_driver *driver, ret = qemuMonitorAddUSBDeviceExact(priv->mon, hostdev->source.subsys.u.usb.bus, hostdev->source.subsys.u.usb.device); + qemuDomainObjExitMonitorWithDriver(driver, vm); virDomainAuditHostdev(vm, hostdev, "attach", ret == 0); if (ret < 0) @@ -990,6 +1034,7 @@ int qemuDomainAttachHostDevice(struct qemud_driver *driver, /* Resolve USB product/vendor to bus/device */ if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB && + !hostdev->redirection && hostdev->source.subsys.u.usb.vendor) { usbDevice *usb = usbFindDevice(hostdev->source.subsys.u.usb.vendor, @@ -1017,9 +1062,14 @@ int qemuDomainAttachHostDevice(struct qemud_driver *driver, break; case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: - if (qemuDomainAttachHostUsbDevice(driver, vm, - hostdev) < 0) + if (hostdev->redirection) { + if (qemuDomainAttachUsbRedirDevice(driver, vm, + hostdev) < 0) + goto error; + } else if (qemuDomainAttachHostUsbDevice(driver, vm, + hostdev) < 0) goto error; + break; default: diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h index 009f1f6..85c5d31 100644 --- a/src/qemu/qemu_hotplug.h +++ b/src/qemu/qemu_hotplug.h @@ -53,6 +53,9 @@ int qemuDomainAttachHostPciDevice(struct qemud_driver *driver, int qemuDomainAttachHostUsbDevice(struct qemud_driver *driver, virDomainObjPtr vm, virDomainHostdevDefPtr hostdev); +int qemuDomainAttachUsbRedirDevice(struct qemud_driver *driver, + virDomainObjPtr vm, + virDomainHostdevDefPtr hostdev); int qemuDomainAttachHostDevice(struct qemud_driver *driver, virDomainObjPtr vm, virDomainHostdevDefPtr hostdev); diff --git a/src/security/security_dac.c b/src/security/security_dac.c index 58d57ec..3f50052 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -280,6 +280,9 @@ virSecurityDACSetSecurityHostdevLabel(virSecurityManagerPtr mgr, if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) return 0; + if (dev->redirection) + return 0; + switch (dev->source.subsys.type) { case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: { usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus, @@ -351,6 +354,9 @@ virSecurityDACRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr, if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) return 0; + if (dev->redirection) + return 0; + switch (dev->source.subsys.type) { case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: { usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus, diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 5e6145f..fd39e33 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -667,6 +667,9 @@ SELinuxSetSecurityHostdevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) return 0; + if (dev->redirection) + return 0; + switch (dev->source.subsys.type) { case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: { usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus, @@ -736,6 +739,9 @@ SELinuxRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) return 0; + if (dev->redirection) + return 0; + switch (dev->source.subsys.type) { case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: { usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus, diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.args b/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.args new file mode 100644 index 0000000..0949585 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.args @@ -0,0 +1,8 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults -chardev socket,id=charmonitor,path=/tmp/test-monitor,server,nowait -mon chardev=charmonitor,id=monitor,mode=readline -no-acpi -boot c \ +-device ich9-usb-ehci1,id=usb,bus=pci.0,multifunction=on,addr=0x4.0x7 \ +-device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pci.0,multifunction=on,addr=0x4.0x0 \ +-device ich9-usb-uhci2,masterbus=usb.0,firstport=2,bus=pci.0,multifunction=on,addr=0x4.0x1 \ +-device ich9-usb-uhci3,masterbus=usb.0,firstport=4,bus=pci.0,multifunction=on,addr=0x4.0x2 \ +-chardev socket,id=charusbredir0,host=localhost,port=4000 \ +-device usb-redir,chardev=charusbredir0,id=usbredir0 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,multifunction=on,addr=0x3.0x0 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml b/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml new file mode 100644 index 0000000..bb50b81 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml @@ -0,0 +1,33 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219136</memory> + <currentMemory>219200</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <devices> + <emulator>/usr/bin/qemu</emulator> + <controller type='usb' index='0' model='ich9-ehci1'> + <address type='pci' domain='0' bus='0' slot='4' function='7'/> + </controller> + <controller type='usb' index='0' model='ich9-uhci1'> + <master startport='0'/> + <address type='pci' domain='0' bus='0' slot='4' function='0'/> + </controller> + <controller type='usb' index='0' model='ich9-uhci2'> + <master startport='2'/> + <address type='pci' domain='0' bus='0' slot='4' function='1'/> + </controller> + <controller type='usb' index='0' model='ich9-uhci3'> + <master startport='4'/> + <address type='pci' domain='0' bus='0' slot='4' function='2'/> + </controller> + <hostdev mode='subsystem' type='usb' redirection='tcp'> + <source mode='connect' host='localhost' service='4000'/> + </hostdev> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 9a8ecca..35e6d27 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -508,6 +508,10 @@ mymain(void) QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_PIIX3_USB_UHCI, QEMU_CAPS_USB_HUB, QEMU_CAPS_ICH9_USB_EHCI1); + DO_TEST("usb-redir", false, + QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_USB_HUB, + QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_USB_REDIR); DO_TEST("smbios", false, QEMU_CAPS_SMBIOS_TYPE); -- 1.7.6 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list