1.1 设备透传与重定向

在私有云桌面中,设备的透传(passthrough)与重定向(redirection)一直以来都是作为基本功能出现的。两者的在使用上的区别是前者一般将主机上的设备直接传递给在其中运行的虚拟机,后者则是将客户端的设备通过网络传递给其正在连接的虚拟机,相同点是当传递至虚拟机或虚拟机归还设备时,这对于主机来说是个设备热插拔操作。

1.1.1PCI/PCI-E设备

在QEMU中,PCI/PCI-E设备目前仅支持透传(某些商业软件可对PCI/PCI-E设备进行重定向),且需要在主机BIOS设置中CPU打开Intel VT-d/选项(AMD CPU与之对应的是AMD Vi),可透传的设备包括显卡、声卡、HBA卡、网卡、USB控制器等,其中某些设备需要额外设置(比如IOMMU)才可进行透传。

使用libvirt透传PCI/PCI-E设备时需要知道要透传设备的总线地址,以在域定义中指定要透传的设备。一般落实到QEMU中有这些为透传准备的设备模型,包括pci-assgn、vfio-pci、vfio-vga等。

以透传主机网卡为例:

[root@node1 ~]# lspci00:00.0 Host bridge: Intel Corporation 440BX/ZX/DX - 82443BX/ZX/DX Host bridge...02:05.0 Ethernet controller: Intel Corporation 82545EM Gigabit Ethernet Controller (Copper) (rev 01)

然后新建一个设备定义文件,在虚拟机运行时添加此设备,也可将其写入至虚拟机的域定义文件作为永久设备:

[root@node1 ~]# cat >> pci-e1000.xml<<EOF<hostdev mode='subsystem' type='pci' managed='yes'><source><address domain='0x0000' bus='0x02' slot='0x05' function='0x0'/></source></hostdev>EOF[root@node1 ~]# virsh attach-device win7 pci-e1000.xml

如此便可将主机网卡透传至虚拟机中,如果使用vfio-pci需要加载vfio相关内核模块,具体可参考以下两节内容。

需要注意的是,不是所有的主机、虚拟机系统和PCI/PCI-E设备都支持热插拔,在不支持的系统中进行热插拔的话可能会造成虚拟机死机,甚至可能造成主机死机。

1.1.2SR-IOV

SR-IOV全称为Single Root I/O Virtualization,是一种基于硬件的虚拟化解决方案,可提高设备利用率,其功能实现最早在Linux系统中。SR-IOV 标准允许在虚拟机之间共享PCI-E设备,并且它是在硬件中实现的,虚拟设备可以获得与透传方式相当的I/O 性能。

SR-IOV中引入了物理功能(Physical Function)与虚拟功能(Virtual Function)两个概念,其中物理功能是指物理设备拥有可配置的完整资源,虚拟功能则使得虚拟设备能够共享一部分物理资源以提供给虚拟机使用。启用了 SR-IOV 并且具有适当的硬件和设备驱动支持的 PCI-E设备在系统中可显示为多个独立的虚拟设备,每个都拥有自己的I/O空间。目前使用最多的SR-IOV设备是万兆网卡,主要厂商有Intel、QLogic等。

笔者将以支持SR-IOV功能的Intel 82599网卡为例介绍SR-IOV的完整使用过程,其中会涉及到QEMU的vfio-pci透传设备模型以及设备IOMMU。

首先,我们需要修改主机启动引导参数以开启intel-iommu。此处读者可能会将intel-iommu与iommu混淆,前者控制的是基于Intel VT-d的IOMMU,它可以使系统进行设备的DMA地址重映射(DMAR)等多种高级操作为虚拟机使用做准备,且此项默认关闭,而后者主要控制是GART(Graphics Address Remapping Table) IOMMU,目的是让有32位内存访问大小的设备可以进行DMAR操作,通常用于USB设备、声卡、集成显卡等,会在主机内存3GB以上的系统中默认开启。

