VFIO(Virtual Function IO)
把设备通过 IOMMU 映射的 DMA 物理内存地址映射到 用户态
中,让 用户态程序
可以自行操纵数据的传输,还可以自行注册中断处理函数,从而在 用户态
下实现设备的驱动程序。
介绍
- 要使用 VFIO 驱动,则必须开启 IOMMU 支持
- VFIO 是一套完整的
用户态驱动(userspace driver)
方案,因为它可以安全地把设备 I/O
、中断
、DMA
等能力呈现给用户空间
IOMMU
中 IOMMU_GROUP
代表一组被隔离的设备的集合
VFIO Container
:在 IOMMU_GROUP
的基础上,VFIO封装了一层Container Class
,Container的作用是,当我们想在不同的IOMMU_GROUP之间共享TLB和page tables(用于地址翻译的页表)时,就将这些group放到同一个container中,因此Container可以看做是IOMMU_GROUP的集合
- 特点:使用 VFIO 可以实现安全的,非特权的,用户空间驱动程序
示例
环境
VM 有两块网卡
- ens33 172.20.0.132/24 用于 SSH 连接(在VM存放目录文件,修改
<name>.vmwarevm/<name>.vmx
中 ethernet0.virtualDev = "e1000"
为 ethernet0.virtualDev = "vmxnet3"
,可以将该网卡与其默认网卡绑在不同的 pci 设备上)
- ens36 192.168.2.129/24 用于 VFIO 验证
# ens36 设备
$ lspci
02:04.0 Ethernet controller: Intel Corporation 82545EM Gigabit Ethernet Controller (Copper) (rev 01)
...
$ lspci -vvv -s 02:04.0
02:04.0 Ethernet controller: Intel Corporation 82545EM Gigabit Ethernet Controller (Copper) (rev 01)
DeviceName: Ethernet1
Subsystem: VMware PRO/1000 MT Single Port Adapter
Physical Slot: 36
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV+ VGASnoop- ParErr- Stepping- SERR+ FastB2B- DisINTx-
Status: Cap+ 66MHz+ UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0 (63750ns min), Cache Line Size: 64 bytes
Interrupt: pin A routed to IRQ 18
Region 0: Memory at fc020000 (64-bit, non-prefetchable) [size=128K]
Region 2: Memory at fc050000 (64-bit, non-prefetchable) [size=64K]
Region 4: I/O ports at 1000 [size=64]
Expansion ROM at fc080000 [disabled] [size=64K]
Capabilities: [dc] Power Management version 2
Flags: PMEClk- DSI+ D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=1 PME-
Capabilities: [e4] PCI-X non-bridge device
Command: DPERE- ERO+ RBC=512 OST=1
Status: Dev=ff:1f.0 64bit+ 133MHz+ SCD- USC- DC=simple DMMRBC=2048 DMOST=1 DMCRS=16 RSCEM- 266MHz- 533MHz-
Kernel driver in use: e1000
Kernel modules: e1000
VMware 虚拟机
默认的网卡是 Intel Corporation 82545EM
配置步骤
- 启用 IOMMU
- 确认 kernel 是否包含 vfio
$ cat /lib/modules/$(uname -r)/modules.builtin | grep vfio
kernel/drivers/vfio/vfio.ko
kernel/drivers/vfio/vfio_virqfd.ko
kernel/drivers/vfio/vfio_iommu_type1.ko
kernel/drivers/vfio/pci/vfio-pci.ko
- 加载VFIO-PCI module,默认在 builtin 已经加载
modprobe vfio-pci
$ dmesg | grep -i VFIO
[ 3.121466] VFIO - User Level meta-driver version: 0.3
$ readlink /sys/bus/pci/devices/0000:02:04.0/iommu_group
../../../../kernel/iommu_groups/5
iommu_group
的 group id 为 5
$ ls /sys/bus/pci/devices/0000:02:04.0/iommu_group/devices
0000:00:11.0 0000:02:01.0 0000:02:03.0 0000:02:04.0
为了将设备透传到虚拟机中,需要将设备所在的iommu_group的所有设备与其对应的驱动解绑,这样该设备才可以使用VFIO的驱动
$ echo 0000:00:11.0 | sudo tee /sys/bus/pci/devices/0000:00:11.0/driver/unbind
0000:00:11.0
$ echo 0000:02:01.0 | sudo tee /sys/bus/pci/devices/0000:02:01.0/driver/unbind
0000:02:01.0
$ echo 0000:02:03.0 | sudo tee /sys/bus/pci/devices/0000:02:03.0/driver/unbind
0000:02:03.0
$ echo 0000:02:04.0 | sudo tee /sys/bus/pci/devices/0000:02:04.0/driver/unbind
$ lspci -n -s 02:04.0
02:04.0 0200: 8086:100f (rev 01)
网卡的Vendor为 8086
,DeviceID
为 100f
$ echo 8086 100f | sudo tee /sys/bus/pci/drivers/vfio-pci/new_id
8086 100f
$ qemu-system-x86_64 -m 1024 -vnc :0 -hda cirros-0.5.2-x86_64-disk.img -enable-kvm -cpu host -device vfio-pci,host=02:04.0
$ lspci
00:04.0 Class 0200: 8086:100f
虚拟机
中网卡和宿主机上的信息一样,证明宿主机网卡透传到 虚拟机
成功