[libvirt] [PATCH 0/5] add usb redirection filter support

BZ RFE https://bugzilla.redhat.com/show_bug.cgi?id=795929 qemu support: http://git.qemu.org/?p=qemu.git;a=commitdiff;h=6af165892cf900291046f1d25f954... Since qemu has have the code to support USB redirection filter. This set of patches try to support it from libvirt. The XML format is like this: <devices> ... <redirdev bus='usb' type='spicevmc'> <address type='usb' bus='0' port='4'/> </redirdev> <redirfilter> <usbdev class='0x08' vendor='0x1234' product='0xbeef' \ version='2.00' allow='yes'/> <usbdev class='-1' vendor='-1' product='-1' version='-1' allow='no'/> </redirfilter> ... </devices> Multiple <usbdev> element as one of filter rule could be added into parent element <redirfilter>, only no more than <redirfilter> element could exists. There is no 1:1 mapping between ports and redirected devices and qemu and spicy client couldn't decide into which usbredir ports the client can 'plug' redirected devices. So it make sense to apply all of filter rules global to all existing usb redirection devices. class attribute is USB Class codes. version is bcdDevice value of USB device. vendor and product is USB vendorId and productId. -1 can be used to allow any value for a field. Except allow attribute the other four are optional, default value is -1. The above XML will be converted to the following qemu command line: If there are multiple usb-redir device, all of them have the same filter rules. -device usb-redir,chardev=charredir0,id=redir0,\ filter=0x08:0x1234:0xBEEF:0x2000:1|-1:-1:-1:-1:0,bus=usb.0,port=4 Guannan Ren(0/5) qemu: add usb-redir.filter qemu capability flag qemu: define and parse USB redirection filter XML qemu: build USB redirection filter qemu command line test: add xml2argvtest for usb-redir filter and update doc: update usb redirection filter infomation on docs/formatdomain.html.in | 38 ++- docs/schemas/domaincommon.rng | 66 ++++ src/conf/domain_conf.c | 346 ++++++++++++++++++++ src/conf/domain_conf.h | 21 ++ src/qemu/qemu_capabilities.c | 4 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 45 +++- src/qemu/qemu_command.h | 5 +- src/qemu/qemu_hotplug.c | 3 +- .../qemuxml2argv-usb-redir-filter.args | 10 + .../qemuxml2argv-usb-redir-filter.xml | 45 +++ tests/qemuxml2argvtest.c | 6 + 12 files changed, 571 insertions(+), 19 deletions(-)

Add a qemu flag for USB redirection filter support. The output: usb-redir.chardev=chr usb-redir.debug=uint8 usb-redir.filter=string usb-redir.port=string --- src/qemu/qemu_capabilities.c | 4 ++++ src/qemu/qemu_capabilities.h | 1 + 2 files changed, 5 insertions(+), 0 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 5472267..bb60329 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -172,6 +172,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST, "bridge", /* 100 */ "lsi", "virtio-scsi-pci", + "usb-redir.filter", ); @@ -1403,6 +1404,7 @@ qemuCapsExtractDeviceStr(const char *qemu, "-device", "virtio-blk-pci,?", "-device", "virtio-net-pci,?", "-device", "scsi-disk,?", + "-device", "usb-redir,?", NULL); /* qemu -help goes to stdout, but qemu -device ? goes to stderr. */ virCommandSetErrorBuffer(cmd, &output); @@ -1448,6 +1450,8 @@ qemuCapsParseDeviceStr(const char *str, virBitmapPtr flags) qemuCapsSet(flags, QEMU_CAPS_NEC_USB_XHCI); if (strstr(str, "name \"usb-redir\"")) qemuCapsSet(flags, QEMU_CAPS_USB_REDIR); + if (strstr(str, "usb-redir.filter")) + qemuCapsSet(flags, QEMU_CAPS_USB_REDIR_FILTER); if (strstr(str, "name \"usb-hub\"")) qemuCapsSet(flags, QEMU_CAPS_USB_HUB); if (strstr(str, "name \"ich9-ahci\"")) diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index d606890..0655c9c 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -138,6 +138,7 @@ enum qemuCapsFlags { QEMU_CAPS_NETDEV_BRIDGE = 100, /* bridge helper support */ QEMU_CAPS_SCSI_LSI = 101, /* -device lsi */ QEMU_CAPS_VIRTIO_SCSI_PCI = 102, /* -device virtio-scsi-pci */ + QEMU_CAPS_USB_REDIR_FILTER = 103, /* usb-redir.filter */ QEMU_CAPS_LAST, /* this must always be the last item */ }; -- 1.7.7.6

