Using USB pass-through under libvirt and KVM

Virtualization solutions typically include a feature called USB pass-through: making a USB device attached to the host machine appear directly as a USB device attached to a virtual machine. KVM, the fully open-source virtualization solution for Linux, can do USB pass-through. It inherits this feature from QEMU, which KVM incorporates to provide system and device virtualization (KVM proper is focused on processor virtualization, and runs in kernel space; QEMU runs in user space).

But there's a hitch: KVM is most often used via libvirt and virt-manager, which provide a virtualization management infrastructure and graphical user interface. libvirt has some support for USB pass-through; but virt-manager doesn't support it at all. So here's a guide to using the libvirt command shell to get to this feature. These instructions require somewhat recent versions of KVM (74 and up) and libvirt (0.4.4 and up).

You will need to hand-edit the XML documents that libvirt uses to describe virtual machine instances (domains, in libvirt terminology). You do this via virsh, the command shell included with libvirt. virsh is fairly spartan, though it does have a decent on-line help facility (accessed via the help command). Run virsh as root, and use the list command to see your VM instances and their names:

virsh # list --all
 Id Name                 State
  - windowsxp            shut off

If list --all didn't show any VM instances, you should create some using virt-manager.

You can view the domain definition XML with the dumpxml command:

virsh # dumpxml windowsxp
<domain type='kvm'>

The edit command will open the domain definition XML in an editor:

virsh # edit windowsxp
Edit the XML as desired
Domain windowsxp XML configuration edited.

Update: I recently noticed that the edit command only appeared in libvirt version 0.4.5. Some current editions of popular Linux distributions still have an earlier version. In that case, you can edit the XML domain definition files under /etc/libvirt/qemu directly, but you will need to restart libvirtd afterwards.

We want to edit this XML to add a hostdev element as documented here on the libvirt site. But first, you need to work out the USB vendor and product IDs for the relevant device. You can discover these by attaching the device and running /sbin/lsusb on the host. For example, here's the lsusb output on my laptop:

$ /sbin/lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 005 Device 012: ID 0a5c:2110 Broadcom Corp. Bluetooth Controller
Bus 005 Device 003: ID 0483:2016 SGS Thomson Microelectronics Fingerprint Reader
Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

The pairs of hexadecimal numbers on each line are the vendor and produce IDs. For example, the bluetooth controller has a vendor ID of 0a5c, and a product ID of 2110.

To forward that to my windowsxp VM, I edit the domain definition as follows:

<domain type='kvm'>
    <hostdev mode='subsystem' type='usb'>
        <vendor id='0x0a5c'/>
        <product id='0x2110'/>

Note that it's a good idea to prevent the host from using the device before attaching it to a VM. In this case, I made sure the bluetooth controller was not being used by removing the relevant kernel modules with rmmod. For USB storage devices, it's sufficient to make sure that they are not mounted by the host kernel. And for custom USB devices, without drivers in the Linux kernel, it won't try to do anything with them, so you're usually fine.

There are a couple of limitations to this USB pass-through support. The first is that the change won't take effect until you next start the VM. The second is that it only works if the USB device in question is connect at the time you start the VM. That's quite a serious restriction. It's often convenient, and sometimes necessary, to be able to connect a device to, and disconnect it from, a running machine. In a follow-up post, I'll describe a way to avoid this limitation. It's now up here.

But once it's in operation, this USB pass-through support does work well. I've used it with a range of USB devices, with complete success.

Comment from Divan

I've tried this with ubuntu 9.04 jaunty but the auto libvirt usb passthrough doesn't seem to work.

I can get it working manually as per this howto and it see the usb etc however if I try write or access it the windows VM slows down so much it almost/and sometimes does freeze. Any ideas?

Comment from El AdministraDero

When say "it's sufficient to make sure that they are not mounted by the host kernel" meaning is that the filesystem isn't mounted, or realy mean is that usb_storage is not loaded?


Comment from Management Dissertation Help

Whenever i see the post like your's i feel that there are still helpful people who share information for the help of others, it must be helpful for other's. thanx and good job.

Management Dissertation Proposal