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

(This is not a new set of patches, it's rebased version) 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 +- tests/qemuxml2argvdata/qemuxml2argv-usb-redir-filter.args | 10 +++++ tests/qemuxml2argvdata/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(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index ed85b6f..623c6a0 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -176,6 +176,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST, "disable-s3", "disable-s4", /* 105 */ + "usb-redir.filter", ); struct qemu_feature_flags { @@ -1407,6 +1408,7 @@ qemuCapsExtractDeviceStr(const char *qemu, "-device", "virtio-net-pci,?", "-device", "scsi-disk,?", "-device", "PIIX4_PM,?", + "-device", "usb-redir,?", NULL); /* qemu -help goes to stdout, but qemu -device ? goes to stderr. */ virCommandSetErrorBuffer(cmd, &output); @@ -1452,6 +1454,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 49d64e5..3b9629b 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -141,6 +141,7 @@ enum qemuCapsFlags { QEMU_CAPS_BLOCKIO = 103, /* -device ...logical_block_size & co */ QEMU_CAPS_DISABLE_S3 = 104, /* S3 BIOS Advertisement on/off */ QEMU_CAPS_DISABLE_S4 = 105, /* S4 BIOS Advertisement on/off */ + QEMU_CAPS_USB_REDIR_FILTER = 106, /* usb-redir.filter */ QEMU_CAPS_LAST, /* this must always be the last item */ }; -- 1.7.11.2

On Wed, Sep 12, 2012 at 04:35:46PM +0800, Guannan Ren wrote:
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(+)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index ed85b6f..623c6a0 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -176,6 +176,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST, "disable-s3",
"disable-s4", /* 105 */ + "usb-redir.filter", );
struct qemu_feature_flags { @@ -1407,6 +1408,7 @@ qemuCapsExtractDeviceStr(const char *qemu, "-device", "virtio-net-pci,?", "-device", "scsi-disk,?", "-device", "PIIX4_PM,?", + "-device", "usb-redir,?", NULL); /* qemu -help goes to stdout, but qemu -device ? goes to stderr. */ virCommandSetErrorBuffer(cmd, &output); @@ -1452,6 +1454,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 49d64e5..3b9629b 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -141,6 +141,7 @@ enum qemuCapsFlags { QEMU_CAPS_BLOCKIO = 103, /* -device ...logical_block_size & co */ QEMU_CAPS_DISABLE_S3 = 104, /* S3 BIOS Advertisement on/off */ QEMU_CAPS_DISABLE_S4 = 105, /* S4 BIOS Advertisement on/off */ + QEMU_CAPS_USB_REDIR_FILTER = 106, /* usb-redir.filter */
QEMU_CAPS_LAST, /* this must always be the last item */ };
ACK 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 09/12/2012 11:19 PM, Daniel P. Berrange wrote:
On Wed, Sep 12, 2012 at 04:35:46PM +0800, Guannan Ren wrote:
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(+)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index ed85b6f..623c6a0 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -176,6 +176,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST, "disable-s3",
"disable-s4", /* 105 */ + "usb-redir.filter", );
struct qemu_feature_flags { @@ -1407,6 +1408,7 @@ qemuCapsExtractDeviceStr(const char *qemu, "-device", "virtio-net-pci,?", "-device", "scsi-disk,?", "-device", "PIIX4_PM,?", + "-device", "usb-redir,?", NULL); /* qemu -help goes to stdout, but qemu -device ? goes to stderr. */ virCommandSetErrorBuffer(cmd, &output); @@ -1452,6 +1454,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 49d64e5..3b9629b 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -141,6 +141,7 @@ enum qemuCapsFlags { QEMU_CAPS_BLOCKIO = 103, /* -device ...logical_block_size & co */ QEMU_CAPS_DISABLE_S3 = 104, /* S3 BIOS Advertisement on/off */ QEMU_CAPS_DISABLE_S4 = 105, /* S4 BIOS Advertisement on/off */ + QEMU_CAPS_USB_REDIR_FILTER = 106, /* usb-redir.filter */
QEMU_CAPS_LAST, /* this must always be the last item */ }; ACK
Daniel
Thanks and pushed.

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(+) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 8952b69..dc89eae 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) @@ -1674,6 +1688,8 @@ void virDomainDefFree(virDomainDefPtr def) virSysinfoDefFree(def->sysinfo); + virDomainRedirFilterDefFree(def->redirfilter); + if (def->namespaceData && def->ns.free) (def->ns.free)(def->namespaceData); @@ -7222,6 +7238,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, @@ -9454,6 +9670,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; @@ -10419,6 +10655,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 @@ -10687,6 +10978,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)) { @@ -13019,6 +13321,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) @@ -13587,6 +13930,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 3995c2d..232c875 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; @@ -1299,6 +1305,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, @@ -1704,6 +1723,7 @@ struct _virDomainDef { virDomainMemballoonDefPtr memballoon; virCPUDefPtr cpu; virSysinfoDefPtr sysinfo; + virDomainRedirFilterDefPtr redirfilter; void *namespaceData; virDomainXMLNamespace ns; @@ -1815,6 +1835,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.11.2

On Wed, Sep 12, 2012 at 04:35:47PM +0800, Guannan Ren wrote:
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'/>
I find it a little odd to output XML which uses both hex and decimal. If the value is '-1', then can't we just omit the attribute entirely.
</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(+)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 8952b69..dc89eae 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;
s/int/size_t/;
+ + 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) @@ -1674,6 +1688,8 @@ void virDomainDefFree(virDomainDefPtr def)
virSysinfoDefFree(def->sysinfo);
+ virDomainRedirFilterDefFree(def->redirfilter); + if (def->namespaceData && def->ns.free) (def->ns.free)(def->namespaceData);
+static virDomainRedirFilterDefPtr +virDomainRedirFilterDefParseXML(const xmlNodePtr node, + xmlXPathContextPtr ctxt) +{ + int i, n;
i can be size_t, while n must remain signed.
+ 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,
@@ -13019,6 +13321,47 @@ virDomainRedirdevDefFormat(virBufferPtr buf, }
static int +virDomainRedirFilterDefFormat(virBufferPtr buf, + virDomainRedirFilterDefPtr filter) +{ + int i;
size_t
+ + 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) @@ -13587,6 +13930,9 @@ virDomainDefFormatInternal(virDomainDefPtr def,
+struct _virDomainRedirFilterUsbDevDef { + int usbClass; + int vendor; + int product; + int version; + unsigned int allow :1; +}; + +struct _virDomainRedirFilterDef { + int nusbdevs;
size_t
+ virDomainRedirFilterUsbDevDefPtr *usbdevs; +};
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 09/12/2012 11:26 PM, Daniel P. Berrange wrote:
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'/> I find it a little odd to output XML which uses both hex and decimal. If the value is '-1', then can't we just omit
On Wed, Sep 12, 2012 at 04:35:47PM +0800, Guannan Ren wrote: the attribute entirely.
Thanks for the review. attributes class, vendor, product and version are optional for input xml, default value: -1; allow attribute is mandatory for input xml only. Because -1 is so special(why -1?) that I output them out in output xml as a kind of help for user to use later. It's ok not to output these attributes with default value. This will be fixed in v2. Guannan

<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 a83d6de..208a57c 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3437,10 +3437,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, @@ -3460,6 +3463,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; @@ -6274,7 +6315,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 7c5e8dd..2332431 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -139,8 +139,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 a8a904c..0b2596f 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.11.2

On Wed, Sep 12, 2012 at 04:35:48PM +0800, Guannan Ren wrote:
<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(-)
+ 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:");
Here you're adding '-1' for either 0 or any negative number. When parsing & formatting though, you're treating '0' in the same way as positive numbers. I think we need to treat 0 as we do any other number, because it is valid for a vendor to use a product ID of 0x0 for their device. 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 :|

--- 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(+) 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 c2c6184..916872d 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -2375,6 +2375,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"/> @@ -2671,6 +2714,13 @@ </optional> </element> </define> + <define name="redirfilter"> + <element name="redirfilter"> + <zeroOrMore> + <ref name="usbdevfilter"/> + </zeroOrMore> + </element> + </define> <define name="hostdev"> <element name="hostdev"> <optional> @@ -2834,6 +2884,7 @@ <ref name="smartcard"/> <ref name="hub"/> <ref name="redirdev"/> + <ref name="redirfilter"/> </choice> </zeroOrMore> <optional> @@ -3447,16 +3498,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..1141f7e --- /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 47c3f6c..15b5298 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -676,6 +676,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.11.2

--- docs/formatdomain.html.in | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 503685f..94363ba 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -2136,6 +2136,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> @@ -2152,21 +2156,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.11.2

On Wed, Sep 12, 2012 at 04:35:50PM +0800, Guannan Ren wrote:
--- docs/formatdomain.html.in | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 503685f..94363ba 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -2136,6 +2136,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>
Same note about just omitting the attributes completely when they are '-1' 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 :|
participants (2)
-
Daniel P. Berrange
-
Guannan Ren