mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-21 10:52:22 +00:00
Add "redirdev" redirection device
- create a new "redirdev" element for this purpose
This commit is contained in:
parent
fdd14a9d05
commit
162efa1a7c
@ -1387,6 +1387,45 @@
|
|||||||
not used by qemu.</dd>
|
not used by qemu.</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
|
<h4><a name="elementsRedir">Redirected devices</a></h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
USB device redirection through a character device is
|
||||||
|
supported <span class="since">since after 0.9.5 (KVM
|
||||||
|
only)</span>:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
...
|
||||||
|
<devices>
|
||||||
|
<redirdev bus='usb' type='tcp'>
|
||||||
|
<source mode='connect' host='localhost' service='4000'/>
|
||||||
|
</redirdev>
|
||||||
|
</devices>
|
||||||
|
...</pre>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt><code>redirdev</code></dt>
|
||||||
|
<dd>The <code>redirdev</code> element is the main container for
|
||||||
|
describing redirected devices. <code>bus</code> must be "usb"
|
||||||
|
for a USB device.
|
||||||
|
|
||||||
|
An additional attribute <code>type</code> is required,
|
||||||
|
matching one of the
|
||||||
|
supported <a href="#elementsConsole">serial device</a> types,
|
||||||
|
to describe the host side of the
|
||||||
|
tunnel; <code>type='tcp'</code>
|
||||||
|
or <code>type='spicevmc'</code> (which uses the usbredir
|
||||||
|
channel of a <a href="#elementsGraphics">SPICE graphics
|
||||||
|
device</a>) are typical. Further sub-elements, such
|
||||||
|
as <code><source></code>, may be required according to
|
||||||
|
the given type, although a <code><target></code>
|
||||||
|
sub-element is not required (since the consumer of the
|
||||||
|
character device is the hypervisor itself, rather than a
|
||||||
|
device visible in the guest).</dd>
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
<h4><a name="elementsSmartcard">Smartcard devices</a></h4>
|
<h4><a name="elementsSmartcard">Smartcard devices</a></h4>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@ -1724,21 +1724,25 @@
|
|||||||
</element>
|
</element>
|
||||||
</define>
|
</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">
|
<define name="qemucdevSrcType">
|
||||||
<attribute name="type">
|
<attribute name="type">
|
||||||
<choice>
|
<ref name="qemucdevSrcTypeChoice"/>
|
||||||
<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>
|
|
||||||
</attribute>
|
</attribute>
|
||||||
</define>
|
</define>
|
||||||
<define name="qemucdevSrcDef">
|
<define name="qemucdevSrcDef">
|
||||||
@ -1975,6 +1979,19 @@
|
|||||||
</optional>
|
</optional>
|
||||||
</element>
|
</element>
|
||||||
</define>
|
</define>
|
||||||
|
<define name="redirdev">
|
||||||
|
<element name="redirdev">
|
||||||
|
<attribute name="bus">
|
||||||
|
<choice>
|
||||||
|
<value>usb</value>
|
||||||
|
</choice>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="type">
|
||||||
|
<ref name="qemucdevSrcTypeChoice"/>
|
||||||
|
</attribute>
|
||||||
|
<ref name="qemucdevSrcDef"/>
|
||||||
|
</element>
|
||||||
|
</define>
|
||||||
<define name="hostdev">
|
<define name="hostdev">
|
||||||
<element name="hostdev">
|
<element name="hostdev">
|
||||||
<optional>
|
<optional>
|
||||||
@ -2139,6 +2156,7 @@
|
|||||||
<ref name="channel"/>
|
<ref name="channel"/>
|
||||||
<ref name="smartcard"/>
|
<ref name="smartcard"/>
|
||||||
<ref name="hub"/>
|
<ref name="hub"/>
|
||||||
|
<ref name="redirdev"/>
|
||||||
</choice>
|
</choice>
|
||||||
</zeroOrMore>
|
</zeroOrMore>
|
||||||
<optional>
|
<optional>
|
||||||
|
@ -308,6 +308,66 @@ cleanup:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virDomainAuditRedirdev:
|
||||||
|
* @vm: domain making a change in pass-through host device
|
||||||
|
* @redirdev: device being attached or removed
|
||||||
|
* @reason: one of "start", "attach", or "detach"
|
||||||
|
* @success: true if the device passthrough operation succeeded
|
||||||
|
*
|
||||||
|
* Log an audit message about an attempted device passthrough change.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
virDomainAuditRedirdev(virDomainObjPtr vm, virDomainRedirdevDefPtr redirdev,
|
||||||
|
const char *reason, bool success)
|
||||||
|
{
|
||||||
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
||||||
|
char *vmname;
|
||||||
|
char *address;
|
||||||
|
char *device;
|
||||||
|
const char *virt;
|
||||||
|
|
||||||
|
virUUIDFormat(vm->def->uuid, uuidstr);
|
||||||
|
if (!(vmname = virAuditEncode("vm", vm->def->name))) {
|
||||||
|
VIR_WARN("OOM while encoding audit message");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(virt = virDomainVirtTypeToString(vm->def->virtType))) {
|
||||||
|
VIR_WARN("Unexpected virt type %d while encoding audit message", vm->def->virtType);
|
||||||
|
virt = "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (redirdev->bus) {
|
||||||
|
case VIR_DOMAIN_REDIRDEV_BUS_USB:
|
||||||
|
if (virAsprintf(&address, "USB redirdev") < 0) {
|
||||||
|
VIR_WARN("OOM while encoding audit message");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
VIR_WARN("Unexpected redirdev bus while encoding audit message: %d",
|
||||||
|
redirdev->bus);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(device = virAuditEncode("device", VIR_AUDIT_STR(address)))) {
|
||||||
|
VIR_WARN("OOM while encoding audit message");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
|
||||||
|
"virt=%s resrc=dev reason=%s %s uuid=%s bus=%s %s",
|
||||||
|
virt, reason, vmname, uuidstr,
|
||||||
|
virDomainRedirdevBusTypeToString(redirdev->bus),
|
||||||
|
device);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FREE(vmname);
|
||||||
|
VIR_FREE(device);
|
||||||
|
VIR_FREE(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* virDomainAuditCgroup:
|
* virDomainAuditCgroup:
|
||||||
* @vm: domain making the cgroups ACL change
|
* @vm: domain making the cgroups ACL change
|
||||||
@ -538,6 +598,11 @@ virDomainAuditStart(virDomainObjPtr vm, const char *reason, bool success)
|
|||||||
virDomainAuditHostdev(vm, hostdev, "start", true);
|
virDomainAuditHostdev(vm, hostdev, "start", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = 0 ; i < vm->def->nredirdevs ; i++) {
|
||||||
|
virDomainRedirdevDefPtr redirdev = vm->def->redirdevs[i];
|
||||||
|
virDomainAuditRedirdev(vm, redirdev, "start", true);
|
||||||
|
}
|
||||||
|
|
||||||
virDomainAuditMemory(vm, 0, vm->def->mem.cur_balloon, "start", true);
|
virDomainAuditMemory(vm, 0, vm->def->mem.cur_balloon, "start", true);
|
||||||
virDomainAuditVcpu(vm, 0, vm->def->vcpus, "start", true);
|
virDomainAuditVcpu(vm, 0, vm->def->vcpus, "start", true);
|
||||||
|
|
||||||
|
@ -101,5 +101,10 @@ void virDomainAuditVcpu(virDomainObjPtr vm,
|
|||||||
void virDomainAuditSecurityLabel(virDomainObjPtr vm,
|
void virDomainAuditSecurityLabel(virDomainObjPtr vm,
|
||||||
bool success)
|
bool success)
|
||||||
ATTRIBUTE_NONNULL(1);
|
ATTRIBUTE_NONNULL(1);
|
||||||
|
void virDomainAuditRedirdev(virDomainObjPtr vm,
|
||||||
|
virDomainRedirdevDefPtr def,
|
||||||
|
const char *reason,
|
||||||
|
bool success)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
|
||||||
|
|
||||||
#endif /* __VIR_DOMAIN_AUDIT_H__ */
|
#endif /* __VIR_DOMAIN_AUDIT_H__ */
|
||||||
|
@ -127,7 +127,8 @@ VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST,
|
|||||||
"watchdog",
|
"watchdog",
|
||||||
"controller",
|
"controller",
|
||||||
"graphics",
|
"graphics",
|
||||||
"hub")
|
"hub",
|
||||||
|
"redirdev")
|
||||||
|
|
||||||
VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST,
|
VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST,
|
||||||
"none",
|
"none",
|
||||||
@ -441,6 +442,9 @@ VIR_ENUM_IMPL(virDomainState, VIR_DOMAIN_CRASHED+1,
|
|||||||
VIR_ENUM_IMPL(virDomainHub, VIR_DOMAIN_HUB_TYPE_LAST,
|
VIR_ENUM_IMPL(virDomainHub, VIR_DOMAIN_HUB_TYPE_LAST,
|
||||||
"usb")
|
"usb")
|
||||||
|
|
||||||
|
VIR_ENUM_IMPL(virDomainRedirdevBus, VIR_DOMAIN_REDIRDEV_BUS_LAST,
|
||||||
|
"usb")
|
||||||
|
|
||||||
#define VIR_DOMAIN_NOSTATE_LAST (VIR_DOMAIN_NOSTATE_UNKNOWN + 1)
|
#define VIR_DOMAIN_NOSTATE_LAST (VIR_DOMAIN_NOSTATE_UNKNOWN + 1)
|
||||||
VIR_ENUM_IMPL(virDomainNostateReason, VIR_DOMAIN_NOSTATE_LAST,
|
VIR_ENUM_IMPL(virDomainNostateReason, VIR_DOMAIN_NOSTATE_LAST,
|
||||||
"unknown")
|
"unknown")
|
||||||
@ -1013,6 +1017,17 @@ void virDomainHubDefFree(virDomainHubDefPtr def)
|
|||||||
VIR_FREE(def);
|
VIR_FREE(def);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void virDomainRedirdevDefFree(virDomainRedirdevDefPtr def)
|
||||||
|
{
|
||||||
|
if (!def)
|
||||||
|
return;
|
||||||
|
|
||||||
|
virDomainChrSourceDefClear(&def->source.chr);
|
||||||
|
virDomainDeviceInfoClear(&def->info);
|
||||||
|
|
||||||
|
VIR_FREE(def);
|
||||||
|
}
|
||||||
|
|
||||||
void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
|
void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
|
||||||
{
|
{
|
||||||
if (!def)
|
if (!def)
|
||||||
@ -1052,6 +1067,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
|
|||||||
case VIR_DOMAIN_DEVICE_HUB:
|
case VIR_DOMAIN_DEVICE_HUB:
|
||||||
virDomainHubDefFree(def->data.hub);
|
virDomainHubDefFree(def->data.hub);
|
||||||
break;
|
break;
|
||||||
|
case VIR_DOMAIN_DEVICE_REDIRDEV:
|
||||||
|
virDomainRedirdevDefFree(def->data.redirdev);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
VIR_FREE(def);
|
VIR_FREE(def);
|
||||||
@ -5344,7 +5362,6 @@ virDomainHostdevDefParseXML(const xmlNodePtr node,
|
|||||||
virBitmapPtr bootMap,
|
virBitmapPtr bootMap,
|
||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
|
|
||||||
xmlNodePtr cur;
|
xmlNodePtr cur;
|
||||||
virDomainHostdevDefPtr def;
|
virDomainHostdevDefPtr def;
|
||||||
char *mode, *type = NULL, *managed = NULL;
|
char *mode, *type = NULL, *managed = NULL;
|
||||||
@ -5391,8 +5408,8 @@ virDomainHostdevDefParseXML(const xmlNodePtr node,
|
|||||||
if (xmlStrEqual(cur->name, BAD_CAST "source")) {
|
if (xmlStrEqual(cur->name, BAD_CAST "source")) {
|
||||||
if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
|
if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
|
||||||
def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
|
def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
|
||||||
if (virDomainHostdevSubsysUsbDefParseXML(cur, def) < 0)
|
if (virDomainHostdevSubsysUsbDefParseXML(cur, def) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
|
if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
|
||||||
def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
|
def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
|
||||||
@ -5445,6 +5462,68 @@ error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static virDomainRedirdevDefPtr
|
||||||
|
virDomainRedirdevDefParseXML(const xmlNodePtr node,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
xmlNodePtr cur;
|
||||||
|
virDomainRedirdevDefPtr def;
|
||||||
|
char *bus, *type = NULL;
|
||||||
|
|
||||||
|
if (VIR_ALLOC(def) < 0) {
|
||||||
|
virReportOOMError();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bus = virXMLPropString(node, "bus");
|
||||||
|
if (bus) {
|
||||||
|
if ((def->bus = virDomainRedirdevBusTypeFromString(bus)) < 0) {
|
||||||
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("unknown redirdev bus '%s'"), bus);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
def->bus = VIR_DOMAIN_REDIRDEV_BUS_USB;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = virXMLPropString(node, "type");
|
||||||
|
if (type) {
|
||||||
|
if ((def->source.chr.type = virDomainChrTypeFromString(type)) < 0) {
|
||||||
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("unknown redirdev character device type '%s'"), type);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"%s", _("missing type in redirdev"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = node->children;
|
||||||
|
while (cur != NULL) {
|
||||||
|
if (cur->type == XML_ELEMENT_NODE) {
|
||||||
|
if (xmlStrEqual(cur->name, BAD_CAST "source")) {
|
||||||
|
int remaining;
|
||||||
|
|
||||||
|
remaining = virDomainChrSourceDefParseXML(&def->source.chr, cur, flags);
|
||||||
|
if (remaining != 0)
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FREE(bus);
|
||||||
|
VIR_FREE(type);
|
||||||
|
return def;
|
||||||
|
|
||||||
|
error:
|
||||||
|
virDomainRedirdevDefFree(def);
|
||||||
|
def = NULL;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
static int virDomainLifecycleParseXML(xmlXPathContextPtr ctxt,
|
static int virDomainLifecycleParseXML(xmlXPathContextPtr ctxt,
|
||||||
const char *xpath,
|
const char *xpath,
|
||||||
int *val,
|
int *val,
|
||||||
@ -5650,6 +5729,10 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps,
|
|||||||
dev->type = VIR_DOMAIN_DEVICE_HUB;
|
dev->type = VIR_DOMAIN_DEVICE_HUB;
|
||||||
if (!(dev->data.hub = virDomainHubDefParseXML(node, flags)))
|
if (!(dev->data.hub = virDomainHubDefParseXML(node, flags)))
|
||||||
goto error;
|
goto error;
|
||||||
|
} else if (xmlStrEqual(node->name, BAD_CAST "redirdev")) {
|
||||||
|
dev->type = VIR_DOMAIN_DEVICE_REDIRDEV;
|
||||||
|
if (!(dev->data.redirdev = virDomainRedirdevDefParseXML(node, flags)))
|
||||||
|
goto error;
|
||||||
} else {
|
} else {
|
||||||
virDomainReportError(VIR_ERR_XML_ERROR,
|
virDomainReportError(VIR_ERR_XML_ERROR,
|
||||||
"%s", _("unknown device type"));
|
"%s", _("unknown device type"));
|
||||||
@ -7069,6 +7152,22 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
|
|||||||
}
|
}
|
||||||
VIR_FREE(nodes);
|
VIR_FREE(nodes);
|
||||||
|
|
||||||
|
/* analysis of the redirected devices */
|
||||||
|
if ((n = virXPathNodeSet("./devices/redirdev", ctxt, &nodes)) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (n && VIR_ALLOC_N(def->redirdevs, n) < 0)
|
||||||
|
goto no_memory;
|
||||||
|
for (i = 0 ; i < n ; i++) {
|
||||||
|
virDomainRedirdevDefPtr redirdev = virDomainRedirdevDefParseXML(nodes[i],
|
||||||
|
flags);
|
||||||
|
if (!redirdev)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
def->redirdevs[def->nredirdevs++] = redirdev;
|
||||||
|
}
|
||||||
|
VIR_FREE(nodes);
|
||||||
|
|
||||||
/* analysis of security label */
|
/* analysis of security label */
|
||||||
if (virSecurityLabelDefParseXML(def, ctxt, flags) == -1)
|
if (virSecurityLabelDefParseXML(def, ctxt, flags) == -1)
|
||||||
goto error;
|
goto error;
|
||||||
@ -10158,6 +10257,22 @@ virDomainHostdevDefFormat(virBufferPtr buf,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
virDomainRedirdevDefFormat(virBufferPtr buf,
|
||||||
|
virDomainRedirdevDefPtr def,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
const char *bus;
|
||||||
|
|
||||||
|
bus = virDomainRedirdevBusTypeToString(def->bus);
|
||||||
|
|
||||||
|
virBufferAsprintf(buf, " <redirdev bus='%s'", bus);
|
||||||
|
if (virDomainChrSourceDefFormat(buf, &def->source.chr, false, flags) < 0)
|
||||||
|
return -1;
|
||||||
|
virBufferAddLit(buf, " </redirdev>\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
virDomainHubDefFormat(virBufferPtr buf,
|
virDomainHubDefFormat(virBufferPtr buf,
|
||||||
@ -10592,6 +10707,10 @@ virDomainDefFormatInternal(virDomainDefPtr def,
|
|||||||
if (virDomainHostdevDefFormat(&buf, def->hostdevs[n], flags) < 0)
|
if (virDomainHostdevDefFormat(&buf, def->hostdevs[n], flags) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
|
for (n = 0 ; n < def->nredirdevs ; n++)
|
||||||
|
if (virDomainRedirdevDefFormat(&buf, def->redirdevs[n], flags) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
for (n = 0 ; n < def->nhubs ; n++)
|
for (n = 0 ; n < def->nhubs ; n++)
|
||||||
if (virDomainHubDefFormat(&buf, def->hubs[n], flags) < 0)
|
if (virDomainHubDefFormat(&buf, def->hubs[n], flags) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
@ -939,6 +939,23 @@ struct _virDomainHostdevDef {
|
|||||||
virDomainDeviceInfo info; /* Guest address */
|
virDomainDeviceInfo info; /* Guest address */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum virDomainRedirdevBus {
|
||||||
|
VIR_DOMAIN_REDIRDEV_BUS_USB,
|
||||||
|
|
||||||
|
VIR_DOMAIN_REDIRDEV_BUS_LAST
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _virDomainRedirdevDef virDomainRedirdevDef;
|
||||||
|
typedef virDomainRedirdevDef *virDomainRedirdevDefPtr;
|
||||||
|
struct _virDomainRedirdevDef {
|
||||||
|
int bus; /* enum virDomainRedirdevBus */
|
||||||
|
|
||||||
|
union {
|
||||||
|
virDomainChrSourceDef chr;
|
||||||
|
} source;
|
||||||
|
|
||||||
|
virDomainDeviceInfo info; /* Guest address */
|
||||||
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO,
|
VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO,
|
||||||
@ -979,6 +996,7 @@ enum virDomainDeviceType {
|
|||||||
VIR_DOMAIN_DEVICE_CONTROLLER,
|
VIR_DOMAIN_DEVICE_CONTROLLER,
|
||||||
VIR_DOMAIN_DEVICE_GRAPHICS,
|
VIR_DOMAIN_DEVICE_GRAPHICS,
|
||||||
VIR_DOMAIN_DEVICE_HUB,
|
VIR_DOMAIN_DEVICE_HUB,
|
||||||
|
VIR_DOMAIN_DEVICE_REDIRDEV,
|
||||||
|
|
||||||
VIR_DOMAIN_DEVICE_LAST,
|
VIR_DOMAIN_DEVICE_LAST,
|
||||||
};
|
};
|
||||||
@ -1000,6 +1018,7 @@ struct _virDomainDeviceDef {
|
|||||||
virDomainWatchdogDefPtr watchdog;
|
virDomainWatchdogDefPtr watchdog;
|
||||||
virDomainGraphicsDefPtr graphics;
|
virDomainGraphicsDefPtr graphics;
|
||||||
virDomainHubDefPtr hub;
|
virDomainHubDefPtr hub;
|
||||||
|
virDomainRedirdevDefPtr redirdev;
|
||||||
} data;
|
} data;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1312,6 +1331,9 @@ struct _virDomainDef {
|
|||||||
int nhostdevs;
|
int nhostdevs;
|
||||||
virDomainHostdevDefPtr *hostdevs;
|
virDomainHostdevDefPtr *hostdevs;
|
||||||
|
|
||||||
|
int nredirdevs;
|
||||||
|
virDomainRedirdevDefPtr *redirdevs;
|
||||||
|
|
||||||
int nsmartcards;
|
int nsmartcards;
|
||||||
virDomainSmartcardDefPtr *smartcards;
|
virDomainSmartcardDefPtr *smartcards;
|
||||||
|
|
||||||
@ -1479,6 +1501,7 @@ void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def);
|
|||||||
void virDomainVideoDefFree(virDomainVideoDefPtr def);
|
void virDomainVideoDefFree(virDomainVideoDefPtr def);
|
||||||
void virDomainHostdevDefFree(virDomainHostdevDefPtr def);
|
void virDomainHostdevDefFree(virDomainHostdevDefPtr def);
|
||||||
void virDomainHubDefFree(virDomainHubDefPtr def);
|
void virDomainHubDefFree(virDomainHubDefPtr def);
|
||||||
|
void virDomainRedirdevDefFree(virDomainRedirdevDefPtr def);
|
||||||
void virDomainDeviceDefFree(virDomainDeviceDefPtr def);
|
void virDomainDeviceDefFree(virDomainDeviceDefPtr def);
|
||||||
int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info,
|
int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info,
|
||||||
int type);
|
int type);
|
||||||
@ -1760,6 +1783,7 @@ VIR_ENUM_DECL(virDomainVideo)
|
|||||||
VIR_ENUM_DECL(virDomainHostdevMode)
|
VIR_ENUM_DECL(virDomainHostdevMode)
|
||||||
VIR_ENUM_DECL(virDomainHostdevSubsys)
|
VIR_ENUM_DECL(virDomainHostdevSubsys)
|
||||||
VIR_ENUM_DECL(virDomainHub)
|
VIR_ENUM_DECL(virDomainHub)
|
||||||
|
VIR_ENUM_DECL(virDomainRedirdevBus)
|
||||||
VIR_ENUM_DECL(virDomainInput)
|
VIR_ENUM_DECL(virDomainInput)
|
||||||
VIR_ENUM_DECL(virDomainInputBus)
|
VIR_ENUM_DECL(virDomainInputBus)
|
||||||
VIR_ENUM_DECL(virDomainGraphics)
|
VIR_ENUM_DECL(virDomainGraphics)
|
||||||
|
@ -219,6 +219,7 @@ virDomainAuditHostdev;
|
|||||||
virDomainAuditMemory;
|
virDomainAuditMemory;
|
||||||
virDomainAuditNet;
|
virDomainAuditNet;
|
||||||
virDomainAuditNetDevice;
|
virDomainAuditNetDevice;
|
||||||
|
virDomainAuditRedirdev;
|
||||||
virDomainAuditSecurityLabel;
|
virDomainAuditSecurityLabel;
|
||||||
virDomainAuditStart;
|
virDomainAuditStart;
|
||||||
virDomainAuditStop;
|
virDomainAuditStop;
|
||||||
@ -375,6 +376,8 @@ virDomainObjSetState;
|
|||||||
virDomainObjTaint;
|
virDomainObjTaint;
|
||||||
virDomainObjUnlock;
|
virDomainObjUnlock;
|
||||||
virDomainObjUnref;
|
virDomainObjUnref;
|
||||||
|
virDomainRedirdevBusTypeFromString;
|
||||||
|
virDomainRedirdevBusTypeToString;
|
||||||
virDomainRemoveInactive;
|
virDomainRemoveInactive;
|
||||||
virDomainSaveConfig;
|
virDomainSaveConfig;
|
||||||
virDomainSaveStatus;
|
virDomainSaveStatus;
|
||||||
|
@ -606,6 +606,33 @@ qemuAssignDeviceHostdevAlias(virDomainDefPtr def, virDomainHostdevDefPtr hostdev
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
qemuAssignDeviceRedirdevAlias(virDomainDefPtr def, virDomainRedirdevDefPtr redirdev, int idx)
|
||||||
|
{
|
||||||
|
if (idx == -1) {
|
||||||
|
int i;
|
||||||
|
idx = 0;
|
||||||
|
for (i = 0 ; i < def->nredirdevs ; i++) {
|
||||||
|
int thisidx;
|
||||||
|
if ((thisidx = qemuDomainDeviceAliasIndex(&def->redirdevs[i]->info, "redir")) < 0) {
|
||||||
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||||
|
_("Unable to determine device index for redirected device"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (thisidx >= idx)
|
||||||
|
idx = thisidx + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virAsprintf(&redirdev->info.alias, "redir%d", idx) < 0) {
|
||||||
|
virReportOOMError();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
qemuAssignDeviceControllerAlias(virDomainControllerDefPtr controller)
|
qemuAssignDeviceControllerAlias(virDomainControllerDefPtr controller)
|
||||||
{
|
{
|
||||||
@ -653,6 +680,10 @@ qemuAssignDeviceAliases(virDomainDefPtr def, virBitmapPtr qemuCaps)
|
|||||||
if (qemuAssignDeviceHostdevAlias(def, def->hostdevs[i], i) < 0)
|
if (qemuAssignDeviceHostdevAlias(def, def->hostdevs[i], i) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
for (i = 0; i < def->nredirdevs ; i++) {
|
||||||
|
if (qemuAssignDeviceRedirdevAlias(def, def->redirdevs[i], i) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
for (i = 0; i < def->nvideos ; i++) {
|
for (i = 0; i < def->nvideos ; i++) {
|
||||||
if (virAsprintf(&def->videos[i]->info.alias, "video%d", i) < 0)
|
if (virAsprintf(&def->videos[i]->info.alias, "video%d", i) < 0)
|
||||||
goto no_memory;
|
goto no_memory;
|
||||||
@ -2348,6 +2379,45 @@ qemuBuildPCIHostdevPCIDevStr(virDomainHostdevDefPtr dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *
|
||||||
|
qemuBuildRedirdevDevStr(virDomainRedirdevDefPtr dev,
|
||||||
|
virBitmapPtr qemuCaps)
|
||||||
|
{
|
||||||
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
||||||
|
|
||||||
|
if (dev->bus != VIR_DOMAIN_REDIRDEV_BUS_USB) {
|
||||||
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||||
|
_("Redirection bus %s is not supported by QEMU"),
|
||||||
|
virDomainRedirdevBusTypeToString(dev->bus));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
virBufferAsprintf(&buf, "usb-redir,chardev=char%s,id=%s",
|
||||||
|
dev->info.alias,
|
||||||
|
dev->info.alias);
|
||||||
|
|
||||||
|
if (qemuBuildDeviceAddressStr(&buf, &dev->info, qemuCaps) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (virBufferError(&buf)) {
|
||||||
|
virReportOOMError();
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return virBufferContentAndReset(&buf);
|
||||||
|
|
||||||
|
error:
|
||||||
|
virBufferFreeAndReset(&buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev,
|
qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev,
|
||||||
virBitmapPtr qemuCaps)
|
virBitmapPtr qemuCaps)
|
||||||
@ -4839,6 +4909,32 @@ qemuBuildCommandLine(virConnectPtr conn,
|
|||||||
virCommandAddArgList(cmd, "-watchdog-action", action, NULL);
|
virCommandAddArgList(cmd, "-watchdog-action", action, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add redirected devices */
|
||||||
|
for (i = 0 ; i < def->nredirdevs ; i++) {
|
||||||
|
virDomainRedirdevDefPtr redirdev = def->redirdevs[i];
|
||||||
|
char *devstr;
|
||||||
|
|
||||||
|
virCommandAddArg(cmd, "-chardev");
|
||||||
|
if (!(devstr = qemuBuildChrChardevStr(&redirdev->source.chr,
|
||||||
|
redirdev->info.alias,
|
||||||
|
qemuCaps))) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
virCommandAddArg(cmd, devstr);
|
||||||
|
VIR_FREE(devstr);
|
||||||
|
|
||||||
|
if (!qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
virCommandAddArg(cmd, "-device");
|
||||||
|
if (!(devstr = qemuBuildRedirdevDevStr(redirdev, qemuCaps)))
|
||||||
|
goto error;
|
||||||
|
virCommandAddArg(cmd, devstr);
|
||||||
|
VIR_FREE(devstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Add host passthrough hardware */
|
/* Add host passthrough hardware */
|
||||||
for (i = 0 ; i < def->nhostdevs ; i++) {
|
for (i = 0 ; i < def->nhostdevs ; i++) {
|
||||||
virDomainHostdevDefPtr hostdev = def->hostdevs[i];
|
virDomainHostdevDefPtr hostdev = def->hostdevs[i];
|
||||||
|
@ -120,6 +120,7 @@ char * qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev,
|
|||||||
virBitmapPtr qemuCaps);
|
virBitmapPtr qemuCaps);
|
||||||
|
|
||||||
char * qemuBuildHubDevStr(virDomainHubDefPtr dev, virBitmapPtr qemuCaps);
|
char * qemuBuildHubDevStr(virDomainHubDefPtr dev, virBitmapPtr qemuCaps);
|
||||||
|
char * qemuBuildRedirdevDevStr(virDomainRedirdevDefPtr dev, virBitmapPtr qemuCaps);
|
||||||
|
|
||||||
|
|
||||||
int qemuNetworkIfaceConnect(virDomainDefPtr def,
|
int qemuNetworkIfaceConnect(virDomainDefPtr def,
|
||||||
@ -189,8 +190,9 @@ int qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr ad
|
|||||||
int qemuDomainNetVLAN(virDomainNetDefPtr def);
|
int qemuDomainNetVLAN(virDomainNetDefPtr def);
|
||||||
int qemuAssignDeviceNetAlias(virDomainDefPtr def, virDomainNetDefPtr net, int idx);
|
int qemuAssignDeviceNetAlias(virDomainDefPtr def, virDomainNetDefPtr net, int idx);
|
||||||
int qemuAssignDeviceDiskAlias(virDomainDiskDefPtr def, virBitmapPtr qemuCaps);
|
int qemuAssignDeviceDiskAlias(virDomainDiskDefPtr def, virBitmapPtr qemuCaps);
|
||||||
int qemuAssignDeviceHostdevAlias(virDomainDefPtr def, virDomainHostdevDefPtr net, int idx);
|
int qemuAssignDeviceHostdevAlias(virDomainDefPtr def, virDomainHostdevDefPtr hostdev, int idx);
|
||||||
int qemuAssignDeviceControllerAlias(virDomainControllerDefPtr controller);
|
int qemuAssignDeviceControllerAlias(virDomainControllerDefPtr controller);
|
||||||
|
int qemuAssignDeviceRedirdevAlias(virDomainDefPtr def, virDomainRedirdevDefPtr redirdev, int idx);
|
||||||
|
|
||||||
int
|
int
|
||||||
qemuParseKeywords(const char *str,
|
qemuParseKeywords(const char *str,
|
||||||
|
@ -4978,6 +4978,13 @@ qemuDomainAttachDeviceLive(virDomainObjPtr vm,
|
|||||||
dev->data.hostdev = NULL;
|
dev->data.hostdev = NULL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case VIR_DOMAIN_DEVICE_REDIRDEV:
|
||||||
|
ret = qemuDomainAttachRedirdevDevice(driver, vm,
|
||||||
|
dev->data.redirdev);
|
||||||
|
if (!ret)
|
||||||
|
dev->data.redirdev = NULL;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||||
_("device type '%s' cannot be attached"),
|
_("device type '%s' cannot be attached"),
|
||||||
|
@ -911,6 +911,49 @@ error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int qemuDomainAttachRedirdevDevice(struct qemud_driver *driver,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
virDomainRedirdevDefPtr redirdev)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
|
char *devstr = NULL;
|
||||||
|
|
||||||
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
||||||
|
if (qemuAssignDeviceRedirdevAlias(vm->def, redirdev, -1) < 0)
|
||||||
|
goto error;
|
||||||
|
if (!(devstr = qemuBuildRedirdevDevStr(redirdev, priv->qemuCaps)))
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VIR_REALLOC_N(vm->def->redirdevs, vm->def->nredirdevs+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);
|
||||||
|
virDomainAuditRedirdev(vm, redirdev, "attach", ret == 0);
|
||||||
|
if (ret < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
vm->def->redirdevs[vm->def->nredirdevs++] = redirdev;
|
||||||
|
|
||||||
|
VIR_FREE(devstr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
VIR_FREE(devstr);
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
int qemuDomainAttachHostUsbDevice(struct qemud_driver *driver,
|
int qemuDomainAttachHostUsbDevice(struct qemud_driver *driver,
|
||||||
virDomainObjPtr vm,
|
virDomainObjPtr vm,
|
||||||
virDomainHostdevDefPtr hostdev)
|
virDomainHostdevDefPtr hostdev)
|
||||||
|
@ -53,6 +53,9 @@ int qemuDomainAttachHostPciDevice(struct qemud_driver *driver,
|
|||||||
int qemuDomainAttachHostUsbDevice(struct qemud_driver *driver,
|
int qemuDomainAttachHostUsbDevice(struct qemud_driver *driver,
|
||||||
virDomainObjPtr vm,
|
virDomainObjPtr vm,
|
||||||
virDomainHostdevDefPtr hostdev);
|
virDomainHostdevDefPtr hostdev);
|
||||||
|
int qemuDomainAttachRedirdevDevice(struct qemud_driver *driver,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
virDomainRedirdevDefPtr hostdev);
|
||||||
int qemuDomainAttachHostDevice(struct qemud_driver *driver,
|
int qemuDomainAttachHostDevice(struct qemud_driver *driver,
|
||||||
virDomainObjPtr vm,
|
virDomainObjPtr vm,
|
||||||
virDomainHostdevDefPtr hostdev);
|
virDomainHostdevDefPtr hostdev);
|
||||||
|
8
tests/qemuxml2argvdata/qemuxml2argv-usb-redir.args
Normal file
8
tests/qemuxml2argvdata/qemuxml2argv-usb-redir.args
Normal file
@ -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=charredir0,host=localhost,port=4000 \
|
||||||
|
-device usb-redir,chardev=charredir0,id=redir0 \
|
||||||
|
-device virtio-balloon-pci,id=balloon0,bus=pci.0,multifunction=on,addr=0x3.0x0
|
38
tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml
Normal file
38
tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<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>
|
||||||
|
<clock offset='utc'/>
|
||||||
|
<on_poweroff>destroy</on_poweroff>
|
||||||
|
<on_reboot>restart</on_reboot>
|
||||||
|
<on_crash>destroy</on_crash>
|
||||||
|
<devices>
|
||||||
|
<emulator>/usr/bin/qemu</emulator>
|
||||||
|
<controller type='usb' index='0' model='ich9-ehci1'>
|
||||||
|
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x7'/>
|
||||||
|
</controller>
|
||||||
|
<controller type='usb' index='0' model='ich9-uhci1'>
|
||||||
|
<master startport='0'/>
|
||||||
|
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
|
||||||
|
</controller>
|
||||||
|
<controller type='usb' index='0' model='ich9-uhci2'>
|
||||||
|
<master startport='2'/>
|
||||||
|
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x1'/>
|
||||||
|
</controller>
|
||||||
|
<controller type='usb' index='0' model='ich9-uhci3'>
|
||||||
|
<master startport='4'/>
|
||||||
|
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x2'/>
|
||||||
|
</controller>
|
||||||
|
<redirdev bus='usb' type='tcp'>
|
||||||
|
<source mode='connect' host='localhost' service='4000'/>
|
||||||
|
<protocol type='raw'/>
|
||||||
|
</redirdev>
|
||||||
|
<memballoon model='virtio'/>
|
||||||
|
</devices>
|
||||||
|
</domain>
|
@ -507,6 +507,10 @@ mymain(void)
|
|||||||
DO_TEST("usb-ports", false,
|
DO_TEST("usb-ports", false,
|
||||||
QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_USB_HUB,
|
QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_USB_HUB,
|
||||||
QEMU_CAPS_NODEFCONFIG);
|
QEMU_CAPS_NODEFCONFIG);
|
||||||
|
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);
|
DO_TEST("smbios", false, QEMU_CAPS_SMBIOS_TYPE);
|
||||||
|
|
||||||
|
@ -189,6 +189,8 @@ mymain(void)
|
|||||||
DO_TEST("lease");
|
DO_TEST("lease");
|
||||||
DO_TEST("event_idx");
|
DO_TEST("event_idx");
|
||||||
|
|
||||||
|
DO_TEST("usb-redir");
|
||||||
|
|
||||||
/* These tests generate different XML */
|
/* These tests generate different XML */
|
||||||
DO_TEST_DIFFERENT("balloon-device-auto");
|
DO_TEST_DIFFERENT("balloon-device-auto");
|
||||||
DO_TEST_DIFFERENT("channel-virtio-auto");
|
DO_TEST_DIFFERENT("channel-virtio-auto");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user