写这个文章主要是因为最近收了一张洋垃圾ConnectX-6 Dx网卡,看文档的时候突然发现这个东西支持一个叫ASAP2的功能,说是网卡的ASIC上面有个embedded switch(下面简称e-switch)可以加速vm的流量转发。听上去就很厉害,于是我试着配置了一下。结果一折腾就是一整个月哈哈😂😂😂,今天回想了一下觉得还挺有意思的,就写一篇文记录下来。
首先说点Disclaimer,本人不是网络工程师也不是专业运维,可能有些地方会说错,还请大家指正。另外就是既然你搜到了这个文章,应该也不会是新手小白,请直接看感兴趣的部分就行😋。
介绍
(上来就盗一张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
在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 # 查看网卡路径
这里我们复制我高亮出来的网卡路径
查看固件SRIOV状态
mlxconfig -d /dev/mst/mt4125_pciconf0 q | grep -e SRIOV_EN -e NUM_OF_VFS
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
如果用的是systemd-boot引导的话(zfs安装是systemd引导)
vi /etc/kernel/cmdline
# 然后在最后面加上 intel_iommu=on iommu=pt
# 或者如果是amd平台的话 amd_iommu=on iommu=pt 如下图
proxmox-boot-tool refresh
启用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
切换网卡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上面操作就可以了
接下来可以启动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
如果跟我一样看到一大堆东西出来就是一切正常了
接下来我们可以随便玩玩,想好接下来的固定配置要配什么。
备注
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
到这里整个这一步就做完了,可以重启一下机器验证一下配置有没有成功啦🎉🎉🎉。
最后
谢谢你能看到这里!🥳