奥门巴黎人手机网址【app】

【科技世界】通晓 Linux 网络栈(2):非虚构化Linux 意况中的 Segmentation Offloading 工夫

2019-10-10 09:39·澳门巴黎人线上娱乐

八年多前的八个过去的事情

从Linux2.6.8内核的三个TSO/NATbug引出的网络难题每一种核查观点(附贰个skb的优化点)

梦里没错与对,梦中从不恨和悔...最佳闭上你的嘴,这样才算可爱...作者不会说:那不公道,笔者不能够经受。我会用朴素的文字记录一点一滴,中午4点多起来,一气呵成前段时间的获取与商议,愤怒与忏悔。

 

本种类小说总结 Linux 网络栈,包罗:

大致在2008年的时候,作者每一种审核了一个标题。难题汇报如下:

七年多前的多少个历史

大致在二〇〇五年的时候,笔者每种考察了贰个标题。难点呈报如下:

 

服务端:Linux Kernel 2.6.8/192.168.188.100
客户端:Windows XP/192.168.40.34
业务流程(简化版):
1.顾客端向服务端发起SSL连接
2.传输数据

现象:SSL握手的时候,服务端发送Certificate比极慢。

 

分析:
切切实实思路,也正是马上怎么想到的,作者已经忘了,可是切记二个结论,那正是纠出了Linux 2.6.8的NAT模块的二个bug。
在抓取了不菲数额包后,作者开采本机总是发给本身叁个ICMP need frag的报错音讯,发掘服务端的Certificate太大,超越了本机出网卡的MTU,以下的一步步的思绪,最后纠出了bug:

1.认证服务端程序设置了DF标识。那是刚烈的,因为独有DF标记的数目包才会触发ICMP need frag音讯。

 

2.疑问:在TCP往IP发送数据的时候,会检查实验MTU,进而明确MSS,明知道MSS的值,怎么还有大概会发送超过限度的包吗?总括错误恐怕十分的小,毕竟Linux也是准工业级的了。

 

3.疑问解答:幸好小编任何时候还真知道某个名词,于是想到了TCP Segment Offload这个工夫。

TCP Segment Offload简称TSO,它是对准TCP的硬件分段本领,实际不是本着IP分片的,那五头分别应该精晓,所以那与IP头的DF标记非亲非故。对于IP分片,唯有首先个分片才会有完整的高层消息(要是头长能够总结在多少个IP分片中的话),而对于TSO导致的IP数据包,每贰个IP数据包都会有正规的TCP头,网卡硬件自行计算每一个分层尾部的校验值,类别号等底部字段且自动封装IP头。它目的在于加强TCP的习性。

 

4.印证:果然服务器启用了TSO

 

5.疑问:五个赶过MTU的IP报文发送到了IP层,且它是的数量二个TCP段,那表明TCP已经知道自身所在的机器有TSO的成效,否则对于本机始发的数据包,TCP会严苛遵从MSS封装,它不会卷入三个大包,然后让IP去分片的,那是出于对于本机始发来说,TCP MSS对MTU是能够感知到的。对于转载来说,就不是那般了,然则,对于这里的情景,显明是本机始发,TCP是明亮TSO的留存的。

 

6.臆想:既然TCP具备对TSO的留存感知,可是在IP发送的时候,却又不见了这种回想,从TCP发往IP的入口,到IP分片决定的终点,中间确定产生了怎么样严重的事,迫使TCP错过了TSO的记念。

 

7.疑惑:这种故障处境是自己在同盟社效仿的,通过报告人士的音讯,笔者精通到却非兼具的图景都会那样。事实上,我直接不太认但是Linux左券栈本身的难题,不然早已被Fix了,我直接猜忌是表面模块只怕部非常表展现举个例子抓包导致的。

 

8.可用的新闻:到此甘休,作者还大概有二个音信,那就是一旦加载NAT模块(事实上那是分析出来的,报告职员是不亮堂所谓的NAT模块的,只晓得NAT法则)就能够有那些地方,于是目的很引人瞩目,死盯NAT模块。

 

9.起始debug:由于Linux Netfilter NAT模块比较轻便,根本无需高等的能够touch到内部存款和储蓄器级的工具,只供给printk就可以,可是在哪儿print是个难点。

 

10.出错点:在调用ip_fragment(正是该函数里面发送了ICMP need frag)从前,有一个断定(省略了不相干的):

if (skb->len > dst_pmtu(skb->dst) && !skb_shinfo(skb)->tso_size) {
    return ip_fragment(skb, ip_finish_output);
}

