USB pass-through with libvirt and KVM, part two

A recent post here discussed how to enable USB pass-through under libvirt. But the technique there only allowed devices to be added when a VM was next started; you couldn't connect devices to a running VM.

This is a fairly major limitation. At best, the need to restart the VM is inconvenient. At worst, it makes the use of a USB device impossible. The full use of many USB devices involves disconnecting and reconnecting them to a running machine.

Recent versions of QEMU (and so KVM) do in fact have support for this; it's just that libvirt doesn't expose it. The QEMU support involves marking USB devices (identified by a vendor/product ID pair) for autoconnect. QEMU will then listen for connection events from the host OS, and repond to connections from the relevant devices by signalling a connection of the pass-through device to an emulated USB hub within the VM.

When libvirt runs KVM/QEMU, it specifies the pass-through USB devices through command line options. So by introducing a wrapper script that rewrites the command line options, we can enable autoconnect under libvirt.

Note that you will need a recent version of the KVM userspace support for this to work. It works for me with kvm-84. kvm-74, as included in Fedora 10 and Ubuntu 8.10 is not recent enough.

Here is the script I use:

#!/bin/sh
exec /usr/bin/qemu-kvm `echo $* | sed 's|-usbdevice host:\([^ ]*\)|-usbdevice host:auto:*.*:\1|g'`

Note that different Linux distributions use slightly different names for the KVM/QEMU binary. /usr/bin/qemu-kvm above is correct for RHEL/Fedora systems; under Ubuntu, you should substitute /usr/bin/kvm.

Save the script as /etc/libvirt/qemu/qemu-kvm, and make it executable. With that in place, you need to tell libvirt to use it instead of the real KVM binary. Do that by editing the VM XML description as described in my previous post. You need to edit the //domain/devices/emulator entry to refer to the wrapper script, e.g.

<domain type='kvm'>
  <name>windowsxp</name>
  …
  <devices>
    <emulator>/etc/libvirt/qemu/qemu-kvm</emulator>
    …
  </devices>
</domain>

Restart the relevant VMs, and USB pass-through with autoconnect should now work.

It's tempting to ask why this functionality isn't built-in to libvirt. My impression is that they are aiming for something more ambitious: The ability to enumerate devices on the host and then selectively pass those through to running VMs. This will be good when it's done, it's just a shame that it isn't there yet.

Comment from Andy Schiller

This is what I was looking for sometime now. Thanks!

Two things though:
1) You have a little error on your XML - it should read:

<devices>
<emulator>/etc/libvirt/qemu/qemu-kvm</emulator>
...
</devices>

2) I'm doing this on Ubuntu Jaunty right now. There is /usr/bin/kvm the original emulator from your wrapper.

Another thing: Could you please point us to where the auto-option is documented?

Comment from David

Hi Andy,

Thanks for letting me know about the XML mistake - it's fixed now.

As far as I know, the usbdevice auto option is undocumented outside of the qemu source code.

Comment from Daniel

I had no idea the ':auto' option even existed for QEMU. I'm not sure how we'd deal with this in libvirt, but I'd certainly like to try and figure out a way - it'd be very useful to be able to specify the device at startup and have it auto-connect/disconnect as you hot-plug/unplug in the host machine. Feel free to file a bug against libvirt, or start a topic on the mailing list about getting this officially supported...

Daniel (libvirt lead developer)

Comment from Anonymous

I get this when running the wrapper script:

error: internal error unable to start guest: libvir: error : cannot execute binary /etc/libvirt/qemu/qemu-kvm: Permission denied

Im running virsh as sudo on ubuntu. 775 permissions on file and it looks like your example. Funnily enough, with an older winXP guest initially created in VMware and converted a couple of years ago to QEMU, this worked fine. It is only with a very recently (5 days ago) built winXP VM, created with virt-install, that this is an issue. weird. Any ideas?

Comment from EcclesialDreamer

I am getting the same error Anonymous posted above when I try this. Hopefully I can figure it out. Thanks for posting this.

Comment from tarheelcoxn

I had to edit both /etc/apparmor.d/abstractions/libvirt-qemu and /etc/apparmor.d/usr.sbin.libvirtd to add the following:

/usr/local/bin/qemu-usb-passthrough-kvm Ux,

And then it worked.

Comment from tarheelcoxn

Err. Note that if you were following this howto more closely, you would use /etc/libvirt/qemu/qemu-kvm instead of /usr/local/bin/qemu-usb-passthrough-kvm (in case that wasn't obvious.

Comment from Anonymous

Seems it doesn't work for me:
internal error cannot parse QEMU version number in ''

QEMU PC emulator version 0.12.3 (qemu-kvm-0.12.3), Copyright (c) 2003-2008 Fabrice Bellard

Ubuntu 64 10.04 with all updates
I did changes exacly as described here:
/etc/libvirt/qemu/VMxml.xml:
/etc/libvirt/qemu/qemu-kvm
/etc/libvirt/qemu/qemu-kvm:
#!/bin/sh
exec /usr/bin/kvm `echo $* | sed 's|-usbdevice host:\([^ ]*\)|-usbdevice host:auto:*.*:\1|g'`
chmod 755 on file
works fine with --help

There is no qspice-libs or any spice package in Ubuntu. Any advices?