# 修改/boot/grub2/grub.cfg,形式如下linux16 /vmlinuz-3.10.0-327.3.1.el7.x86_64 root=UUID=ff78a51d-4759-464f-a1fd-2712a4943202 ro rhgb quiet LANG=zh_CN.UTF-8 intel_iommu=oninitrd16 /initramfs-3.10.0-327.3.1.el7.x86_64.im

然后重新加载网卡驱动模块,并设置模块中的最大VF数以使得设备虚拟出一定数量的网卡。不同厂商的网卡的驱动模块不同,其打开虚拟功能的参数也不同。另外,部分设备由于厂商策略原因,Linux内核自带的驱动不一定拥有VF相关设置,需要从官网单独下载并替换原有驱动。

# 查看网络设备总线地址,此款网卡拥有双万兆网口

[root@node3 ~]# lspci -nn | grep -i ethernet04:00.0 Ethernet controller [0200]: Intel Corporation Ethernet 10G 2P X520 Adapter [8086:154d] (rev 01)04:00.1 Ethernet controller [0200]: Intel Corporation Ethernet 10G 2P X520 Adapter [8086:154d] (rev 01)

# 查看设备驱动

[root@node3 ~]# lspci -s 04:00.0 -k04:00.0 Ethernet controller: Intel Corporation Ethernet 10G 2P X520 Adapter (rev 01)Subsystem: Intel Corporation 10GbE 2P X520 AdapterKernel driver in use: ixgbe

# 查看驱动参数

[root@node3 ~]# modinfo ixgbefilename: /lib/modules/3.10.0-327.3.1.el7.x86_64/kernel/drivers/net/ethernet/intel/ixgbe/ixgbe.koversion: 4.0.1-k-rh7.2license: GPLdeion: Intel(R) 10 Gigabit PCI Express Network Driverauthor: Intel Corporation, <linux.nics@intel.com>rhelversion: 7.2srcversion: FFFD5E28DF8860A5E458CCBalias: pci:v00008086d000015ADsv*sd*bc*sc*i*...alias: pci:v00008086d000010B6sv*sd*bc*sc*i*depends: mdio,ptp,dcaintree: Yvermagic: 3.10.0-327.3.1.el7.x86_64 SMP mod_unload modversionssigner: CentOS Linux kernel signing keysig_key: 3D:4E:71:B0:42:9A:39:8B:8B:78:3B:6F:8B:ED:3B:AF:09:9E:E9:A7sig_hashalgo: sha256parm: max_vfs:Maximum number of virtual functions to allocate per physical function - default is zero and maximum value is 63 (uint)parm: allow_unsupported_sfp:Allow unsupported and untested SFP+ modules on 82599-based adapters (uint)parm: debug:Debug level (0=none,...,16=all) (int)# 重新加载内核,修改max_vfs为4,并将此参数写入/etc/modprobe.d/下的文件以便开机加载[root@node3 ~]# modprobe -r ixgbe; modprobe ixgbe max_vfs=4[root@node3 ~]# cat >> /etc/modprobe.d/ixgbe.conf<<EOFoptions ixgbe max_vfs=4EOF

# 再次查看网络设备,可发现多了4个虚拟网卡,并且设备ID不同于物理网卡

[root@node3 ~]# lspci | grep -i ethernet02:00.3 Ethernet controller [0200]: Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe [14e4:1657] (rev 01)04:00.0 Ethernet controller [0200]: Intel Corporation Ethernet 10G 2P X520 Adapter [8086:154d] (rev 01)04:00.1 Ethernet controller [0200]: Intel Corporation Ethernet 10G 2P X520 Adapter [8086:154d] (rev 01)04:10.0 Ethernet controller [0200]: Intel Corporation 82599 Ethernet Controller Virtual Function [8086:10ed] (rev 01)04:10.1 Ethernet controller [0200]: Intel Corporation 82599 Ethernet Controller Virtual Function [8086:10ed] (rev 01)04:10.2 Ethernet controller [0200]: Intel Corporation 82599 Ethernet Controller Virtual Function [8086:10ed] (rev 01)04:10.3 Ethernet controller [0200]: Intel Corporation 82599 Ethernet Controller Virtual Function [8086:10ed] (rev 01)