前二个肯定分明为真,借使要想调用ip_fragment的话,后三个判别必定假若假,实际上,假使翻开了TSO,就不应当调用ip_fragment的。

 

11.查找tso_size字段:事情很确定了,一定是哪些地方将tso_size设置成了0!并且一定在NAT模块中(98%以上的只怕吧...),于是在NAT模块中寻找设置tso_size的地方。

 

12.跟踪ip_nat_fn:那是NAT的进口,步入那么些进口的时候,tso_size不是0,然而调用了skb_checksum_help之后tso_size正是0了,难题必就要那么些函数中,注意,调用那几个help有二个前提,那就是硬件已经总结了校验和。在那一个help函数中,有三个skb_copy的操作,正是在这一个copy之后,tso_size形成了0,于是尤其看skb_copy,最后一定到,copy_skb_header的末梢,并未将原始skb的tso_size复制到新的skb中,这正是难点所在!

 

13.触发条件:哪天会调用skb_copy呢?极粗略,如若skb不完全属于当前的推行流的意况下,遵照写时拷贝的尺度,供给复制一份。故障现象就是慢,而数据为本机始发,且为TCP。大家清楚,TCP在未有ACK在此之前,skb是不能够被剔除的,因而当前的skb显然只是三个别本,由此就须要拷贝一份了。

 

14.震慑:如此底层的三个函数。搜索代码,影响巨大,各类慢!对于此番的慢,其慢的流程为:socket发送DF数据--感知TSO--错过TSO--ICMP need frag--TCP裁成小段继续发送...假使禁绝了lo的ICMP,那么更加慢,因为TCP会触发超时重传,而不是ICMP的建议收缩,而且重传是不会成功的,直到客商程序感知,自行减小发送长度。

(1)Linux 互联网左券栈总括

服务端:Linux Kernel 2.6.8/192.168.188.100

何以好玩的事重提

提及那事有八个原因,其一是任何时候尚无记录下来整个进度,可是后续的patch却一贯在用,最后笔者要好都快不知其所以然了,其二,是透过本次的深入分析,根据现行反革命的知情,即可发现Linux合同栈的两个优化点,即TCP情形下,由于保留了多少skb队列直到ack,那么继续向下的装有skb管理流程都起码要因此叁次skb_copy,这种复制操作难道就不能够躲过吗?如若加载了几许Netfilter钩子,必要对skb举办写操作,这种串行化行为会严重影响Linux网络左券栈的管理功用,这是Netfilter的隐疾之一。

(2)非虚构化Linux情形中的网络分段卸载技能GSO/TSO/UFO/LRO/GRO

客户端:Windows XP/192.168.40.34

附:skb操作的优化点

1.比如把多少和元数据到底分手是还是不是更加好呢?
2.尤为将写操作的粒度细分

有一点点写操作是对准每贰个数据包的,那么些只可以复制,可是能还是不能够有个别复制,然后使用分流集中IO进行拼接呢?尽量利用指针操作而不是复制数据本人,那正是借鉴了UNIX fork模型以致设想地址空间的COW。假若把skb的半空中拓宽细粒度划分,那么就足以做到,要求COW哪部分就只有那有些,不会促成全局复制。

(3)QEMU/KVM + VxLAN 情况下的 Segmentation Offloading 本领(发送端) 

业务流程(简化版):

今天的贰个TCP难点排查进程

(4)QEMU/KVM + VxLAN 碰到下的 Segmentation Offloading 本事(接收端)

1.顾客端向服务端发起SSL连接

气象与经过

已经无独有偶了这种惊魂动魄的三规章制度度(规定的时刻,规定的地址,和鲜明的人联手消除难点),反而不习贯了鲁人持竿了。事情是那样的。

周天的时候,深夜,正在跟朋友齐声聊天吃饭,收到了集团的短信,说是有三个恐怕与TCP/IP有关的故障,必要固定,笔者尚未随之复苏,因为这种事情屡次要求多量的音信,而那些音讯日常短信传来的时候曾经经过了N手,所以为了不做无用功,等关于职员打电话给自家再说吧。

...

 

(以下描述有所简化)
小编方服务端:Linux/IP不鲜明(处在内网,不知晓NAT计谋以致是不是有代理以致其余七层管理景况)
测量检验客商端:Windows/192.168.2.100/GW 192.168.2.1
中等链路:公共Internet
可用接入格局:3G/无线拨号
服务端设备:第三方负载均衡设备。防军火等
业务流程:客商端与服务端建构SSL连接
故障:
客户端连接3G网卡使用有线链路,业务健康;顾客端应用有线链路,SSL握手不成功,SSL握手进程的Client Certificate传输战败。

 

