MTU和MSS的原理

原创 2019-01-31 01:15 阅读(151)次

以太网是当今现有局域网采用的最通用的通信协议标准。而以太网规定了MTU。什么是MTU?

我们先看看网络的原理图

 不过这张图不是很准确。因为如果上层传输的数据包很大,就会被拆分。

举个例子, 网络层的数据如果过长, 是没法直接加载链路层上的, 需要将网络层的数据分片, 然后在数据链路层组装成多个帧(而不是一个)。

这点在图上没体现出来。但想想也挺难画出来的。看到网上有朋友碰这张图误人子弟。其实有点难为这张图了。

拆分后有什么坏处呢?

网络通信,尽一切可能避免IP的分片!为什么?因为负责IP分片的那台主机、路由器会花费很多CPU资源来处理分片,同时负责重组IP分片的主机、路由器则需要更多的CPU资源来重组这些IP包的分片。

曾经在实验室里做过实验,比如一台路由器的数据处理能力是10G,如果处理分片则降低到2G左右,这种对比是基于同样大小的IP报,这还是比较高端的平台,采用硬件,软件CPU一起协作才达到的水平,如果比较低端的平台,纯粹采用CPU软件来处理,那数据包处理能力更是惨不忍睹!

正是因为分片对系统的性能影响颇大,TCP/IP协议的创造者们知道这一点,那就是避免IP分片。同样在其他层上,避免分片也是一种优化性能的方法。

当然要明白,完全不分片是不可能的,我数据包就是这么大的时候,还是得分的。但分完后的数据帧需要到接收端再次拼装在一起,这就是需要传输中数据包的一部分不要丢失。TCP协议是可靠的,但如果是UDP协议包,UDP本身不是可靠的,那就只能接受现实了。

回到正题。

先看看 ,EthernetII帧的结构DMAC+SMAC+Type+Data+CRC。也就是出了数据Data外,还有前后这些数据需要在一个帧里一起传输。

由于以太网传输电气方面的限制,每个以太网帧都有最小的大小64bytes,最大不能超过1518bytes,对于小于或者大于这个限制的以太网帧我们都可以视之为错误的数据帧,一般的以太网转发设备会丢弃这些数据帧。(注:小于64Bytes的数据帧一般是由于以太网冲突产生的“碎片”或者线路干扰或者坏的以太网接口产生的,对于大于1518Bytes的数据帧我们一般把它叫做Giant帧,这种一般是由于线路干扰或者坏的以太网口产生)

MTU: Maximum Transmit Unit,最大传输单元,即物理接口(数据链路层)提供给其上层最大一次传输数据的大小,比如IP层、MPLS层等等,因为目前应用最多的接口是以太网,所以谈谈以太网口的MTU,假定其上层协议是IP,缺省MTU=1500,这是一个固定值。为什么是1500呢?

由于以太网EthernetII最大的数据帧是1518Bytes这样,刨去以太网帧的帧头(DMAC目的地址MAC48bit=6Bytes)+(SMAC源MAC地址48bit=6Bytes)+(Type域2bytes)14Bytes和帧尾CRC校验部分4Bytes(这个部门有时候大家也把它叫做FCS),那么剩下承载上层协议的地方也就是Data域最大就只能有1500Bytes. 这个值我们就把它称之为MTU。每个以太网帧都有最小的大小64bytes,最大不能超过1518bytes。

MTU的意思是:整个IP包最大从这个接口发送出去的是1500个字节。可以通过配置修改成更大或更小的值,只要在系统的边界值以内即可,但是切记要在链路的两端都要修改,而且要大小一样,如果不一样,会造成大侧的数据被小侧丢弃!

丢弃!对,没错,丢弃。细看下文。

IP MTU是一个三层概念,它包含了三层头部及所有载荷,根据下层为上层服务的,上层基于下层才能做进一步的扩展的原则,尽管IP MTU的变化范围很大(68-65535),但也不得不照顾以太网MTU的限制,说白了就是ip对以太网的妥协。

当两台远程PC互联的时候,它们的数据需要穿过很多的路由器和各种各样的网络媒介才能到达对端,网络中不同媒介的MTU各不相同,就好比一长段的水管,由不同粗细的水管组成(MTU不同 :))通过这段水管最大水量就要由中间最细的水管决定。

