伴随着电商等用户在双 11、秒杀之类业务高峰期流量的迅猛增长,对虚拟机网络性能提升的需求日益迫切,25G 网络逐渐成为一种标配。为了解决传统纯软件 Virtual Switch 方案带来的性能瓶颈,我们在调研了业界主流的智能网卡方案之后,最终决定采用基于 OpenvSwitch 的开源方案,并成功在公有云落地应用。

相较于传统方案,新的智能网卡方案在整个 switch 的转发上性能为小包 24Mpps,单 VF 的接收性能达 15Mpps,网卡整体性能提升 10 倍以上。应用于云主机后,可将其网络能力提升至少 4 倍,时延降低 3 倍,有效解决电商等业务高峰期的稳定性问题。本文将详细讲讲新方案从选型到落地过程中遇到的坑及解决之道,希望能给人以借鉴与启发。

业界主流的智能网卡方案对比

传统的软件 Virtual Switch 的性能瓶颈,在于其从物理网卡接收报文后,是按照转发逻辑发送给 vhost 线程,vhost 再传递给虚拟机的方式执行,如此一来,vhost 的处理能力就成为了影响虚拟机网络性能的关键。

于是,在宿主机上通过 25G SmartNIC 对网络流量进行卸载成为业界公认的主流方向。现阶段,智能网卡的实现百花齐放,例如:AWS 采用基于通用 ARM 的众核方案、Azure 采用基于 FPGA 的方案、华为云采用基于专用网络处理器(NP)的方案、阿里云采用基于可编程 ASIC 芯片的方案。就目前来看各个方案各有优劣,并没有特别突出一统天下的方案。

基于通用 ARM、MIPS 的众核方案,简单将原来跑在宿主机上的 vSwitch 移植到网卡上,既可以支持 Linux Kernel 也可以支持 DPDK,从而达到释放宿主机计算资源的目的。而其他基于 FPGA、NP 和可编程 ASIC 的方案,大多在网卡上维护一个快速转发路径(Fast Path),当收到报文后,首先检查是否在 Fast Path 已经缓存了该类报文的处理规则,如果找到,则直接按照规则执行动作,否则就转发到 Slow Path 去处理。而这个 Slow Path 可以是 DPDK,也可以是 Linux Kernel。

因此,Fast Path 最重要的是看是否支持足够多的 Action,以及自定义 Action 的可扩展性。Slow Path 和 Fast Path 通信除了各厂商的私有接口外,也有标准的 TC Offload 接口和 DPDK 提供的 RTE Flows 接口。

不过,FPGA 的功耗和成本较高,研发周期长且不能快速地落地,从硬件到软件都需要投入大量的资源。而其他基于第三方网卡厂家的软件定制化方案,对于网卡软件的稳定性严重依赖于第三方厂商, 遇到问题时不能快速的定位排障。

我们的选择

在业界没有非常完美的实现方案下,我们开始将目光转向开源技术,由于 OpenvSwitch 本身支持基于 Linux Tc Flower Offload 卸载接口, 对现有控制管理面影响小,并且能够快速应用落地开发给用户使用。因此,我们选择了基于 Tc Flower Offload 的 OpenvSwitch 开源方案。

报文处理可以被看做是通过一系列顺序操作将一个报文从接收发送到最终的目的地,最典型处理的是发送或者丢弃。这一系列操作通常是连续的 match 然后执行 action。Linux kernel TC 子系统的 Tc Flower 可以将报文基于流进行控制转发,而流通常是基于报文常见域来分类,这些域组成了名叫 flow key 的 match 项,flow key 包括了报文常见域和可选的隧道信息,TC actions 对报文执行丢弃、修改、发送等操作。

这个方式类似于 OpenvSwitch 的分类方式。通过 Tc Flower 分类器的 offload 对于 flow-based 的系统提供强有力的方法来增加吞吐量并减少 CPU 利用率。

基于 OpenvSwitch 卸载的智能网卡落地实践

方案选定之后,我们开始在原有架构上进行落地实践,这个过程并非一帆风顺,在具体落地的过程中,我们也遇到了几个方面的问题:

1. 虚拟机的迁移

落地之初,首先要进行虚拟机的迁移。因为各个厂商的 SmartNIC 都是基于 VF passthrough 的方案,而 VF 的不可迁移性为虚拟机迁移带来了困难。在业界,Azure 主要通过 bonding VF 和 virtio-net device 的方案解决这一问题,但是这种方法需要用户在一定层面上的介入,带来了虚拟机镜像管理的问题。