分析:

1.透过抓包剖判,在有线链路上,发送客商端证书(长度超越1500)后,会接收一条ICMP need frag音讯,说是长度超过限度,链路MTU为1480,而实际发送的是1500。通过有线链路,同样收取了这么些ICMP need frag,只是告诉的MTU分裂,有线链路对应的是1400。

 

2.有线链路,客户端接受ICMP need frag,重新发送,只是截掉了20字节的长短,不过抓包开采顾客端会不断重传这么些包,始终收不到服务端的ACK,其间,由于顾客端久久不能发送成功数据到服务端,服务端会回复Dup ACK,以示督促。

 

3.猜测:早先,我以为是时间戳的开始和结果,由于双方未有展开TCP时间戳,所以在RTT乃至重传间隔推断方面会有基值误差,但是那不能够解说百分之百败诉的景况,假若是由于时间戳计算的来由,那不会百分之百难倒,因为总计结果受波动权值影响会很大。

 

4.相对来说有线链路,和有线链路的独一区别就是ICMP报告的MTU分裂。

 

5.中途总计:
5.1.此时,笔者并从未把思路往运维商链路上带领,因为自个儿始终以为那不会有标题,相同,笔者也不感觉是SSL的难点,因为漏洞非常多总是在发送大包后展现,事实上,接受了ICMP need frag后,在此以前发的丰裕超过限度包已经被扬弃,重新发送的是三个小一些的包,对于TCP另一端来说,那是一点一滴平常的。
5.2.平素不必要查看服务日志,因为还尚未达到那多少个档次。抓包结果很引人注目,正是大包传然则去,其实已经依照MTU发掘的值传输了,照旧闭塞,而有线链路能过去。由此相应不是MTU的难题。

5.3.除了运转商链路,MTU,服务端管理之外,还或许会是哪的难题吧?事实上,程序的bug亦不是不大概的,或许说是一些茫然的动作,不管怎么着,供给隔开难题。

 

6.猜度是在那之中某台设备无法管理大包,那些和MTU未有提到,大概正是它管理不了恐怕根本上不想管理大包,多大啊?反正1480的包管理不了,减去IP头,TCP头,剩余的是1440的纯数据。于是写多个简练的TCP client程序,在TCP握手完结后任何时候发送(为了幸免由于不是Client Hello而主动断开,由此必得及时发,只是为着考查针对大包的TCP ACK情形,此时与劳动非亲非故)长度1440的数额,验证!

 

7.果然没有ACK急忙回到,顾客端不断重试发送1440的包(之后10秒到20秒,会有ACK到来,但不是历次都会赶来,这眼看是不正规的)。为了印证这种方法的合理,发送有线链路上MTU限制的数码大小,即1400-20-20=1360的数额,ACK秒回。由此测度中间设备的多少包管理的长度临界点在1360和1440中间。

 

8.经过持续的测量检验,二分法查询临界点,找到了1380是可处理长度临界点。发送1380的纯数据是平常的,发送1381的纯数据就不平时了。抓包的指标地址是12.23.45.67,简称MA,未来不分明的是MA是怎样,是笔者方的器具,照旧它方的道具,假如是小编方的设施,排错继续,若是还是不是,排错终止。不问可以预知,1380以此临界点是一个问号,常规来说是失常的,但也不可能解除有如此限制的健康理由。有线链路没不符合规律是因为有线链路的MTU不大,最大纯数据长度1360小与临界值1380。

 

9.补充测量检验,模拟难点机器,将其本机的MTU改为1380+20+20=1420,传输也是常规的,不过改为1421,就可怜了。(注意,独有本机的MTU修改才使得,因为独有TCP数据始发设备,MSS才与MTU关联)

 

.....

 

1x.第9步前面包车型地铁每种调查小编平素不涉足,可是最后,小编方设备确实尚未接收客商端SSL握手进度传出的申明,说显著实是中间设备阻止了这一个”大包“的传导,至于它毕竟是哪个人,到底怎么回事,与大家无关了,但对此笔者个人来讲,对其依然比较感兴趣的。

 

2.传输数据

对于该次排错的计算

