在 CentOS 上使用 SRIOV

CentOS 下 sriov 环境配置笔记.

0x00 检查基础环境

查看 BIOS 是否支持 VT-d 功能,如支持的话开启相关的功能。

查看物理网卡是否支持 SR-IOV:

1
2
3
4
5
lspci -vv

...
Initial VFs: 64, Total VFs: 64, Number of VFs: 0, Function Dependency Link: 00
...

可以尝试保存成文本并搜索 SR-IOV 关键字,如果有表示网卡支持 SR-IOV 功能,同时 Total VFs: 64 表示该 PF 最多支持 64 个 VF。

0x01 开启 SR-IOV

1. 开启 IOMMUO 功能

开启 SR-IOV 会导致 DPDK 的 igb_uio 和 kni 无法使用. 强行使用 igb_uio dpdk eal 初始化会显示因网卡可使用队列为 0 无法初始化, kni 端口则不会出现在 ip addr 列表中.

/etc/default/grub 文件最后加上参数, 不同品牌的 CPU 所需的内核参数并不同:

  • 对于 Intel CPU(VT-d), 使用 intel_iommu=on
  • 对于 AMD CPU(AMD-Vi), 使用 amd_iommu=on

同时需要设置iommu=pt, 这将防止Linux试图接触(touching)无法直通的设备:

1
2
3
4
5
6
7
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet intel_iommu=on iommu=pt"
GRUB_DISABLE_RECOVERY="true"

重新生成 grub.cfg

1
2
3
4
5
6
7
8
9
10
# 备份
# 如果是 BIOS
cp /boot/grub2/grub.cfg /boot/grub2/grub.cfg.bak
# 如果是 UEFI
cp /boot/efi/EFI/centos/grub.cfg /boot/efi/EFI/centosgrub.cfg.bak

# 重新生成配置 BIOS
grub2-mkconfig -o /boot/grub2/grub.cfg
# 重新生成配置 UEFI
grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg

确认 IOMMU 功能确实打开

1
2
3
4
5
dmesg | grep -e DMAR -e IOMMU

...
DMAR: IOMMU enabled
...

2. 开启 Virtual Function

确认网卡的驱动:

1
2
3
4
5
ethtool -i enp24s0f0

...
driver: ixgbe
...

有三种方式开启 Virtual Function:

  1. 创建或修改驱动配置文件

增加 vfs 相关的配置。如在 /etc/modprobe.d/ixgbe.conf 中添加:

1
options ixgbe max_vfs=2

重新生成配置后重启系统生效.

  1. 修改 /etc/default/grub

如在最后添加相关配置:

1
2
3
4
5
6
7
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet intel_iommu=on iommu=pt ixgbe.max_vfs=2"
GRUB_DISABLE_RECOVERY="true"

重新生成配置后重启系统生效.

  1. 临时启用
1
echo 2 | tee /sys/bus/pci/devices/0000:18:00.0/sriov_numvfs

检查:

1
2
3
4
5
6
lspci -vv  | grep 82599

18:00.0 Ethernet controller: Intel Corporation 82599ES 10-Gigabit SFI/SFP+ Network Connection (rev 01)
18:00.1 Ethernet controller: Intel Corporation 82599ES 10-Gigabit SFI/SFP+ Network Connection (rev 01)
18:10.0 Ethernet controller: Intel Corporation 82599 Ethernet Controller Virtual Function (rev 01)
18:10.2 Ethernet controller: Intel Corporation 82599 Ethernet Controller Virtual Function (rev 01)

0x02 配置 Virtual Function

查看 VF 的 MAC 地址:

1
2
3
4
5
6
7
ip link show
...
2: enp130s0f0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq master br0 state UP mode DEFAULT qlen 1000
link/ether 00:1b:21:ba:99:a4 brd ff:ff:ff:ff:ff:ff
vf 0 MAC 00:00:00:00:00:00, spoof checking on, link-state auto, trust off
vf 1 MAC 00:00:00:00:00:00, spoof checking on, link-state auto, trust off
...

给 VF 配置默认 MAC 地址, 之后的 virtio 的 mac 地址需要和这里设置的地址一样:

1
ip link set <pf_name> vf <vf_num> mac <mac_address>

给 VF 开启组播允许功能:

1
ip link set <pf_name> vf <vf_num> trust on

0x03 Flow Director 配置

1
2
3
4
5
6
7
8
9
10
11
# 配置 FDir 规则
# 根据访问目的 ip
ethtool -N <PORT_NAME> flow-type tcp4 src-ip $sipass_addr action $queue_index_in_VFn
# 根据访问目的 ip 和目的 port
ethtool -N <PORT_NAME> flow-type tcp4 src-ip $sipass_addr dst-port $sipass_port action $queue_index_in_VFn

# 查看规则
ethtool -n <PORT_NAME>

# 删除规则
ethtool -N <PORT_NAME> delete <RULE_NUM>

其中 $queue_index_in_VFn:

  • 39:32 位代表 VF id + 1
  • 低 32 位代表 VF 的队列号

因此 $queue_index_in_VFn = (0xn & 0xFF) << 32 + [queue index].

1
2
63    40 | 39   30 | 31        0
0x000000 | VF_ID+1 | QUEUE_INDEX

参考:

intel 技术支持

DPDK 文档