How to Pass Through USB Devices to KVM Virtual Machines: A Step-by-Step Guide


2 views

When working with KVM virtualization, passing through USB devices to guest VMs can be particularly useful for scenarios like:

  • Testing USB hardware in isolated environments
  • Running proprietary USB dongle-protected software
  • Accessing specialized USB peripherals from within VMs

Before attempting USB passthrough, ensure your system meets these requirements:

# Verify KVM and libvirt are properly installed
$ virsh --version
$ lsmod | grep kvm

# Check USB controller support
$ lsusb -t

The first step is to properly identify your USB device on the host system:

$ lsusb
Bus 002 Device 004: ID 13fe:5100 Kingston Technology Company Inc. Flash Drive
Bus 002 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub

Note the vendor ID (13fe) and product ID (5100) for your target device.

There are two primary methods to attach USB devices to KVM VMs:

Method 1: Permanent Attachment via XML

Edit your VM's configuration using virsh:

$ virsh edit your_vm_name

Add the following device section:

<devices>
    <hostdev mode='subsystem' type='usb' managed='yes'>
        <source>
            <vendor id='0x13fe'/>
            <product id='0x5100'/>
        </source>
    </hostdev>
</devices>

Method 2: Temporary Hotplug Attachment

For temporary attachment without VM restart:

$ virsh attach-device your_vm_name usb_device.xml

Where usb_device.xml contains the same hostdev configuration as above.

If your USB device isn't appearing in the guest VM:

Permission Problems

Check and adjust udev rules if needed:

# Create a udev rule for your device
SUBSYSTEM=="usb", ATTR{idVendor}=="13fe", ATTR{idProduct}=="5100", MODE="0666"

AppArmor/SELinux Restrictions

Temporarily disable to test:

$ sudo systemctl stop apparmor
$ sudo setenforce 0

USB Controller Conflicts

Ensure your VM has proper USB controller definitions:

<controller type='usb' index='0' model='ich9-ehci1'/>
<controller type='usb' index='0' model='ich9-uhci1'/>

Inside your guest VM, verify the device appears:

$ lsusb
$ dmesg | grep usb

For Windows VMs, you may need additional drivers:

  1. Install VirtIO drivers in the Windows VM
  2. Use the following device definition:
<hostdev mode='subsystem' type='usb' managed='yes'>
    <source>
        <vendor id='0x13fe'/>
        <product id='0x5100'/>
    </source>
    <address type='usb' bus='0' port='1'/>
</hostdev>

For more flexible USB sharing:

$ sudo apt install spice-vdagent
$ virt-viewer --connect qemu:///system --spice-usbredir-auto-redirect-filter=0x03,-1,-1,-1,0

When working with KVM virtualization, passing through USB devices can be particularly challenging due to the complex interaction between host systems, virtual machines, and USB controllers. The key challenge lies in ensuring proper device isolation and driver handling between host and guest systems.

Before attempting USB passthrough, it's crucial to examine your VM configuration. The XML dump reveals several important aspects of your current setup:

<controller type='usb' index='0' model='ich9-ehci1'>
  <alias name='usb0'/>
  <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x7'/>
</controller>
<controller type='usb' index='0' model='ich9-uhci1'>
  <alias name='usb0'/>
  <master startport='0'/>
  <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0' multifunction='on'/>
</controller>

The error message indicating the USB device is in use by QEMU while remaining accessible on the host suggests a conflict in device ownership. This typically occurs when:

  • The host system maintains control over the USB device
  • Permissions prevent proper device handoff
  • The VM lacks proper USB controller support

Here's a more robust approach to USB passthrough:

# First, identify the USB device
lsusb -v

# Then detach it from the host kernel driver
sudo sh -c "echo 0 > /sys/bus/usb/devices/2-4/bConfigurationValue"
sudo sh -c "echo -n '2-4' > /sys/bus/usb/drivers/usb/unbind"

# Modify your VM configuration with virsh edit
<hostdev mode='subsystem' type='usb' managed='no'>
  <source>
    <vendor id='0x13fe'/>
    <product id='0x5100'/>
    <address bus='2' device='4'/>
  </source>
  <address type='usb' bus='0' port='1'/>
</hostdev>

If the basic approach fails, consider these advanced methods:

# Check kernel messages for USB events
dmesg | grep -i usb

# Verify QEMU permissions
ls -l /dev/bus/usb/*/*

# Temporarily disable USB autosuspend
for i in /sys/bus/usb/devices/*/power/autosuspend; do
  echo -1 > $i
done

When direct passthrough fails, consider these alternatives:

  1. Use USB redirection via SPICE protocol
  2. Create a dedicated USB controller for the VM
  3. Implement USB/IP for network-based sharing
# Example of dedicated USB controller
<controller type='usb' index='1' model='nec-xhci'>
  <alias name='usb1'/>
  <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
</controller>