PMTU

MTU问题多多,那么尽可能避免由MTU引发的网络问题将显得尤为重要。通常而言,我们可以使用以下方法来检测和避免MTU问题:
1.      手工测试发现MTU值
2.      TCP-MSS
3.      PathMTU Discovery
 
今天我们就来聊聊以上工具的具体细节以及如何通过他们发现链路MTU的最佳值,同时奉上两个典型的由MTU引发的问题案例。
 
什么是最佳MTU值?
最佳MTU值,是指保证数据包不被分片的情况下,以字节为基本单位的链路单个数据包尺寸的最大临界值。如果数据包再多一个字节长度,数据包就会被分片。此值称为最佳MTU值。
 MTU下篇:TCP-MSS,Path MTU Discovery详解以及常见问题分析
MTU工具测试环境介绍
为了演示常见MTU检测方法,特搭建网络测试环境如下:
                           
 
上图网络拓扑中,存在两个网络站点A和B。A站点和B站点可以通过ISP运营商互联互通。
A站点出口路由器为SRX01,出口IP为1.1.1.1
B站点出口路由器为SRX02,出口IP为2.2.2.2
站点A和站点B出口路由器的MTU值如下:
A站点的出口MTU值为巨型MTU值9000字节。
B站点的出口MTU 值为2000字节。
在A,B站点各有公网服务器一台:
A站点Server 7, IP:3.3.3.3
B站点Server 8, IP:4.4.4.4
两者可以通过ISP的BGP路由互联互通。
 场景介绍:
此场景存在的问题为:运营商内核心路由器之间的MTU值未知。但由于网络通信是一个端到端的整体行为,若不通过某种方法获悉运营商之间的链路MTU值。那A和B之间的通信可能存在数据包分片甚至丢包的行为。
 
在开始研究如何发现端到端的链路最优MTU值之前,让我们先做一个简单的Ping联通性测试以确保SRX01和SRX02能够正常通信。
 
Ping包成功,两端链路通信正常。通过Traceroute可以看出穿越的运营商路由器IP地址。
注:上图中,默认情况下,Juniper的Ping包负载尺寸为56字节。
 
服务器连通性测试:
环境确认测试完成,让我们来逐一介绍MTU的发现方式:
 1.冷兵器时代:手工测试
最简单也是最直观的MTU检测方式自然是手工测试。
手工测试提供了其他工具无法比拟的优势:可视性,直观性。
 手工测试示例
让我们来看看如何通过手工测试法发现链路的MTU值。
 
1
2
3
4
5
6
7
8
lab@SRX01> ping 2.2.2.2 source 1.1.1.1 rapid count 1 do-not-fragment size 8000   
PING 2.2.2.2 (2.2.2.2): 8000 data bytes
36 bytes from 1.1.1.100: frag needed and DF set (MTU 1500)
Vr HL TOS  Len   ID Flg off TTL Pro  cks      Src     Dst
 4  5  001f5c c999   2 0000  40  014c02 1.1.1.1  2.2.2.2
.
--- 2.2.2.2 ping statistics ---
1 packets transmitted, 0 packets received, 100% packet loss
 
针对上面的Ping测试,有几点需要说明:
1.      Do-not-fragment关键字很重要,在《MTU共计解析与常见问题汇总-上篇》中曾经提到过,发送方可以自主确定数据包是否需要被分片。而决定的方法为设置DF=1,告知下游路由器请不要对数据包进行分片。在此测试案例中,我指定了do-not-fragment。顾名思义,SRX01会根据我的要求把ICMP包的DF设置为1。
 
2.      Size 8000是告知SRX01请产生一个8000字节的载荷并封装到ICMP中。为什么要用8000,是因为SRX01的本地链路MTU最大值为9000字节(包含IP包头+ICMP包头),所以我需要随机选择一个比9000稍小的数。
 
在上面测试中,当我用8k字节ping一个数据包的时候,ping测试失败。从而证明中间链路的MTU值是小于8000字节的。
 
同时,在Ping 2.2.2.2 的过程中,SRX01收到一个错误信息。
36 bytes from 1.1.1.100: frag neededand DF set (MTU 1500)
有一条从1.1.1.100发过来的消息,内容大致如下:
你的数据包太大。要想往前走,数据包需要分片,可是DF=1,我没法给你分。(顺便悄悄告诉你,前方MTU值为1500。)
 难道ISP运营商内部还有咱的人,还给透露小道消息,在这里先不管这高人是谁,后续聊到Path MTU Discovery时,将通过抓包揭晓谜底。
