Forwarding USB to a virtual machine over a network using UsbRedir and QEMU
Tutorial
Today, there are quite a few ways to transfer a USB device to another computer or virtual machine over the network.
Of the most popular - hardware such as AnywhereUSB and purely software products, of those that I tried myself: USB Redirector and USB / IP.
I would like to tell you about another interesting method that works directly with the QEMU emulator.
It is also part of the spice project officially supported by RedHat.
UsbRedir is an open protocol for forwarding usb devices via tcp to a remote virtual server developed with RedHat support as part of the spice project. But as it turned out, it can be quite successfully used without spice. Usbredirserver acts as a server, which fumbles a usb device to a specific port, and QEMU itself as a client, which emulates the connection of an exported usb device to a specific usb controller of your virtual machine. Thanks to this approach, absolutely any OS can be used as a guest system, since it does not even know that the device is forwarded remotely, and all the logic rests on QEMU.
First, a few words about the above solutions
AnywhereUSB is a pretty good solution, but expensive and has unpleasant glitches, for example, if the shared flash drive falls off, then you can reconnect it only by physically removing and inserting it.
USB / IP - OpenSource project. It seems like it was abandoned. In fact, it's pretty buggy. When the connection is broken, the machine often goes into a complete freezee, and windows shows BSOD
USB Redirector - Great software. To share devices from linux to linux is free, in all other cases it already costs money, not as much as AnywhereUSB, but not for free as we would like :)
Apparently there is plenty to choose from, but let's finally try another way - UsbRedir?
Virtual machine setup
In order to connect exported devices to the virtual machine, you need to create the necessary usb controllers:
In the source virtual machine configuration file in the node we remove all USB controllers and add the following block:
By the way, if you use spice, then adding 3 more special devices to the controllers, it will be possible to forward usb devices from the spice client to the server.
Example under the spoiler
For qemu
We add the following options to the start command of the virtual machine, in addition to the controllers that we defined earlier:
This block is placed before the tag. , next to the controllers we defined earlier:
It can also be executed with the virsh attach-device command
Or via qemu-monitor
We go to the hypervisor and in qemu-monitor of our machine we execute the following commands:
# Добавляем наше устройство
chardev-add socket,id=usbredirchardev1,port=4000,host=192.168.1.123
# Подключем его в ehci контроллер (USB-2.0)
device_add usb-redir,chardev=usbredirchardev1,id=usbredirdev1,bus=ehci.0,debug=4
To disable the flash drive, such a command is enough:
device_del usbredirdev1
That's all, after these steps, your VM will see your flash drive and will be able to work with it natively.
If there are many devices and they are all the same
Here an interesting problem appeared, how to forward several identical devices to different VMs?
In this case, it is worth noting that all devices have the same vendorid: prodid pair, and the usbbus-usbaddr pair is not at all constant, you just need to remove and insert the device, so it will immediately change its usbaddr.
I solved it with udev.
By the way, if you don’t quite understand how udev works, there is a cool article on udev on the Debian Wiki
So let's get started
First, we need to find out the serial number of our device, by which we will identify it in udev:
Run the udev monitor:
$ udevadm monitor --environment --udev
And insert our device, after that we will immediately see a list of variables of this device that udev kindly initialized for us:
Information about the serial and other attributes can be obtained in another way, but it is worth considering that for writing the rules we will use the variables from the command above, and not the attributes from the command below. Otherwise, the remove trigger will not work when the device is turned off.
$ udevadm info -a -n /dev/bus/usb/003/011 | grep '{serial}'
Now create the file /etc/udev/rules.d/99-usb-serial.rules and write the following rules into it:
Done, now when you connect our device, it will automatically fumble on the port we need, and when you disconnect usbredirserver will stop its work.
By analogy, we add the remaining devices.
That's all. Thank you for your interest :)
UPD: Those who are interested in what came of it in the end, you can look here