如何在Proxmox VE 8上配置使用Mellanox网卡的OVS Hardware Offload

3,456 阅读8分钟

写这个文章主要是因为最近收了一张洋垃圾ConnectX-6 Dx网卡,看文档的时候突然发现这个东西支持一个叫ASAP2的功能,说是网卡的ASIC上面有个embedded switch(下面简称e-switch)可以加速vm的流量转发。听上去就很厉害,于是我试着配置了一下。结果一折腾就是一整个月哈哈😂😂😂,今天回想了一下觉得还挺有意思的,就写一篇文记录下来。

首先说点Disclaimer,本人不是网络工程师也不是专业运维,可能有些地方会说错,还请大家指正。另外就是既然你搜到了这个文章,应该也不会是新手小白,请直接看感兴趣的部分就行😋。

介绍

(上来就盗一张NV的图) 盗一张NV的图

e-switch offload的原理大概就是上面这个样子,网卡通过启动SRIOV虚拟化生成VF(virtual function)分配给虚拟机,然后Host上面的openvswitch(下面简称OVS)或者Linux Bridge通过监听网桥上面的流量,把对应的flow规则写到网卡的ASIC上面,接下来网卡硬件就能根据记下来规则转发封包,不需要Host的网桥软件参与,实现硬件转发。而且因为转发是发生在ASIC上面,vf之间的转发速度上限最后会落到PCIE总线或者内存速度上(看cpu性能还有vm数量),而不是网络接口上。

给大家看一张从Linux Bridge切换到e-switch之后的Server Load对比:

服务器负载对比

我这台机主要负载是文件服务,可以看到使用了e-switch之后Server Load差不多减少了50%

配置流程

安装MLNX驱动 ==> 启用SRIOV ===> 配置PCI直通 ==> 配置SRIOV ==> 配置OVS ==> 保存最终配置

其实除了最后一步,都能在网络上找到教程或者相关的文档,我会把相应的链接贴到步骤的最后面

安装MLNX驱动

首先去Nvidia官网下载MLNX_EN驱动(Proxmox自带的驱动似乎不行,可能是我太菜🫠):

network.nvidia.com/products/et…

选择最新版,Debian 12,iso或者tgz看你喜欢,我选择tgz

image.png

在Proxmox的控制台下载驱动压缩包:

wget 'https://www.mellanox.com/downloads/ofed/MLNX_EN-23.10-1.1.9.0/mlnx-en-23.10-1.1.9.0-debian12.1-x86_64.tgz' # 记得把上面的链接换成最新的链接

记得把上面的链接换成最新的链接!

这里插一句题外话,其实我这部机的proxmox 8.10用的是Ubuntu23.10的内核,但是因为系统依赖的关系,Ubuntu版驱动装不上。

解压缩:

tar -xf mlnx-en-23.10-1.1.9.0-debian12.1-x86_64.tgz # 同上,记得替换成最新的文件名

安装驱动:

cd mlnx-en-23.10-1.1.9.0-debian12.1-x86_64
./install --skip-distro-check # 跳过distro检查,因为proxmox不是debian

(其实装mlnx-en而不是mlnx-ofed一个原因是proxmox上面安装ofed版本驱动会有依赖冲突,另一个原因是我本身只用ethernet)

这里驱动就安装完成了,建议重启一次电脑

配置SRIOV

ConnectX这个系列网卡的SRIOV功能要在固件层面先打开

启动mst并查看网卡路径

mst start  # 启动mst
mst status # 查看网卡路径

image.png

这里我们复制我高亮出来的网卡路径

查看固件SRIOV状态

mlxconfig -d /dev/mst/mt4125_pciconf0 q | grep -e SRIOV_EN -e NUM_OF_VFS

image.png

SRIOV_EN是网卡SRIOV功能的状态,我这里是true,就是已启动

NUM_OF_VFS是网卡最多支持的VF数量,就是虚拟网卡的数量,这里是16,就是最多支持16个

启动固件SRIOV

如果查询出来的SRIOV_EN是false或者NUM_OF_VFS是0还是太小的数值的话:

mlxconfig -d /dev/mst/mt4125_pciconf0 set SRIOV_EN=1 NUM_OF_VFS=4 # 改成你需要的vf数量

这里要注意vf的数量是够用就好,不是越大越好。

到这里启动SRIOV的部分就完成了,上面的这些固件改动需要电脑重启之后才能生效,没有改动的话也可以不重启

备注

配置固件的方法以NV的文档为准: enterprise-support.nvidia.com/s/article/H…

配置PCI Passthrough

确认主板已启动IOMMU

这里以主板manual为准

启用kernel IOMMU参数

如果用的是默认的grub引导的话

vi /etc/default/grub
# 然后在 GRUB_CMDLINE_LINUX_DEFAULT 里面加上 intel_iommu=on iommu=pt
# 或者如果是amd平台的话 amd_iommu=on iommu=pt 如下图

update-grub

image.png

如果用的是systemd-boot引导的话(zfs安装是systemd引导)

vi /etc/kernel/cmdline
# 然后在最后面加上 intel_iommu=on iommu=pt
# 或者如果是amd平台的话 amd_iommu=on iommu=pt 如下图

proxmox-boot-tool refresh

image.png

启用vfio modules

vi /etc/modules
# 然后在最后面加上
# vfio
# vfio_iommu_type1
# vfio_pci

update-initramfs -u -k all

重启电脑并验证IOMMU功能

journalctl -k | grep -e DMAR -e IOMMU -e AMD-Vi

找一下出来的结果里面有没有这句话:

DMAR: IOMMU enabled

