tx-udp_tnl-segmentation

Overlay网络,例如VxLAN,现在应用的越来越多。Overlay网络可以使得用户不受物理网络的限制,进而创建,配置并管理所需要的虚拟网络连接。同时Overlay可以让多个租户共用一个物理网络,提高网络的利用率。Overlay网络有很多种,但是最具有代表性的是VxLAN。VxLAN是一个MAC in UDP的设计,具体格式如下所示。

img

从VxLAN的格式可以看出,以VxLAN为代表的Overlay网络在性能上存在两个问题。一个是Overhead的增加,VxLAN在原始的Ethernet Frame上再包了一层Ethernet+IP+UDP+VXLAN,这样每个Ethernet Frame比原来要多传输50个字节。所以可以预见的是,Overlay网络的效率必然要低于Underlay网络。另一个问题比传50个字节更为严重,那就是需要处理这额外的50个字节。这50个字节包括了4个Header,每个Header都涉及到拷贝,计算,都需要消耗CPU。而我们现在迫切的问题在于CPU可以用来处理每个网络数据包的时间更少了。

首先,VxLAN的这50个字节是没法避免的。其次,那就只能降低它的影响。这里仍然可以采用Jumbo Frames的思想,因为50个字节是固定的,那网络数据包越大,50字节带来的影响就相对越小。

先来看一下虚拟机的网络连接图。虚拟机通过QEMU连接到位于宿主机的TAP设备,之后再通过虚机交换机转到VTEP(VxLAN Tunnel EndPoint),封装VxLAN格式,发给宿主机网卡。

img

理想情况就是,一大段VxLAN数据直接传给网卡,由网卡去完成剩下的分片,分段,并对分成的小的网络包分别封装VxLAN,计算校验和等工作。这样VxLAN对虚机网络带来影响就可以降到最低。实际中,这是可能的,但是需要一系列的前提条件。

首先,虚拟机要把大的网络包发到宿主机。因为虚拟机里面也运行了一个操作系统,也有自己的TCP/IP协议栈,所以虚拟机完全有能力自己就把大的网络包分成多个小的网络包。从前面介绍的内容看,只有TSO才能真正将一个大的网络包发到网卡。GSO在发到网卡的时候,已经在进入驱动的前一刻将大的网络包分成了若干个小的网络数据包。所以这里要求:虚机的网卡支持TSO(Virtio默认支持),并且打开TSO(默认打开),同时虚机发出的是TCP数据。

之后,经过QEMU,虚拟交换机的转发,VTEP的封装,这个大的TCP数据被封装成了VxLAN格式。50个字节的VxLAN数据被加到了这个大的TCP数据上。接下来问题来了,这本来是个TCP数据,但是因为做了VxLAN的封装,现在看起来像是个UDP的数据。如果操作系统不做任何处理,按照前面的介绍,那就应该走GSO做IP Fragmentation,并在发送给网卡的前一刻分成多个小包。这样,如果网卡本来支持TSO现在就用不上了。并且更加严重的是,现在还没做TCP Segmentation。我们在上一篇花了很大的篇幅介绍其必要性的TCP Segmentation在这里也丢失了。

对于现代的网卡,除了TSO,GSO等offload选项外,还多了一个选项tx-udp_tnl-segmentation。如果这个选项打开,操作系统自己会识别封装成VxLAN的UDP数据是一个tunnel数据,并且操作系统会直接把这一大段VxLAN数据丢给网卡去处理。在网卡里面,网卡会针对内层的TCP数据,完成TCP Segmentation。之后再为每个TCP Segment加上VxLAN封装(50字节),如下图右所示。这样,VxLAN封装对于虚拟机网络来说,影响降到了最低。

从前面描述看,要达成上述的效果,需要宿主机网卡同时支持TSO和tx-udp_tnl-segmentation。如果这两者任意一个不支持或者都不支持。那么系统内核会调用GSO,将封装成VxLAN格式的大段TCP数据,在发给网卡驱动前完成TCP Segmentation,并且为每个TCP Segment加上VxLAN封装。如下图左所示。

img

如果关闭虚拟机内的TSO,或者虚拟机内发送的是UDP数据。那么在虚拟机的TCP/IP协议栈会调用GSO,发给虚拟机网卡驱动的前一刻,完成了分段、分片。虚拟机最终发到QEMU的网络数据包就是多个小的网络数据包。这个时候,无论宿主机怎么配置,都需要处理多个小的网络包,并对他们做VxLAN封装。

See the source image