目录
1. 什么是MTU?
MTU是数据链路层的概念,指数据链路层对数据帧长度的限制。不同链路介质类型的网络有不同的默认MTU值,以下是一些常见网络的默认值:
2. 为什么MTU的范围是46-1500?
网络中通常以数据包为单位进行信息传递,那么,一次传送多大的包合适、多大的包最高效就成为一个核心问题之一。如果包大小设置的很大,意味着报文中的有效数据也更多,通信效率更高,但传送一个数据包的延迟也越大,数据包中bit位发生错误的概率也越大。并且如果这个报文丢掉了,重传的代价也很大。如果包大小设置的过小,则意味传输相同的数据量,设备需要处理更多的报文,这样会极大的考验设备的线速转发能力。通过设置MTU来调节网络上数据包的大小,让不同的网络找到最适宜的MTU从而提高转发效率,这就是MTU的作用。
RFC标准定义以太网的默认MTU值为1500。那么这1500的取值是怎么来的呢?
早期的以太网使用共享链路的工作方式,为了保证CSMA/CD(载波多路复用/冲突检测)机制,所以规定了以太帧长度最小为64字节,最大为1518字节。最小64字节是为了保证最极端的冲突能被检测到,64字节是能被检测到的最小值;最大不超过1518字节是为了防止过长的帧传输时间过长而占用共享链路太长时间导致其他业务阻塞。所以规定以太网帧大小为64~1518字节,虽然技术不断发展,但协议一直没有更改。刨去帧头14字节和帧尾CRC校验部分4字节,可知MTU的大小46-1500字节。
3. MTU和TCP MSS的关系
TCP MSS(Maximum Segment Size)是指TCP协议所允许的从对方收到的最大报文长度,即TCP数据包每次能够传输的最大数据分段,只包含TCP Payload,不包含TCP Header和TCP Option。MSS是TCP用来限制application层最大的发送字节数。为了达到最佳的传输效能,TCP协议在建立连接的时候通常要协商双方的MSS值,这个值TCP协议在实现的时候往往根据MTU值来计算(需要减去IP包头20字节和TCP包头20字节),所以通常MSS为1460=1500(MTU)- 20(IP Header) -20 (TCP Header)。
在OSI七层模型中,用户数据是按照如下图一层一层封装的。不同的协议层对数据包有不同的称谓,在传输层叫做段(segment),在网络层叫做数据报(datagram),在链路层叫做帧(frame)。数据封装成帧后发到传输介质上,到达目的主机后每层协议再剥掉相应的首部,最后将应用层数据交给应用程序处理。
4. 数据包超过MTU时如何进行分片?
以太网缺省MTU=1500字节,这是以太网接口对IP层的约束,如果IP层有<=1500字节需要发送,只需要一个IP包就可以完成发送任务;如果IP层有>1500字节数据需要发送,需要分片才能完成发送。
以主机发送一个数据载荷长度为2000字节的报文为例说明其分片的过程(假设出接口的MTU值为1500)。在网络层会对报文进行封装,其结构组成:IP头部20字节+数据载荷长度2000字节,报文封装后,整个报文长度为2020字节。在出接口进行转发的时候,发现IP报文的长度超过了MTU的值1500,因此要进行分片处理,详情见下图。
第一片报文,IP报文头固定20字节,数据载荷可以封装1480字节(MTU值1500字节-IP报文头20字节,数据载荷长度须是8的倍数);
第二片报文,复制第一片的IP头,IP报文头固定20字节,数据载荷为剩余的520字节(总数据载荷长度2000字节减去第一片中已封装的1480字节)。如果最后一片报文的长度不足46字节,会自动填充至46字节。
所有分片报文在发送至目的主机后,在目的主机进行分片重组,恢复为原报文。在进行重组时,通过IP标志位中的MF用来分辨这是不是最后一个分片,片偏移用来分辨这个分片相对原数据报的位置。通过这几个字段,可以准确的完成数据报的重组操作。
5. tcp和udp数据包大小限制说明
根据前面分析,我们可以知道:
UDP 包的最大长度是 1500 - IP头(20) - UDP头(8) = 1472(Bytes)
TCP 包的最大长度是 1500 - IP头(20) - TCP头(20) = 1460 (Bytes)
如果我们定义的TCP和UDP包没有超过范围,那么我们的包在IP层就不用分包,这样传输过程中就避免了在IP层组包发生的错误;如果超过范围,既IP数据报大于1500字节,发送方IP层就需要将数据包分成若干片,而接收方IP层就需要进行数据报的重组。更严重的是,如果使用UDP协议,当IP层组包发生错误,那么包就会被丢弃。接收方无法重组数据报,将导致丢弃整个IP数据报。
在wireshark抓包中,我们可以通过ip.flags.df==1条件过滤出分片的数据。这里的分片标志:三个bit位。第一位保留,未使用。第二位是DF(Don’t Fragment),如果为1,表示不允许分片。第三位是MF(More Fragment),如果为1,表示后面还有分片,并且除了分片出的最后一个报文中此标志为0,其余报文中此标志均为1。
5.1 关于UDP传输的特殊说明
如果UDP包的Data <= 1472个字节,UDP包(UDPHeader+Data)在网络层不用分片,直接封装上IPHeader发往链路层。
如果UDP包的payload > 1472,那么UDP包(UDPHeader + Data)在网络层需要分片,如何分片?
网络层并不会在每个分片里复制一次UDP头,它是把完整的UDP包切开,加上IP头发送出去,除了第一个分片有UDP头,后面的分片都不包含UDP头。
目的主机的网络层接收到多个UDP分片包后,网络层必须重组才能交给上层,为什么?
因为多个分片包只有第一个是有UDP头的,它可以根据UDP头里的端口号通知相应的应用取走,但是后面的分片包由于没有UDP头,传输层无法把分片包交给正确的应用程序。所以UDP分片包必须在网络层重组成一个完整的UDP包,交给传输层处理
网络层根据什么重组呢?UDP分片的时候会分成多个ID一样的IP包。
如果某些分片包没有被目的主机的网络层接收到,造成UDP包重组失败,接收方会丢弃整个数据包,这是UDP不可靠传输的一个表现。
6. 结合抓包实例解释如何进行数据填充?
以太网EthernetII规定,以太网帧数据部分最小为46字节,也就是以太网帧最小是6+6+2+46+4=64。除去4个字节的FCS,因此,抓包时就是60字节。当数据字段的长度小于46字节时,MAC子层就会在数据字段的后面填充以满足数据帧长不小于64字节。
由于填充数据是由MAC子层负责,也就是设备驱动程序。不同的抓包程序和设备驱动程序所处的优先层次可能不同,抓包程序的优先级可能比设备驱动程序更高,也就是说,我们的抓包程序可能在设备驱动程序还没有填充不到64字节的帧的时候,抓包程序已经捕获了数据。
因此不同的抓包工具抓到的数据帧的大小可能不同:使用wireshark和sniffer抓包,TCP 的ACK确认帧的大小一个是54字节,一个是60字节。wireshark抓取时没有填充数据段,sniffer抓取时有填充数据段。
7. 总结
- 以太网(Ethernet)数据帧的长度必须在46-1500字节之间,这是由以太网的物理特性决定的。
- 这个1500字节被称为链路层的MTU(最大传输单元)。但这并不是指链路层的长度被限制在1500字节,其实这个MTU指的是链路层的数据区。并不包括链路层的首部和尾部的18个字节。所以,事实上这个1500字节就是网络层IP数据报的长度限制。
- 因为IP数据报的首部为20字节,所以IP数据报的数据区长度最大为1480字节。而这个1480字节就是用来放TCP传来的TCP报文段或UDP传来的UDP数据报的。
- 因为UDP数据报的首部8字节,所以UDP数据报的数据区最大长度为1472字节;TCP报文段的首部长度为20字节,所以TCP数据去最大长度为1460字节。