文章首发于公-众-号,汽车网络诊断通信
我们知道MTU是网卡的参数,是数据链路层对网络层的IP包大小的限制。当网络层的IP包(包括IP头,VLAN tag)的大小超过了MTU时,需要先在网络层进行分片,切割成小于MTU的IP包,再发往链路层
MSS
试想下,一台主机下的多个APP需要通过TCP协议,发送大量的数据进行通信。形成这样一种局面:多个TCP报文,到达网络层时,封装成多个IP包,这些IP包由于数据太大,大于MTU,需要进行分片,才能发往链路层。这么多的数据包都需要在网络层分片切割,是不是降低了效率?
既然从TCP来的数据由于太大,而全部挤在网络层进行分片,为什么不想一个办法,让TCP来的每一份数据,正好符合在网络层不需要分片呢,这样岂不是你好我好大家好
MSS
Maximum Segment Size,最大报文长度,TCP payload的最大值,TCP协议定义的一个选项,MSS是TCP用来限制应用层最大的发送字节数
MSS选项用于在TCP连接建立时,收发双方协商通信时每一个报文段所能承载的最大数据长度
TCP在建立连接时,收发双方根据MTU计算出各自的MSS,通过三次握手把自己的MSS告知对方,互相确认彼此的MSS大小,取较小的MSS值作为双方在TCP层分段的最大payload
如何根据MTU计算MSS?
以太网的缺省MTU = 1500 = IPHeader(20) +TCPHeader(20) + Data,TCP的有效数据Data的最大值就是1500-20-20 = 1460,这就是MSS的值
客户端在SYN报文中携带自己的MSS,服务器在回复的ACK+SYN中携带自己的MSS
这样就实现了TCP通信时,通过在三次握手阶段确定最小MSS,根据MSS,传输层把不超过MSS的数据封装,下压给网络层,网络层避免了IP包分片,而接收方也不会出现数据帧超过MTU而无法接收的情况
PMTUD
收发双方在TCP协议通信时,根据取较小MSS的原则,避免了发送方在网络层分片,接收方在网卡由于超过MTU而无法接收的情况
但是,以太网通信不是只有两台主机,它们通信的途中还有路由器和交换机,路由器和交换机都有自己的MTU,如果数据帧超过了它们的MTU会怎么样呢?
对于路由器来说,接收到的数据帧如果超过了自己的MTU,在从出口发出去时,需要进行分片,网络层分片IP包,需要根据什么决定?
答案是:IP头的DF分片位
- 如果DF = 0,表示可以分片
- 如果DF = 1,表示不能分片
DF = 0
两台主机在TCP握手阶段,确定了MSS = 1480 - 20 - 20 = 1440,那么发送的IP包就是1440 + 20 + 20 = 1480,这样的IP包在发出去的时候不会分片,而接收端也可以接收到
当IP包到达路由器时,需要从另一个接口发出,而接口MTU为1450,必须分片才能发送,这时候路由器就会检查IP包的DF位,以确定这个IP包是否支持分片
发现DF位是0,表示可以分片,就把这个IP包分成两份,1450和30,由于第一份1450是有IP头的,可以直接下发到链路层发出,而第二份30是没有IP头的,需要加上IP头20个字节,形成一份新的IP包,大小是50个字节,同样下发到链路层,发出
DF = 1
与上面DF = 0的情况不同的是,路由器发现IP包需要分片,然而查看了IP包的DF位,发现值为1,显示不能分片,此时路由器只能丢弃此IP包,同时给源主机回复一个ICMP目的不可达的消息,Type = 3,code = 4
code = 4的含义是:
同时,在ICMP消息里还会携带路由器的MTU的大小,告知源主机这个路由器的MTU是多少,这样源主机就可以继续调整自己的MSS值,如果有多个路由器,多个路由器都会这样操作,最终确定一个这条路径上的最小MTU,这就是PMTUD
另外,ICMP目的不可达消息,还会把丢弃的IP包的各层报头也放在里面
PMUTD
Path MTU Discovery,不用再过多解释了
另外请注意
路由器的MTU只针对出接口
PMTUD只有TCP支持,UDP并不支持