Intéressé par des cours d'informatique en ligne ?
Visitez mon nouveau site https://www.yesik.it !

Que ce soit à titre personnel ou dans ma pratique professionnelle, je privilégie systématiquement Linux ou les systèmes Unix-like. Mais je dois aussi compter avec monde dans lequel Windows reste une plate-forme répandue. Il m'arrive donc régulièrement de devoir préparer des manipulations destinées aux utilisateurs du système d'exploitation de Microsoft. La virtualisation avec KVM me permet de composer avec cette contrainte: ainsi, sur mon portable sous Debian, je dispose de quelques machines virtuelles installées avec l'une ou l'autre des versions de Windows, que je peux transporter partout et utiliser quand c'est nécessaire.

C'est dans ce contexte que j'ai été amené à préparer récemment des tutoriels d'initiation pour la carte Arduino destinés à des utilisateurs de PC sous Windows. Je me suis donc demandé comment accéder à un périphérique USB à partir d'une machine virtuelle KVM. Et, comme vous allez le voir, les choses sont des plus simples … une fois le périphérique identifié et ses permissions ajustées.

Partager le périphérique

Obtenir les identifiants de produit et de vendeur

Une étape préliminaire avant de partager un périphérique USB entre un hôte et une machine virtuelle KVM est d'obtenir les identifiants de vendeur et de produit du périphérique USB considéré.

La première source d'information pour obtenir ces informations est le journal du noyau. Celui-ci contient un certain nombre d'informations permettant d'identifier précisément le périphérique USB. Vous pouvez y accéder en examinant le fichier /var/log/syslog ou à l'aide de la commande dmesg:

# Connecter le périphérique USB maintenant
sh$ dmesg | tail
usb 2-1.2.6: new full speed USB device using ehci_hcd and address 84
usb 2-1.2.6: New USB device found, idVendor=0403, idProduct=6001
usb 2-1.2.6: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 2-1.2.6: Product: FT232R USB UART
usb 2-1.2.6: Manufacturer: FTDI

Plus simplement, si elle est disponible sur votre système, vous pouvez utiliser la commande lsusb (du paquet usbutils sous Debian):

sh$ lsusb
Bus 002 Device 084: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC
Bus 002 Device 078: ID 058f:6361 Alcor Micro Corp. Multimedia Card Reader
Bus 002 Device 054: ID 046d:c062 Logitech, Inc. 
Bus 002 Device 053: ID 2001:f103 D-Link Corp. DUB-H7 7-port USB 2.0 hub
Bus 002 Device 002: ID 8087:0020 Intel Corp. Integrated Rate Matching Hub
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 003: ID 0408:2fb1 Quanta Computer, Inc. 
Bus 001 Device 002: ID 8087:0020 Intel Corp. Integrated Rate Matching Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

Dans les deux cas, les informations à rechercher sont:

  1. le nom du périphérique (ici FT232R USB UART) – pour s'assurer que c'est bien celui qui vous intéresse;
  2. et surtout ses identifiants de produit et de vendeur.
Produit ID vendeur ID produit
FTDI FT232 USB UART CI 0403 6001

Dans mon exemple, bien que ce soit une carte Arduino Nano qui a été connectée, vous voyez qu'il est plutôt fait référence à un adaptateur FT232R USB-Série. C'est simplement parce que les cartes Arduino utilisent le circuit FTDI FT232R pour supporter le port USB. C'est donc ce circuit qui s'annonce auprès de l'hôte à la connexion. D'après http://www.linux-usb.org/usb.ids, l'identifiant de vendeur 0403 correspond bien à Future Technology Devices International, Ltd (FTDI) et l'identifiant de produit 6001 est bien chez ce fabriquant celui du circuit FT232 USB-Serial.

Dernière chose à noter, et qui va prendre de l'importance tout bientôt, mon périphérique est relié au bus USB 2 de ma machine et a pour numéro de périphérique 84.

Adapter manuellement les permissions sur le périphérique...

Maintenant que nous savons précisément quel est le périphérique USB que nous ciblons, il faut s'assurer que les utilisateurs de KVM possèderont les permissions nécessaires pour y accéder. La commande ls va nous permettre de vérifier si c'est le cas. Il suffit de retrouver le périphérique dans l'arborescence de /dev grâce à son numéro de bus et son identifiant:

