既不回头,何必不忘。既然无缘,何需誓言。
今日种种,似水无痕。明夕何夕,君已陌路。

PVE下开启网卡SR-IOV

一、什么是SR-IOV?

单根 I/O 虚拟化 (SR-IOV) 接口是 PCI Express (PCIe) 的扩展。SR-IOV 允许设备(最常见的是网卡)在各种 PCIe 硬件功能之间分离其资源的访问。启用后,设备会拥有物理功能(Physical Function/PF)以及(Virtual Function/VF)。

VF 是支持 SR-IOV 接口的网卡上的轻型 PCIe 功能。 VF 与网卡上的 VF 相关联,并表示网卡的虚拟化实例。 每个 VF 都有自己的 PCI 配置空间。 每个 VF 还与 PF 和其他 VF 共享网络适配器上的一个或多个物理资源,例如网卡上的物理网口。

PF 是支持 SR-IOV 接口的网络适配器的 PCI Express (PCIe) 功能。PF 在 PCIe 配置空间中包括 SR-IOV 扩展功能。该功能用于配置和管理网络适配器的 SR-IOV 功能,例如启用虚拟化和公开 VF。

一般来说一个物理网口对应一个PF,一个PF对应4个,64个或者更多的VF(取决于不同的网卡型号)。

二、SR-IOV的优点

上图中左边表示我们常规情况下的虚拟化架构。所有虚拟机通过虚拟网卡连接到一个由Hypervisor/VMM(PVE, ESXi等)管理的虚拟交换机上。由虚拟交换机连接物理网卡和外界通讯。上图的右边展示了SR-IOV的工作架构。启用了SR-IOV的虚拟机可以直接使用物理网卡上的虚拟功能,不需要经过VMM的虚拟交换机处理。不同VF之间也可以通过网卡上自带的虚拟网桥直接通讯。

总的来说,启用SR-IOV降低了IO延迟和对CPU的占用,让每一个虚拟机都可以获得接近原生的IO性能。效果随着虚拟机数量的增多以及网络负载较大的情况下会越来越明显。

三、SR-IOV的缺点

开启SR-IOV后无法使用快照,同时需要预分配所有的内存才能正常启动。这一定程度上降低了虚拟机的灵活性。

SR-IOV和直通的区别

听起来SR-IOV和直通有很多相似之处。但是直通有一个非常大的缺陷,那就是一张物理网卡只能够被直通给一个虚拟机。也就是说,如果我开4个虚拟机,那就需要4张物理网卡,这显然是不实际的。而使用SR-IOV则可以将一张物理网卡拆分出多个VF,分配给多个虚拟机。SR-IOV 使得单根端口下的单个快速外围组件互连(PCIe) 物理设备可显示为多个单独的物理设备。既有直通设备的性能优势,又可以支持多个虚拟机,一举两得。

四、在PVE下启用网卡SR-IOV

1. 安装必要的软件包

apt install net-tools -y
apt install ethtool -y

2. 开启IOMMU

# 打开/etc/default/grub,找到GRUB_CMDLINE_LINUX_DEFAULT这一行
nano /etc/default/grub

修改为:

# AMD:
GRUB_CMDLINE_LINUX_DEFAULT="amd_iommu=on iommu=pt quiet"
# Intel:
GRUB_CMDLINE_LINUX_DEFAULT="intel_iommu=on iommu=pt quiet"
# 更新grub:
update-grub

打开/etc/modules,添加以下内容:

 vfio
 vfio_iommu_type1
 vfio_pci
 vfio_virqfd
# 应用开机加载模块并重启:
update-initramfs -u -k all
reboot

重启后检查IOMMU是否成功开启:

根据不同的系统版本和硬件,执行命令后可能显示IOMMU, Directed I/O 或者 Interrupt Remapping is enabled,这些都说明IOMMU已经成功开启

3. 启用SR-IOV

(1) 测试是否能正常开启

使用下面的命令来查看自己设备的网卡名称

ip a
# 例如我想要创建两个VF,我的网卡名是enp161s0f0:
echo 2 > /sys/class/net/enp161s0f0/device/sriov_numvfs
# 输入命令后没有任何显示是正常的。
# 接下来使用下面的命令列出网卡,有”Virtual Function”出现就成功啦
lspci | grep Eth

(2)让VF能够跟随系统启动一起初始化

首先在/etc/systemd/system中创建一个service文件,可以自定义名称,我这里叫sriov.service

编辑这个service文件

