Проброс USB в виртуалку по сети средствами UsbRedir и QEMU

Материал из support.qbpro.ru

На сегодняшний день существет довольно много способов пробросить USB-устройство на другой компьютер или виртуалку по сети. Из наиболее популярных — железячные такие как AnywhereUSB и чисто програмные продукты, из тех что я попробовал сам: USB Redirector и USB/IP. Я бы хотел рассказать вам еще об одном интересном способе, который работает непосредственно с эмулятором QEMU. Он так же является частью проекта spice, официально поддерживаемым RedHat.

UsbRedir, это открытый протокол для проброса usb-устройств по tcp на удаленный виртуальный сервер, разработанный при поддержке RedHat в рамках проекта spice. Но как оказалось им можно вполне успешно пользоваться и без spice. В роли сервера выступает usbredirserver, который шарит usb-устройство на определенный порт, а в качестве клиента сам QEMU, который эмулирует подключение экспортированного usb-устройства в определенный usb-контроллер вашей виртуальной машины. Благодаря такому подходу в качестве гостевой системы может использоваться абсолютно любая ОС, так как она даже не знает, что устройство является проброшенным удаленно, а вся логика ложится на QEMU.

Для начала несколько слов о вышеперчисленных решениях

   AnywhereUSB — довольно неплохое решение, но дорогое, и имеет неприятние глюки, например бывает если расшаренная флешка
отваливается, то переподключить ее обратно можно только физически вынув и вставив ее. USB/IP — OpenSource проект. Вроде как был заброшен. По факту глючит довольно сильно. При разрыве соединения, машина частенько
уходит в полнейший freezee, а windows показывает BSOD USB Redirector — Замечательная софтина. Для расшаривания устройств с linux на linux бесплатна, во всех остальных случаях уже стоит денег, не так много как AnywhereUSB, но и не бесплатно как хотелось бы :)


Как видно есть из чего выбрать, но давайте же наконец попробуем еще один способ — UsbRedir?

Настройка виртуальной машины


Для того что бы было куда подключать экспортированные устройства, на виртуальной машине нужно создать необходимые usb-контроллеры:

   uhci — для USB1.0
   ehci — для USB2.0
   xhci — для USB3.0


Для qemu (без libvirt)


Добавьте опции в команду запуска виртуальной машины:

-device ich9-usb-ehci1,id=ehci,addr=1d.7,multifunction=on
-device ich9-usb-uhci1,id=uhci-1,addr=1d.0,multifunction=on,masterbus=ehci.0,firstport=0
-device ich9-usb-uhci2,id=uhci-2,addr=1d.1,multifunction=on,masterbus=ehci.0,firstport=2
-device ich9-usb-uhci3,id=uhci-3,addr=1d.2,multifunction=on,masterbus=ehci.0,firstport=4


Для libvirt

В исходном файле конфигурации виртуальной машины в узле <devices> удаляем все USB контроллеры и добавляем следущий блок:

<controller type='usb' index='0' model='ich9-ehci1'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x7'/>
</controller>
<controller type='usb' index='0' model='ich9-uhci1'>
<master startport='0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0' multifunction='on'/>
</controller>
<controller type='usb' index='0' model='ich9-uhci2'>
<master startport='2'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x1'/>
</controller>
<controller type='usb' index='0' model='ich9-uhci3'>
<master startport='4'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x2'/>
</controller>


Кстати, если вы используете spice, то добавив к контроллерам еще 3 специальных девайса, станет возможен проброс usb-устройств с клиента spice на сервер. Пример под спойлером Для qemu

Добавляем следующие опции в команду запуска виртуальной машины, помимо контроллеров определеных нами раньше:

-chardev spicevmc,name=usbredir,id=usbredirchardev1
-device usb-redir,chardev=usbredirchardev1,id=usbredirdev1,debug=3
-chardev spicevmc,name=usbredir,id=usbredirchardev2
-device usb-redir,chardev=usbredirchardev2,id=usbredirdev2,debug=3
-chardev spicevmc,name=usbredir,id=usbredirchardev3
-device usb-redir,chardev=usbredirchardev3,id=usbredirdev3,debug=3


Для libvirt

В исходном файле конфигурации виртуальной машины в узле <devices> добавляем следующие опции, помимо контроллеров определеных нами раньше:

