На сегодняшний день существет довольно много способов пробросить 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)
Скачайте конфиг ehci-uhci.cfg, положите его в /etc/qemu/
$ curl http://cgit.freedesktop.org/spice/qemu/plain/docs/ich9-ehci-uhci.cfg --create-dirs -o /etc/qemu/ich9-ehci-uhci.cfg
И добавьте его в качестве опции в команду запуска виртуальной машины:
-readconfig /etc/qemu/ich9-ehci-uhci.cfg
Для 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>
Для libvirt (вариант второй)
Так как предыдущий вариант у меня почему-то не заработал, и я решил пойти другим путем, а именно явно указть libvirt конфиг который нужно подсунуть qemu:
Этот блок рамещается перед тегом </domain>:
<qemu:commandline>
<qemu:arg value="-readconfig"/>
<qemu:arg value="/etc/qemu/ich9-ehci-uhci.cfg"/>
</qemu:commandline>
Не забудьте так же скачать ehci-uhci.cfg и сохранить в /etc/qemu/ как в случае с qemu без libvirtКстати, если вы используете spice, то добавив к контроллерам еще 4 специальных девайса, станет возможен проброс usb-устройств с клиента spice на сервер.
Для qemu
$ curl http://cgit.freedesktop.org/spice/qemu/plain/docs/ich9-ehci-uhci.cfg --create-dirs -o /etc/qemu/ich9-ehci-uhci.cfg
Добавляем следующие опции в команду запуска виртуальной машины:
-readconfig /etc/qemu/ich9-ehci-uhci.cfg
-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> удаляем все 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>
<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>
Для libvirt (вариант второй)
Этот блок рамещается перед тегом </domain>:
<qemu:commandline>
<qemu:arg value="-readconfig"/>
<qemu:arg value="/etc/qemu/ich9-ehci-uhci.cfg"/>
<qemu:arg value="-chardev"/>
<qemu:arg value="spicevmc,name=usbredir,id=usbredirchardev1"/>
<qemu:arg value="-device"/>
<qemu:arg value="usb-redir,chardev=usbredirchardev1,id=usbredirdev1,bus=ehci.0,debug=3"/>
<qemu:arg value="-chardev"/>
<qemu:arg value="spicevmc,name=usbredir,id=usbredirchardev2"/>
<qemu:arg value="-device"/>
<qemu:arg value="usb-redir,chardev=usbredirchardev2,id=usbredirdev2,bus=ehci.0,debug=3"/>
<qemu:arg value="-chardev"/>
<qemu:arg value="spicevmc,name=usbredir,id=usbredirchardev3"/>
<qemu:arg value="-device"/>
<qemu:arg value="usb-redir,chardev=usbredirchardev3,id=usbredirdev3,bus=ehci.0,debug=3"/>
</qemu:commandline>
Не забудьте так же скачать конфиг ehci-uhci.cfg, и сохранить его в /etc/qemu/ как в случае с qemu без libvirtТеперь все готово для осуществления проброса.
Запуск сервера
Пакет 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
-device usb-redir,chardev=usbredirchardev1,id=usbredirdev1,bus=ehci.0,debug=4
Для libvirt
Этот блок рамещается перед тегом </domain>:
<qemu:commandline>
<qemu:arg value="-chardev"/>
<qemu:arg value="socket,id=usbredirchardev1,port=4000,host=192.168.1.123"/>
<qemu:arg value="-device"/>
<qemu:arg value="usb-redir,chardev=usbredirchardev1,id=usbredirdev1,bus=ehci.0,debug=4"/>
</qemu:commandline>
Или через 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
Если у вас libvirt, то команды в qemu-monitor можно отправить следующим образом:
$ virsh qemu-monitor-command --hmp my_vm 'chardev-add socket,id=usbredirchardev1,port=4000,host=192.168.1.123'
$ virsh qemu-monitor-command --hmp my_vm 'device_add usb-redir,chardev=usbredirchardev1,id=usbredirdev1,bus=ehci.0,debug=4'
$ virsh qemu-monitor-command --hmp my_vm '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 будет прекращать свою работу.
По аналогии добавляем и остальные устройства.
На этом все. Спасибо за проявленный интерес :)
UPD: Тем кому интересно, что из этого в итоге получилось, можете посмотреть здесь
Источники:
umvirt.ru/node/82
opennebula.org/opennebula-for-virtual-desktops
opennet.ru/opennews/art.shtml?num=30773
lists.gnu.org/archive/html/qemu-devel/2013-07/msg05244.html
askubuntu.com/questions/49910/how-to-distinguish-between-identical-usb-to-serial-adapters
Комментарии (16)
VGusev2007
21.08.2015 11:01Как считаете, возможно-ли пробросить таким образом USB2COM? Или подобные хитрые железки?
kvaps
21.08.2015 12:42Думаю что пробросить можно пробросить любое usb-устройство, которое определится и появится в /dev/bus/usb
VGusev2007
21.08.2015 13:52Я пришёл к выводу, что пробросить то можно всё что угодно… А вот реально работать может ДАЛЕКО, ДАЛЕКО не всё… То ли команды USB не все пробрасываются, или чего ещё… Пробовал в своё время: USB/IP — не работало. Пробовал пробрасывать через настройки ESXi — не заработало.
В любом случае, спасибо за статью. Надо попробовать. Но если у Вас будет возможность пробросить что-то специфическое — будет здорово. Есть же всякие, видеокарты USB, видеотюнеры… — Но я предлагаю, Вам попробовать пробросить USB видеокамеру… — По-моему отличный тест будет!kvaps
21.08.2015 19:57Я уже пробрасывал встроенную в ноутбук камеру таким образом, вот вам пара скриншотов для подтверждения
VGusev2007
22.08.2015 00:19Выглядит обнадёживающе… Хочу пробросить таким образом USB2COM, чтобы считывать показания с древних электроустановок на работе.
Turilion
21.08.2015 16:03Не совсем понимаю зачем такой огород городить, если устройство можно просто воткнуть в usb порт на хосте и пробросить в виртуалку штатными средствами qemu.
kvaps
21.08.2015 20:38+1В данной статье хотелось описать именно удаленный проброс usb, то есть с одного компьютера на гипервизор, а не в пределах одного гипервизора.
Кстати, как было сказано выше в статье, после подобной настроки qemu, станет возможен проброс usb по протоколу spice простым пользователям через virt-viewerTurilion
24.08.2015 01:07Ну если так, то и тут есть куча более простых решений, навскидку сразу USB-over-Network. Клиент-серверная фигня, причём позволяет пробросить что угодно куда угодно, главное, что бы были USB.
PS к тому же кроссплатформенная, и когда последний раз смотрел была ещё и бесплатная)
jkreet
24.09.2015 00:11Нужно пробросить HASP в виртуалку на Proxmox 3.4
ОС в виртуалке — Win2012 R2
Делаю всё по вашей инструкции, устройства пробрасываются, но в Windows возникает ошибка USB\DEVICE_DESCRIPTOR_FAILURE
Пробовал также другие USB-устройства (флешка, сетевушка и пр.) — результат тот же.
Подскажите, в чём может быть проблема?
amaranth
Можно ли пробросить с помощью данной методики Sentinel HL на HyperV под управлением Windows Server 2012?
kvaps
Неа, работает только в связке с qemu
ink08
Можно, если на Windows поставить клиент и подключаться по сети к серверу. Но такая связка уже денег стоит
amaranth
Какой клиент?
ink08
ответил в личку
kvaps
Вы точно не путаете UsbRedir с USB Redirector?
ink08
Да, точно, я USB Redirector имел в виду