配置 SR-IOV

通过配置物理服务器节点支持创建带有 SR-IOV(Single Root I/O Virtualization)网卡的虚拟机,实现虚拟机的更低延迟,同时支持独立 IPv6 以及双栈 IPv4/IPv6 功能。

术语

术语定义
Multus CNI作为其他 CNI 插件的中间件,使 Kubernetes 支持 Pod 的多网络接口。
SR-IOV允许对节点上的物理 NIC 进行虚拟化,将其拆分为多个 VF 供 Pod 或虚拟机使用,提供更优异的网络性能。
VF从物理 PCI 设备创建的虚拟设备;VF 可以直接分配给虚拟机或容器,类似独立的物理 PCI 设备,显著提升 I/O 性能。

约束与限制

SR-IOV 功能依赖于 glibc,仅支持 glibc 版本 2.34 及以上。但 Kylin V10 和 CentOS 7.x 操作系统均不支持该版本,因此这两种操作系统无法使用 SR-IOV 功能。

前提条件

获取以下 charts 和镜像并上传至镜像仓库。本文档以仓库地址 build-harbor.example.cn 为例。具体获取 charts 和镜像的方法,请联系相关人员。

Chart

  • build-harbor.example.cn/example/chart-sriov-network-operator:v3.15.0

镜像

  • build-harbor.example.cn/3rdparty/sriov/sriov-network-operator:4.13
  • build-harbor.example.cn/3rdparty/sriov/sriov-network-operator-config-daemon:4.13
  • build-harbor.example.cn/3rdparty/sriov/sriov-cni:4.13
  • build-harbor.example.cn/3rdparty/sriov/ib-sriov-cni:4.13
  • build-harbor.example.cn/3rdparty/sriov/sriov-network-device-plugin:4.13
  • build-harbor.example.cn/3rdparty/sriov/network-resources-injector:4.13
  • build-harbor.example.cn/3rdparty/sriov/sriov-network-operator-webhook:4.13
  • build-harbor.example.cn/3rdparty/kubectl:v3.15.1

操作步骤

注意:以下所有命令均在终端执行。

在物理机 BIOS 中启用 SR-IOV

配置前,使用以下命令查看主板信息。

dmidecode -t 1
# dmidecode 3.3
Getting SMBIOS data from sysfs.
SMBIOS 2.7 present.

Handle 0x0100, DMI type 1, 27 bytes
System Information
    Product Name: PowerEdge R620
    Version: Not Specified
    Serial Number: 7SJNF62
    UUID: 4c4c4544-0053-4a10-804e-b7c04f463632
    Wake-up Type: Power Switch
    SKU Number: SKU=NotProvided;ModelName=PowerEdge R620
    Family: Not Specified

BIOS 中启用 SR-IOV 的操作因服务器厂商不同而异,请参考对应厂商文档。一般步骤如下:

  1. 重启服务器。

  2. BIOS POST 期间屏幕显示品牌 Logo 时,按 F2 键进入系统设置。

  3. 点击 Processor Settings > Virtualization Technology,将 Virtualization Technology 设置为 Enabled

  4. 点击 Settings > Integrated devices,将 SR-IOV Global Enable 设置为 Enabled

  5. 保存配置并重启服务器。

启用 IOMMU

启用 IOMMU 的操作因操作系统不同而异,请参考对应操作系统文档。本文档以 CentOS 为例。

  1. 编辑 /etc/default/grub 文件,在 GRUB_CMDLINE_LINUX 配置项中添加 intel_iommu=on iommu=pt

    GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=centos/root rhgb quiet intel_iommu=on iommu=pt"
  2. 执行以下命令生成 grub.cfg 文件。

    grub2-mkconfig -o /boot/grub2/grub.cfg
  3. 重启服务器。

  4. 执行以下命令,若输出包含 IOMMU enabled,则表示启用成功。

    dmesg | grep -i iommu