虚拟网卡被主机发现以后,我们需要额外加载vfio-pci以及vfio-iommu-type1两个模块,然后将虚拟网卡与原驱动解绑并重新绑定至vfio-pci驱动。其中vfio-pci驱动是专门为现在支持DMAR和中断地址重映射的PCI设备开发的驱动模块,它依赖于VFIO驱动框架,并且借助于vfio-iommu-type1模块实现IOMMU的重用:

# 加载vfio-pci

[root@node3 ~]# modprobe vfio-pci

# 加载vfio-iommu-type1以允许中断地址重映射,如果主机的主板不支持中断重映射功能则需要指定参数“allow_unsafe_interrupt=1”

[root@node3 ~]# modprobe vfio-iommu-type1 allow_unsafe_interrupt=1

# 将虚拟网卡与原驱动解绑

[root@node3 ~]# echo 0000:04:10.0 > /sys/bus/pci/devices/0000:04:10.0/driver/unbind[root@node3 ~]# echo 0000:04:10.1 > /sys/bus/pci/devices/0000:04:10.1/driver/unbind[root@node3 ~]# echo 0000:04:10.2 > /sys/bus/pci/devices/0000:04:10.2/driver/unbind[root@node3 ~]# echo 0000:04:10.3 > /sys/bus/pci/devices/0000:04:10.3/driver/unbind

# 将虚拟网卡按照设备ID全部与vfio-pci驱动绑定

[root@node3 ~]# echo 8086 10ed > /sys/bus/pci/drivers/vfio-pci/new_id

# 查看虚拟设备现在使用的驱动

[root@node3 ~]# lspci -k -s 04:10.004:10.0 Ethernet controller: Intel Corporation 82599 Ethernet Controller Virtual Function (rev 01)Subsystem: Intel Corporation Device 7b11Kernel driver in use: vfio-pci

然后我们即可在虚拟机中使用这些虚拟网卡,需要在QEMU命令行中添加设备选项,形似“-device vfio-pci,host=04:10.0,id=hostdev0,bus=pci.0,multifunction=on,addr=0x9”,对应的libvirt定义如下

<hostdev mode='subsystem' type='pci' managed='yes'><driver name='vfio'/><source><address domain='0x0000' bus='0x04' slot='0x10' function='0x2'/></source><alias name='igbxe'/><address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0' multifunction='on'/></hostdev>

如果使用vfio-pci透传PCI-E设备,我们需要使用QEMU机器模型Q35,并添加相应的PCI-E总线参数,除此之外,设备驱动的解绑与绑定操作可以简化为如下所示的脚本操作:

[root@node3 ~]# cat vfio-bind.sh#!/bin/bashmodprobe vfio-pcifor var in "$@"; dofor dev in $(ls /sys/bus/pci/devices/$var/iommu_group/devices); dovendor=$(cat /sys/bus/pci/devices/$dev/vendor)device=$(cat /sys/bus/pci/devices/$dev/device)if [ -e /sys/bus/pci/devices/$dev/driver ]; thenecho $dev > /sys/bus/pci/devices/$dev/driver/unbindfiecho $vendor $device > /sys/bus/pci/drivers/vfio-pci/new_iddonedone

1.1.3USB

USB包括控制器和外设,控制器位于主机上且一个主机可同时拥有多个USB控制器,控制器通过root hub提供接口供其他USB设备连接,而这些USB设备又可以分为hub、存储、智能卡、加密狗、打印机等。目前常用的USB协议有1.1、2.0、3.0、3.1(Type-C)等。

在QEMU中,我们一般可以对USB控制器进行透传,外设进行透传或重定向。

首先USB控制器也位于PCI总线上,所以我们将整个控制器及其上面的hub、外设全部透传至虚拟机中,可以参考上一节中的相关域定义,不同的是我们需要找到USB控制器对应的PCI总线地址,如下所示:

[root@node4 ~]# lspci -nn| grep -i usb00:1a.0 USB controller [0c03]: Intel Corporation C610/X99 series chipset USB Enhanced Host Controller #2 [8086:8d2d] (rev 05)00:1d.0 USB controller [0c03]: Intel Corporation C610/X99 series chipset USB Enhanced Host Controller #1 [8086:8d26] (rev 05)