通过调研 upstream(https://patchwork.ozlabs.org

/cover/920005/)“Enable virtio_net toact as a standby for a passthrough device” 方案,我们发现此环境下,用户不需要手工设置 bonding 操作或者制作特定的镜像,可以完美的解决用户介入的问题。最终,我们采用了 VF+standby virtio-net 的方式进行虚拟机的迁移。具体迁移过程为:

创建虚拟机自带 virtio-net 网卡,随后在 Host 上选择一个 VF 作为一个 hostdev 的网卡,设置和 virtio-net 网卡一样的 MAC 地址,attach 到虚拟机里面,这样虚拟机就会对 virtio-net 和 VF 网卡自动形成类似 bonding 的功能,此时,在 Host 上对于虚拟机就有两个网络 Data Plane;

virtio-net backend 的 tap device 在虚拟机启动时自动加入到 Host 的 OpenvSwitch bridge 上,当虚拟机网卡进行切换的时候 datapath 也需要进行切换。VF attach 到虚拟机后,在 OpenvSwitch bridge 上将 VF_repr 置换掉 tap device;

2. VXLAN encap/decap 不能 offload

接下来需要做 SmartNIC 端的适配。以 Mellanox CX5 网卡为例,软件环境包括 OpenvSwitch-2.10.0、ukernel-4.14 和 MLNX_OFED-4.4-1.0.0.0。由于 mlx5_coredriver 最新版本并不支持 Ethernet over GRE tunnel offload,所以我们先通过 VXLAN 进行了测试。

如下图,eth2 是 PF, mlx_0 是 VF0 的 representor,通过以下命令就进行初始化。首先,开启一个 VF 设备,将 VF 设备在 driver mlx5_core 上解绑,设置 PF 设备的 IP 地址,设置 PF 网卡相关 switched 模式,开启 PF 网卡 encap 功能。

OpenvSwitch 配置如下:虚拟机 VF 利用 representor mlx_0 连接到 br0,通过 vxlan0 发送给对端。VXLAN 隧道本地地址为 172.168.152.75,对端地址为 172.168.152.208。

Encap/decap 报文都能有效收发,但是并没有 offload 到网卡上:

首先发现 dmesg 显示错误:

查询原因后发现 OpenvSwitch 在创建 vxlan device 时,并没有将 vxlan dport 信息注册进网卡。OpenvSwitch 通常是通过 vxlan device 的 netdev_ops->ndo_add_vxlan_port 接口完成这一功能,但是在较新的内核比如 ukernel-4.14 中是通过 netdev_ops->ndo_udp_tunnel_add 接口完成的。

后来我们给 OpenvSwitch 提交 patch “datapath: support upstream ndo_udp_tunnel_add in net_device_ops”https://patchwork.ozlabs.org/patch/953417/来解决这一问题。

3. Decap 报文不能 offload

解决上述问题后,egress 方向的 encap 报文虽然可以有效的 offload,但是 ingress decap 报文却依然不可以。

case2 的 vxlan decap 打印是在 mlx_0 VF 上,因此我们推测 decap 规则可能也下发到了 VF port 上。由于 tc 规则设置于 vxlan_sys 的虚拟 device 上,因而很可能是在寻找设置的物理网卡上出现了问题。

通过代码分析,可以看到虚拟 device 的设置物理网卡是通过 action device 找到的,即 mlx_0 VF,而 OpenvSwitch 下发给 mlx_0 VF 的 tc_flower 带着 egress_dev 为 true 的标志,由此推断,TC 规则是设置在 VF 对应的 PF 上。

沿着此推断,我们查看了 mlx5 driver 的代码 backports/0060-BACKPORT-drivers-net-ethernet-mellanox-mlx5-core-en_.patch

发现 ukernel-4.14 可以支持 cls_flower->egress_devflag,但并不支持 HAVE_TC_TO_

NETDEV_EGRESS_DEV。因此,我们断定 mlx5_core driver 在内核兼容性的判断上出现问题。随后,我们提交了相应的 patch 给 Mellanox 解决此问题。

4. Backend tap device encap 报文被丢弃

