[libvirt] [PATCH] Fix USB passthrough based on product/vendor
Daniel Veillard
veillard at redhat.com
Fri Mar 5 14:34:08 UTC 2010
On Thu, Mar 04, 2010 at 11:52:43AM +0000, Daniel P. Berrange wrote:
> Changeset
>
> commit 5073aa994af460e775cb3e548528e28d7660fcc8
> Author: Cole Robinson <crobinso at redhat.com>
> Date: Mon Jan 11 11:40:46 2010 -0500
>
> Added support for product/vendor based passthrough, but it only
> worked at the security driver layer. The main guest XML config
> was not updated with the resolved bus/device ID. When the QEMU
> argv refactoring removed use of product/vendor, this then broke
> launching guests.
>
> THe solution is to move the product/vendor resolution up a layer
> into the QEMU driver. So the first thing QEMU does is resolve
> the product/vendor to a bus/device and updates the XML config
> with this info. The rest of the code, including security drivers
> and QEMU argv generated can now rely on bus/device always being
> set.
>
> * src/util/hostusb.c, src/util/hostusb.h: Split vendor/product
> resolution code out of usbGetDevice and into usbFindDevice.
> Add accessors for bus/device ID
> * src/security/virt-aa-helper.c, src/security/security_selinux.c,
> src/qemu/qemu_security_dac.c: Remove vendor/product from the
> usbGetDevice() calls
> * src/qemu/qemu_driver.c: Use usbFindDevice to resolve vendor/product
> into a bus/device ID
> ---
> src/libvirt_private.syms | 3 +
> src/qemu/qemu_driver.c | 102 +++++++++++++++++++++++++++++++++++----
> src/qemu/qemu_security_dac.c | 8 +--
> src/security/security_selinux.c | 8 +--
> src/security/virt-aa-helper.c | 4 +-
> src/util/hostusb.c | 39 +++++++++++----
> src/util/hostusb.h | 13 +++--
> 7 files changed, 136 insertions(+), 41 deletions(-)
>
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index ce9f013..c5ee23d 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -599,7 +599,10 @@ virArgvToString;
>
> # usb.h
> usbGetDevice;
> +usbFindDevice;
> usbFreeDevice;
> +usbDeviceGetBus;
> +usbDeviceGetDevno;
> usbDeviceFileIterate;
>
> # uuid.h
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index ef3cd6c..50bd55b 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -2283,17 +2283,15 @@ cleanup:
> return ret;
> }
>
> +
> static int
> -qemuPrepareHostDevices(struct qemud_driver *driver,
> - virDomainDefPtr def)
> +qemuPrepareHostPCIDevices(struct qemud_driver *driver,
> + virDomainDefPtr def)
> {
> pciDeviceList *pcidevs;
> int i;
> int ret = -1;
>
> - if (!def->nhostdevs)
> - return 0;
> -
> if (!(pcidevs = qemuGetPciHostDeviceList(def)))
> return -1;
>
> @@ -2344,6 +2342,62 @@ cleanup:
> return ret;
> }
>
> +
> +static int
> +qemuPrepareHostUSBDevices(struct qemud_driver *driver ATTRIBUTE_UNUSED,
> + virDomainDefPtr def)
> +{
> + int i;
> + for (i = 0 ; i < def->nhostdevs ; i++) {
> + virDomainHostdevDefPtr hostdev = def->hostdevs[i];
> +
> + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
> + continue;
> + if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
> + continue;
> +
> + /* Resolve a vendor/product to bus/device */
> + if (hostdev->source.subsys.u.usb.vendor) {
> + usbDevice *usb
> + = usbFindDevice(hostdev->source.subsys.u.usb.vendor,
> + hostdev->source.subsys.u.usb.product);
> +
> + if (!usb)
> + return -1;
> +
> + hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb);
> + hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb);
> +
> + fprintf(stderr, "Resolve %u %u -> %u %u\n",
> + hostdev->source.subsys.u.usb.vendor,
> + hostdev->source.subsys.u.usb.product,
> + hostdev->source.subsys.u.usb.bus,
> + hostdev->source.subsys.u.usb.device );
> +
> + usbFreeDevice(usb);
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int
> +qemuPrepareHostDevices(struct qemud_driver *driver,
> + virDomainDefPtr def)
> +{
> + if (!def->nhostdevs)
> + return 0;
> +
> + if (qemuPrepareHostPCIDevices(driver, def) < 0)
> + return -1;
> +
> + if (qemuPrepareHostUSBDevices(driver, def) < 0)
> + return -1;
> +
> + return 0;
> +}
> +
> +
> static void
> qemudReattachManagedDevice(pciDevice *dev)
> {
> @@ -6114,6 +6168,23 @@ static int qemudDomainAttachHostDevice(struct qemud_driver *driver,
> return -1;
> }
>
> + /* Resolve USB product/vendor to bus/device */
> + if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB &&
> + hostdev->source.subsys.u.usb.vendor) {
> + usbDevice *usb
> + = usbFindDevice(hostdev->source.subsys.u.usb.vendor,
> + hostdev->source.subsys.u.usb.product);
> +
> + if (!usb)
> + return -1;
> +
> + hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb);
> + hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb);
> +
> + usbFreeDevice(usb);
> + }
> +
> +
> if (driver->securityDriver &&
> driver->securityDriver->domainSetSecurityHostdevLabel &&
> driver->securityDriver->domainSetSecurityHostdevLabel(vm, hostdev) < 0)
> @@ -6677,11 +6748,22 @@ static int qemudDomainDetachHostUsbDevice(struct qemud_driver *driver,
>
> unsigned bus = vm->def->hostdevs[i]->source.subsys.u.usb.bus;
> unsigned device = vm->def->hostdevs[i]->source.subsys.u.usb.device;
> -
> - if (dev->data.hostdev->source.subsys.u.usb.bus == bus &&
> - dev->data.hostdev->source.subsys.u.usb.device == device) {
> - detach = vm->def->hostdevs[i];
> - break;
> + unsigned product = vm->def->hostdevs[i]->source.subsys.u.usb.product;
> + unsigned vendor = vm->def->hostdevs[i]->source.subsys.u.usb.vendor;
> +
> + if (dev->data.hostdev->source.subsys.u.usb.bus &&
> + dev->data.hostdev->source.subsys.u.usb.device) {
> + if (dev->data.hostdev->source.subsys.u.usb.bus == bus &&
> + dev->data.hostdev->source.subsys.u.usb.device == device) {
> + detach = vm->def->hostdevs[i];
> + break;
> + }
> + } else {
> + if (dev->data.hostdev->source.subsys.u.usb.product == product &&
> + dev->data.hostdev->source.subsys.u.usb.vendor == vendor) {
> + detach = vm->def->hostdevs[i];
> + break;
> + }
> }
> }
>
> diff --git a/src/qemu/qemu_security_dac.c b/src/qemu/qemu_security_dac.c
> index f281b96..6911f48 100644
> --- a/src/qemu/qemu_security_dac.c
> +++ b/src/qemu/qemu_security_dac.c
> @@ -206,9 +206,7 @@ qemuSecurityDACSetSecurityHostdevLabel(virDomainObjPtr vm,
> switch (dev->source.subsys.type) {
> case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
> usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus,
> - dev->source.subsys.u.usb.device,
> - dev->source.subsys.u.usb.vendor,
> - dev->source.subsys.u.usb.product);
> + dev->source.subsys.u.usb.device);
>
> if (!usb)
> goto done;
> @@ -277,9 +275,7 @@ qemuSecurityDACRestoreSecurityHostdevLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED,
> switch (dev->source.subsys.type) {
> case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
> usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus,
> - dev->source.subsys.u.usb.device,
> - dev->source.subsys.u.usb.vendor,
> - dev->source.subsys.u.usb.product);
> + dev->source.subsys.u.usb.device);
>
> if (!usb)
> goto done;
> diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
> index 06a2479..b2c8581 100644
> --- a/src/security/security_selinux.c
> +++ b/src/security/security_selinux.c
> @@ -491,9 +491,7 @@ SELinuxSetSecurityHostdevLabel(virDomainObjPtr vm,
> switch (dev->source.subsys.type) {
> case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
> usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus,
> - dev->source.subsys.u.usb.device,
> - dev->source.subsys.u.usb.vendor,
> - dev->source.subsys.u.usb.product);
> + dev->source.subsys.u.usb.device);
>
> if (!usb)
> goto done;
> @@ -561,9 +559,7 @@ SELinuxRestoreSecurityHostdevLabel(virDomainObjPtr vm,
> switch (dev->source.subsys.type) {
> case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
> usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus,
> - dev->source.subsys.u.usb.device,
> - dev->source.subsys.u.usb.vendor,
> - dev->source.subsys.u.usb.product);
> + dev->source.subsys.u.usb.device);
>
> if (!usb)
> goto done;
> diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c
> index 066e18b..78bef41 100644
> --- a/src/security/virt-aa-helper.c
> +++ b/src/security/virt-aa-helper.c
> @@ -836,9 +836,7 @@ get_files(vahControl * ctl)
> switch (dev->source.subsys.type) {
> case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
> usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus,
> - dev->source.subsys.u.usb.device,
> - dev->source.subsys.u.usb.vendor,
> - dev->source.subsys.u.usb.product);
> + dev->source.subsys.u.usb.device);
>
> if (usb == NULL)
> continue;
> diff --git a/src/util/hostusb.c b/src/util/hostusb.c
> index bf96539..afba325 100644
> --- a/src/util/hostusb.c
> +++ b/src/util/hostusb.c
> @@ -159,9 +159,7 @@ cleanup:
>
> usbDevice *
> usbGetDevice(unsigned bus,
> - unsigned devno,
> - unsigned vendor,
> - unsigned product)
> + unsigned devno)
> {
> usbDevice *dev;
>
> @@ -170,14 +168,6 @@ usbGetDevice(unsigned bus,
> return NULL;
> }
>
> - if (vendor) {
> - /* Look up bus.dev by vendor:product */
> - if (usbFindBusByVendor(vendor, product, &bus, &devno) < 0) {
> - VIR_FREE(dev);
> - return NULL;
> - }
> - }
> -
> dev->bus = bus;
> dev->dev = devno;
>
> @@ -194,6 +184,21 @@ usbGetDevice(unsigned bus,
> return dev;
> }
>
> +
> +usbDevice *
> +usbFindDevice(unsigned vendor,
> + unsigned product)
> +{
> + unsigned bus = 0, devno = 0;
> +
> + if (usbFindBusByVendor(vendor, product, &bus, &devno) < 0) {
> + return NULL;
> + }
> +
> + return usbGetDevice(bus, devno);
> +}
> +
> +
> void
> usbFreeDevice(usbDevice *dev)
> {
> @@ -202,6 +207,18 @@ usbFreeDevice(usbDevice *dev)
> }
>
>
> +unsigned usbDeviceGetBus(usbDevice *dev)
> +{
> + return dev->bus;
> +}
> +
> +
> +unsigned usbDeviceGetDevno(usbDevice *dev)
> +{
> + return dev->dev;
> +}
> +
> +
> int usbDeviceFileIterate(usbDevice *dev,
> usbDeviceFileActor actor,
> void *opaque)
> diff --git a/src/util/hostusb.h b/src/util/hostusb.h
> index bc22671..9a1b1b7 100644
> --- a/src/util/hostusb.h
> +++ b/src/util/hostusb.h
> @@ -26,11 +26,14 @@
>
> typedef struct _usbDevice usbDevice;
>
> -usbDevice *usbGetDevice (unsigned bus,
> - unsigned devno,
> - unsigned vendor,
> - unsigned product);
> -void usbFreeDevice (usbDevice *dev);
> +usbDevice *usbGetDevice(unsigned bus,
> + unsigned devno);
> +usbDevice *usbFindDevice(unsigned vendor,
> + unsigned product);
> +void usbFreeDevice (usbDevice *dev);
> +
> +unsigned usbDeviceGetBus(usbDevice *dev);
> +unsigned usbDeviceGetDevno(usbDevice *dev);
>
> /*
> * Callback that will be invoked once for each file
Okay, it's a bit of a lng patch but makes sense with the explanations,
ACK,
Daniel
--
Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/
daniel at veillard.com | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library http://libvirt.org/
More information about the libvir-list
mailing list