然后选择要透传的USB控制器,我们需要查看主机线路简图或外设简图以确定要透传的USB接口,如果是对主机直接操作需避免将连有USB键盘鼠标设备的控制器透传至虚拟机,否则会造成后续操作的不便。

[root@node4 ~]# lsusbBus 001 Device 002: ID 8087:800a Intel Corp.Bus 002 Device 002: ID 8087:8002 Intel Corp.Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hubBus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hubBus 002 Device 003: ID 12d1:0003 Huawei Technologies Co., Ltd.

参考上一节中的驱动绑定,使用vfio-pci对USB控制器进行透传,假设要透传的控制器为2号控制器,它的总线地址为00:1a.0,设备ID为8086:8d26:

[root@node3 ~]# echo 0000:00:1a.0 > /sys/bus/pci/devices/0000:04:10.0/driver/unbind[root@node3 ~]# echo 8086 8d26 > /sys/bus/pci/drivers/vfio-pci/new_id

最后在QEMU中添加参数形如“-device vfio-pci,host=00:1a.0,id=hostdev0,bus=pci.0,multifunction=on,addr=0x9”即可。

QEMU下USB外设的透传相对比较容易,只需要在域定义中添加对应的USB外设的厂商与设备ID即可,以透传USB-Key为例:

# 查看设备总线地址与ID

[root@node1 ~]# lsusbBus 001 Device 002: ID 8087:800a Intel Corp.Bus 002 Device 002: ID 8087:8002 Intel Corp.Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hubBus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hubBus 001 Device 003: ID 04b9:8001 Rainbow Technologies, Inc.Bus 002 Device 005: ID 096e:0202 Feitian Technologies, Inc.Bus 002 Device 004: ID 12d1:0003 Huawei Technologies Co., Ltd.

# 然后在域定义中添加设备ID,也可指定设备的总线地址

<hostdev mode='subsystem' type='usb' managed='yes'><source><vendor id='0x04b9'/><product id='0x8001'/></source></hostdev>

对应到QEMU的参数即是“-device usb-host,vendorid=0x04b9,productid=0x8001”或者“-device usb-host,hostbus=1,hostaddr=3,id=hostdev0”,也可是“-usbdevice host:0529:0001”等形式。

外设重定向

USB外设的重定向是私有桌面云的必备功能之一,目前其实现方法包括硬件和软件两种,其中软件实现最为常用的是USB over TCP/IP,即通过TCP/IP协议重定向客户端USB外设到虚拟机中。QEMU桌面协议Spice里的对应实现是Spice USB Redirection,即通过添加一个专用的channel用于客户端到虚拟机的USB重定向。

USB over TCP/IP的一般实现如图9-1所示,其中PDD为具体的USB外设驱动(Peripheral Device Driver),HCD为USB控制器驱动(Host Controller Driver),Stub Driver为客户端USB外设的统一驱动,VHCI Driver为虚拟机中的USB控制器驱动。当客户端插入USB外设时,系统会对其使用Stub驱动,设备重定向后USB请求与数据会被Stub驱动封装,经由TCP/IP传递至虚拟机的VHCI驱动,反过来亦如此。

图9-1 USB over IP原理

接下来笔者使用usbredir-server工具,将Ubuntu客户端的U盘重定向至另一主机中的虚拟机。

首先在Ubuntu中确定U盘的设备ID,安装usbredir-server并在44444端口监听:

root@ubuntu:~# apt-get install usbredir-serverroot@ubuntu:~# lsusbBus 001 Device 004: ID 0781:5567 SanDisk Corp. Cruzer BladeBus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hubBus 002 Device 003: ID 0e0f:0002 VMware, Inc. Virtual USB HubBus 002 Device 002: ID 0e0f:0003 VMware, Inc. Virtual MouseBus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

# 这里可以将USB设备的总线地址或者设备ID作为参数

root@ubuntu:~# usbredirserver -p 44444 -v 4 0781:5567然后在另一台主机中启动虚拟机,并添加如下设备定义:<redirdev bus='usb' type='tcp'><source mode='connect' host='192.168.0.58' service='44444'/><protocol type='raw'/><alias name='redir2'/></redirdev>