# 由于VF的mac地址会在每次重启后被随机分配,这可能会导致像软路由这样的虚拟机出现问题。如果出现了重新启动后虚拟机工作不正常的情况请在下方固定一下给VF分配的mac地址。
[Unit]
Description=Enable SR-IOV

[Service]
Type=oneshot

# 创建VF 数字8代表创建8个VF
ExecStart=/usr/bin/bash -c '/usr/bin/echo 8 > /sys/class/net/enp1s0f0/device/sriov_numvfs'

# 固定VF的mac地址
ExecStart=/usr/bin/bash -c '/usr/bin/ip link set dev enp1s0f0 vf 0 mac 00:19:80:04:25:01'
ExecStart=/usr/bin/bash -c '/usr/bin/ip link set dev enp1s0f0 vf 1 mac 00:19:80:04:25:02'
ExecStart=/usr/bin/bash -c '/usr/bin/ip link set dev enp1s0f0 vf 2 mac 00:19:80:04:25:03'
ExecStart=/usr/bin/bash -c '/usr/bin/ip link set dev enp1s0f0 vf 3 mac 00:19:80:04:25:04'
ExecStart=/usr/bin/bash -c '/usr/bin/ip link set dev enp1s0f0 vf 4 mac 00:19:80:04:25:05'
ExecStart=/usr/bin/bash -c '/usr/bin/ip link set dev enp1s0f0 vf 5 mac 00:19:80:04:25:06'
ExecStart=/usr/bin/bash -c '/usr/bin/ip link set dev enp1s0f0 vf 6 mac 00:19:80:04:25:07'
ExecStart=/usr/bin/bash -c '/usr/bin/ip link set dev enp1s0f0 vf 7 mac 00:19:80:04:25:08'

Restart=on-failure

[Install]
WantedBy=multi-user.target

我们可以先测试一下这个脚本。先把”你想要创建的vf个数”改为0,然后:

systemctl enable sriov.service --now

接着使用和上面同样的命令查看网卡:

lspci | grep Eth

如果之前出现的”Virtual Function”消失了那么说明脚本没问题,修改”你想要创建的vf个数”后重载一下service就可以了。完成这一步后理论上每次重启pve之后VF也会在开机时一起被创建。

4. 让PF跟随开机启动

要使用VF我们得让PF先启动。这一步就比较简单了,我们只需要在pve的web后台中将网卡改成自动启动就可以了。操作完成后点击右边的应用设置。

如果想要后续给Windows虚拟机分配VF网卡,建议先将这些vf都设置为开机自启

5. 阻止PVE加载VF

由于我们要将vf分配给虚拟机,pve加载这些vf可能导致一些问题。

首先执行以下命令查看虚拟网卡所使用的驱动

lspci -nnk | grep -A4 Eth

可以看到,我的X520-DA2的VF使用的是驱动名字是ixgbevf。

接着在 /etc/modprobe.d/pve-blacklist.conf中添加下面这行:

blacklist 驱动名称

# 接着保存文件,运行以下命令应用修改:
update-initramfs -u -k all

然后重启pve即可。顺利的话开机后在web后台的网络中就能看到VF出现并已经是启用状态啦!

6. 给虚拟机分配SR-IOV网卡

(1) Linux

Linux下没什么好说的,大部分都自带驱动。我们只要在虚拟机的硬件设置中的PCI设备中添加生成的VF之后正常开机即可。

注意不要勾选All Functions,勾了All Functions以后所以的VF都会被分配到这一个虚拟机里。

如果是想将之前已经使用了Virt-IO网卡的虚拟机替换为SR-IOV网卡或者是需要使用Cloud-init新建虚拟机,最好先将Virt-IO网卡的名称改成”eth0″,不然大概率需要手动配置ip上去。

(2)Windows

分配VF

Windows虚拟机开机之前必须保证分配进去的VF是活动状态!!!

如果不是活动状态的话,之后windows里会一直显示网线被拔出,无法正常联网。

同时建议先同时分配一个Virt-IO的网卡进去,方便下载驱动。

在添加VF的时候记得勾上PCI-Express

加载Windows下VF驱动

首先从Intel官网下载驱动包 (Wired-Driver就行)

https://www.intel.com/content/www/us/en/download/18293/intel-network-adapter-driver-for-windows-10.html

对于老网卡来说最新的驱动可能会有问题。比如我的X520-DA2使用最新的27.3驱动会一直显示网线被拔出。使用26.4版本的驱动可以正常工作。