我们就只需要知道有高人指点,前方ISO网络层数据包MTU大小最大为1500字节。
 抱着半信半疑的态度,我们再Ping测试一次。
但是在开始测试之前,先打一个小算盘:
网络层1500字节=20字节IP头+8字节ICMP头+1472字节的载荷。
 按照上面的推理,我猜如果Ping数据包载荷size=1472字节的话,就会成功。而如果稍稍多一点,例如1473字节Ping就会失败。
 通过实验证明:
Ping Size=1472字节的包:
1
2
3
4
5
6
lab@SRX01>ping 2.2.2.2 source 1.1.1.1 rapid count 1 do-not-fragment size 1472 
PING2.2.2.2 (2.2.2.2): 1472 data bytes
!
--- 2.2.2.2ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-tripmin/avg/max/stddev = 28.471/28.471/28.471/0.000 ms
Ping Size=1473字节的包:
1
2
3
4
5
6
7
8
lab@SRX01>ping 2.2.2.2 source 1.1.1.1 rapid count 1 do-not-fragment size 1473   
PING2.2.2.2 (2.2.2.2): 1473 data bytes
36 bytesfrom 1.1.1.100: frag needed and DF set (MTU 1500)
Vr HLTOS  Len  ID Flg  off TTL Pro  cks     Src      Dst
 4 5  00 05dd d60b   2 0000 40  01 590f 1.1.1.1  2.2.2.2
.
--- 2.2.2.2ping statistics ---
1 packets transmitted, 0 packets received, 100% packet loss
验证成功。我们现在可以100%确定,此神秘人物透露的1500字节的MTU值是绝对可信的。同时也获悉端到端链路ISO第三层的最佳MTU值为1500字节。
 以上就是手工测试法,简单明了。
 但是有一个问题?
 作为管理员,我们通过测试明确了端到端MTU的实际值。可是我们如何也让网络中的应用程序也知晓这1500字节的MTU值呢?
 2.小米加步:TCP-MSS协商
TCP-MSS,全称TCP maximum segment size。翻译过来是TCP最大报文尺寸。它的值代表TCP传输层期望对端发送给自己单个TCP报文的最大尺寸。
通俗来说,当TCP协议两端在初始协商进行TCP三次握手协议的时候,主机两端会把自己当前所在链路的MSS值告知对方。当一端主机收到另外一端的MSS值候,它会评估其MSS值并与自己的MSS值做对比,取最小的值来决定TCP发送的最大报文尺寸。
如何计算本地MSS值?
本地MSS=MTU-20字节的标准IP头-20字节的标准TCP头(换个角度看其实就是TCP负载)
 
那TCP-MSS如何在避免数据包分片中,发挥它的作用呢?
 让我们来看一个实际示例:
 还记得在测试环境中介绍的两台服务器Server 7 和Server 8吗?
 
现在两台服务器要搞事情了。
 tcp三次握手图解如上图,服务器Server 7 要往Server 8 用SCP的方式传送一个40M的文件。Server7 的MTU 为9000字节,Server8 的MTU 2000 字节。
TCP行为理论分析:
TCP协商期间,Server 7和Server 8之间会把自己当前的MSS值告知对方,通过对比本地MSS与对方的MSS值后,取两者最小值,如下:
Server 7MSS值为9000-40=8960字节。
Server 8 MSS值为2000-40=1960字节。
很明显,Server 7和Server8 会达成协议,两者中取Server 8的MSS值,即1960字节。这个值将是他们的TCP数据传输过程中单个TCP数据包载荷的最大值。
 让我们通过实验抓包来验证理论分析:
如上图,正如理论分析。在Server 7(3.3.3.3)与Server8(4.4.4.4)TCP三次握手期间,Server7发送了8960字节的MSS,而Server8发送了1960字节的MSS。
 为了证明Server7 选择了较低的1960字节的MSS,让我们看看数据包传输过程中的TCP数据包大小。
因为TCP存在窗口流控机制,TCP速率不会从一开始就达到最大值,而是一个循序渐进增长的过程,当然最后还是如上图红框所示达到了TCP的单包最大值2014字节,即TCP-MSS值。
这里的2014为整个数据包大小,分拆后如下:
2014字节=14字节二层帧头+20字节IP头+20字节标准TCP头+12字节TCP可选项+1948的负载。
此处的TCP-MSS仍然为1960字节,只是被拆分成为了12字节的TCP可选项+1948的负载。
(记住MSS计算是以标准的20 字节TCP头为参考,在计算时拖挂的TCP选项被放在负载之内考虑)

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。