GSO/TSO/GRO等对VirtIO虚机的网络性能影响分析(by quqi99)
作者:张华 发表于:2016-04-05
版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明
( http://blog.csdn.net/quqi99 )
IP层叫分片,TCP/UDP层叫分段。网卡能做的事(TCP/UDP组包校验和分段,IP添加包头校验与分片)尽量往网卡做,网卡不能做的也尽量迟后分片(发送)或提前合并片(接收)来减少在网络栈中传输和处理的包数目,从而减少数据传输和上下文切换所需要的CPU计算时间。
发数据
- TSO(TCP分段,TCP Segmentation Offload)在TCP处做,UFO(UDP分片,UDP Fragmentation Offload)因为UDP不支持分段所以移到下层的IP层做分片。TSO是使得网络协议栈能够将大块buffer推送至网卡,然后网卡执行分片工作,这样减轻了CPU 的负荷,但TSO需要硬件来实现分片功能;
- GSO(Generic Segmentation Offload)比TSO更通用,基本思想就是尽可能的推迟数据分片直至发送到网卡驱动之前,如果硬件不支持TSO分段则由dev_hard_start_xmit中的dev_gso_segment先软件分段的segs赋值给skb->next(skb->next = segs), 如果网卡硬件支持分段则直接将GSO大帧(skb-next)传给网卡驱动(dev_hard_start_xmit中的ndo_start_xmit)(所以它传给virtio驱动的是GSO大帧),然后继续进行IP分片后再发往网卡。GSO自动检测网卡支持特性, 硬件不支持也可以使用GSO它更通用(TSO一定需要硬件支持)。当打开GSO时,GSO会在xmit那块做GSO分片时调用TCP/UDP的回调函数自动添加TCP/UDP头(不使用GSO的只有第一个分片有TCP/UDP头,后面接着的分片是没有的,这也是为什么在虚机里打开TSO/GSO时对于隧道会多出一块数据的原因),然后再调IP层回调函数为每个分片添加IP头。
1, 物理网卡不支持GSO时, 使用TSO时TCP分段在驱动处调用硬件做,不使用TSO时TCP分段在TCP协议处软件做。
2, 物理网卡不支持UFO时,使用GSO时在发送给驱动前一刻做,不使用GSO在IP层软件做。
3, 物理网卡不支持TSO时,使用GSO时在发送给驱动前一刻做,不使用GSO在TCP层软件做。
TSO与GSO的重要区别
1, TSO只有第一个分片有TCP头和IP头,接着的分段只有IP头。意味着第一个分段丢失,所有分段得重传。
2, GSO在分段时会调用TCP或UDP的回调函数(udp4_ufo_fragment)为每个分段都加上IP头,由于分段是通过mss设置的(mss由发送端设置),所以长度仍然可能超过mtu值,所以在IP层还得再分片(代码位于dev_hard_start_xmit)。
收数据
- LRO(Large Receive Offload),TSO是发,LRO是收。将多个TCP分段聚合成一个skb结构,以减小上层协议栈的skb的开销。skb的数据保存在skb->data中,分段的数据保存在skb_shared_info->frag_list中。
- GRO(Generic Receive Offloading),GSO是发,GRO是收。LRO使用发送方和目的地IP地址,IP封包ID,L4协议三者来区分段,对于从同一个SNAT域的两个机器发向同一目的IP的两个封包可能会存在相同的IP封包ID(因为不是全局分配的ID),这样会有所谓的卷绕的bug。GRO采用发送方和目的地IP地址,源/目的端口,L4协议三者来区分作为改进。所以对于后续的驱动都应该使用GRO的接口,而不是LRO。另外,GRO也支持多协议。
1, 物理网卡不支持GRO时, 使用LRO在驱动处合并了多个skb一次性通过网络栈,对CPU负荷的减轻是显然的。
2, 物理网卡不支持LRO时,使用GRO在从驱动接收数据那一刻合并了多个skb一次性通过网络栈,对CPU负荷的减轻是显然的。
性能影响
对TCP来说,在CPU资源充足的情况下,TSO/GSO 能带来的效果不大,但是在CPU资源不足的情况下,其带来的改观还是很大的。
对UDP来说,其改进效果一般,改进效果不超过20%。所以在VxLAN环境中,其实是可以把GSO关闭,从而避免它带来的一些潜在问题。
Offloading 带来的潜在问题
分段offloading可能会带来潜在的问题,比如网络传输的延迟latency,因为packets的大小的增加,大大增加了driver queue的容量(capacity)。比如说,系统一方面在使用大的packet size传输大量的数据,同时在运行许多的交换式应用(interactive application)。因为交互式应用会定时发送许多小的packet,这时候可能会应为这些小的packets被淹没在大的packets之中,需要等待较长的时间才能被处理,这可能会带来不可接受的延迟。在网络上也能看到一些建议,在使用这些offloading技术时如果发现莫名的网络问题,建议先将这些技术关闭后再看看情况有没有改变。
# ethtool -K interface gso off
# ethtool -K interface tso off
VirtIO
在guest中有virtio前端驱动, 如针对网络的virtio-net,和其他驱动如virtio-pci等共同经过virt-queue的notify的trap中断到主机的hypervisor中执行host中面向guest前端驱动的api接口与后端驱动(virtio-backend driver)。guest内核的rx0与tx0两个队列与host的rx与tx两个队列通过socket共享内存交换数据。
下面是如何打开virtqueue的调试功能
echo -n "func virtqueue_add +flmpt" | sudo tee /sys/kernel/debug/dynamic_debug/control
sudo cat /sys/kernel/debug/dynamic_debug/control | grep virtio
这样能看到 virtqueue_add() 函数的信息:
drivers/virtio/virtio_ring.c:294 [virtio_ring]virtqueue_add =pmflt "Added buffer head %i to %p\012"
drivers/virtio/virtio_ring.c:236 [virtio_ring]virtqueue_add =pmflt "Can't add buf len %i - avail = %i\012"
vxlan的实现
从guest出来的tcp数据到达host的vxlan driver时会调用vxlan_xmit, 它的主要逻辑是获取 vxlan dev,然后为 sk_buff 中的每一个skb调用vxlan_xmit_skb方法, vlan_xmit_skb除了计算 tos,ttl,df,src_port,dst_port,md,flags等以外,也调用skb_set_inner_protocol(skb, htons(ETH_P_TEB))设置GSO参数。最后调用udp_tunnel_xmit_skb将skb传给udp tunnel协议栈继续处理。
这样也就进了IP层的ip_finish_output_gso,如果硬件支持,则由硬件调用linux内核中的UDP GSO函数(当有GSO时,由 UDP协议栈提供UDP分片逻辑而不是IP分片逻辑,这使得每个分片都有完整的UDP包头,然后继续IP层的GSO分片。所以GSO本身是对UFO的优化);如果硬件不支持,则在进入device driver queue之前由linux内核调用UDP GSO分片函数,然后再一直往下到网卡。
static int ip_finish_output_gso(struct net *net, struct sock *sk,
struct sk_buff *skb, unsigned int mtu){
...
#调用回调函数, 对于UDP则是调用UDP的gso_segment回调函数进行UDP GSO分段
segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK);
...
do {
struct sk_buff *nskb = segs->next;
int err;
segs->next = NULL;
#有必要则IP分片,因为UDP GSO是按照MSS进行,MSS还是有可能超过IP分段所使用的host物理网卡MTU
err = ip_fragment(net, sk, segs, mtu, ip_finish_output2);
if (err && ret == 0)
ret = err;
segs = nskb;
} while (segs);
这里是udp_offload.c中定义的回调函数:
static const struct net_offload udpv4_offload = {
.callbacks = {
.gso_segment = udp4_ufo_fragment,
...
},
};
可见,在整个过程中,有客户机上TCP协议层设置的skb_shinfo(skb)->gso_size始终保持不变为MSS,因此,在网卡中最终所做的针对UDP GSO数据报的GSO分片所依据的分片的长度还是根据skb_shinfo(skb)->gso_size的值即TCP MSS,所以vxlan协议有一个问题,即host的IP分片是根据geuest中TCP连接的MSS来进行的。
从geust到host的包流向
1, netif_needs_gso先判断网卡是否支持GSO(guest里的virtio nic肯定支持),if(unlikely(foo))认为foo通常为0, 所以如果网卡支持TSO时dev_gso_segment将返回0(skb->next==NULL),也就是说,当guest网卡的GSO特性打开时,guest会直接将没有分段的GSO大帧传递到virtio-net driver中。
int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
struct netdev_queue *txq)
{
...
if (netif_needs_gso(skb, features)) {
if (unlikely(dev_gso_segment(skb, features)))
goto out_kfree_skb;
if (skb->next)
goto gso;
}
gso:
do {
struct sk_buff *nskb = skb->next;
skb->next = nskb->next;
...
rc = ops->ndo_start_xmit(nskb, dev);
...
} while (skb->next);
static int dev_gso_segment(struct sk_buff *skb, netdev_features_t features)
{
struct sk_buff *segs;
segs = skb_gso_segment(skb, features);
/* Verifying header integrity only. */
if (!segs)
return 0;
skb->next = segs;
DEV_GSO_CB(skb)->destructor = skb->destructor;
skb->destructor = dev_gso_skb_destructor;
return 0;
}
2, virtio_net.c中的如下代码定义了virtio-net driver的xmit函数为start_xmit,它会直接将这个GSO大帧通过vring(<=64K)传给host上的virtio backend driver.
static const struct net_device_ops virtnet_netdev = {
...
.ndo_start_xmit = start_xmit,
3, 然后host上的tap和bridge都会原封不动动转发这个GSO大帧(payload, inner-tcp, inner-ip, inner-ethernet)。
4, host上的vxlan driver在原GSO大帧上添加vxlan帧头,从(payload, inner-tcp, inner-ip, inner-ethernet)变成(payload, inner-tcp, inner-ip, inner-ethernet, vxlan)。
5, 如果host不支持GSO,那么在host的IP层直接对外层的UDP分片,注意:只有第1个分片有UDP头,接下来的分片没有UDP头。
分片1: payload, inner-tcp, inner-ip, inner-ethernet, vxlan,outer-udp, outer-ip
分片2: payload, inner-tcp, inner-ip, inner-ethernet, vxlan,outer-ip
6, 如果host支持GSO,在host的dev_hard_start_xmit处(代码回到第1步),如果物理网卡支持TSO直接将大帧(payload, inner-tcp, inner-ip, inner-ethernet, vxlan)将给物理网卡的TSO去硬件分片。如果物理网卡不支持TSO将调用skb_gso_segment软件执行GSO。GSO由于会调用UDP的回调函数,但vxlan没有GSO回调函数,所以这里的GSO分片应该每一个分片都有UDP头部,但是只有第一个分片有vxlan头部。
分片1: payload, inner-tcp, inner-ip, inner-ethernet, vxlan,outer-udp, outer-ip
分片2: payload, inner-tcp, inner-ip, inner-ethernet,outer-udp, outer-ip
7, 但是host的物理网卡是根据mss(由sender确定,也就是guest设定,而不是由mtu设定)发给远端的。host打开GSO增加outer-udp时可能会造成包大于mss值从而继续在添加outer-ip时做ip分片。所以redhat的最佳实践要求关闭host机上的GSO特性。
从host到guest的包流向
4194304
hua@node1:~$ cat /proc/sys/net/ipv4/ipfrag_low_thresh
3145728
hua@node1:~$ cat /proc/sys/net/ipv4/ipfrag_time
30
net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0
VMware STT隧道
解决办法
1, 若用隧道guest中设置mtu
2, echo 0 > /proc/sys/net/bridge/bridge-nf-call-iptable (可选,如果有Linux Bridge的话)
3, 关闭host上的GSO, TSO, GRO (如果为使用conntract特性没有关闭bridge-nf-call-iptable的话)
4, 重点关注host机上物理网卡与Linux bridge上的mtu,其他的虚拟网卡的mtu可以默认设置很大如65000 (可选)
5, 也可以试试关闭tx与rx两个offload特性,sudo ethtool --offload eth0 rx off tx off sg off tso off, 注意:在tx与rx打开时,chksum是在硬件网卡处做的,tcpdump的输出“cksum 0x0a2b (incorrect -> xxx”应该是正常的。
参考
[1] http://www.pagefault.info/?p=159
[2] https://kris.io/2015/10/01/kvm-network-performance-tso-and-gso-turn-it-off/
[3] http://www.cnblogs.com/sammyliu/p/5227121.html
[4] https://patchwork.ozlabs.org/patch/415791/
[5] http://www.ibm.com/developerworks/cn/linux/l-virtio/
[6] http://www.cnblogs.com/sammyliu/p/5228581.html
[7] http://royluo.org/2014/08/09/virtio-netdev-send/
[8] https://markmc.fedorapeople.org/virtio-code-review/VirtioCodeReview.pdf
[9] http://blog.csdn.net/majieyue/article/details/7929398
[10] https://ask.openstack.org/en/question/58607/poor-network-connection-issue-with-windows-instance/
[11] https://sokratisg.net/2012/04/01/udp-tcp-checksum-errors-from-tcpdump-nic-hardware-offloading/
GSO/TSO/GRO等对VirtIO虚机的网络性能影响分析(by quqi99)的更多相关文章
- openstack新建虚机、网络、路由时候对应的ovs网桥的变化
[root@wb5 ~]# [root@wb5 ~]# [root@wb5 ~]# [root@wb5 ~]# [root@wb5 ~]# [root@wb5 ~]# [root@wb5 ~]# [r ...
- Neutron 理解 (9): OpenStack 是如何实现 Neutron 网络 和 Nova虚机 防火墙的 [How Nova Implements Security Group and How Neutron Implements Virtual Firewall]
学习 Neutron 系列文章: (1)Neutron 所实现的虚拟化网络 (2)Neutron OpenvSwitch + VLAN 虚拟网络 (3)Neutron OpenvSwitch + GR ...
- Terraform:创建 Azure 虚机
笔者在前文<Terraform 简介>中简单介绍了 Terraform 相关的概念,本文让我们使用 Terraform 在 Azure 上创建一个虚机,以此来直观体验一下 Terrafor ...
- Neutron 理解(5):Neutron 是如何向 Nova 虚机分配固定IP地址的 (How Neutron Allocates Fixed IPs to Nova Instance)
学习 Neutron 系列文章: (1)Neutron 所实现的虚拟化网络 (2)Neutron OpenvSwitch + VLAN 虚拟网络 (3)Neutron OpenvSwitch + GR ...
- Nova 操作汇总(限 libvirt 虚机) [Nova Operations Summary]
本文梳理一下 Nova 主要操作的流程. 0. Nova REST-CLI-Horizon 操作对照表 Nova 基本的 CRUD 操作和 extensions: # 类别 Nova V2 REST ...
- Nova: 虚机的块设备总结 [Nova Instance Block Device]
和物理机一样,虚拟机包括几个重要的部分:CPU.内存.磁盘设备.网络设备等.本文将简要总结虚机磁盘设备有关知识. 1. Nova boot CLI 中有关虚机块设备的几个参数 nova boot CL ...
- KVM 介绍(6):Nova 通过 libvirt 管理 QEMU/KVM 虚机 [Nova Libvirt QEMU/KVM Domain]
学习 KVM 的系列文章: (1)介绍和安装 (2)CPU 和 内存虚拟化 (3)I/O QEMU 全虚拟化和准虚拟化(Para-virtulizaiton) (4)I/O PCI/PCIe设备直接分 ...
- [译] libvirt 虚机的生命周期 (Libvirt Virtual Machine Lifecycle)
翻译自:http://wiki.libvirt.org/page/VM_lifecycle 这篇文章描述虚机生命周期的基本概念.其目的在于在一篇文章中提供完整的关于虚机创建.运行.停止.迁移和删除 ...
- 010.KVM虚机冷迁移
一 实验环境 原虚机名称:vm01-centos6.8 原虚机所在宿主机:kvm-host-2 迁移后虚机名称:vm01-cloud-centos6.8 迁移后虚机所在宿主机:kvm-host-2 二 ...
随机推荐
- MAC OS下使用OpenSSL生成私钥和公钥的方法
MAC OS自带了OpenSSL,所以不用去编译那一坨跟SHIT一样的源码.直接在命令行里使用OPENSSL就可以. 打开命令行工具,然后输入 openssl打开openssl,接着只要三句命令就可以 ...
- Android中的一些简单的adb命令
外设为手机.也配置好了Android的adb环境变量,就可以执行了.
- LG3377 【模板】左偏树(可并堆)
好博客 1 2 上面那个用数组写的跑的快,且便于封装,就用他的代码了. 代码 #include<cstdlib> #include<cstdio> #include<cm ...
- RPC好,还是RESTful好?
看到知乎上有这样一个问题 WEB开发中,使用JSON-RPC好,还是RESTful API好? 还有其他优秀的推荐方案吗? -------------------------------------- ...
- 【python】面试常考数据结构算法
这里整理的都是基础的不能再基础的算法,目的就是进行一个回忆,同时作为剑指offer的一个补充~嘿嘿~ 查找算法二分查找# 实现一个二分查找# 输入:一个顺序list# 输出: 待查找的元素的位置def ...
- 虚拟机中的CentOS 7设置固定IP连接最理想的配置
说明:在网上搜了好多文章都是大同小异,都没有完全解决我想要的固定IP后要达到的如下效果, 1.笔记本主机IP为设置自动获取,不管什么情况下,不受虚拟机影响,只要连接外网就可以正常上网: 2.只要笔记本 ...
- TensorFlow笔记-02-Windows下搭建TensorFlow环境(win版非虚拟机)
TensorFlow笔记-02-Windows下搭建TensorFlow环境(win版非虚拟机) 本篇介绍的是在windows系统下,使用 Anaconda+PyCharm,不使用虚拟机,也不使用 L ...
- 树莓派做下载机+Web服务器(Aria2下载+yaaw做UI+nginx)
今天收到了小派,UK产的绿板子,还配了个透明盒子,装在里面闪亮亮的很好看,而且只有卡片大小,寻思着用它做什么好呢?想来想去,看到人家拿小派作家庭媒体中心,还有人拿它当下载机,于是就萌生了一个家庭媒体中 ...
- mybatis 生成 映射文件生成工具 mybatisGenerator 使用
第一:新建 generatorConfig.xml 文件 ,写入下面的 内容 <?xml version="1.0" encoding="UTF-8"?& ...
- 使用fiddler进行genymotion安卓虚拟机手机抓包
1.首先先下载fiddler,这个直接百度就有啦. 2.打开fiddler ,可以看到这个界面还是挺帅的: 3.选择Tools - Fiddler Options -Https选项卡将配置设置为如下: ...