那是八个独立的互联网难题,涉及到IP和TCP,细节不多,但丰盛典型。其实那一个标题与最后的思想政治工作逻辑没有关系,可是事实一再是,只有在职业逻辑不恐怕通常时,这类底层的标题才会揭发,那是TCP/IP合同栈的性质所致。此类主题素材的逐个审查要点在于,你要用最快的速度把它与高层协商隔绝开来,何况不能够陷入任何细节。
TCP细节:为啥不必思索TCP细节?那类场景既不极度,又不复杂,假如陷入TCP细节的话,会蒙蔽或然忽略多量横向的难题,比方您会死瞧着TCP的重传机制做细致商讨,也许细致地钻研RTT总计办法,最后也不鲜明能获取什么结论。换句话说,你必定要相信TCP是正规的。
服务程序细节:这几个也是要切断的。因为服务器并不曾真正初阶服务,且故障是百分百复出的,因而得以分明这不是何等复杂的主题素材所导致,真正复杂的标题一再不是百分百复出,即正是您发现出其复发规律,也够你喝一壶的。
TCP难题和IP难题的相异:它们纵然都以网络契约栈的一员,不过利用办法却大分化样。实际上TCP升高了使用者的门道,平时来讲,TCP是让程序去选拔的,由此你要想TCP跑起来,最少要精通其大要原理,恐怕说懂socket机制,倘若你上网浏览网页,即便也是用的TCP,它确实跑起来了,不过使用者不是你,而是你的浏览器。IP就差异,IP的配置者能够是小白,并且随便配置都不会报错。再往下,布线难题,拓扑难点,差不离从未什么样法门,可是却更加的便于出错。因而首先要去掉的就是那类难点。
防火墙计策或然程序BUG:实际上,第一步就要求驾驭助理馆员,是不是防火墙上特殊的攻略所致,但是对于不可能获得这几个音讯的时候,你就无法从那儿初步了。接下来,与之同样的是存疑程序的管理BUG,此时,隔开分离出原始的事情逻辑细节是尤为重要的,现象是大包不可能接收ACK,此时将要忽视掉这些大包的开始和结果以至其上下文,直接发送一个大肆大包实行测量检验。

于是,那类难点的排查是二个稳步隔断的进度,绝对五年前的这一次NAT bug的逐个审查核对,那些故障在技能上要更便于些,全体的纷纭和时间的花菇全体在人口和煦调换上,职员时期新闻的误传恐怕漏传也是一个难点,七年前的充足NAT bug,是多少个本领上特别深入的主题素材,涉及到了基石公约栈代码等级,同期以前,作者还要找到那一个点,可是它的轻易点在于,那几个主题材料只提到到本身壹个人,何况也是百分百复发。

天与地,贵在未有记念,一切伤疤总是会被冲刷,一切荣耀,总是会了无印痕......

) 梦之中从不错与对,梦之中从不恨和悔...最佳闭上您的嘴,那样才算...

第一篇小说总括了Linux 互连网合同栈的牢笼和功效。本文化总同盟结非虚构化遭逢中的种种 Segmentation Offloading 能力。

情景:SSL握手的时候,服务端发送Certificate相当慢。

1. 为啥须要 Segmentation offloading

科技世界 1

   从第一篇小说的牵线中大家精通,Linux 内核传输层和互连网层都要做大量的盘算职业,具体见上海体育场地,那一个总括都在服务器的主 CPU 中实行。这里有一点网络协议栈计算机本事切磋所供给的 CPU 能源的一部分参照他事他说加以考察数据。大要上,发送或然吸取 1 bit/s 的多寡供给 1 赫兹的 CPU 管理技术,也正是说,5 Git/s (625 MB/s) 的网络流量大约供给 5 GHz 的 CPU 管理技能,也正是此时内需 2 个 2.5 Ghz 的多核管理器。因为以太网是单向的,发送和选取 10 Gbit/s (吞吐量正是 二〇〇九 Gbit/s)时,大约必要 8 个 2.5 GHz 的 CPU 内核。

   这一个计算大约能够分为两类:(1)数据计算,举个例子校验和计量和认证、分包和组包等,那一个和所拍卖的 packets 的数目有关(2)数据传输和上下文切换带来的 overhead,那些和传导和切换的次数有关。

  为了缓慢解决难点,思量到更为多的情理网卡具备较强的处理本领,就涌出了三个思路:

(1)借使网卡能够协助少数 Linux 内核公约栈所承担的总结任务,那么就足以将那个总计从事商业事栈 offload (卸载)到大意网卡。