https://bugzilla.redhat.com/show_bug.cgi?id=795929 http://git.qemu.org/?p=qemu.git;a=commitdiff;h=6af165892cf900291046f1d25f954... This patch define and parse the XML of USB redirection filter. <devices> ... <redirdev bus='usb' type='spicevmc'> <address type='usb' bus='0' port='4'/> </redirdev> <redirfilter> <usbdev class='0x08' vendor='0x1234' product='0xbeef' \ version='2.00' allow='yes'/> <usbdev class='-1' vendor='-1' product='-1' version='-1' allow='no'/> </redirfilter> ... </devices> There is no 1:1 mapping between ports and redirected devices and qemu and spicy client couldn't decide into which usbredir ports the client can 'plug' redirected devices. So it make sense to apply all of filter rules global to all existing usb redirection devices. class attribute is USB Class codes. version is bcdDevice value of USB device. vendor and product is USB vendorId and productId. -1 can be used to allow any value for a field. Except allow attribute the other four are optional, default value is -1. --- src/conf/domain_conf.c | 346 ++++++++++++++++++++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 21 +++ 2 files changed, 367 insertions(+), 0 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 851284a..899bfc7 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1438,6 +1438,20 @@ void virDomainRedirdevDefFree(virDomainRedirdevDefPtr def) VIR_FREE(def); } +void virDomainRedirFilterDefFree(virDomainRedirFilterDefPtr def) +{ + int i; + + if (!def) + return; + + for (i = 0; i < def->nusbdevs; i++) + VIR_FREE(def->usbdevs[i]); + + VIR_FREE(def->usbdevs); + VIR_FREE(def); +} + void virDomainDeviceDefFree(virDomainDeviceDefPtr def) { if (!def) @@ -1636,6 +1650,8 @@ void virDomainDefFree(virDomainDefPtr def) virSysinfoDefFree(def->sysinfo); + virDomainRedirFilterDefFree(def->redirfilter); + if (def->namespaceData && def->ns.free) (def->ns.free)(def->namespaceData); @@ -7007,6 +7023,206 @@ error: goto cleanup; } +/* + * This is the helper function to convert USB version from a + * format of JJ.MN to a format of 0xJJMN where JJ is the major + * version number, M is the minor version number and N is the + * sub minor version number. + * e.g. USB 2.0 is reported as 0x0200, + * USB 1.1 as 0x0110 and USB 1.0 as 0x0100. + */ +static int +virDomainRedirFilterUsbVersionHelper(const char *version, + virDomainRedirFilterUsbDevDefPtr def) +{ + char *version_copy = NULL; + char *temp = NULL; + int ret = -1; + size_t len; + size_t fraction_len; + unsigned int major; + unsigned int minor; + unsigned int hex; + + if (!(version_copy = strdup(version))) { + virReportOOMError(); + return -1; + } + + len = strlen(version_copy); + /* + * The valid format of version is like 01.10, 1.10, 1.1, etc. + */ + if (len > 5 || + !(temp = strchr(version_copy, '.')) || + temp - version_copy < 1 || + temp - version_copy > 2 || + !(fraction_len = strlen(temp + 1)) || + fraction_len > 2) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Incorrect USB version format %s"), version); + goto cleanup; + } + + *temp = '\0'; + temp++; + + if ((virStrToLong_ui(version_copy, NULL, 0, &major)) < 0 || + (virStrToLong_ui(temp, NULL, 0, &minor)) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("Cannot parse USB version %s"), version); + goto cleanup; + } + + hex = (major / 10) << 12 | (major % 10) << 8; + if (fraction_len == 1) + hex |= (minor % 10) << 4; + else + hex |= (minor / 10) << 4 | (minor % 10) << 0; + + def->version = hex; + ret = 0; + +cleanup: + VIR_FREE(version_copy); + return ret; +} + +static virDomainRedirFilterUsbDevDefPtr +virDomainRedirFilterUsbDevDefParseXML(const xmlNodePtr node) +{ + char *class; + char *vendor = NULL, *product = NULL; + char *version = NULL, *allow = NULL; + virDomainRedirFilterUsbDevDefPtr def; + + if (VIR_ALLOC(def) < 0) { + virReportOOMError(); + return NULL; + } + + class = virXMLPropString(node, "class"); + if (class) { + if ((virStrToLong_i(class, NULL, 0, &def->usbClass)) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("Cannot parse USB Class code %s"), class); + goto error; + } + + if (def->usbClass != -1 && def->usbClass &~ 0xFF) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Invalid USB Class code %s"), class); + goto error; + } + } else { + def->usbClass = -1; + } + + vendor = virXMLPropString(node, "vendor"); + if (vendor) { + if ((virStrToLong_i(vendor, NULL, 0, &def->vendor)) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("Cannot parse USB vendor ID %s"), vendor); + goto error; + } + } else { + def->vendor = -1; + } + + product = virXMLPropString(node, "product"); + if (product) { + if ((virStrToLong_i(product, NULL, 0, &def->product)) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("Cannot parse USB product ID %s"), product); + goto error; + } + } else { + def->product = -1; + } + + version = virXMLPropString(node, "version"); + if (version) { + if (STREQ(version, "-1")) + def->version = -1; + else if ((virDomainRedirFilterUsbVersionHelper(version, def)) < 0) + goto error; + } else { + def->version = -1; + } + + allow = virXMLPropString(node, "allow"); + if (allow) { + if (STREQ(allow, "yes")) + def->allow = 1; + else if (STREQ(allow, "no")) + def->allow = 0; + else { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Invalid allow value, either 'yes' or 'no'")); + goto error; + } + } else { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("Missing allow attribute for USB redirection filter")); + goto error; + } + +cleanup: + VIR_FREE(class); + VIR_FREE(vendor); + VIR_FREE(product); + VIR_FREE(version); + VIR_FREE(allow); + return def; + +error: + VIR_FREE(def); + def = NULL; + goto cleanup; +} + +static virDomainRedirFilterDefPtr +virDomainRedirFilterDefParseXML(const xmlNodePtr node, + xmlXPathContextPtr ctxt) +{ + int i, n; + xmlNodePtr *nodes = NULL; + xmlNodePtr save = ctxt->node; + virDomainRedirFilterDefPtr def = NULL; + + if (VIR_ALLOC(def) < 0) + goto no_memory; + + ctxt->node = node; + if ((n = virXPathNodeSet("./usbdev", ctxt, &nodes)) < 0) { + goto error; + } + + if (n && VIR_ALLOC_N(def->usbdevs, n) < 0) + goto no_memory; + + for (i = 0; i < n; i++) { + virDomainRedirFilterUsbDevDefPtr usbdev = + virDomainRedirFilterUsbDevDefParseXML(nodes[i]); + + if (!usbdev) + goto error; + def->usbdevs[def->nusbdevs++] = usbdev; + } + VIR_FREE(nodes); + + ctxt->node = save; + return def; + +no_memory: + virReportOOMError(); + +error: + VIR_FREE(nodes); + virDomainRedirFilterDefFree(def); + return NULL; +} + static int virDomainLifecycleParseXML(xmlXPathContextPtr ctxt, const char *xpath, int *val, @@ -9152,6 +9368,26 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, } VIR_FREE(nodes); + /* analysis of the redirection filter rules */ + if ((n = virXPathNodeSet("./devices/redirfilter", ctxt, &nodes)) < 0) { + goto error; + } + if (n > 1) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("only one set of redirection filter rule is supported")); + goto error; + } + + if (n) { + virDomainRedirFilterDefPtr redirfilter = + virDomainRedirFilterDefParseXML(nodes[0], ctxt); + if (!redirfilter) + goto error; + + def->redirfilter = redirfilter; + } + VIR_FREE(nodes); + /* analysis of cpu handling */ if ((node = virXPathNode("./cpu[1]", ctxt)) != NULL) { xmlNodePtr oldnode = ctxt->node; @@ -10117,6 +10353,61 @@ cleanup: return identical; } +static bool +virDomainRedirFilterDefCheckABIStability(virDomainRedirFilterDefPtr src, + virDomainRedirFilterDefPtr dst) +{ + int i; + bool identical = false; + + if (src->nusbdevs != dst->nusbdevs) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Target USB redirection filter rule " + "count %d does not match source %d"), + dst->nusbdevs, src->nusbdevs); + goto cleanup; + } + + for (i = 0; i < src->nusbdevs; i++) { + virDomainRedirFilterUsbDevDefPtr srcUsbDev = src->usbdevs[i]; + virDomainRedirFilterUsbDevDefPtr dstUsbDev = dst->usbdevs[i]; + if (srcUsbDev->usbClass != dstUsbDev->usbClass) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Target USB Class code does not match source")); + goto cleanup; + } + + if (srcUsbDev->vendor != dstUsbDev->vendor) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Target USB vendor ID does not match source")); + goto cleanup; + } + + if (srcUsbDev->product != dstUsbDev->product) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Target USB product ID does not match source")); + goto cleanup; + } + + if (srcUsbDev->version != dstUsbDev->version) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Target USB version does not match source")); + goto cleanup; + } + + if (srcUsbDev->allow != dstUsbDev->allow) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Target USB allow '%s' does not match source '%s'"), + dstUsbDev->allow ? "yes" : "no", + srcUsbDev->allow ? "yes" : "no"); + goto cleanup; + } + } + identical = true; + +cleanup: + return identical; +} /* This compares two configurations and looks for any differences * which will affect the guest ABI. This is primarily to allow @@ -10385,6 +10676,17 @@ bool virDomainDefCheckABIStability(virDomainDefPtr src, if (!virDomainHubDefCheckABIStability(src->hubs[i], dst->hubs[i])) goto cleanup; + if ((!src->redirfilter && dst->redirfilter) || + (src->redirfilter && !dst->redirfilter)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Target domain USB redirection filter count %d does not match source %d"), + dst->redirfilter ? 1 : 0, src->redirfilter ? 1 : 0); + goto cleanup; + } + + if (src->redirfilter && + !virDomainRedirFilterDefCheckABIStability(src->redirfilter, dst->redirfilter)) + goto cleanup; if ((!src->watchdog && dst->watchdog) || (src->watchdog && !dst->watchdog)) { @@ -12592,6 +12894,47 @@ virDomainRedirdevDefFormat(virBufferPtr buf, } static int +virDomainRedirFilterDefFormat(virBufferPtr buf, + virDomainRedirFilterDefPtr filter) +{ + int i; + + virBufferAddLit(buf, " <redirfilter>\n"); + for (i = 0; i < filter->nusbdevs; i++) { + virDomainRedirFilterUsbDevDefPtr usbdev = filter->usbdevs[i]; + virBufferAddLit(buf, " <usbdev"); + if (usbdev->usbClass > 0) + virBufferAsprintf(buf, " class='0x%02X'", usbdev->usbClass); + else + virBufferAddLit(buf, " class='-1'"); + + if (usbdev->vendor > 0) + virBufferAsprintf(buf, " vendor='0x%04X'", usbdev->vendor); + else + virBufferAddLit(buf, " vendor='-1'"); + + if (usbdev->product > 0) + virBufferAsprintf(buf, " product='0x%04X'", usbdev->product); + else + virBufferAddLit(buf, " product='-1'"); + + if (usbdev->version > 0) + virBufferAsprintf(buf, " version='%d.%d'", + ((usbdev->version & 0xf000) >> 12) * 10 + + ((usbdev->version & 0x0f00) >> 8), + ((usbdev->version & 0x00f0) >> 4) * 10 + + ((usbdev->version & 0x000f) >> 0)); + else + virBufferAddLit(buf, " version='-1'"); + + virBufferAsprintf(buf, " allow='%s'/>\n", usbdev->allow ? "yes" : "no"); + + } + virBufferAddLit(buf, " </redirfilter>\n"); + return 0; +} + +static int virDomainHubDefFormat(virBufferPtr buf, virDomainHubDefPtr def, unsigned int flags) @@ -13116,6 +13459,9 @@ virDomainDefFormatInternal(virDomainDefPtr def, if (virDomainRedirdevDefFormat(buf, def->redirdevs[n], flags) < 0) goto cleanup; + if (def->redirfilter) + virDomainRedirFilterDefFormat(buf, def->redirfilter); + for (n = 0 ; n < def->nhubs ; n++) if (virDomainHubDefFormat(buf, def->hubs[n], flags) < 0) goto cleanup; diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index fd0e89e..fc1f98d 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -92,6 +92,12 @@ typedef virDomainHubDef *virDomainHubDefPtr; typedef struct _virDomainRedirdevDef virDomainRedirdevDef; typedef virDomainRedirdevDef *virDomainRedirdevDefPtr; +typedef struct _virDomainRedirFilterUsbDevDef virDomainRedirFilterUsbDevDef; +typedef virDomainRedirFilterUsbDevDef *virDomainRedirFilterUsbDevDefPtr; + +typedef struct _virDomainRedirFilterDef virDomainRedirFilterDef; +typedef virDomainRedirFilterDef *virDomainRedirFilterDefPtr; + typedef struct _virDomainSmartcardDef virDomainSmartcardDef; typedef virDomainSmartcardDef *virDomainSmartcardDefPtr; @@ -1283,6 +1289,19 @@ struct _virDomainRedirdevDef { virDomainDeviceInfo info; /* Guest address */ }; +struct _virDomainRedirFilterUsbDevDef { + int usbClass; + int vendor; + int product; + int version; + unsigned int allow :1; +}; + +struct _virDomainRedirFilterDef { + int nusbdevs; + virDomainRedirFilterUsbDevDefPtr *usbdevs; +}; + enum { VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO, VIR_DOMAIN_MEMBALLOON_MODEL_XEN, @@ -1664,6 +1683,7 @@ struct _virDomainDef { virDomainMemballoonDefPtr memballoon; virCPUDefPtr cpu; virSysinfoDefPtr sysinfo; + virDomainRedirFilterDefPtr redirfilter; void *namespaceData; virDomainXMLNamespace ns; @@ -1873,6 +1893,7 @@ void virDomainHostdevDefClear(virDomainHostdevDefPtr def); void virDomainHostdevDefFree(virDomainHostdevDefPtr def); void virDomainHubDefFree(virDomainHubDefPtr def); void virDomainRedirdevDefFree(virDomainRedirdevDefPtr def); +void virDomainRedirFilterDefFree(virDomainRedirFilterDefPtr def); void virDomainDeviceDefFree(virDomainDeviceDefPtr def); virDomainDeviceDefPtr virDomainDeviceDefCopy(virCapsPtr caps, const virDomainDefPtr def, -- 1.7.7.6