参考:https://forum.level1techs.com/t/solved-sr-iov-network-works-for-linux-but-not-windows/179507/6

下载后使用bandizip或者其他压缩软件解压exe文件(虽然他看起来是个exe但是是可以打开提取里面的文件的)。这时候就要找一找里面一堆文件夹里哪个是包含你自己的网卡的驱动了。找对对应网卡以及系统版本后把这个文件夹复制出来。我的X520在Win11下能用的驱动是在/PROXGB/Winx64/NDIS68下面。

打开设备管理器,其他设备里应该会有个没驱动的以太网控制器,右键安装驱动,路径指向刚才导出来的文件夹

没问题的话刷新一下设备管理器,就能看到网卡正常工作了。如果是DHCP的话现在就能上网了,用静态ip的话正常配置一下就行。

部分网卡在开启SR-IOV后的虚拟机无法ping通其他虚拟机的解决方法

在PVE下开完SR-IOV后发现使用VF的虚拟机ping不通其他使用virt-io网卡的虚拟机。谷歌上搜索后发现应该是英特尔部分老网卡(包括我的X520)的驱动问题。左侧的 VM(通过 VF 驱动程序)无法与右侧的 VM 通信(通过 PF 的网桥),而两者都可以与PF本身和外部主机通信。

总之我找到了一个非常棒的自动化脚本可以完美解决这个问题。这个脚本可以定时帮你检查容器或VM的所有mac地址是否已经在接口的ForwardDB中,如果不在的话就帮你添加进去。

#!/usr/bin/bash
#
# vf_add_maddr.sh Version 1.1
# Script is based on kriss35
# Update by Rama: Added vmbridge macaddress itself, simplified, systemd-service(RestartOnFailure) Compatible and speeded up with a tmpfile(one readout).
# Usage: execute directly without arguments, make an systemd-service or add it to crontab to run every x Minutes.
#
CTCONFDIR=/etc/pve/nodes/proxmox/lxc
VMCONFDIR=/etc/pve/nodes/proxmox/qemu-server
IFBRIDGE=enp35s0f0
LBRIDGE=vmbr0
TMP_FILE=/tmp/vf_add_maddr.tmp

C_RED='\e[0;31m'
C_GREEN='\e[0;32m'
C_NC='\e[0m'

if [ ! -d $CTCONFDIR ] || [ ! -d $VMCONFDIR ]; then
        echo -e "${C_RED}ERROR: Not mounted, self restart in 5s!${C_NC}"
        exit 1
else
        MAC_LIST_VMS=" $(cat ${VMCONFDIR}/*.conf | grep bridge | grep -Eo '([[:xdigit:]]{1,2}[:-]){5}[[:xdigit:]]{1,2}' | tr '[:upper:]' '[:lower:]') $(cat ${CTCONFDIR}/*.conf | grep hwaddr | grep -Eo '([[:xdigit:]]{1,2}[:-]){5}[[:xdigit:]]{1,2}' | tr '[:upper:]' '[:lower:]')"
        MAC_ADD2LIST="$(cat /sys/class/net/$LBRIDGE/address)"
        MAC_LIST="$MAC_LIST_VMS $MAC_ADD2LIST"
        /usr/sbin/bridge fdb show | grep "${IFBRIDGE} self permanent" > $TMP_FILE

        for mactoregister in ${MAC_LIST}; do
                if ( grep -Fq $mactoregister $TMP_FILE ); then
                        echo -e "${C_GREEN}$mactoregister${C_NC} - Exists!"
                else
                        /usr/sbin/bridge fdb add $mactoregister dev ${IFBRIDGE}
                        echo -e "${C_RED}$mactoregister${C_NC} - Added!"
                fi
        done
        exit 0
fi

复制上面的内容,将它保存为一个.sh的脚本文件。我这里名字为“sr-iov-registermacaddr.sh” 接着我们可以先试运行一下:

chmod +x sr-iov-registermacaddr.sh && ./sr-iov-registermacaddr.sh

由于我前面已经运行过了所以显示Exists。总之只要显示的是绿色的就没问题。出现红色的报错就检查一下上面脚本里的”CTCONFDIR”和”VMCONFDIR”两个路径是不是和你本地PVE的虚拟机config存放路径一样。

现在再试试从启用了SR-IOV网卡的机器中ping其他机器,正常的话应该就通了。

赞(3)
未经允许不得转载:疯言疯语 » PVE下开启网卡SR-IOV