在系统内核加载 VFIO 模块

  1. 执行以下命令加载 vfio-pci 模块。

    modprobe vfio-pci
  2. 加载后执行以下命令,若能正常显示配置信息,则表示 VFIO 内核模块加载成功。

    # CentOS 下检查 VFIO 加载状态
    lsmod | grep vfio
    vfio_pci               41993  0
    vfio_iommu_type1       22440  0
    vfio                   32657  2 vfio_iommu_type1, vfio_pci
    irqbypass              13503  2 kvm, vfio_pc
    
    
    # Ubuntu 下检查 VFIO 加载状态
    cat /lib/modules/$(uname -r)/modules.builtin | grep vfio
    kernel/drivers/vfio/vfio.ko
    kernel/drivers/vfio/vfio_virqfd.ko
    kernel/drivers/vfio/vfio_iommu_type1.ko
    kernel/drivers/vfio/pci/vfio-pci-core.ko
    kernel/drivers/vfio/pci/vfio-pci.ko

创建 VF 设备

  1. 执行以下命令查看当前支持的 VF 设备。

    find /sys -name *vfs*
    
    /sys/devices/pci0000:00/0000:00:03.0/0000:05:00.1/sriov_totalvfs
    /sys/devices/pci0000:00/0000:00:03.0/0000:05:00.1/sriov_numvfs
    /sys/devices/pci0000:00/0000:00:03.0/0000:05:00.0/sriov_totalvfs
    /sys/devices/pci0000:00/0000:00:03.0/0000:05:00.0/sriov_numvfs

    输出信息说明:

    • 0000:05:00 .1:SR-IOV 物理网卡 enp5s0f1 的 PCI 地址。

    • 0000:05:00 .0:SR-IOV 物理网卡 enp5s0f0 的 PCI 地址。

    • sriov_totalvfs:支持的 VF 数量。

    • sriov_numvfs:当前 VF 数量。

  2. 执行以下命令查看物理机的网卡信息。

    ifconfig
    
    enp5s0f0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet 192.168.66.213  netmask 255.255.255.0  broadcast 192.168.66.255
            inet6 1066::192:168:66:213  prefixlen 112  scopeid 0x0<global>
            inet6 fe80::a236:9fff:fe29:6c00  prefixlen 64  scopeid 0x20<link>
            ether a0:36:9f:29:6c:00  txqueuelen 1000  (Ethernet)
            RX packets 13889  bytes 1075801 (1.0 MB)
            RX errors 0  dropped 1603  overruns 0  frame 0
            TX packets 5057  bytes 440807 (440.8 KB)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    
    enp5s0f1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet6 fe80::a236:9fff:fe29:6c02  prefixlen 64  scopeid 0x20<link>
            ether a0:36:9f:29:6c:02  txqueuelen 1000  (Ethernet)
            RX packets 1714  bytes 227506 (227.5 KB)
            RX errors 0  dropped 1604  overruns 0  frame 0
            TX packets 70  bytes 19241 (19.2 KB)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
  3. 执行命令 ethtool -i <NIC name> 获取对应物理网卡的 PCI 地址,如下所示。

    ethtool -i enp5s0f0
    driver: ixgbe
    version: 5.15.0-76-generic
    firmware-version: 0x8000030d, 14.5.8
    expansion-rom-version:
    bus-info: 0000:05:00.0     ## enp5s0f0 网卡的 PCI 地址
    supports-statistics: yes
    supports-test: yes
    supports-eeprom-access: yes
    supports-register-dump: yes
    supports-priv-flags: yes
    
    
    ethtool -i enp5s0f1
    driver: ixgbe
    version: 5.15.0-76-generic
    firmware-version: 0x8000030d, 14.5.8
    expansion-rom-version:
    bus-info: 0000:05:00.1    ## enp5s0f1 网卡的 PCI 地址
    supports-statistics: yes
    supports-test: yes
    supports-eeprom-access: yes
    supports-register-dump: yes
    supports-priv-flags: yes
  4. 执行以下命令创建 VF。本文档以配置 enp5s0f1 网卡为例,若需虚拟化多个网卡,则需全部配置。

    cat /sys/devices/pci0000:00/0000:00:03.0/0000:05:00.1/sriov_totalvfs   ## 查看支持的 VF 数量
    63
    
    echo 8 > /sys/devices/pci0000:00/0000:00:03.0/0000:05:00.1/sriov_numvfs  ## 设置当前 VF 数量
    
    cat /sys/devices/pci0000:00/0000:00:03.0/0000:05:00.1/sriov_numvfs   ## 查看当前 VF 数量
    8
  5. 执行以下命令检查 VF 是否创建成功。

    注意:可看到配置的 8 个 VF 地址,如 05:10.1,这些 VF 地址需补充 Domain Identifier,最终格式为:0000:05:10.1

    lspci | grep Virtual
    00:11.0 PCI bridge: Intel Corporation C600/X79 series chipset PCI Express Virtual Root Port (rev 05)
    05:10.1 Ethernet controller: Intel Corporation 82599 Ethernet Controller Virtual Function (rev 01)
    05:10.3 Ethernet controller: Intel Corporation 82599 Ethernet Controller Virtual Function (rev 01)
    05:10.5 Ethernet controller: Intel Corporation 82599 Ethernet Controller Virtual Function (rev 01)
    05:10.7 Ethernet controller: Intel Corporation 82599 Ethernet Controller Virtual Function (rev 01)
    05:11.1 Ethernet controller: Intel Corporation 82599 Ethernet Controller Virtual Function (rev 01)
    05:11.3 Ethernet controller: Intel Corporation 82599 Ethernet Controller Virtual Function (rev 01)
    05:11.5 Ethernet controller: Intel Corporation 82599 Ethernet Controller Virtual Function (rev 01)
    05:11.7 Ethernet controller: Intel Corporation 82599 Ethernet Controller Virtual Function (rev 01)