(2)假使网卡不可能支撑那些计算,那么尽恐怕地将那一个总括在 Linux 内核网络栈中延后(传输进度)和提前(接收进程)来降低 overhead。以 TCP 分组可能 IP 分片为例,延迟该进度,能够减小在网络栈中传输和拍卖的 packets 的数量,进而减弱多少传输和上下文切换所须要的主 CPU 计算本领。

分析:

2.  Segmentation offloading 技术

现实思路,也正是立刻怎么想到的,我早就忘了,可是切记三个定论,那正是纠出了Linux 2.6.8的NAT模块的三个bug。

2.1 TSO (TCP Segmentation Offloading)

在抓取了过多数目包后,我开掘本机总是发给本人二个ICMP need frag的报错消息,发掘服务端的Certificate太大,超越了本机出网卡的MTU,以下的一步步的思绪,最后纠出了bug:

2.1.1 TCP Segmentation (TCP 分段)

  MSS(马克西um Segment Size): MSS 是 TCP 数据段每便能够传输的最大数据分段的长度。为了到达最好的传导效率,TCP 磋商在制造连接的时候日常要切磋双方的 MSS 值,那么些值 TCP 合同在促成的时候往往用 MTU 值代替( MSS = MTU - IP 数据手提包头大小20Bytes

  • TCP 数据段的呼和浩特大小20Bytes),所以在私下认可以太网 MTU 为 1500 bytes 时,MSS为 1460。

  TCP 分段:当网络选择发给 TCP 的 message 的长度超越 MSS 时,TCP 会对它依照 MSS 的高低将其分成八个小的 packet,並且在每一种 packet 上增多TCP Header 成为一个 TCP 段(segement)。

科技世界 2

1.证实服务端程序设置了DF标识。那是显明的,因为独有DF标识的数据包才会触发ICMP need frag消息。

2.1.2 TSO  

  TSO 是一种选取网卡分割大数据包,减小 CPU 负荷的一种手艺,也被叫做 LSO (Large segment offload) ,假设数据包的类别只好是 TCP,则被叫作 TSO,假若硬件援救 TSO 作用的话,也急需同期协理硬件的 TCP 校验计算和分流

  • 聚焦 (Scatter Gather) 功用。能够见到 TSO 的落到实处,要求一些中心尺度,而这一个实际是由软件和硬件结合起来达成的,对于硬件,具体说来,硬件可以对大的多少包实行分片,分片之后,还要能够对各样分片附着相关的头顶。

  TSO 就是将由 TCP 商业事务栈所做的 TCP 分段交给具备这种力量的大要网卡去做,因此它须要如下扶助:

  • 大意网卡支持。
  • Linux 网卡驱动匡助。能够采取 ethtool -K ethX tso on 命令张开网卡和驱动对 TSO 的扶助,借使回到错误则意味着不扶助。
  • 还需要 Net:TCP checksum offloading and Net:Scatter Gather 支持。

  使用 TSO 以往,应用发出的大的数据块在不超越 64k 的情状下,将会直接通过Linux 互联网栈发到网卡的驱动的 driver queue,然后在网卡中依照 skb 中的预设分组数据(首如若 MSS)对它实行 TCP 分段。下图是采纳 TSO 和不行使 TSO 的事态的自己检查自纠:

科技世界 3

2.疑问:在TCP往IP发送数据的时候,会检查实验MTU,进而鲜明MSS,明知道MSS的值,怎么还有也许会发送超过限度的包吗?总计错误恐怕相当小,终究Linux也是准工业级的了。

2.2 UFO - UDP Fragmentation Offload

   UDP 数据报,由于它不会融洽开展分层,因而当长度超越了 MTU 时,会在网络层举办 IP 分片。一样,ICMP(在网络层中)同样会现出IP分片意况。

3.疑问解答:幸好作者登时还真知道有些名词,于是想到了TCP Segment Offload这么些技能。

2.2.1 IP fragmentation (分片)

MTU 和 IP 分片:

  • MTU:上文已经说过了,MTU 是链路层中的网络对数据帧的一个范围,依然以以太网为例,默许 MTU 为1500字节。
  • IP 分片:二个 IP 数据报在以太网中传输,即便它的长度超越该 MTU 值,就要开展分片传输,使得每片数据报的尺寸小于MTU。分片传输的 IP 数据报不料定按序达到,但 IP 首部中的消息能让那一个多少报片按序组装。IP数据报的分片与构成是在网络层进完毕的。

