USB设备直通

创建的虚拟机有时需要使用主机的USB设备,例如U盘或者鼠标之类的,所以研究了下USB设备直通。

实验环境

宿主机系统(host):CentOS Linux release 7.4.1708 (Core)

libvirt:3.2.0

qemu: 2.9.0

USB总线架构

USB(Universal Serial Bus ),通用串行总线,是一种外部总线标准,用于规范电脑与外部设备的连接和通讯。

对于每个USB系统来说,都有一个称为主机控制器的设备,该控制器和一个根 Hub作为一个整体。这个根Hub下可以接多级的Hub,每个子Hub又可以接子Hub。每个USB设备作为一个节点接在不同级别的Hub上。 每条USB总线上最多可以接127个设备。如下图所示:

usb_arch_1

usb_arch_2

USB控制器类型

简单地讲,OHCI、UHCI都是USB1.1的接口标准,而EHCI是对应USB2.0的接口标准,最新的xHCI是USB3.0的接口标准。

USB信息查询

usb信息查询可以通过lsusb命令,如果没有该命令,需要安装usbutils-007-5.el7.x86_64.rpm。

lsusb可以很方便查看到usb设备信息,推荐使用。

[root@localhost ~]# lsusb
Bus 002 Device 005: ID 12d1:0003 Huawei Technologies Co., Ltd. 
Bus 002 Device 004: ID 048d:1234 Integrated Technology Express, Inc. 
Bus 002 Device 002: ID 8087:8002 Intel Corp. 
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 002: ID 8087:800a Intel Corp. 
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

每项的含义:

Bus 002 
    表示第二个USB主控制器(机器上总共有2个usb主控制器 -- 可以通过命令lspci | grep USB查看)

Device 005
    表示系统给USB分配的设备号(devnum),同时也可以看到该设备是插入到了第二个usb主控制器

ID 12d1:0003
    表示usb设备的ID(这个ID由芯片制造商设置,可以唯一表示该设备,idVendor:idProduct)

Huawei Technologies Co., Ltd.
    表示设备的描述信息

用lsusb -t还可以看到USB设备的层级关系

[root@localhost xqk]# lsusb -t
/:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/2p, 480M
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/8p, 480M
        |__ Port 1: Dev 3, If 0, Class=Mass Storage, Driver=usb-storage, 480M
        |__ Port 6: Dev 5, If 0, Class=Human Interface Device, Driver=usbhid, 12M
        |__ Port 6: Dev 5, If 1, Class=Human Interface Device, Driver=usbhid, 12M
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/2p, 480M
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/6p, 480M

每项含义:

[root@localhost xqk]# lsusb -t
/:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/2p, 480M
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/8p, 480M
        |__ Port 1: Dev 3, If 0, Class=Mass Storage, Driver=usb-storage, 480M


Bus 02.Port 1
    表示第二个USB主控制器,Port号为1
    
Dev 1, Class=root_hub
    分配的设备号为1,类型是root_hub
    
Driver=ehci-pci/2p
    root_hub的类型是ehci(usb 2.0),总共有两个port
    
|__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/8p, 480M
    root_hub的其中一个port有个Hub设备,port的id是1,此Hub有8个port。
    
    |__ Port 1: Dev 3, If 0, Class=Mass Storage, Driver=usb-storage, 480M  
    Hub的其中一个port有大容量USB设备,port的id为1.3(树状结构,依次以.作为低一级设备成员)

如果没有lsusb或者想确认下lsusb显示内容,可以进入目录

cd /sys/bus/usb/devices/
[root@localhost devices]# ls |grep -v ":"  (过滤掉以:分割的文件夹)
1-1
2-1
2-1.1
2-1.6
usb1
usb2
其中数字编号含义为(bus num)-(port num),usb1与usb2,对应控制器中的roothub。
[root@localhost devices]# cd 2-1.6
[root@localhost 2-1.6]# ll
...
-r--r--r-- 1 root root  4096 Mar  9 10:26 devnum(devnum 号)
-r--r--r-- 1 root root  4096 Apr  3 15:07 devpath(port id-r--r--r-- 1 root root  4096 Mar  9 10:26 idProduct(即ID 12d1:0003中的0003)
-r--r--r-- 1 root root  4096 Mar  9 10:26 idVendor(即ID 12d1:0003中的12d1)
...

其实lsusb对于root_hub的port指定有些问题,port号应该为0,或许是版本的bug。

USB设备直通

USB控制器添加

对于要添加的usb类型要在虚拟机xml中定义相应的controller,libvirt目前控制器支持为:

<controller type='usb' index='2' model='piix3-uhci'>     
 <alias name='usb1'/>
</controller>
<controller type='usb' index='1' model='ehci'>
  <alias name='usb'/>
</controller>
<controller type='usb' index='0' model='nec-xhci'>
  <alias name='usb'/>
</controller>

参数含义:

index:控制器的顺序,优先级0最高,多个控制器时需要指定,一般情况下controller只需要有一个即可。
model:控制器类型,对应类型上文已说明

对于多个controller要慎重,usb会优先匹配index为0的控制器,而不会自动适配相应的控制器。例如插入U盘是2.0,如果第一个controller是1.0,则会挂载到1.0总线下面。

如果设备是usb 1.0/1.1:

<controller type='usb' index='0' model='piix3-uhci'>     
 <alias name='usb1'/>
</controller>

如果设备是usb 2.0:

<controller type='usb' index='0' model='ehci'>
  <alias name='usb'/>
</controller>

如果有多个设备,既有1.0或2.0或者3.0,则用xhci,兼容uhci与ehci:

<controller type='usb' index='0' model='nec-xhci'>
  <alias name='usb'/>
</controller>

USB设备直通

其实虚拟机使用USB设备可以通过两种方式:

  1. pci设备直通

    这种方式其实是通过PCI直通,把整条USB控制器给虚拟机用,这样usb控制器线上的所有设备虚拟机都可以使用,USB控制器的pci相关信息可以通过lspci grep USB查看得到。
    [root@localhost vm_work]# lspci |grep USB
    00:1a.0 USB controller: Intel Corporation C610/X99 series chipset USB Enhanced Host Controller #2 (rev 05)
    00:1d.0 USB controller: Intel Corporation C610/X99 series chipset USB Enhanced Host Controller #1 (rev 05)
       
    

    属于pci设备直通范围,此篇不做展开讲述。

  2. 设备直通

    设备直通按照libvirt定义规范,在devices下直接添加就行

    <hostdev mode='subsystem' type='usb' managed='yes'>
          <source>
            <vendor id='0x048d'/>
            <product id='0x1234'/>
            <address bus='0' device='2'/>
        </source>
    </hostdev>
    

    相关的信息都可以用lsusb查询到。

    vendor、product以及address并不需要同时填写,只要有足够的信息确定某一个usb即可。

    例如,物理主机没有完全一样的厂家设备时,可以只填写:

    <vendor id='0x048d'/>
    <product id='0x1234'/>
    

    或者

    <address bus='0' device='2'/>
    

qemu支持

qemu支持hostaddr,hostport以及vendorid,productid等信息的组合

  (1) vendorid+productid -- match for a specific device, pass it to
      the guest when it shows up somewhere in the host.

  (2) hostbus+hostport -- match for a specific physical port in the
      host, any device which is plugged in there gets passed to the
      guest.

  (3) hostbus+hostaddr -- most useful for ad-hoc pass through as the
      hostaddr isn't stable, the next time you plug in the device it
      gets a new one ...

相对于libvirt,多了hostport的支持,hostport即是主机usb的port。

注意点

参考文档

Linux USB总线架构

几种USB控制器类型

Table of Contents