Qemu虚拟机pci设备透传——网卡

在qemu虚拟机中为了提高网络的性能,将本地host端的多余网卡透传到虚拟机中使用。

设备的透传需要主机支持Intel(VT-d)AMD (IOMMU)硬件虚拟化加速技术

qemu_net_passthrough

查看是否开启IOMMU

1
dmesg | grep -e DMAR -e IOMMU

开启IOMMU功能

操作系统:Centos7,cpu: Intel(R) Xeon(R)

编辑/boot/efi/EFI/centos/grub.cfg文件,在系统启动内核的选项linuxefi中追加intel_iommu=on

1
2
3
<       linuxefi /vmlinuz-3.10.0-1127.18.2.el7.x86_64 root=/dev/mapper/centos-root ro crashkernel=auto spectre_v2=retpoline rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet LANG=en_US.UTF-8 intel_iommu=on
---
> linuxefi /vmlinuz-3.10.0-1127.18.2.el7.x86_64 root=/dev/mapper/centos-root ro crashkernel=auto spectre_v2=retpoline rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet LANG=en_US.UTF-8

系统重启后,查看支持IOMMU的设备:

1
2
3
4
# find /sys/kernel/iommu_groups/ -type l
/sys/kernel/iommu_groups/0/devices/0000:00:00.0
/sys/kernel/iommu_groups/1/devices/0000:00:04.0
...

查看BIOS是否开启intel-vt-x/vt-d

1
cat /proc/cpuinfo | grep vmx

如果没有开启需要在BOIS中使能intel-vt-x/vt-d

选择绑定网卡

通过ifconfig ethx down/up开关相应的网络节点,获取相应的pci地址,该地址可以通过dmesg查看判断

1
2
3
4
# dmesg -c
# ifconfig p1p1 down
# dmesg
[27244.804247] ixgbe 0000:3b:00.0: removed PHC on p1p1

p1p1端口对应网卡的pci地址:0000:3b:00.0

加载vfio驱动

1
2
modprobe vfio
modprobe vfio-pci

网卡透传

Host端解绑网卡

1
echo "0000:3b:00.0" > /sys/bus/pci/devices/0000\:3b\:00.0/driver/unbind

注意在解绑网卡是需要将该网卡下的所有端口设备全部解绑,比如

1
2
ls /sys/bus/pci/devices/0000\:18\:00.0/iommu_group/devices/
0000:18:00.0 0000:18:00.1

需要将0000:18:00.00000:18:00.1全部进行解绑

生成vfio设备

1
2
3
# lspci -s 0000:3b:00.0 -n
3b:00.0 0200: 8086:154d (rev 01)
# echo "8086 154d" > /sys/bus/pci/drivers/vfio-pci/new_id

/dev/vfio/下面会有个以阿拉伯数字命名的文件,对应vfio设备组

绑定vfio总线驱动

1
echo "0000:3b:00.0" > /sys/bus/pci/drivers/vfio-pci/bind

虚拟机参数

1
-device vfio-pci,host=0000:3b:00.0

在qemu的启动参数中添加上面参数,该物理网卡将被透传到虚拟机中。

问题

在进行网卡的透传过程中,出现以下错误:

1
2
2020-09-23T10:16:51.707664Z qemu-system-x86_64: -device vfio-pci,host=0000:3b:00.0,id=hostdev0,bus=pci.0,addr=0xa: vfio 0000:3b:00.0: group 25 is not viable
Please ensure all devices within the iommu_group are bound to their vfio bus driver.

该错误的原因:在进行网卡透传时,以上提到的pci地址(0000:3b:00.0)其实为一张物理网卡的一个端口地址,一般的网卡都是两个端口,而此时只绑定了一个端口,需要将两个端口设备都进行解绑并绑定到vfio总线驱动上

1
2
# ls /sys/bus/pci/devices/0000\:18\:00.0/iommu_group/devices/
0000:18:00.0 0000:18:00.1

脚本处理

为了以后处理方便将host端的配置进行脚本处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#/bin/bash
#set -x

PCI_ADDR="18:00.1"

modprobe vfio
modprobe vfio-pci
lsmod | grep vfio

lspci -s $PCI_ADDR -n #em2

device_id=`lspci -s $PCI_ADDR -n | awk '{print $3}'`
device_id=${device_id/:/ } #去除:号
echo "PCI: $PCI_ADDR, Device ID:$device_id"

#生成vfio设备
echo "$device_id" > /sys/bus/pci/drivers/vfio-pci/new_id

#pci设备绑定vfio总线驱动(解绑--绑定)
pci_device=/sys/bus/pci/devices/0000:$PCI_ADDR/iommu_group/devices/
pci_device=`echo $pci_device | sed 's/:/\\:/g'` #添加转移符,echo打印不出来
#ls $pci_device
for dev in `ls $pci_device`
do
echo "---dev:$dev"
_pci_dev_unbind="/sys/bus/pci/devices/$dev/driver/unbind"
_pci_dev_unbind=`echo $_pci_dev_unbind | sed 's/:/\\:/g'`
#ls $_pci_dev_unbind
echo "$dev" > $_pci_dev_unbind
echo "$dev" > /sys/bus/pci/drivers/vfio-pci/bind
lspci -s $dev -k
done

ls /dev/vfio/

virsh命令解除绑定

Host端的设备解除绑定(就是不被host系统所管理使用)后,通过给guest系统使用前的必备操作

  • 列出设备ID

    1
    2
    3
    # virsh nodedev-list | grep pci   | grep 18
    pci_0000_18_00_0
    pci_0000_18_00_1
  • 查询当前使用的驱动程序

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    # virsh nodedev-dumpxml pci_0000_18_00_0
    <device>
    <name>pci_0000_18_00_0</name>
    <path>/sys/devices/pci0000:17/0000:17:03.0/0000:18:00.0</path>
    <parent>pci_0000_17_03_0</parent>
    <driver>
    <name>vfio-pci</name>
    </driver>
    <capability type='pci'>
    <domain>0</domain>
    <bus>24</bus>
    <slot>0</slot>
    <function>0</function>
    <product id='0x165f'>NetXtreme BCM5720 2-port Gigabit Ethernet PCIe</product>
    <vendor id='0x14e4'>Broadcom Inc. and subsidiaries</vendor>
    <iommuGroup number='26'>
    <address domain='0x0000' bus='0x18' slot='0x00' function='0x0'/>
    <address domain='0x0000' bus='0x18' slot='0x00' function='0x1'/>
    </iommuGroup>
    <numa node='0'/>
    <pci-express>
    <link validity='cap' port='0' speed='5' width='2'/>
    <link validity='sta' speed='5' width='1'/>
    </pci-express>
    </capability>
    </device>

    这是设备手动解除绑定后dump出的详细信息,如果没有解除绑定数据可能不同

  • 解绑当前设备

    1
    2
    # virsh nodedev-detach pci_0000_18_00_0
    # virsh nodedev-detach pci_0000_18_00_1

参考

  • https://www.kernel.org/doc/Documentation/vfio.txt
  • https://wiki.archlinux.org/index.php/PCI_passthrough_via_OVMF
  • KVM网卡透传
  • Qemu 虚拟机网卡透传(PCI Pass Through)