本文的目的是描述如何使能OpenStack中可用的Open vSwitch硬件卸载offloading功能(使用OpenStack Networking)。此功能首先在OpenStack Pike版本引入。本文作为一个指南,展示如何配置OpenStack Networking和计算节点,来使能Open vSwitch硬件卸载功能。
基础 The basics
Open vSwitch是一个生成级别质量,多层虚拟交互机,使用开源 Apache 2.0许可。它被设计来通过可编程扩展使能大规模的网络自动化,但任然支持标准的管理接口和协议。Open vSwitch (OVS)运行虚拟机VM彼此之间或与外部世界通信。基于OVS软件的方案是耗费CPU的,影响系统性能,并且阻止完全的使用可用带宽。
Term | Definition |
---|---|
PF | Physical Function. 支持SR-IOV的物理以太网控制 |
VF | Virtual Function. 创建于物理以太网控制器的虚拟PCIe设备 |
Representor Port | 类似于SR-IOV端口的虚拟网络接口,表示Nova实例 |
First Compute Node | OpenStack计算节点可包含计算实例(VM) |
Second Compute Node | OpenStack计算节点可包含计算实例(VM) |
支持的以太网控制器
已知可工作的生产厂商网卡如下:
- Mellanox ConnectX-4 NIC (VLAN Offload)
- Mellanox ConnectX-4 Lx/ConnectX-5 NICs (VLAN/VXLAN Offload)
更多有关 Mellanox Ethernet Cards 的信息, 参见 Mellanox: Ethernet Cards - Overview。
前提
- Linux Kernel >= 4.13
- Open vSwitch >= 2.8
- iproute >= 4.12
- Mellanox NIC
注: Mellanox NIC 支持 Open vSwitch 硬件卸载的固件:
ConnectX-5 >= 16.21.0338
ConnectX-4 >= 12.18.2000
ConnectX-4 Lx >= 14.21.0338
使用 Open vSwitch 硬件卸载
为了使能Open vSwitch的硬件卸载功能,需要以下的步骤:
#. 使能 SR-IOV
#. 配置NIC为 switchdev 模式 (相关节点)
#. 使能 Open vSwitch 硬件卸载
注:
本文中,“enp3s0f0”用作PF,“eth3”用作Representor Port。在不同的环境这些端口可能不同。我们使用“systemctl”工具重启OpenStack服务,对于使用“systemd”的操作系统这是正确的。在其它环境中应使用其它方法重启服务。
创建计算虚拟功能
为用于SR-IOV的网络接口创建VFs。我们使用“enp3s0f0”作为PF,其也被用来作为VLAN provider网络的接口,具有访问所有节点的私有网络的权限。
注:
以下的步骤详述如何在Intel平台上使用Mellanox ConnectX-4网卡和SR-IOV以太网卡创建VFs。步骤可能根据你选择的硬件而不同。
#. 确保系统的 SR-IOV 和 VT-d 以及启用.
在Linux中使能 IOMMU,需要添加 “intel_iommu=on” 到内核启动参数中,例如,使用GRUB.
#. 在每个计算节点上创建VFs:
# echo '4' > /sys/class/net/enp3s0f0/device/sriov_numvfs
注:
一个网络接口可用于PCI passthrough的PF,或者SR-IOV的VFs。如果使用PF功能,保存在“sriov_numvfs”中的VF数量值将丢失。如果PF再次连接到操作系统,赋予此接口的VF数量将清零。要保持赋予接口的VFs数量值,编辑你的OS的相关文件。如下的示例:
在 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”来创建VFs。尽管如此,“max_vfs”参数被废弃,所以使用/sys接口时首选方法。
你可决定PF可支持的VFs数量:
# cat /sys/class/net/enp3s0f0/device/sriov_totalvfs
8
#. 验证VFs是否已创建,并处于“up”状态:
注:
PF (03:00.0) 和 VFs (03:00.2 … 03:00.5) 的PCI总线号之后将用到。
# 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
如果接口状态为down,在启动客户机之前设置它们到“up”状态,否则,客户机将创建失败:
# ip link set enp3s0f0 up
配置 Open vSwitch 硬件卸载
#. 修改PF设备的 e-switch 模式从 legacy 到 switchdev。这也将在客户机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)
#. 使能 Open vSwitch 硬件卸载功能, 设置PF到 switchdev 模式并且重新绑定回 VFs.
# 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)
#. 重启 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 配置)
#. 更新控制节点的文件 “/etc/neutron/plugins/ml2/ml2_conf.ini”
[ml2]
tenant_network_types = vlan
type_drivers = vlan
mechanism_drivers = openvswitch
#. 更新控制节点的文件 “/etc/neutron/neutron.conf”
[DEFAULT]
core_plugin = ml2
#. 更新控制节点文件 “/etc/nova/nova.conf”
[filter_scheduler]
enabled_filters = PciPassthroughFilter
#. 更新计算节点文件 “/etc/nova/nova.conf”
[pci]
#VLAN Configuration passthrough_whitelist example
passthrough_whitelist ={"'"address"'":"'"*:'"03:00"'.*"'","'"physical_network"'":"'"physnet2"'"}
配置节点 (VXLAN 配置)
#. 更新控制节点文件 ”/etc/neutron/plugins/ml2/ml2_conf.ini“
[ml2]
tenant_network_types = vxlan
type_drivers = vxlan
mechanism_drivers = openvswitch
#. 更新控制节点文件 “/etc/neutron/neutron.conf”
[DEFAULT]
core_plugin = ml2
#. 更新控制节点文件 “/etc/nova/nova.conf”
[filter_scheduler]
enabled_filters = PciPassthroughFilter
#. 更新计算节点文件 ”/etc/nova/nova.conf“
注:
VXLAN 配置需要 “physical_network” 为空.
[pci]
#VLAN Configuration passthrough_whitelist example
passthrough_whitelist ={"'"address"'":"'"*:'"03:00"'.*"'","'"physical_network"'":null}
#. 重启 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报文。之后,我们将检查Representor Port上的TCP报文,我们将会看到只有第一个报文出现在这里。其它的报文都被卸载。
#. 在“private”网络上创建一个端口“direct”
# openstack port create --network private --vnic-type=direct --binding-profile '{"capabilities": ["switchdev"]}' direct_port1
#. 使用direct端口在’First Compute Node’上创建实例
# openstack server create --flavor m1.small --image mellanox_fedora --nic port-id=direct_port1 vm1
注:
在此示例中,我们使用的Mellanox NIC驱动镜像可由以下链接下载:http://www.mellanox.com/repository/solutions/openstack/images/mellanox_eth.img
#. 重复以上的步骤,在’Second Compute Node’上创建第二个实例
# openstack port create --network private --vnic-type=direct --binding-profile '{"capabilities": ["switchdev"]}' direct_port2
# openstack server create --flavor m1.small --image mellanox_fedora --nic port-id=direct_port2 vm2
注:
你可使用 --availability-zone nova:compute_node_1 选项指定想要的计算节点。
#. 连接 instance1 并发送 ICMP Echo 请求报文到 instance2
# vncviewer localhost:5900
vm_1# ping vm2
#. 连接 ‘Second Compute Node’ 并找到实例的 Representor Port。
注:
首先找到 Representor Port, 在我们的示例中其为 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
#. 检查 Representor Port 上的流量. 验证仅第一个 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