虚拟机启动后,可以看到对应的QEMU命令中多了一个特殊的usb-redir设备,形似“-chardev socket,id=charredir2,host=192.168.0.58,port=44444-device usb-redir,chardev=charredir2,id=redir2”。这个设备即是QEMU的USB重定向设备后端,它可用在USB over TCP/IP中,也可作为Spice USB channel的设备后端。

需要注意的是,上述实现中hypervisor会主动发送请求到客户端端口(Spice USB Redirection无此要求),而这在实际场景中往往比较难以实现。采用这种实现的私有云厂平台会在特定服务器(也可以是hypervisor)中启用代理网关或者网络隧道,客户端将网络端口映射到其上的某个端口,Hypervisor再与服务器连接,从而完成双方间接通信,技术细节可以参考Spice协议的squid代理实现。

1.1.4串口与并口

QEMU中串口与并口设备一般都可进行透传与重定向操作,其中透传比较简单,只需要将本地串口/并口的设备节点当做设备后端即可,形如“-parallel /dev/lp0”,而重定向的思路与USB over TCP/IP较为类似。

重定向时我们需要使用工具将客户端串口/并口设备的输入/输出暴露到客户端的网络端口,hypervisor再将客户端的IP地址与TCP端口作为虚拟机的串口/并口设备后端参数进行连接,如图9-2所示。

Linux客户端中可以使用ser2net作为串口/并口的服务端,Windows客户端中也有对应的实现,笔者以Linux中的ser2net为例,介绍QEMU中的串口与并口重定向。

首先在客户端启动监听服务:

# 本地串口为ttyS1,并口打印机为lp0(非parport0)root@ubuntu:~# apt-get install ser2netroot@ubuntu:~# ser2net -C 44444:raw:0:/dev/ttyS1root@ubuntu:~# ser2net -C 44445:rawlp:0:/dev/lp0然后在服务端添加串口/并口设备,QEMU命令行如下所示:root@ubuntu:~# qemu-kvm -m 2G -smp 2,sockets=1-device isa-serial,chardev=serial0-chardev socket,id=serial0,host=192.168.0.40,port=44444-device isa-parallel,chardev=lp0-chardev socket,id=lp0,host=192.168.0.40,port=44445和USB over TCP/IP相同,在实际场景中可能需要代理网关或网络隧道。