对于网络层的上层协议而言(我们以TCP/IP协议族为例)它们对水管粗细不在意它们认为这个是网络层的事情。网络层IP协议会检查每个从上层协议下来的数据包的大小,并根据本机MTU的大小决定是否作“分片”处理。分片最大的坏处就是降低了传输性能,本来一次可以搞定的事情,分成多次搞定,所以在网络层更高一层(就是传输层)的实现中往往会对此加以注意!有些高层因为某些原因就会要求我这个面包不能切片,我要完整地面包,所以会在IP数据包包头里面加上一个标签:DF(Donot Fragment)。这样当这个IP数据包在一大段网络(水管里面)传输的时候,如果遇到MTU小于IP数据包的情况,转发设备就会根据要求丢弃这个数据包。然后返回一个错误信息给发送者。这样往往会造成某些通讯上的问题,不过幸运的是大部分网络链路都是MTU1500或者大于1500。

对于UDP协议而言,这个协议本身是无连接的协议,对数据包的到达顺序以及是否正确到达不甚关心,所以一般UDP应用对分片没有特殊要求。

对于TCP协议而言就不一样了,这个协议是面向连接的协议,对于TCP协议而言它非常在意数据包的到达顺序以及是否传输中有错误发生。所以有些TCP应用对分片有要求---不能分片(DF)

花开两朵,各表一枝,说完MTU的故事我们该讲讲今天的第二个猪脚---PPPoE所谓PPPoE就是在以太网上面跑PPP协议,有人奇怪了,PPP协议和Ethernet不都是链路层协议吗?怎么一个链路层跑到另外一个链路层上面去了,难道升级成网络层协议了不成。其实这是个误区:就是某层协议只能承载更上一层协议。
为什么会产生这种奇怪的需求呢?这是因为随着宽带接入(这种宽带接入一般为Cable Modem或者xDSL或者以太网的接入)由于以太网缺乏认证计费机制而传统运营商是通过PPP协议来对拨号等接入服务进行认证计费的,所以就出了这么一个怪胎:PPPoE。(有关PPPoE的详细介绍参见V大以及本站其他成
员的一些介绍文章,我就不啰里啰唆的了)
 
PPPoE带来了好处,也带来了一些坏处,比如:二次封装耗费资源,降低了传输效能等等,这些坏处俺也不多说了,最大的坏处就是PPPoE导致MTU变小了以太网的MTU是1500,再减去PPP的包头包尾的开销(8Bytes),就变成1492。

如果两台主机之间的某段网络使用了PPPoE那么就会导致某些不能分片的应用无法通讯。

这个时候就需要我们调整一下主机的MTU,通过降低主机的MTU,这样我们就能够顺利地进行通讯了。
 
当然对于TCP应用而言还有另外的解决方案。马上请出今天第三位猪脚:MSS。
MSS最大传输大小的缩写,是TCP协议里面的一个概念。MSS就是TCP数据包每次能够传输的最大数据分段。为了达到最佳的传输效能TCP协议在建立连接的时候通常要协商双方的MSS值,这个值TCP协议在实现的时候往往用MTU值代替(需要减去IP数据包包头的大小20Bytes和TCP数据段的包头20Bytes)所以往往MSS为1460。通讯双方会根据双方提供的MSS值得最小值确定为这次连接的最大MSS值。

我们回过头来看前言里面的那个问题,我们试想一下,如果我们在中间路由器上把每次TCP连接的最大MSS进行调整这样使得通过PPPoE链路的最大MSS值加上数据包头包尾不会超过PPPoE的MTU大小1492这样就不会造成无法通讯的问题。

这样双向通信都可以避免因为IP包太大引起的分片。但是MSS能完全避免IP分片吗?不能!

为什么MSS不能避免分片?

记住一点MSS只是解决源主机、目的主机第一跳first hop MTU问题,这样保证第一跳不分片,但是这种方式不能克服路径中有更小的MTU而造成的分片。

Path MTU Discovery 即 传输路径MTU的发现

还是拿第一个例子来讲,IP包= 1500,从源主机发送出来了,然后在互联网上一跳一跳奔向目的地,突然到了一台路由器上,需要从一个接口发送出去,这个接口MTU只有1000,由于IP包 1500 >1000,这个IP包必须分片才能出去,于是就分成了两个IP分片发送出了,那能否让这台路由器不分片呢?可以的,大家记得IP头有一个标志位DF,Dont Fragment,如果为1,意思是这个IP包在传输的过程中不能分片,如果此IP包大于物理接口的MTU,请直接丢弃,并发消息告诉源主机!什么消息?ICMP的消息,告诉包因为太大了,因为不能分片所以被丢了,并告诉源主机可以重新发小于等于MTU的包;那发什么样的ICMP消息?