绑定 VFIO 驱动

  1. 下载 绑定脚本,执行 python3 dpdk-devbind.py -b vfio-pci <带域标识的 VF 地址> 命令,将 enp5s0f1 网卡的 8 个 VF 绑定到 vfio-pci 驱动,示例如下。

    python3 dpdk-devbind.py -b vfio-pci 0000:05:10.1
    python3 dpdk-devbind.py -b vfio-pci 0000:05:10.3
    python3 dpdk-devbind.py -b vfio-pci 0000:05:10.5
    python3 dpdk-devbind.py -b vfio-pci 0000:05:10.7
    python3 dpdk-devbind.py -b vfio-pci 0000:05:11.1
    python3 dpdk-devbind.py -b vfio-pci 0000:05:11.3
    python3 dpdk-devbind.py -b vfio-pci 0000:05:11.5
    python3 dpdk-devbind.py -b vfio-pci 0000:05:11.7
  2. 绑定成功后,执行以下命令检查绑定结果。在输出结果的 Network devices using DPDK-compatible driver 区域查找已绑定的 VF,其中 VF 设备 ID 为 10ed

    python3 dpdk-devbind.py --status
    
    Network devices using DPDK-compatible driver
    ============================================
    0000:05:10.1 '82599 Ethernet Controller Virtual Function 10ed' drv=vfio-pci unused=ixgbevf
    0000:05:10.3 '82599 Ethernet Controller Virtual Function 10ed' drv=vfio-pci unused=ixgbevf
    0000:05:10.5 '82599 Ethernet Controller Virtual Function 10ed' drv=vfio-pci unused=ixgbevf
    0000:05:10.7 '82599 Ethernet Controller Virtual Function 10ed' drv=vfio-pci unused=ixgbevf
    0000:05:11.1 '82599 Ethernet Controller Virtual Function 10ed' drv=vfio-pci unused=ixgbevf
    0000:05:11.3 '82599 Ethernet Controller Virtual Function 10ed' drv=vfio-pci unused=ixgbevf
    0000:05:11.5 '82599 Ethernet Controller Virtual Function 10ed' drv=vfio-pci unused=ixgbevf
    0000:05:11.7 '82599 Ethernet Controller Virtual Function 10ed' drv=vfio-pci unused=ixgbevf
    
    Network devices using kernel driver
    ===================================
    0000:01:00.0 'NetXtreme BCM5720 Gigabit Ethernet PCIe 165f' if=eno1 drv=tg3 unused=vfio-pci
    0000:01:00.1 'NetXtreme BCM5720 Gigabit Ethernet PCIe 165f' if=eno2 drv=tg3 unused=vfio-pci
    0000:02:00.0 'NetXtreme BCM5720 Gigabit Ethernet PCIe 165f' if=eno3 drv=tg3 unused=vfio-pci
    0000:02:00.1 'NetXtreme BCM5720 Gigabit Ethernet PCIe 165f' if=eno4 drv=tg3 unused=vfio-pci
    0000:05:00.0 'Ethernet 10G 2P X520 Adapter 154d' if=enp5s0f0 drv=ixgbe unused=vfio-pci *Active*
    0000:05:00.1 'Ethernet 10G 2P X520 Adapter 154d' if=enp5s0f1 drv=ixgbe unused=vfio-pci
    
    No 'Baseband' devices detected
    ==============================
    
    No 'Crypto' devices detected
    ============================
    
    No 'DMA' devices detected
    =========================
    
    No 'Eventdev' devices detected
    ==============================
    
    No 'Mempool' devices detected
    =============================
    
    No 'Compress' devices detected
    ==============================
    
    No 'Misc (rawdev)' devices detected
    ===================================
    
    No 'Regex' devices detected
    ===========================