有的话这一步就完成了

备注

这里以proxmox文档为准: pve.proxmox.com/pve-docs/pv…

配置SRIOV

找到你的网卡

ip link show

或者直接去proxmox的web ui看,这里我的网卡叫 enp7s0f0np0

image.png

切换网卡eswitch模式为 switchdev

echo switchdev > /sys/class/net/enp129s0f1/compat/devlink/mode

添加SRIOV VF:

这里先添加两个vf

echo 2 > /sys/class/net/enp7s0f0np0/device/sriov_numvfs # enp7s0f0np0 替换成你的网卡

然后你就能看到新建出来两个vf和两个vf representor,见上图(有个vf被我屏蔽了)

enp7s0f0v0 enp7s0f0v1 是vf,注意结尾是v0和v1。

enp7s0f0npf0vf0 enp7s0f0npf0vf1 是vf representor,注意结尾是npf0vf0和npf0vf1,(当然中间不一定是pf0,也可能是pf1什么的,要看vf所属于的pf序号是几)

vf到时候可以分配给vm或者lxc用,vf representor是添加到linux bridge或者ovs里面代表vf用的,这里要注意一点是sysfs的改动在电脑重启之后会被抹除,所以这里我们可以先配着继续配着玩一玩,在确认了最后的网络配置之后,我们再编写具体的配置文件保存配置。

配置OVS

我们可以先把一个vf分配给vm,在web ui上面操作就可以了

image.png

接下来可以启动vm,Linux vm基本上是免驱的,自带mlx5_core module.

Windows vm需要去nv官网下载WinOF-2驱动: network.nvidia.com/products/ad…

vm启动之后我们ping一下就会发现没有连上网,这是因为我们还需要把vf representor添加到ovs里面:

创建OVS网桥并添加端口

ethtool -K enp7s0f0np0 hw-tc-offload on
ovs-vsctl set Open_vSwitch . other_config:hw-offload=true # 启动硬件卸载
systemctl restart openvswitch.service

ovs-vsctl add-br vmbr2
ovs-vsctl add-port vmbr2 enp7s0f0np0
ovs-vsctl add-port vmbr2 enp7s0f0npf0vf0
ovs-vsctl add-port vmbr2 enp7s0f0npf0vf1

ip link set dev enp7s0f0np0
ip link set dev enp7s0f0npf0vf0
ip link set dev enp7s0f0npf0vf1

这一步做完就会发现已经有网了,接下来可以验证一下hardware offload有没有运作

ovs-appctl dpctl/dump-flows type=offloaded

如果跟我一样看到一大堆东西出来就是一切正常了

image.png

接下来我们可以随便玩玩,想好接下来的固定配置要配什么。

备注

nv的官方文档: docs.nvidia.com/networking/…

openstack的ovs offload文档: docs.openstack.org/neutron/zed…

intel的switchdev脚本: edc.intel.com/content/www…

保存最终配置

上面我们说到sysfs重启之后就会被清除,而proxmox开机的时候也会删除ovs-db,于是我们现在还需要多一步来保存最后决定的配置

我这里使用udev来保持sriov的状态,用proxmox自带的ifupdown2来保持ovs的配置

配置udev

注意我们首先要获得网卡的mac,用你熟悉的方式就行不赘述

cat <<EOF > etc/udev/rules.d/99-sriov.rules
ACTION=="add", SUBSYSTEM=="net", ENV{ID_NET_DRIVER}=="mlx5_core", ATTR{address}=="08:c0:eb:32:98:11", ATTR{compat/devlink/mode}="switchdev"
ACTION=="add", SUBSYSTEM=="net", ENV{ID_NET_DRIVER}=="mlx5_core", ATTR{address}=="08:c0:eb:32:98:11", ATTR{device/sriov_numvfs}="2"
EOF

这里第一句是修改网卡eswitch模式为switchdev,第二句是创建2个vf

注意文件名99-sriov.rules可以改成你喜欢的名字,还有网卡的mac地址要改成你的网卡的地址

配置ifupdown2

vi /etc/network/interfaces

这里可以参考我的配置:

auto enp7s0f0np0
iface enp7s0f0np0 inet manual
	ovs_type OVSPort
	ovs_bridge vmbr2

auto enp7s0f0npf0vf0
iface enp7s0f0npf0vf0 inet manual
	ovs_type OVSPort
	ovs_bridge vmbr2

auto enp7s0f0npf0vf1
iface enp7s0f0npf0vf1 inet manual
	ovs_type OVSPort
	ovs_bridge vmbr2

auto vmbr2
iface vmbr2 inet static
	address 192.168.1.101/24
	gateway 192.168.1.1
	ovs_type OVSBridge
	ovs_ports enp7s0f0np0 enp7s0f0npf0vf0 enp7s0f0npf0vf1
	pre-up /usr/bin/ovs-vsctl set Open_vSwitch . other_config:hw-offload=true
	pre-up /usr/bin/ovs-vsctl set Open_vSwitch . other_config:max-idle=30000
	pre-up /usr/bin/systemctl restart openvswitch-switch.service
	post-up /usr/sbin/ethtool -K enp7s0f0np0 hw-tc-offload on
	post-up /usr/sbin/ip link set enp7s0f0np0 vf 0 mac BA:DD:AD:DE:AD:30
	post-up /usr/sbin/ip link set enp7s0f0np0 vf 1 mac BA:DD:AD:DE:AD:31

到这里整个这一步就做完了,可以重启一下机器验证一下配置有没有成功啦🎉🎉🎉。

最后

谢谢你能看到这里!🥳