IP 分片和 TCP 分段的差异:

  • IP 数据报分片后,独有首先片带有UDP首部或ICMP首部,其他的分片独有IP尾部,到了端点后基于IP尾部中的信息再互联网层举办整合。而 TCP 报文段的种种分段中都有TCP 首部,到了端点后根据 TCP 首部的音信在传输层进行结合。IP数据报分片后,唯有达到目标地后才进行整合,并不是向别的网络左券,在下一站将在开展重组。
  • 对 IP 分片的 TCP segment (段)来说,尽管只错失一片数量, TCP 层也要再一次传整个数据报。这是因为IP层本人并未有过期重传机制------由越来越高层(例如TCP)来顶住超时和重传。当来自TCP报文段的某一段(在IP数据报的某一片中)错失后,TCP在逾期后会重发整个TCP报文段,该报文段对应于一份IP数据报(大概有三个IP分片),未有艺术只重传数据报中的三个数量分片。那正是怎么对 TCP 来讲要尽量防止 IP 分片的源委。

IP 分片和 TCP 分段的关系:

  • 在非设想化情状中,MSS 肯定是要比 MTU 小的,由此,每一种 TCP 分组不再需求 IP 分片就足以一直付出网卡去传输。
  • 在虚构户境遇中,如果布署失当,虚机网络利用的 TCP 连接的 MSS 比宿主机物理网卡的 MTU 大的气象下,宿主机上依旧会实施 IP 分片的。

TCP Segment Offload简称TSO,它是指向TCP的硬件分段本事,并非针对IP分片的,那二者分别应该精晓,所以那与IP头的DF标记非亲非故。对于IP分片,只有首先个分片才会有整机的高层消息(如  果头长能够包罗在八个IP分片中的话),而对此TSO导致的IP数据包,每叁个IP数据包都会有行业内部的TCP头,网卡硬件自行总计每三个分层底部的校验值,体系号等尾部字段且自动封装IP头。它意在加强TCP的习性。

2.2.2 UFO

  UDP 协议层本人不对大的数目报开展分片,而是交由 IP 层去做。因而,UFO 正是将 IP 分片 offload 到网卡(NIC)中张开。其原理同 TSO。

  "IPv4/IPv6: UFO (UDP Fragmentation Offload) Scatter-gather approach: UFO is a feature wherein the Linux kernel network stack will offload the IP fragmentation functionality of large UDP datagram to hardware. This will reduce the overhead of stack in fragmenting the large UDP datagram to MTU sized packets"

4.印证:果然服务器启用了TSO

2.3 GSO - Generic Segemetation Offload

   TSO 是驱动网络契约栈可以将大块 buffer 推送至网卡,然后网卡施行分片工作,这样缓慢解决了 CPU 的载荷,但 TSO 必要硬件来贯彻分片功效;而质量上的增加,首要是因为延缓分片而缓慢消除了 CPU 的负荷,由此,能够考虑将 TSO 才干日常化,因为其本质实际是延缓分片,这种技能,在 Linux 中被称之为 GSO(Generic Segmentation Offload)。它比 TSO 更通用,原因在于它无需硬件的支撑分片就可选择,对于支撑 TSO 功效的硬件,则先通过 GSO 作用,然后利用网卡的硬件分片技巧施行分片;而对于不帮忙 TSO 作用的网卡,将分片的实行,放在了将数据推送的网卡的前一刻,也等于在调用驱动的 xmit 函数前。 

5.疑问:贰个压倒MTU的IP报文发送到了IP层,且它是的多少三个TCP段,这表明TCP已经清楚本人所在的机器有TSO的法力,否则对于本机始发的数据包,TCP会严苛听从MSS封装,它不会卷入一个大包,然后让IP去分片的,那是出于对于本机始发来说,TCP MSS对MTU是能够感知到的。对于转发来说,就不是那般了,可是,对于这里的景色,鲜明是本机始发,TCP是领略TSO的留存的。

2.3.1 对于 UDP,在情理网卡不帮助 UFO 时,使用和不行使 GSO 的事态

科技世界 4

瞩目这两侧中间的严重性不一样:

  • 当未有 GSO 时,UDP 包会在 IP 层做 IP 分片,那会拉动比较严重的难题,富含:信任于 PMTU,这几个本事在重重的骨子里互联网中有的时候无法职业;在神速互联网中,IPv4 packet ID 一时候会再次而导致数据损坏(Breaks down on high-bandwidth links because the IPv4 16-bit packet ID value can wrap around, causing data corruption);它将 UDP 头算在 payload 内,因而独有首先个分片有 UDP 头,由此一个分片遗失会形成整个IP包的损失。
  • 当有 GSO 时,由 Linux UDP 构和栈提供 UDP 分片逻辑并非 IP 分片逻辑,那使得各种分片皆有总体的 UDP 宁德,然后继续 IP 层的 GSO 分片。所以 GSO 自个儿是对 UFO 的优化。