<redirdev bus='usb' type='spicevmc'><address type='usb' bus='0' port='3'/></redirdev>
<redirdev bus='usb' type='spicevmc'><address type='usb' bus='0' port='4'/></redirdev>
<redirdev bus='usb' type='spicevmc'><address type='usb' bus='0' port='5'/></redirdev>
<redirdev bus='usb' type='spicevmc'><address type='usb' bus='0' port='6'/></redirdev>



Теперь все готово для осуществления проброса.

Запуск сервера

Пакет usbredirserver можно найти в стандартных репозиториях практически во всех популярных дистрибутивах linux.

Вставляем флешку в компьютер, смотрим вывод usb-устройств:

$ lsusb
...
Bus 003 Device 011: ID 125f:c82a A-DATA Technology Co., Ltd. 
...


Видим что пара vendorid:prodid равна 125f:c82a, а ядро определило флешке 003-001 usbbus-usbaddr соотвественно.

Теперь давайте расшарим ее на 4000 порт:

# Используя пару vendorid:prodid
$ usbredirserver -p 4000 125f:c82a
# Используя пару usbbus-usbaddr
$ usbredirserver -p 4000 003-011


Подключение устройства к виртуальной машине


Через опции при запуске ВМ


Устройство которое нужно подключить к ВМ можно указать при запуске, добавив следующие опции в команду запуска

Для qemu

-chardev socket,id=usbredirchardev1,port=4000,host=192.168.1.123
-device usb-redir,chardev=usbredirchardev1,id=usbredirdev1,bus=ehci.0,debug=4


Для libvirt

Этот блок рамещается перед тегом </devices>, рядом с контроллерами определенными нами раньше:

<redirdev bus='usb' type='tcp'>
</redirdev>

Его так же можно исполнить командой virsh attach-device

Или через qemu-monitor

Заходим на гипервизор и в qemu-monitor нашей машины выполняем следующие команды:

# Добавляем наше устройство
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


Что бы отключить флешку достаточно такой команды:

device_del usbredirdev1


На этом все, после данных шагов ваша ВМ увидит вашу флешку и сможет с ней нативно работать.

Если устройств много и все они одинаковые

Вот тут появилась интересная задачка, как пробросить несколько одинаковых девайсов на разные ВМ? При этом, стоит отметить, все устройства имеют одинаковую пару vendorid:prodid, а пара usbbus-usbaddr совсем не постоянна, стоит только вынуть и вставить устройство, так оно сразу поменяет свой usbaddr.

Я решил ее при помощи udev. Кстати если вы не совсем понимаете как работает udev, на Debian Wiki есть классная статья о udev

И так приступим

Для начала нам надо узнать серийник нашего устройства, по которому и будем идентифицировать его в udev:

Запустим udev-монитор:

$ udevadm monitor --environment --udev


И вставим наше устройство, после этого мы сразу увидим список переменных этого устройства которые udev любезно инициализировал для нас:

...
UDEV  [189056.151508] add      /devices/virtual/bdi/8:16 (bdi)
ACTION=add
DEVPATH=/devices/virtual/bdi/8:16
ID_SERIAL_SHORT=11C130317234004B
SEQNUM=4352
SUBSYSTEM=bdi
USEC_INITIALIZED=189056149826
...


Информацию о серийнике и других аттрибутах можно получить и другим способом, но стоит учитывать что для написания правил мы будем использовать именно переменные из команды выше, а не аттрибуты из команды ниже. В противном случае не будет отрабатывать триггер remove при отключении устройства.

$ udevadm info -a -n /dev/bus/usb/003/011 | grep '{serial}'


Теперь создадаим файл /etc/udev/rules.d/99-usb-serial.rules и запишем в него следующие правила:

ACTION=="add", ENV{ID_SERIAL_SHORT}="11C130317234004B", RUN+="/usr/bin/usbredirserver -p 4000 $attr{busnum}-$attr{devnum}"
ACTION=="remove", ENV{ID_SERIAL_SHORT}="11C130317234004B", RUN+="/usr/bin/fuser -k 4000/tcp"


Перезагрузим udev-правила:

$ udevadm control --reload-rules


Готово, теперь при подключении нашего устройства, оно будет автоматически шарится на нужный нам порт, а при отключении usbredirserver будет прекращать свою работу. По аналогии добавляем и остальные устройства.

На этом все. Спасибо за проявленный интерес :)

взято тут...

* Иногда, особенно в Win7(x64) при создании конфигурации по умолчанию, потом не пробрасывается нормально USB устройство. Для решения такой проблемы, удалите все USBREDIRECTOR, а потом добавьте необходимое устройство. Все должно работать.