ICMP协议里有type字段,还有code字段,发送type=3,code=4,MTU=1000的消息就可以了,当这个ICMP消息到达IP包的源主机,源主机知道原来是IP太大了,那最大可以发送多大的呢?ICMP消息里有,那就是MTU=1000,于是源主机发送小于等于1000字节的就可以避免在传输路径上的分片。那读者可能会说,如果IP包=1000在传输过程中遇到更小的MTU=500怎么办?呵呵,重复以上的步骤就可以了!

有细心的读者会说,如果ICMP type=3 code=4无法到达源主机会发生什么?很显然IP包被静静地丢了,TCP连接超时中断。ICMP为什么回不来?一般被防火墙或者路由器的访问控制列表ACL给无情拒绝通过!如果你可以管理配置这些设备,只要允许ICMP type=3 code=4通过就可以了,否则只有老老实实关闭 Path MTU Discovery 这个功能了,至少分片可以通信,而不分片则彻底无法通信了,这就是聊胜于无,无奈的选择!

源主机的IP包被丢弃谁来重传?

如果是UDP的应用,由application 来重传。如果TCP session,由TCP来重传

先明确这个前提,再来分析这个因为IP包太大被中途丢弃所引起的一系列动作


1) IP 1500 > RouterX 出接口MTU 1000,DF=1,于是RouterX丢弃,并发送ICMP给source host,type=3,code=4,在ICMP消息里还包含了五元组:Source IP,Destination IP,Source Port,Destination Port,IP协议号:6,即TCP,还有一个关键消息,即RouterX 出接口MTU的值,即这里的1000。

2)假定ICMP很幸运到达了 source host,IP层解开这个包,得到

a) 五元组
b) RouterX MTU =1000

IP通过五元组知道这是哪个TCP连接,即刻修改 [Source IP, Destination IP] 这条路径的PMTU值=1000,IP层给TCP session发送两个通知

a) 包被丢失
b) PMTU 变小到1000

当TCP session知道包被丢失,先发送重传队列,很显然还是会被丢弃,当接收到到PMTU变小到1000的通知消息时,相应修改MMS_S= 980(maximumsend transport-message size, 包含TCP头 ),对新生成的TCP Segment则使用960字节,最终IP包为1000字节。

3) TCP Adjust-MSS

有时企业网的设计者为了怕引起在传输路径上的分片,采用这个feature,比如在分公司出口网关WAN接口上使用此feature,检查TCP SYN消息里的option 4,即MSS,可以将双向的MSS修改成更小的值,比如1380,这样即使这个IP包可能会通过GRE Tunnel,IP security VPN Tunnel,会被加上几十个字节的新的IP头信息,GRE Tunnel头信息也不会分片。

此feature 只对TCP连接有用,不适用UDP应用!另外这个feature是cisco 私有的实现,不是标准,这里把它拎出来也是加深对MSS得理解。


谈完以上话题,再谈谈二层交换机,交换机接口下也有MTU,缺省值一般为1500,如果有一个帧1600字节需要从这个发出去,会发生什么?一般直接丢,会不会发什么ICMP消息出来?不会的!那如果1508字节的帧呢?转发还是丢弃?我们称这种帧为baby giant 帧,即比1500大那么一点的帧,一般是加入了MPLS label造成的,具体到不同的产品有不同的动作,有直接丢的,也有原封不动继续转发的,提到这些只是提供一些参考,不具有太现实得意义,我切说,你且听,具体到特定的平台,有这些概念在心中,会有一个提前的准备。


为什么数据中心常用 > 8192字节的MTU?

曾经在实验室里做过实验,把一台路由器设备的进出接口MTU=9218,然后用各种尺寸的包打流量,来测试系统数据throughput, 结果证明,包越大,系统得吞吐量越大,也就是传输效率越高。所以用更大的MTU可以提供更高的数据传输能力。

NFS网络服务器之间的数据读取、存储最小单位是磁盘扇区,而服务器扇区经常使用8192这个值,而且为了避免被分片,发送这些扇区数据的IP包的DF设置为1,意思是不允许分片,那最好的办法就是提供数据中心全网的MTU>8192,由于还要考虑IP 头,UDP头,文件系统头,一般选择9000左右足够用的了。