6.估摸:既然TCP具备对TSO的留存感知,但是在IP发送的时候,却又不见了这种记忆,从TCP发往IP的输入,到IP分片决定的终端,中间分明发生了哪些严重的事,迫使TCP错过了TSO的记得。

2.3.2 GSO for UDP 代码分析

GSO for UDP 代码在 :

  • UDP GSO 回调函数:

    static const struct net_offload udpv4_offload = {

    .callbacks = {
        .gso_segment = udp4_ufo_fragment,
        .gro_receive  =    udp4_gro_receive,
        .gro_complete =    udp4_gro_complete,
    },
    

    }

函数 udp4_ufo_fragment 最后调用 skb_segment 函数举行分片:

     /**
  *      skb_segment - Perform protocol segmentation on skb.
  *      @head_skb: buffer to segment
  *      @features: features for the output path (see dev->features)
  *
  *      This function performs segmentation on the given skb.  It returns
  *      a pointer to the first in a list of new skbs for the segments.
  *      In case of error it returns ERR_PTR(err).
  */
 struct sk_buff *skb_segment(struct sk_buff *head_skb,
                             netdev_features_t features)
  • 在函数 static int ip_finish_output_gso(struct net *net, struct sock *sk,  struct sk_buff *skb, unsigned int mtu) 中能见到,首先根据 MSS 做 GSO,然后在调用 ip_fragment 做 IP 分片。可以预知,在平凡状态下(虚机 TCP MSS 要比物理网卡 MTU 小),只做 UDP GSO 分段,IP 分片是无需做的;唯有在奇特处境下 (虚机 TCP MSS 超越了宿主机物理网卡 MTU),IP 分片才会做。那几个和考试中见到的成效是完全一样的。

7.思疑:这种故障处境是自己在小卖部效仿的,通过报告人士的音信,笔者打听到并非颇有的情况都会这么。事实上,笔者一贯不太认可是Linux左券栈本身的难点,不然早已被Fix了,小编一贯存疑是表面模块或许有些外表表现例如抓包导致的。

2.3.3 对 TCP,在网卡不协理 TSO 时,使用和不选拔 GSO 的气象

科技世界 5

两侧都以 TCP 分片,只是地方不一致。

8.可用的新闻:到此甘休,作者还应该有三个音讯,那正是如果加载NAT模块(事实上那是深入分析出来的,报告人士是不知情所谓的NAT模块的,只知道NAT法则)就能够有其一情景,于是目的很断定,死盯NAT模块。

2.3.4 GSO for TCP 代码逻辑解析

科技世界 6

(1)tcp_output 函数

1. Checks if GSO is enabled:
    sysctl net.inet.tcp.gso = 1
    sysctl net.gso.”ifname”.enable_gso = 1
2. Checks if the packet length exceeds the MTU

If 1 and 2 are true, sets GSO flag: m->m_pkthdr.csum_flags |= GSO_TO_CSUM(GSO_TCP4);

(2)ip_output 函数

If GSO is enabled and required, then avoids checksum (IP & TCP) and avoids IP Fragmentation

(3)ether_output 函数

If GSO is enabled and required: calls gso_dispatch() instead of ifp->transmit()

(4)gso_dispatch 函数

int gso_dispatch(struct ifnet *ifp, struct mbuf *m, u_int mac_hlen)
{
  …
  gso_flags = CSUM_TO_GSO(m->m_pkthdr.csum_flags);
  …
  error = gso_functions[gso_flags](ifp, m, mac_hlen);
  return error;
}

(5)gso_functions 函数

gso_functions[GSO_TCP4]
 gso_ip4_tcp(…) - GSO on TCP/IPv4 packet

1. m_seg(struct mbuf *m0, int hdr_len, int mss, …)
   returns the mbuf queue that contains the segments of the original packet (m0).
   hdr_len - first bytes of m0 that are copied in each new segments
   mss - maximum segment size
2. fixes TCP and IP headers in each new segments
3. sends new segments to the device driver [ifp->if_transmit()] 

9.初步debug:由于Linux Netfilter NAT模块相比较轻易,根本无需高等的能够touch到内部存款和储蓄器级的工具,只须要printk就可以,不过在什么地方print是个难点。