KVM设备透传与重定向相关推荐

  1. Linux的pcie模拟网卡,Qemu虚拟机pci设备透传——网卡

    在qemu虚拟机中为了提高网络的性能,将本地host端的多余网卡透传到虚拟机中使用. 设备的透传需要主机支持Intel(VT-d)或AMD (IOMMU)硬件虚拟化加速技术 查看是否开启IOMMU1d ...

  2. kvm GPU透传(GPU passthrough)

    为了方便对服务器进行自动管理,我们需要对硬件进行虚拟化.对于显卡而言,Nvidia有专门支持GPU虚拟化的显卡,比如GRID GPU系列.以NVIDIA GRID K2为例,显存8GB,可虚拟出2块G ...

  3. 提升KVM异构虚拟机启动效率:透传(pass-through)、DMA映射(VFIO、PCI、IOMMU)、virtio-balloon、异步DMA映射、预处理

    导读:KVM Forum 2020 是 KVM 社区最为重要和权威的大会.本文为阿里云工程师李伟男和郭成在 KVM Forum 2020 中的演讲内容整理而成. 目录 发现问题 设计思路 异步 DMA ...

  4. OpenStack Pike版本+KVM+Passthrough+NVIDIA显卡1060透传

    OpenStack显卡透传主要分两部分: 1.KVM PassThrough Nvidia1060,并制作透传显卡的OpenStack镜像 2.配置OpenStack环境 折腾大半个月,主要解决的问题 ...

  5. 远程ykvm 插件移值java_远程管理KVM,命令行控制KVM,console连接,透传

    远程管理虚拟机 首先,将虚拟机改成桥接模式,才可以相互连接. 打开宿主机的虚拟系统管理器 输入要远程管理的IP地址. 然后输入密码,显示连接. 打开远程管理的主机的设置,设置VNC服务器和所有接口,就 ...

  6. Springboot+Netty实现基于天翼物联网平台CTWing(AIOT)终端TCP协议(透传模式)-设备终端(南向设备)

    电信的天翼物联网平台CTWing(AIOT)原先是我们俗称的aep,主要用于接入nb-iot设备,当然也可以接入其他的设备,在熟悉AIOT平台后,做后端的我有时候急需终端样品(智能门禁,支付识别终端, ...

  7. [嵌入式框架][nrf51822][SDK12.3] BLE分层设计 DFU OTA 透传(NUS) 电量 设备信息 BLE_HID

    一. 目录结构如下 将每个功能抽离处理,使文件起步代码显得干净清晰.官方提供的文件,行数1000+起步. 二. BLE服务创建和事件管理 简化后只有700+,仅保留协议栈事件处理,白名单,对等管理器, ...

  8. java tcp dtu_使用有人DTU设备接入OneNet(基于TCP透传)

    本帖最后由 huizwang 于 2017-4-10 16:49 编辑 本帖是基于<TCP透传功能初探>一文为基础增加使用DTU设备来认识TCP透传功能,步骤如下: 步骤1:创建基于TCP ...

  9. java tcp dtu_【分享】使用有人DTU设备接入OneNet(基于TCP透传)

    本帖是基于<TCP透传功能初探>一文为基础增加使用DTU设备来认识TCP透传功能,步骤如下: 步骤1:创建基于TCP协议的产品(略): 步骤2:创建设备,如下图: QQ截图20170410 ...

  10. 电力载波JST-HPLC-485 系列载波设备(HPLC转485三相透传设备)在物联网通信领域的应用

    JST-HPLC-485 系列载波设备是一款小型化.高速率的电力线载波通信设备,其核心采用 HPLC 高速载波芯片,内部集成 32 位处理器,采用 BPSK 数字调制解调方式传输,内置耦合电 路及 P ...

最新文章

  1. 祝51CTO 生日快乐
  2. 2.Java异常学习
  3. 项目: 实时钟表(C语言)
  4. [转]Nokia是否还有未来 - 小议诺基亚和微软的战略布局
  5. 亚信科技数据库AntDB通过金融分布式事务数据库标准测试
  6. 地球人口承载力估计(信息学奥赛一本通-T1005)
  7. c语言课程设计物业,C语言课程设计报告--物业管理系统.doc
  8. 用u盘安装mysql,奥维互动地图企业服务器基本环境安装 ——U盘引导安装CentOS 6.5...
  9. 医院电子病历系统HIS、LIS、PACS、CIS源码
  10. 如何使用JGIT在远程仓库获取提交详情记录
  11. 常用Cocoa框架概览
  12. 她受马云影响创业,想在全球女性创业者大会上分享这些事
  13. 给十二星座的12封信,句句说中你们的心理要害!
  14. OpenCV开发笔记(四十一):红胖子8分钟带你深入了解scharr滤波器算子边缘检测(图文并茂+浅显易懂+程序源码)
  15. PySpark | RDD
  16. 钉钉的自动打卡上下班辅助android软件
  17. 酷炫的图片轮播框架AndroidImageSlider
  18. MapReduce之单词统计
  19. 『前端大事记』之「几件大事」
  20. 读书-每天为自己打个勾-郭腾尹

热门文章

  1. Python实现分解质因数
  2. 关闭android系统自动更新,彻底关闭魅族flyme系统自动更新的方法分享
  3. 一元线性拟合的matlab,基于MATLAB的一元线性回归分析
  4. matlab求系统根轨迹代码_第九讲? 根轨迹法
  5. 【K8S】K8s部署Metrics-Server服务
  6. 三星android截屏快捷键是什么,三星s10截屏快捷键是什么
  7. Tiny 6410 K9GAG08U0E nand flash移植uboot
  8. 回顾计算机主板中南北桥的作用
  9. Windows 10 删除微软拼音
  10. Chrome Edge与Safari书签同步