<redirdev bus='usb' type='spicevmc'> <address type='usb' bus='0' port='4'/> </redirdev> <redirfilter> <usbdev class='0x08' vendor='0x1234' product='0xbeef' \ version='2.00' allow='yes'/> <usbdev class='-1' vendor='-1' product='-1' version='-1' allow='no'/> </redirfilter> will be converted to: -device usb-redir,chardev=charredir0,id=redir0,\ filter=0x08:0x1234:0xBEEF:0x2000:1|-1:-1:-1:-1:0,bus=usb.0,port=4 --- src/qemu/qemu_command.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- src/qemu/qemu_command.h | 5 +++-- src/qemu/qemu_hotplug.c | 3 ++- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 4ca3047..a1e8105 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3411,10 +3411,13 @@ qemuBuildPCIHostdevPCIDevStr(virDomainHostdevDefPtr dev) char * -qemuBuildRedirdevDevStr(virDomainRedirdevDefPtr dev, +qemuBuildRedirdevDevStr(virDomainDefPtr def, + virDomainRedirdevDefPtr dev, virBitmapPtr qemuCaps) { + int i; virBuffer buf = VIR_BUFFER_INITIALIZER; + virDomainRedirFilterDefPtr redirfilter = def->redirfilter; if (dev->bus != VIR_DOMAIN_REDIRDEV_BUS_USB) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, @@ -3434,6 +3437,44 @@ qemuBuildRedirdevDevStr(virDomainRedirdevDefPtr dev, dev->info.alias, dev->info.alias); + if (redirfilter && redirfilter->nusbdevs) { + if (!qemuCapsGet(qemuCaps, QEMU_CAPS_USB_REDIR_FILTER)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("USB redirection filter is not " + "supported by this version of QEMU")); + goto error; + } + + virBufferAsprintf(&buf, ",filter="); + + for (i = 0; i < redirfilter->nusbdevs; i++) { + virDomainRedirFilterUsbDevDefPtr usbdev = redirfilter->usbdevs[i]; + if (usbdev->usbClass > 0) + virBufferAsprintf(&buf, "0x%02X:", usbdev->usbClass); + else + virBufferAsprintf(&buf, "-1:"); + + if (usbdev->vendor > 0) + virBufferAsprintf(&buf, "0x%04X:", usbdev->vendor); + else + virBufferAsprintf(&buf, "-1:"); + + if (usbdev->product > 0) + virBufferAsprintf(&buf, "0x%04X:", usbdev->product); + else + virBufferAsprintf(&buf, "-1:"); + + if (usbdev->version > 0) + virBufferAsprintf(&buf, "0x%04X:", usbdev->version); + else + virBufferAsprintf(&buf, "-1:"); + + virBufferAsprintf(&buf, "%u", usbdev->allow); + if (i < redirfilter->nusbdevs -1) + virBufferAsprintf(&buf, "|"); + } + } + if (qemuBuildDeviceAddressStr(&buf, &dev->info, qemuCaps) < 0) goto error; @@ -6226,7 +6267,7 @@ qemuBuildCommandLine(virConnectPtr conn, goto error; virCommandAddArg(cmd, "-device"); - if (!(devstr = qemuBuildRedirdevDevStr(redirdev, qemuCaps))) + if (!(devstr = qemuBuildRedirdevDevStr(def, redirdev, qemuCaps))) goto error; virCommandAddArg(cmd, devstr); VIR_FREE(devstr); diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index e999bc7..7c79303 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -132,8 +132,9 @@ char * qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev, virBitmapPtr qemuCaps); char * qemuBuildHubDevStr(virDomainHubDefPtr dev, virBitmapPtr qemuCaps); -char * qemuBuildRedirdevDevStr(virDomainRedirdevDefPtr dev, virBitmapPtr qemuCaps); - +char * qemuBuildRedirdevDevStr(virDomainDefPtr def, + virDomainRedirdevDefPtr dev, + virBitmapPtr qemuCaps); int qemuNetworkIfaceConnect(virDomainDefPtr def, virConnectPtr conn, diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 1251d6b..9a04342 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1022,12 +1022,13 @@ int qemuDomainAttachRedirdevDevice(struct qemud_driver *driver, { int ret; qemuDomainObjPrivatePtr priv = vm->privateData; + virDomainDefPtr def = vm->def; 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))) + if (!(devstr = qemuBuildRedirdevDevStr(def, redirdev, priv->qemuCaps))) goto error; } -- 1.7.7.6