部署 Multus CNI 插件

  1. 进入 Administrator

  2. 在左侧导航栏点击 Cluster Management > Clusters

  3. 点击虚拟机集群名称,切换到 Plugins 标签页。

    • 部署 Multus CNI 插件。

部署 sriov-network-operator

执行以下命令部署 sriov-network-operator。

REGISTRY=<$registry>  # 将 <$registry> 替换为 sriov-network-operator 镜像所在的仓库地址,例如:REGISTRY=build-harbor.example.cn
NICSELECTOR=["<nics>"] # 将 <nics> 替换为网卡名称,例如:NICSELECTOR=["ens802f1","ens802f2"],多个用逗号分隔
NUMVFS=<numVfs> # 将 <numVfs> 替换为 VF 数量,例如:NUMVFS=8

cat <<EOF | kubectl create -f -
apiVersion: operator.alauda.io/v1alpha1
kind: AppRelease
metadata:
  annotations:
    auto-recycle: "true"
    interval-sync: "true"
  name: sriov-network-operator
  namespace: cpaas-system
spec:
  destination:
    cluster: ""
    namespace: "kube-system"
  source:
    charts:
    - name: <chartName> # 将 <chartName> 替换为实际 chart 路径,例如:name = example/chart-sriov-network-operator
      releaseName: sriov-network-operator
      targetRevision: v3.15.0
    repoURL: $REGISTRY
  timeout: 120
  values:
    global:
      registry:
        address: $REGISTRY
    networkNodePolicy:
      nicSelector: $NICSELECTOR
      numVfs: $NUMVFS
EOF

为物理节点设置 Node Role 标识标签

注意:执行此操作前,确保 sriov-network-operator 的 Pod 正常运行。

  1. 进入 Administrator

  2. 在左侧导航栏点击 Cluster Management > Clusters

  3. 点击集群名称,切换到 Nodes 标签页。

  4. 点击支持 SR-IOV 的物理节点 ⋮ > Update Node Labels

  5. 设置节点标签如下:

    • node-role.kubernetes.io/worker: ""
  6. 点击 Update

检查资源是否创建成功

在 CLI 工具中执行命令 kubectl -n cpaas-system get sriovnetworknodestates,检查是否成功创建了 sriovnetworknodestates 资源。如果看到如下类似输出,表示创建成功。若资源创建失败,请检查 Multus CNI 插件和 sriov-network-operator 是否部署成功。

kubectl -n cpaas-system get sriovnetworknodestates
NAME                      SYNC STATUS           AGE
192.168.254.88            Succeeded             5d22h

为物理节点设置 SR-IOV 节点特性标签

注意:执行此操作前,确保已成功创建 sriovnetworknodestates 资源。

  1. 进入 Administrator

  2. 在左侧导航栏点击 Cluster Management > Clusters

  3. 点击集群名称,切换到 Nodes 标签页。

  4. 点击支持 SR-IOV 的物理节点 ⋮ > Update Node Labels

  5. 设置节点标签如下:

    • feature.node.kubernetes.io/network-sriov.capable: "true"

