Open vSwitch 硬件卸载

本页的目的是描述如何在 OpenStack (使用 OpenStack Networking) 中启用 Open vSwitch 硬件卸载功能。此功能最早在 OpenStack Pike 版本中引入。本页旨在作为配置 OpenStack Networking 和 OpenStack Compute 以启用 Open vSwitch 硬件卸载的指南。

基础知识

Open vSwitch 是一个生产质量的多层虚拟交换机,采用开源 Apache 2.0 许可。它旨在通过程序化扩展实现大规模网络自动化,同时仍然支持标准的管理接口和协议。Open vSwitch (OVS) 允许虚拟机 (VM) 相互通信以及与外部世界通信。基于软件的 OVS 解决方案 CPU 密集型,会影响系统性能并阻止充分利用可用带宽。

术语

定义

PF

物理功能。支持 SR-IOV 的物理以太网控制器。

VF

虚拟功能。从物理以太网控制器创建的虚拟 PCIe 设备。

Representor Port

类似于 SR-IOV 端口的虚拟网络接口,代表 Nova 实例。

第一个计算节点

可以托管计算实例 (虚拟机) 的 OpenStack 计算节点。

第二个计算节点

可以托管计算实例 (虚拟机) 的 OpenStack 计算节点。

支持的以太网控制器

已知以下制造商有效

  • Mellanox ConnectX-4 网卡 (VLAN 卸载)

  • Mellanox ConnectX-4 Lx/ConnectX-5 网卡 (VLAN/VXLAN 卸载)

  • Broadcom NetXtreme-S 系列网卡

  • Broadcom NetXtreme-E 系列网卡

有关 Mellanox 以太网卡的信息,请参阅 Mellanox: 以太网卡 - 概述

先决条件

  • Linux Kernel >= 4.13

  • Open vSwitch >= 2.8

  • iproute >= 4.12

  • Mellanox 或 Broadcom 网卡

    注意

    支持 Open vSwitch 硬件卸载的 Mellanox 网卡固件

    ConnectX-5 >= 16.21.0338

    ConnectX-4 >= 12.18.2000

    ConnectX-4 Lx >= 14.21.0338

使用 Open vSwitch 硬件卸载

为了启用 Open vSwitch 硬件卸载,需要执行以下步骤

  1. 启用 SR-IOV

  2. 将网卡配置为 switchdev 模式 (相关节点)

  3. 启用 Open vSwitch 硬件卸载

注意

在本指南中,enp3s0f0 用作 PF,eth3 用作 representor 端口。这些端口在不同的环境中可能会有所不同。

注意

在本指南中,我们使用 systemctl 重启 OpenStack 服务。这对于 systemd OS 是正确的。在其他环境中应使用其他方法来重启服务。

创建计算虚拟功能

为将用于 SR-IOV 的网络接口创建 VF。我们使用 enp3s0f0 作为 PF,它也用作 VLAN 提供商网络的接口,并且可以访问所有节点的私有网络。

注意

以下步骤详细介绍了如何使用 Mellanox ConnectX-4 和 SR-IOV 以太网卡在 Intel 系统上创建 VF。对于您选择的硬件,步骤可能会有所不同。

  1. 确保系统上已启用 SR-IOV 和 VT-d。通过将 intel_iommu=on 添加到内核参数来启用 IOMMU,例如使用 GRUB。

  2. 在每个计算节点上,创建 VF

    # echo '4' > /sys/class/net/enp3s0f0/device/sriov_numvfs
    

    注意

    网络接口可以同时用于 PCI 直通 (使用 PF) 和 SR-IOV (使用 VF)。如果使用 PF,则存储在 sriov_numvfs 文件中的 VF 数量将丢失。如果 PF 再次附加到操作系统,分配给此接口的 VF 数量将为零。为了始终将 VF 数量分配给此接口,请根据您的操作系统更新相关文件。以下是一些示例

    在 Ubuntu 中,修改 /etc/network/interfaces 文件

    auto enp3s0f0
    iface enp3s0f0 inet dhcp
    pre-up echo '4' > /sys/class/net/enp3s0f0/device/sriov_numvfs
    

    在 Red Hat 中,修改 /sbin/ifup-local 文件

    #!/bin/sh
    if [[ "$1" == "enp3s0f0" ]]
    then
        echo '4' > /sys/class/net/enp3s0f0/device/sriov_numvfs
    fi
    

    警告

    或者,您可以将 max_vfs 传递给网络接口的内核模块来创建 VF。但是,max_vfs 参数已被弃用,因此 PCI /sys 接口是首选方法。

    您可以确定 PF 可以支持的最大 VF 数量

    # cat /sys/class/net/enp3s0f0/device/sriov_totalvfs
    8
    
  3. 验证是否已创建 VF 并且处于 up 状态

    注意

    PF 的 PCI 总线编号 (03:00.0) 和 VF (03:00.2 .. 03:00.5) 稍后将使用。

    # lspci | grep Ethernet
    03:00.0 Ethernet controller: Mellanox Technologies MT27800 Family [ConnectX-5]
    03:00.1 Ethernet controller: Mellanox Technologies MT27800 Family [ConnectX-5]
    03:00.2 Ethernet controller: Mellanox Technologies MT27800 Family [ConnectX-5 Virtual Function]
    03:00.3 Ethernet controller: Mellanox Technologies MT27800 Family [ConnectX-5 Virtual Function]
    03:00.4 Ethernet controller: Mellanox Technologies MT27800 Family [ConnectX-5 Virtual Function]
    03:00.5 Ethernet controller: Mellanox Technologies MT27800 Family [ConnectX-5 Virtual Function]
    
    # ip link show enp3s0f0
    8: enp3s0f0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT qlen 1000
       link/ether a0:36:9f:8f:3f:b8 brd ff:ff:ff:ff:ff:ff
       vf 0 MAC 00:00:00:00:00:00, spoof checking on, link-state auto
       vf 1 MAC 00:00:00:00:00:00, spoof checking on, link-state auto
       vf 2 MAC 00:00:00:00:00:00, spoof checking on, link-state auto
       vf 3 MAC 00:00:00:00:00:00, spoof checking on, link-state auto
    

    如果接口处于关闭状态,请在启动来宾之前将其设置为 up,否则实例将无法启动

    # ip link set enp3s0f0 up
    