--- docs/schemas/domaincommon.rng | 66 ++++++++++++++++++++ .../qemuxml2argv-usb-redir-filter.args | 10 +++ .../qemuxml2argv-usb-redir-filter.xml | 45 +++++++++++++ tests/qemuxml2argvtest.c | 6 ++ 4 files changed, 127 insertions(+), 0 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-redir-filter.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-redir-filter.xml diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 35e9f82..a53c853 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -2265,6 +2265,49 @@ </choice> </define> + <define name="usbdevfilter"> + <element name="usbdev"> + <attribute name="allow"> + <choice> + <value>yes</value> + <value>no</value> + </choice> + </attribute> + <optional> + <attribute name="class"> + <choice> + <ref name="usbClass"/> + <ref name="usbIdDefault"/> + </choice> + </attribute> + </optional> + <optional> + <attribute name="vendor"> + <choice> + <ref name="usbId"/> + <ref name="usbIdDefault"/> + </choice> + </attribute> + </optional> + <optional> + <attribute name="product"> + <choice> + <ref name="usbId"/> + <ref name="usbIdDefault"/> + </choice> + </attribute> + </optional> + <optional> + <attribute name="version"> + <choice> + <ref name="usbVersion"/> + <ref name="usbIdDefault"/> + </choice> + </attribute> + </optional> + </element> + </define> + <define name="qemucdevSrcType"> <attribute name="type"> <ref name="qemucdevSrcTypeChoice"/> @@ -2561,6 +2604,13 @@ </optional> </element> </define> + <define name="redirfilter"> + <element name="redirfilter"> + <zeroOrMore> + <ref name="usbdevfilter"/> + </zeroOrMore> + </element> + </define> <define name="hostdev"> <element name="hostdev"> <optional> @@ -2724,6 +2774,7 @@ <ref name="smartcard"/> <ref name="hub"/> <ref name="redirdev"/> + <ref name="redirfilter"/> </choice> </zeroOrMore> <optional> @@ -3337,16 +3388,31 @@ <param name="pattern">(([0-2]?[0-9]?[0-9]\.){3}[0-2]?[0-9]?[0-9])|(([0-9a-fA-F]+|:)+[0-9a-fA-F]+)|([a-zA-Z0-9_\.\+\-]*)</param> </data> </define> + <define name="usbIdDefault"> + <data type="string"> + <param name="pattern">-1</param> + </data> + </define> <define name="usbId"> <data type="string"> <param name="pattern">(0x)?[0-9a-fA-F]{1,4}</param> </data> </define> + <define name="usbVersion"> + <data type="string"> + <param name="pattern">[0-9]{1,2}.[0-9]{1,2}</param> + </data> + </define> <define name="usbAddr"> <data type="string"> <param name="pattern">(0x)?[0-9a-fA-F]{1,3}</param> </data> </define> + <define name="usbClass"> + <data type="string"> + <param name="pattern">(0x)?[0-9a-fA-F]{1,2}</param> + </data> + </define> <define name="usbPort"> <data type="string"> <param name="pattern">((0x)?[0-9a-fA-F]{1,3}\.){0,3}(0x)?[0-9a-fA-F]{1,3}</param> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-redir-filter.args b/tests/qemuxml2argvdata/qemuxml2argv-usb-redir-filter.args new file mode 100644 index 0000000..215844a --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-redir-filter.args @@ -0,0 +1,10 @@ +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,addr=0x4.0x7 \ +-device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pci.0,multifunction=on,addr=0x4 \ +-device ich9-usb-uhci2,masterbus=usb.0,firstport=2,bus=pci.0,addr=0x4.0x1 \ +-device ich9-usb-uhci3,masterbus=usb.0,firstport=4,bus=pci.0,addr=0x4.0x2 \ +-chardev spicevmc,id=charredir0,name=usbredir \ +-device usb-redir,chardev=charredir0,id=redir0,filter=0x08:0x15E1:0x2007:0x0110:1|-1:-1:-1:-1:0,bus=usb.0,port=4 \ +-chardev spicevmc,id=charredir1,name=usbredir \ +-device usb-redir,chardev=charredir1,id=redir1,filter=0x08:0x15E1:0x2007:0x0110:1|-1:-1:-1:-1:0,bus=usb.0,port=5 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-redir-filter.xml b/tests/qemuxml2argvdata/qemuxml2argv-usb-redir-filter.xml new file mode 100644 index 0000000..6ff4da2 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-redir-filter.xml @@ -0,0 +1,45 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <vcpu placement='static'>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' multifunction='on'/> + </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='spicevmc'> + <address type='usb' bus='0' port='4'/> + </redirdev> + <redirdev bus='usb' type='spicevmc'> + <alias name='redir1'/> + <address type='usb' bus='0' port='5'/> + </redirdev> + <redirfilter> + <usbdev class='0x08' vendor='0x15E1' product='0x2007' version='1.10' allow='yes'/> + <usbdev class='-1' vendor='-1' product='-1' version='-1' allow='no'/> + </redirfilter> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index f8d8db5..30b0be1 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -672,6 +672,12 @@ mymain(void) QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_USB_HUB, QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_USB_REDIR, QEMU_CAPS_SPICE, QEMU_CAPS_CHARDEV_SPICEVMC); + DO_TEST("usb-redir-filter", + 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, + QEMU_CAPS_SPICE, QEMU_CAPS_CHARDEV_SPICEVMC, + QEMU_CAPS_USB_REDIR_FILTER); DO_TEST("usb1-usb2", QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_PIIX3_USB_UHCI, -- 1.7.7.6