在做 live migration 时需要用到 backend tap sdevice,OpenvSwitch 在发送报文时将 tc 规则设置到了 tap device 上,依靠 tc 的 in_sw 方式进行 tunnel_key set 然后转发给 gre_sys device 进行发送,但是 gre_sys device 直接将报文丢弃,这让我们非常诧异。

分析其原因,我们发现,在 tc offload 的 in_sw 情况下,报文会绕过 OpenvSwitch 的转发逻辑直接通过 gre_sysdevice 进行发送。而我们使用的是 OpenvSwitch-2.10.0 所带的内核模块代码,内核模块兼容性编译时判断 ukernel-4.14 并不支持 USE_UPSTREAM_TUNNEL,所以,gre_sys device 并不是内核自带的 gre 设备,而是 OpenvSwitch 自己创建的一种不具备 nodo_start_xmit 函数的设备,OpenvSwitch 内核态 gre tunnel 的转发并不通过 gre_sys device 真正做发送。

虽然 ukernel-4.14 不支持 USE_UPSTREAM_

TUNNEL,但对于内核自带的 gre device 是能支持通过 ip_tunnel_key 进行 nodo_start_xmit 发送的,因而对于内核自带的 gredevice 来说,USE_UPSTREAM_TUNNEL 的标志是有效的。

由此,OpenvSwitch 可以通过 acinclude.m4 文件去判断

由于 OpenvSwitch 判断这个功能根据 gre 以及 erspan 来决定的,但 ukernel-4.14 对于 erspan 来说,USE_UPSTREAM_TUNNEL 的标志是无效的。

之后,我们引入上游https://patchwork.ozlabs.org/

cover/848329/ patch 系列 “ERSPAN version 2(type III) support”,使 OpenvSwitch 感知内核支持 USE_UPSTREAM_TUNNEL 来解决 gre_sys device drop 报文的问题。

5. Ethernet over gre tunnel 不能 offload

打入 Mellanox 提供了基于 ethernet over gre 的 patch 后,我们又发现 ingress 的 decap 方向不能做 offload。

这是由于在 gre_sys device 上并没有生成 tc ingress qdisc,OpenvSwitch 通过 vport 的 get_ifinex 获取 device 的 ifindex 设置 tc 规则,而 gre tunnel type 的 vport 并没有 enable get_ifindex 功能。

我们查找了 upstream 的 OpenvSwitch,并通过 patch“netdev-vport: Make gre netdev type to use TC rules” 解决这个问题。

此外,egress encap offload 的报文也不能被对方接收,通过抓包发现 gre header 里面带了 csum field,但是 OpenvSwitch 上的 gre tunnel 并没有设置 csum options。

研究代码 cls_tunne_key 的 set action 里默认是带 csum field 的,必须通过显示的设置 TCA_TUNNEL_KEY_NO_CSUM 才会关闭 csum filed。而 OpenvSwicth-2.10.0 没有做这方面的适配。

我们查找了 upstream 的 OpenvSwitch,并最终通过 patch “netdev-tc-offloads: TC csum option is notmatched with tunnel configuration” 解决了这一问题。

综上,我们详细介绍了 UCloud 25G SmartNIC 的选型方案,以及在实践的过程中遇到的各种技术问题及其解决方案,通过对 ukernel、OpenvSwitch、mlx5_core driver 的功能补全和 bugfix,最后将这一开源方案成功落地应用。

性能对比

落地应用后,我们基于 OpenvSwitch 卸载的高性能 25G 智能网卡方案下,从 vSwitch 性能、虚拟网卡性能等维度进行了系列性能测试。可以看到,

单 VF 的接收性能可达 15Mpps:

整个 vSwitch 的转发性能为小包 24Mpps:

而一般传统纯软件环境下,vSwitch 的转发性能为 2Mpps,虚拟网卡的接收性能仅 1.5Mpps 左右。相较于原方案,网卡整体性能提升了 10 倍以上。

应用在云主机时,同样 8 核配置的主机,以收向 UDP 小包(1 Byte)场景为例,新方案的 PPS 值可达 469w,而原值为 108w。

后续计划

目前,该方案已经成功应用于公有云上,将作为网络增强 2.0 云主机推出,使云主机的网络能力提升到目前网络增强 1.0 版本的 4 倍以上。后续我们计划将该方案移植到 Bare Metal 物理云主机产品上,让公有云和物理云主机在功能和拓扑上一致,并研究有状态的 Firewall/NAT 的 Offload。


↙↙↙阅读原文可查看相关链接,并与作者交流