检查网卡设备支持情况

  1. 执行命令 lspci -n -s <带域标识的 VF 地址> 获取当前网卡设备的厂商 ID 和设备 ID,如下所示。

    lspci -n -s 0000:05:00.1
    05:00.1 0200: 8086:154d (rev 01)

    输出说明:

    • 8086:厂商 ID。
    • 154d:设备 ID。
  2. 执行命令 lspci -s <带域标识的 VF 地址> -vvv | grep Ethernet 获取当前网卡名称,如下所示。

    lspci -s 0000:05:00.1 -vvv | grep Ethernet
    05:00.1 Ethernet controller: Intel Corporation Ethernet 10G 2P X520 Adapter (rev 01)
  3. 在 cpaas-system 命名空间中,找到名为 supported-nic-ids 的 ConfigMap 配置文件,检查其 data 部分是否包含当前网卡的配置信息。

    注意:若当前网卡不在支持列表中,需要参考步骤 4将网卡添加到配置文件中。若已在支持列表中,则跳过步骤 4

    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: supported-nic-ids
      namespace: cpaas-system
    data:
      Broadcom_bnxt_BCM57414_2x25G: 14e4 16d7 16dc
      Broadcom_bnxt_BCM75508_2x100G: 14e4 1750 1806
      Intel_i40e_10G_X710_SFP: 8086 1572 154c
      Intel_i40e_25G_SFP28: 8086 158b 154c
      Intel_i40e_40G_XL710_QSFP: 8086 1583 154c
      Intel_i40e_X710_X557_AT_10G: 8086 1589 154c
      Intel_i40e_XXV710: 8086 158a 154c
      Intel_i40e_XXV710_N3000: 8086 0d58 154c
      Intel_ice_Columbiaville_E810: 8086 1591 1889
      Intel_ice_Columbiaville_E810-CQDA2_2CQDA2: 8086 1592 1889
      Intel_ice_Columbiaville_E810-XXVDA2: 8086 159b 1889
      Intel_ice_Columbiaville_E810-XXVDA4: 8086 1593 1889
  4. <NIC 名称>: <厂商 ID> <设备 ID> <VF 设备 ID> 格式,将当前网卡添加到支持列表的 data 部分,如下所示。

    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: supported-nic-ids
      namespace: cpaas-system
    data:
      Broadcom_bnxt_BCM57414_2x25G: 14e4 16d7 16dc
      Broadcom_bnxt_BCM75508_2x100G: 14e4 1750 1806
    
      Intel_Corporation_X520: 8086 154d 10ed            ## 新增网卡信息
    
      Intel_i40e_10G_X710_SFP: 8086 1572 154c
      Intel_i40e_25G_SFP28: 8086 158b 154c
      Intel_i40e_40G_XL710_QSFP: 8086 1583 154c
      Intel_i40e_X710_X557_AT_10G: 8086 1589 154c
      Intel_i40e_XXV710: 8086 158a 154c
      Intel_i40e_XXV710_N3000: 8086 0d58 154c
      Intel_ice_Columbiaville_E810: 8086 1591 1889
      Intel_ice_Columbiaville_E810-CQDA2_2CQDA2: 8086 1592 1889
      Intel_ice_Columbiaville_E810-XXVDA2: 8086 159b 1889
      Intel_ice_Columbiaville_E810-XXVDA4: 8086 1593 1889

    参数配置说明:

    • Intel_Corporation_X520:网卡名称,可自定义。
    • 8086:厂商 ID。
    • 154d:设备 ID。
    • 10ed:VF 设备 ID,可在绑定结果中找到。

配置 IP 地址

登录交换机配置 DHCP(动态主机配置协议)。

注意:若无法使用 DHCP,请在虚拟机中手动配置 IP 地址。

结果验证

  1. 进入 Container Platform

  2. 在左侧导航栏点击 Virtualization > Virtual Machines

  3. 点击 Create Virtual Machine,添加辅助网卡时,选择 SR-IOV 作为 Network Type

  4. 完成虚拟机创建。

  5. 通过 VNC 访问虚拟机,应该能看到 eth1 成功获取 IP 地址,表示配置成功。

相关说明

CentOS 虚拟机内核参数配置

CentOS 虚拟机使用 SR-IOV 网卡后,需要修改对应网卡的内核参数,具体步骤如下。

  1. 打开终端,执行以下命令修改对应网卡的内核参数。将命令中的 <NIC Name> 替换为实际网卡名称。

    sysctl -w net.ipv4.conf.<NIC Name>.rp_filter=2
    echo "net.ipv4.conf.<NIC Name>.rp_filter=2" >> /etc/sysctl.conf
  2. 执行以下命令加载并应用 /etc/sysctl.conf 文件中的所有内核参数命令,使内核配置生效。输出信息中的值为 2 表示修改成功。

    sysctl -p

    输出信息:

    net.ipv4.conf.<NIC Name>.rp_filter = 2