--- docs/formatdomain.html.in | 38 ++++++++++++++++++++++++-------------- 1 files changed, 24 insertions(+), 14 deletions(-) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 2c5c456..c6ba79b 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -2033,6 +2033,10 @@ <redirdev bus='usb' type='tcp'> <source mode='connect' host='localhost' service='4000'/> </redirdev> + <redirfilter> + <usbdev class='0x08' vendor='0x1234' product='0xbeef' version='2.00' allow='yes'/> + <usbdev class='-1' vendor='-1' product='-1' version='-1' allow='no'/> + </redirfilter> </devices> ...</pre> @@ -2049,21 +2053,27 @@ 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.</dd> - + device</a>) are typical.The redirdev element has an optional + sub-element<code><address></code> which can tie the + device to a particular controller. 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> + <dt><code>redirfilter</code></dt> + <dd>The<code> redirfilter </code>element is used for creating the + filter rule to filter out certain devices from redirection. + It uses sub-element <code><usbdev></code>to define each filter rule. + <code>class</code>attribute is the USB Class code, for example, + 0x08 represents mass storage devices. The USB device can be addressed by + vendor / product id using the<code>vendor</code> and <code>product</code> attributes. + <code>version</code> is the bcdDevice value of USB device, such as 1.00, 1.10 and 2.00. + These four attributes are optional and <code>-1</code> can be used to allow + any value for them. <code>allow</code>attribute is mandatory, + 'yes' means allow, 'no' for deny. + </dd> </dl> - <p> - The redirdev element has an optional sub-element - <code><address></code> which can tie the device to a - particular controller. - </p> - <p> - 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). - </p> <h4><a name="elementsSmartcard">Smartcard devices</a></h4> -- 1.7.7.6

