UCloud基于OpenvSwitch卸载的高性能25G智能网卡实践

伴随着电商等用户在双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。