2.4 LRO (Large Receive Offload)   

    Linux 在 2.6.24 中投入了支撑 IPv4 TCP 左券的 LRO (Large Receive Offload) ,它经过将多少个 TCP 数据聚合在多少个 skb 结构,在稍后的某些时刻作为二个大数据包交付给上层的互连网合同栈,以收缩上层公约栈管理skb 的支付,升高系统接到 TCP 数据包的力量。当然,这一切都急需网卡驱动程序扶助。精晓 LRO 的办事原理,要求知道 sk_buff 结构体对于负载的储存情势,在基础中,sk_buff 可以有三种格局保留真实的载重:

  1. 多少被保留在 skb->data 指向的由 kmalloc 申请的内部存款和储蓄器缓冲区中,这几个数据区日常被称为线性数据区,数据科长度由函数 skb_headlen 给出
  2. 数据被封存在紧随 skb 线性数据区尾巴部分的分享结构体 skb_shared_info 中的成员 frags 所表示的内部存款和储蓄器页面中,skb_frag_t 的数据由 nr_frags 给出,skb_frags_t 中有数量在内部存储器页面中的偏移量和数据区的高低
  3. 多少被保存于 skb_shared_info 中的成员 frag_list 所表示的 skb 分片队列中

    合併了多少个 skb 的特级 skb,能够贰回性通过网络协议栈,并不是几度,那对 CPU 负荷的缓慢消除是显著的。

 科技世界 7

10.出错点:在调用ip_fragment(便是该函数里面发送了ICMP need frag)以前,有一个断定(省略了不相干的):

2.5 GRO (Generic Receive Offloading)

  后边的 LRO 的着力在于:在抽取路径上,将多少个数据包聚合成三个大的数据包,然后传递给网络协议栈管理,但 LRO 的完毕中留存有的毛病:

  • 数据包合併恐怕会毁掉部分场馆
  • 数据包合併条件过于宽泛,导致一些情状下自然供给区分的数量包也被统一了,那对于路由器是不足接受的
  • 在虚构化条件下,必要采纳桥接作用,但 LRO 使得桥接功用不或然运用
  • 实现中,只支持 IPv4 的 TCP 协议

  而解决这个题指标主意正是新建议的 GRO。首先,GRO 的会集条件进一步的严俊和灵活,而且在设计时,就思量接济具备的传输左券,由此,后续的驱动,都应该运用 GRO 的接口,并不是 LRO,内核或然在全数先有驱动员搬迁移到 GRO 接口之后将 LRO 从根本中移除。GRO 和 LRO 的最大分别在于,GRO 保留了种种接收到的数据包的熵音信,这对于像路由器那样的选取关键,而且完毕了对种种协商的援助。以 IPv4 的 TCP 为例,相配的尺度有:

  • 源 / 目标地点相配
  • TOS/ 和煦字段相配
  • 源 / 目标端口相称

  那篇小说 linux kernel 互连网公约栈之GRO(Generic receive offload) 详细深入分析了 GRO 代码。

if (skb->len > dst_pmtu(skb->dst) && !skb_shinfo(skb)->tso_size) {

2.5.1 在不援救 LRO 的状态下,对 TCP 使用和不应用 GRO 的景况

科技世界 8

return ip_fragment(skb, ip_finish_output);

2.6 TCP/UDP Segementation Offload 小结

}

2.6.1 小结

Offload 传输段还是接收端    针对的协议    Offloading 的位置 ethtool 命令输出中的项目 ethtool 命令中的 option 网卡/Linux 内核支持情况
TSO 传输段 TCP NIC tcp-segmentation-offload tso

Linux 内核从 2.5.33 引入 (2002)

网卡普遍支持

UFO 传输段 UDP NIC udp-fragmentation-offload ufo

linux 2.6.15 引入 (2006)

网卡普遍不支持

GSO 传输段 TCP/UDP NIC 或者 离开 IP 协议栈进入网卡驱动之前 generic-segmentation-offload gso

GSO/TCP: Linux 2.6.18 中引入(2006)

GSO/UDP: linux 3.16 (2014)

             
LRO 接收段 TCP NIC large-receive-offload lro

Linux 内核 2.6.24 引入(2008)

网卡普遍支持

GRO 接收段 TCP NIC 或者离开网卡驱动进入 IP 协议栈之前 generic-receive-offload gro

Linux 内核 2.6.18 引入(2006)

网卡普遍支持