On Sun, Aug 19, 2012 at 11:42:43PM +0800, Guannan Ren wrote:
BZ RFE https://bugzilla.redhat.com/show_bug.cgi?id=795929 qemu support: http://git.qemu.org/?p=qemu.git;a=commitdiff;h=6af165892cf900291046f1d25f954...
Since qemu has have the code to support USB redirection filter. This set of patches try to support it from libvirt. The XML format is like this: <devices> ... <redirdev bus='usb' type='spicevmc'> <address type='usb' bus='0' port='4'/> </redirdev> <redirfilter> <usbdev class='0x08' vendor='0x1234' product='0xbeef' \ version='2.00' allow='yes'/> <usbdev class='-1' vendor='-1' product='-1' version='-1' allow='no'/> </redirfilter> ... </devices>
I don't really see the point in this being done on the libvirt side. The <redirdev> code is allowing redirection of a USB device from a client (eg SPICE) app, to the remote QEMU instance and from there to the guest. With this architecture, IMHO filtering of USB devices is something that belongs in the client app, not in QEMU which is a broker inbetween the client & guest OS. So NACK to this whole series 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 08/20/2012 06:06 PM, Daniel P. Berrange wrote:
BZ RFE https://bugzilla.redhat.com/show_bug.cgi?id=795929 qemu support: http://git.qemu.org/?p=qemu.git;a=commitdiff;h=6af165892cf900291046f1d25f954...
Since qemu has have the code to support USB redirection filter. This set of patches try to support it from libvirt. The XML format is like this: <devices> ... <redirdev bus='usb' type='spicevmc'> <address type='usb' bus='0' port='4'/> </redirdev> <redirfilter> <usbdev class='0x08' vendor='0x1234' product='0xbeef' \ version='2.00' allow='yes'/> <usbdev class='-1' vendor='-1' product='-1' version='-1' allow='no'/> </redirfilter> ... </devices> I don't really see the point in this being done on the libvirt side. The <redirdev> code is allowing redirection of a USB device from a client (eg SPICE) app, to the remote QEMU instance and from there to
On Sun, Aug 19, 2012 at 11:42:43PM +0800, Guannan Ren wrote: the guest.
With this architecture, IMHO filtering of USB devices is something that belongs in the client app, not in QEMU which is a broker inbetween the client & guest OS.
So NACK to this whole series
Daniel
Thanks for this review. As far as I know, the spicy client doesn't have the filtering functionality. spicy client could work together with qemu which supports usb-redir.filter to filter usb devices. I really couldn't say anything about the architecture currently. So cc Hans who is the RFE requester. Guannan Ren