配置 Open vSwitch 硬件卸载

  1. 将 e-switch 模式从 legacy 更改为 switchdev,在 PF 设备上。这将还在主机 OS 中创建 VF representor 网络设备。

    # echo 0000:03:00.2 > /sys/bus/pci/drivers/mlx5_core/unbind
    

    这会告诉驱动程序取消绑定 VF 03:00.2

    注意

    应为所有相关 VF (在本例中为 0000:03:00.2 .. 0000:03:00.5) 执行此操作

  2. 启用 Open vSwitch 硬件卸载,将 PF 设置为 switchdev 模式并重新绑定 VF。

    # sudo devlink dev eswitch set pci/0000:03:00.0 mode switchdev
    # sudo ethtool -K enp3s0f0 hw-tc-offload on
    # echo 0000:03:00.2 > /sys/bus/pci/drivers/mlx5_core/bind
    

    注意

    应为所有相关 VF (在本例中为 0000:03:00.2 .. 0000:03:00.5) 执行此操作

  3. 重启 Open vSwitch

    # sudo systemctl enable openvswitch.service
    # sudo ovs-vsctl set Open_vSwitch . other_config:hw-offload=true
    # sudo systemctl restart openvswitch.service
    

    注意

    给定的 OVS aging 以毫秒为单位给出,可以使用以下方式控制

    # ovs-vsctl set Open_vSwitch . other_config:max-idle=30000
    

配置节点 (VLAN 配置)

  1. 更新 Controller 节点上的 /etc/neutron/plugins/ml2/ml2_conf.ini

    [ml2]
    tenant_network_types = vlan
    type_drivers = vlan
    mechanism_drivers = openvswitch
    
  2. 更新 Controller 节点上的 /etc/neutron/neutron.conf

    [DEFAULT]
    core_plugin = ml2
    
  3. 更新 Controller 节点上的 /etc/nova/nova.conf

    [filter_scheduler]
    enabled_filters = PciPassthroughFilter
    
  4. 更新 Compute 节点上的 /etc/nova/nova.conf

    [pci]
    #VLAN Configuration passthrough_whitelist example
    passthrough_whitelist ={"'"address"'":"'"*:'"03:00"'.*"'","'"physical_network"'":"'"physnet2"'"}
    

配置节点 (VXLAN 配置)

  1. 更新 Controller 节点上的 /etc/neutron/plugins/ml2/ml2_conf.ini

    [ml2]
    tenant_network_types = vxlan
    type_drivers = vxlan
    mechanism_drivers = openvswitch
    
  2. 更新 Controller 节点上的 /etc/neutron/neutron.conf

    [DEFAULT]
    core_plugin = ml2
    
  3. 更新 Controller 节点上的 /etc/nova/nova.conf

    [filter_scheduler]
    enabled_filters = PciPassthroughFilter
    
  4. 更新 Compute 节点上的 /etc/nova/nova.conf

    注意

    VXLAN 配置需要 physical_network 为 null。

    [pci]
    #VLAN Configuration passthrough_whitelist example
    passthrough_whitelist ={"'"address"'":"'"*:'"03:00"'.*"'","'"physical_network"'":null}
    
  5. 重启 nova 和 neutron 服务

    # sudo systemctl restart openstack-nova-compute.service
    # sudo systemctl restart openstack-nova-scheduler.service
    # sudo systemctl restart neutron-server.service
    