sh$ ls -ls /dev/bus/usb/002/084 
0 crw-rw-r-- 1 root root 189, 211 Dec 14 14:25 /dev/bus/usb/002/084

Comme vous le constatez, sur ma machine, ce périphérique n'est accessible en lecture/écriture que par root. Pour pouvoir l'utiliser à partir d'une machine virtuelle KVM lancée en tant qu'utilisateur non-privilégié du système, il va falloir modifier ces permissions – ou plutôt, ici, en changer le groupe propriétaire pour que les utilisateurs de KVM disposent des permissions nécessaires.

Bien sûr, vous pouvez la faire manuellement avec chgrp:

# Sous Debian, le groupe kvm contient les utilisateurs autorisés
# à utiliser (l'extension de virtualisation) KVM
sh# chgrp kvm /dev/bus/usb/002/084

Le problème avec cette technique, c'est que ce numéro de périphérique n'existe que tant qu'il est physiquement relié au bus USB. Si vous débranchez le périphérique il disparait de l'arborescence /dev. Et si vous le rebranchez, il revient sous un autre numéro et avec ses permissions par défaut…

...ou automatiquement en configurant udev

En effet, dans beaucoup de distributions Linux, les périphériques USB sont ajoutés et supprimés dynamiquement de l'arborescence /dev par udev. Il va donc falloir ajouter une règle pour ajuster automatiquement le groupe lors de la connexion du périphérique. Voici celle que j'ai utilisée dans mon cas:

sh# cat > /etc/udev/rules.d/90-local-FTDI-for-KVM.rules << EOF
# Set the group owner of FTDI F232-based boards
# to kvm in order to export them to KVM guests
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device",ATTR{idVendor}=="0403" , ATTR{idProduct}=="6001", MODE="0660",GROUP="kvm"
EOF
# Recharger les règles
sh# /etc/init.d/udev reload

Comme vous le voyez, cette nouvelle règle udev désigne le périphérique USB par son identifiant de vendeur et de produit, et définit son groupe à kvm.

Si je débranche puis rebranche mon Arduino Nano, je peux vérifier que les modifications sont bien apportées automatiquement:

sh$ lsusb -d 0403:6001
Bus 002 Device 085: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC
sh$ ls -ls /dev/bus/usb/002/085
0 crw-rw-r-- 1 root kvm 189, 213 Dec 14 14:48 /dev/bus/usb/002/085

Désormais, à chaque connexion au bus USB, le périphérique sera accessible en lecture/écriture pour les membres du groupe kvm. Passons à son utilisation.

Exporter le périphérique USB vers un invité KVM

En fait, c'est le travail préliminaire qui est long. Mais il n'est à faire qu'une fois pour chaque (type de) périphérique que vous voulez exporter. Quand ce sera fait, il suffira d'ajouter l'option adéquate lors de l'invocation de KVM pour exporter le périphérique vers la machine invitée:

sh$ kvm -usbdevice host:0403:6001 # Ajoutez ensuite vos options KVM habituelles

Comme vous le voyez, ici encore j'identifie le périphérique à exporter par son identifiant de vendeur et de produit. L'option -usbdevice supporte d'autres formats pour désigner le périphérique, mais c'est cette manière que je trouve la plus pratique – en particulier parce que ces données ne changent pas d'une connexion à l'autre du périphérique.

En plus, cette technique permet non seulement d'exporter un périphérique qui est déjà branché lorsque vous lancez KVM, mais en plus elle permet aussi de gérer le branchement/débranchement à chaud du périphérique (i.e.: pendant que la machine virtuelle tourne). Du point de vue du système invité, tout se passe exactement comme si le périphérique USB était vraiment branché dessus.

Par contre, il va de soi que vous vous exposez à des désagréments si vous accédez au même périphérique USB simultanément à partir de l'hôte et de la machine virtuelle – ou à partir de plusieurs machines virtuelles. C'est notamment vrai dans le cas d'une clé USB qui ne devra pas être montée simultanément sur plusieurs machines...