Hi, On 08/20/2012 06:06 PM, Daniel P. Berrange wrote:
BZ RFE https://bugzilla.redhat.com/show_bug.cgi?id=795929 qemu support: http://git.qemu.org/?p=qemu.git;a=commitdiff;h=6af165892cf900291046f1d25f954...
Since qemu has have the code to support USB redirection filter. This set of patches try to support it from libvirt. The XML format is like this: <devices> ... <redirdev bus='usb' type='spicevmc'> <address type='usb' bus='0' port='4'/> </redirdev> <redirfilter> <usbdev class='0x08' vendor='0x1234' product='0xbeef' \ version='2.00' allow='yes'/> <usbdev class='-1' vendor='-1' product='-1' version='-1' allow='no'/> </redirfilter> ... </devices> I don't really see the point in this being done on the libvirt side. The <redirdev> code is allowing redirection of a USB device from a client (eg SPICE) app, to the remote QEMU instance and from there to
On Sun, Aug 19, 2012 at 11:42:43PM +0800, Guannan Ren wrote: the guest.
With this architecture, IMHO filtering of USB devices is something that belongs in the client app, not in QEMU which is a broker inbetween the client & guest OS.
We want the admin of the vm to be able to set policy as to which devices can be redirected to the vm, for example for security reasons. Clearly the right place to enforce such a policy is the host and not the client, esp. since the client may be outside of the control of the vm admin. Regards, Hans

On Tue, Aug 21, 2012 at 09:04:03AM +0200, Hans de Goede wrote:
Hi,
On 08/20/2012 06:06 PM, Daniel P. Berrange wrote:
BZ RFE https://bugzilla.redhat.com/show_bug.cgi?id=795929 qemu support: http://git.qemu.org/?p=qemu.git;a=commitdiff;h=6af165892cf900291046f1d25f954...
Since qemu has have the code to support USB redirection filter. This set of patches try to support it from libvirt. The XML format is like this: <devices> ... <redirdev bus='usb' type='spicevmc'> <address type='usb' bus='0' port='4'/> </redirdev> <redirfilter> <usbdev class='0x08' vendor='0x1234' product='0xbeef' \ version='2.00' allow='yes'/> <usbdev class='-1' vendor='-1' product='-1' version='-1' allow='no'/> </redirfilter> ... </devices> I don't really see the point in this being done on the libvirt side. The <redirdev> code is allowing redirection of a USB device from a client (eg SPICE) app, to the remote QEMU instance and from there to
On Sun, Aug 19, 2012 at 11:42:43PM +0800, Guannan Ren wrote: the guest.
With this architecture, IMHO filtering of USB devices is something that belongs in the client app, not in QEMU which is a broker inbetween the client & guest OS.
We want the admin of the vm to be able to set policy as to which devices can be redirected to the vm, for example for security reasons. Clearly the right place to enforce such a policy is the host and not the client, esp. since the client may be outside of the control of the vm admin.
What kind of threat are you expecting this to protect against ? I don't really see that black/white-listing on vendor/product ID is going to provide a very credible level of security protection. Chances are that if there is a flaw in the guest OS or QEMU, the attacker could simply spoof the required product/vendor ID and then send specially crafted USB packets to exploit the flaw anyway. 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 :|

Hi, On 08/21/2012 11:23 AM, Daniel P. Berrange wrote: <Snip>
We want the admin of the vm to be able to set policy as to which devices can be redirected to the vm, for example for security reasons. Clearly the right place to enforce such a policy is the host and not the client, esp. since the client may be outside of the control of the vm admin.
What kind of threat are you expecting this to protect against ? I don't really see that black/white-listing on vendor/product ID is going to provide a very credible level of security protection. Chances are that if there is a flaw in the guest OS or QEMU, the attacker could simply spoof the required product/vendor ID and then send specially crafted USB packets to exploit the flaw anyway.
One example would be the vm to contain sensitive information and the admin not wanting users to be able to redirect USB-mass-storage devices to it, while still allowing the use of other USB peripherals. Note that the filtering is not just by ID, it also is by class. TBH I'm amazed we are having this discussion, everyone I've talked to before agrees that allowing a vm admin to limit which kind of USB devices can be redirected is a reasonable, desirable even thing to have, and agrees the proper place for this, as a per vm setting, is on the host. Also note that the proprietary Spice usb-redir solution which the new FOSS usb-redir code is replacing has this ability too, and currently you can configure a filter from RHEV-M, so from the host / vm management software. Regards, Hans