验证 Open vSwitch 硬件卸载

注意

在本例中,我们将在不同的计算节点上启动两个实例,并在它们之间发送 ICMP Echo Request 数据包。然后,我们将检查 representor 端口上的 TCP 数据包,并看到只有第一个数据包会显示在那里。其余的都将被卸载。

  1. private 网络上创建一个 direct 端口

    # openstack port create --network private --vnic-type=direct direct_port1
    
  2. 使用 direct 端口在“第一个计算节点”上创建一个实例

    # openstack server create --flavor m1.small --image cloud_image --nic port-id=direct_port1 vm1
    
  3. 重复上述步骤并在“第二个计算节点”上创建第二个实例

    # openstack port create --network private --vnic-type=direct direct_port2
    # openstack server create --flavor m1.small --image mellanox_fedora --nic port-id=direct_port2 vm2
    

    注意

    您可以使用 –availability-zone nova:compute_node_1 选项来设置所需的计算节点

  4. 连接到 instance1 并向 instance2 发送 ICMP Echo Request 数据包

    # vncviewer localhost:5900
    vm_1# ping vm2
    
  5. 连接到“第二个计算节点”并找到实例的 representor 端口

    注意

    首先找到 representor 端口,在本例中为 eth3

    compute_node2# ip link show enp3s0f0
    6: enp3s0f0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq master ovs-system state UP mode DEFAULT group default qlen 1000
       link/ether ec:0d:9a:46:9e:84 brd ff:ff:ff:ff:ff:ff
       vf 0 MAC 00:00:00:00:00:00, spoof checking off, link-state enable, trust off, query_rss off
       vf 1 MAC 00:00:00:00:00:00, spoof checking off, link-state enable, trust off, query_rss off
       vf 2 MAC 00:00:00:00:00:00, spoof checking off, link-state enable, trust off, query_rss off
       vf 3 MAC fa:16:3e:b9:b8:ce, vlan 57, spoof checking on, link-state enable, trust off, query_rss off
    
    compute_node2# ls -l /sys/class/net/
    lrwxrwxrwx 1 root root 0 Sep 11 10:54 eth0 -> ../../devices/virtual/net/eth0
    lrwxrwxrwx 1 root root 0 Sep 11 10:54 eth1 -> ../../devices/virtual/net/eth1
    lrwxrwxrwx 1 root root 0 Sep 11 10:54 eth2 -> ../../devices/virtual/net/eth2
    lrwxrwxrwx 1 root root 0 Sep 11 10:54 eth3 -> ../../devices/virtual/net/eth3
    
    compute_node2# sudo ovs-dpctl show
    system@ovs-system:
      lookups: hit:1684 missed:1465 lost:0
      flows: 0
      masks: hit:8420 total:1 hit/pkt:2.67
      port 0: ovs-system (internal)
      port 1: br-enp3s0f0 (internal)
      port 2: br-int (internal)
      port 3: br-ex (internal)
      port 4: enp3s0f0
      port 5: tapfdc744bb-61 (internal)
      port 6: qr-a7b1e843-4f (internal)
      port 7: qg-79a77e6d-8f (internal)
      port 8: qr-f55e4c5f-f3 (internal)
      port 9: eth3
    
  6. 检查 representor 端口上的流量。验证只有第一个 ICMP 数据包出现。

    compute_node2# tcpdump -nnn -i eth3
    
    tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
    listening on eth3, link-type EN10MB (Ethernet), capture size 262144 bytes
    17:12:41.220447 ARP, Request who-has 172.0.0.10 tell 172.0.0.13, length 46
    17:12:41.220684 ARP, Reply 172.0.0.10 is-at fa:16:3e:f2:8b:23, length 42
    17:12:41.260487 IP 172.0.0.13 > 172.0.0.10: ICMP echo request, id 1263, seq 1, length 64
    17:12:41.260778 IP 172.0.0.10 > 172.0.0.13: ICMP echo reply, id 1263, seq 1, length 64
    17:12:46.268951 ARP, Request who-has 172.0.0.13 tell 172.0.0.10, length 42
    17:12:46.271771 ARP, Reply 172.0.0.13 is-at fa:16:3e:1a:10:05, length 46
    17:12:55.354737 IP6 fe80::f816:3eff:fe29:8118 > ff02::1: ICMP6, router advertisement, length 64
    17:12:56.106705 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 62:21:f0:89:40:73, length 300