Pull to refresh

Проброс нескольких одинаковых устройств USB в виртуальную машину libvirt+QEMU

Reading time3 min
Views12K

Конфигурация.


Сервер виртуальных машин на GNU/Linux. Виртуальные машины Windows. Гипервизор QEMU-KVM.
Виртуальные машины запускаются автоматически.

Описание проблемы.


Для двух программ есть два электронных (лицензионных) ключа Guardant одной модели (у них одинаковые Vendor ID и Product ID). Чтобы не возникал конфликт, в libvirt в описании виртуальной машины такие ключи добавляются с указанием аппаратного адреса (bus, device). После перезагрузки может оказаться так, что номера устройств будут другие. А если переключить их в другой порт, то и номер шины может стать другим.

Неудачное решение


Первое, что пришло в голову после изучения документации — указать в конфигурации виртуальной машины все возможные bus и device для этих одинаковых USB-ключей. Но это породило неудобство при просмотре и редактировании виртуальной машины в Virt-Manager.

Окончательное решение.


Разбираться с UDEV желания не было. (Не знаю, можно ли в нём изменить номер устройства на шине USB, а изменить номер шины наверняка невозможно.)
Поэтому было применено максимально универсальное решение: в процессе загрузки после запуска виртуальной машины выполняется скрипт, который выясняет номера шины и номер устройства для каждого из одинаковых электронных ключей, формирует файл-описание устройств для libvirt (формата XML) и добавляет проброс этих устройств в виртуальную машину. Если в скрипте возникнет ошибка, она заносится в syslog и на stderr.
Чтобы не придумывать обработку start/stop/status и проверку зависимостей, скрипт добавлен в rc.local — он заведомо выполняется последним из стартовых скриптов.

Использование этого метода исключает переключение USB-ключей во время работы виртуальной машины — если вытащить ключ и вставить его в другой порт, он не будет подключен повторно. Для сервера это ограничение приемлимо.

Вывод lsusb (для справки), нужные устройства — пятое и шестое на третьей шине:
Bus 003 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 003 Device 003: ID 1a40:0101 Terminus Technology Inc. Hub
Bus 003 Device 008: ID 051d:0002 American Power Conversion Uninterruptible Power Supply
Bus 003 Device 004: ID 064f:0bd8 WIBU-Systems AG BOX/RU
Bus 003 Device 005: ID 0a89:0008
Bus 003 Device 006: ID 0a89:0008
Bus 004 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
Bus 004 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub


Текст скрипта:
#!/bin/sh
# libvirt-win-attach-guardant-keys
# attach all guardant keys into virtual machine "win"

VMachine="win"
MYDIR="/tmp/libvirt-guardant/"
SYSLOG="logger -s -p daemon.error "

if [ -d $MYDIR ]; then rm -f $MYDIR/*_*.xml ; else
 mkdir $MYDIR || ( $SYSLOG "Can't create $MYDIR" ; exit 1 )
fi
cd $MYDIR
echo "Attach guardant keys into virtual machine \"$VMachine\":"
lsusb | awk '/ID 0a89:0008/{gsub(":", "", $4);print "<hostdev mode=\"subsystem\" type=\"usb\" managed=\"yes\">\n <source>\n  <vendor id=\"0x0a89\" /><product id=\"0x8\" />\n  <address bus=\"" $2 "\" device=\"" $4 "\" />\n </source>\n</hostdev>" > ""$2"_"$4".xml"; }' ||  ( $SYSLOG "Error in lsusb|awk: $? $!" ; exit 1 )
for devxml in *_*.xml ; do echo "   USB_${devxml/.xml/} ..." ;  virsh attach-device $VMachine $devxml | grep -vE "^(Device attached successfully|$)" ; done
cd /tmp
rm -f $MYDIR/*.xml
rmdir $MYDIR
echo "Done."

Пояснение к тексту.

Для простоты программа для AWK передаётся в командной строке. При этом, чтобы избежать сложностей с экранированием кавычек и "$", внутри awk-программы переменные шела не используются. Поэтому сделан переход в созданный временный каталог, а также параметры устройств заданы константами (Vendor ID 0x0a89 и Product ID 0x0008).
Tags:
Hubs:
Total votes 18: ↑15 and ↓3+12
Comments11

Articles