On Tue, Aug 21, 2012 at 12:46:41PM +0200, Hans de Goede wrote:
Hi,
On 08/21/2012 11:23 AM, Daniel P. Berrange wrote:
<Snip>
We want the admin of the vm to be able to set policy as to which devices can be redirected to the vm, for example for security reasons. Clearly the right place to enforce such a policy is the host and not the client, esp. since the client may be outside of the control of the vm admin.
What kind of threat are you expecting this to protect against ? I don't really see that black/white-listing on vendor/product ID is going to provide a very credible level of security protection. Chances are that if there is a flaw in the guest OS or QEMU, the attacker could simply spoof the required product/vendor ID and then send specially crafted USB packets to exploit the flaw anyway.
One example would be the vm to contain sensitive information and the admin not wanting users to be able to redirect USB-mass-storage devices to it, while still allowing the use of other USB peripherals. Note that the filtering is not just by ID, it also is by class.
I stil don't think this provides any actual security, it is merely a slight inconvenience. The supposed bad guy has access to both ends, the guest OS and the SPICE client, so if they want to download data out of the VM there is no reason they need to expose a USB mass storage device to the guest. They can tell QEMU they're redirecting a sound card and QEMU has no way of knowing whether the client side really is a sound card. The bad guy just cat's the secret data to the sound device in the guest as "raw audio" and on the client side just save the audio stream back to a file. Pretty much any kind of USB peripheral will have some kind of data channel that can be used in this manner, even if you're just redirecting a keyboard you could transfer data via the LEDS state, particularly since you're not constrained by limitations of having real USB hardware on the client side.
TBH I'm amazed we are having this discussion, everyone I've talked to before agrees that allowing a vm admin to limit which kind of USB devices can be redirected is a reasonable, desirable even thing to have, and agrees the proper place for this, as a per vm setting, is on the host.
Also note that the proprietary Spice usb-redir solution which the new FOSS usb-redir code is replacing has this ability too, and currently you can configure a filter from RHEV-M, so from the host / vm management software.
Well I'll withdraw my NACK from this feature, but I maintain that it is offering little-to-no security. 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 :|

Hi, On 08/21/2012 01:02 PM, Daniel P. Berrange wrote: <Snip>
Also note that the proprietary Spice usb-redir solution which the new FOSS usb-redir code is replacing has this ability too, and currently you can configure a filter from RHEV-M, so from the host / vm management software.
Well I'll withdraw my NACK from this feature,
Thanks.
but I maintain that it is offering little-to-no security.
Oh, I agree, this is not bullet-proof security in anyway, this is not to protect against bad-guys (bad-guys should not have the authorization to connect to the vm), but from end-users doing undesirable things Regards, Hans

On 08/19/2012 11:42 PM, Guannan Ren wrote:
BZ RFE https://bugzilla.redhat.com/show_bug.cgi?id=795929 qemu support: http://git.qemu.org/?p=qemu.git;a=commitdiff;h=6af165892cf900291046f1d25f954...
Since qemu has have the code to support USB redirection filter. This set of patches try to support it from libvirt. The XML format is like this: <devices> ... <redirdev bus='usb' type='spicevmc'> <address type='usb' bus='0' port='4'/> </redirdev> <redirfilter> <usbdev class='0x08' vendor='0x1234' product='0xbeef' \ version='2.00' allow='yes'/> <usbdev class='-1' vendor='-1' product='-1' version='-1' allow='no'/> </redirfilter> ... </devices>
Multiple <usbdev> element as one of filter rule could be added into parent element <redirfilter>, only no more than <redirfilter> element could exists. There is no 1:1 mapping between ports and redirected devices and qemu and spicy client couldn't decide into which usbredir ports the client can 'plug' redirected devices. So it make sense to apply all of filter rules global to all existing usb redirection devices. class attribute is USB Class codes. version is bcdDevice value of USB device. vendor and product is USB vendorId and productId. -1 can be used to allow any value for a field. Except allow attribute the other four are optional, default value is -1.
The above XML will be converted to the following qemu command line: If there are multiple usb-redir device, all of them have the same filter rules. -device usb-redir,chardev=charredir0,id=redir0,\ filter=0x08:0x1234:0xBEEF:0x2000:1|-1:-1:-1:-1:0,bus=usb.0,port=4
Guannan Ren(0/5) qemu: add usb-redir.filter qemu capability flag qemu: define and parse USB redirection filter XML qemu: build USB redirection filter qemu command line test: add xml2argvtest for usb-redir filter and update doc: update usb redirection filter infomation on
docs/formatdomain.html.in | 38 ++- docs/schemas/domaincommon.rng | 66 ++++ src/conf/domain_conf.c | 346 ++++++++++++++++++++ src/conf/domain_conf.h | 21 ++ src/qemu/qemu_capabilities.c | 4 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 45 +++- src/qemu/qemu_command.h | 5 +- src/qemu/qemu_hotplug.c | 3 +- .../qemuxml2argv-usb-redir-filter.args | 10 + .../qemuxml2argv-usb-redir-filter.xml | 45 +++ tests/qemuxml2argvtest.c | 6 + 12 files changed, 571 insertions(+), 19 deletions(-)
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
ping :)
participants (3)
-
Daniel P. Berrange
-
Guannan Ren
-
Hans de Goede