在IPSEC、GRE网络下的MTU、TCP-MSS计算

一、关于MTU的定义

在华为文档(链接)里写得非常清楚,不同厂商可能对MTU定义不一样,但主流设备将MTU用以指示整个IP报文的最大长度(IP头+三层Payload),MTU是一个三层的定义,即MTU = IP MTU。

为什么华为文档说MTU是一个三层定义?因为在二层转发时不判断报文是否超过MTU,也就是说对于一个交换机,在二层转发流量时不判断报文的MTU是否过大。

MTU默认范围是46~1500字节。如果算上14字节以太网帧头+4字节FCS校验,加起来就是64~1518字节。

如果再加上4字节的VLAN标签,那么长度就变成68~1522字节。

Windows的MTU默认值也是1500,用powershell下执行netsh interface ipv4 show subinterfaces命令可以查看当前系统的MTU值。如果用wireshark在Windows上抓到的最长报文长度一般是1514字节,这是因为wireshark抓到的报文里没有校验部分,所以少了4个字节。

二、关于IP MTU分片

什么时候会分片?一个报文的MTU长度超过了系统设置值,IP头中未设置DF位(Don't Fragment,不分片),那么就会分片。按照华为文档(链接)中定义,设备始发的流量(比如从设备发起的ping、BGP等流量会检查)会检查MTU长度并判断是否分片,另外转发ipv4流量时,收到的报文不检查MTU长度,发出报文时才检查MTU长度并判断是否分片。

如果设备发出报文时发现超过了MTU值就会分片,对方设备收到分片会重组。很明显,分片重组会影响处理和转发效率,应该避免。正常情况下,大部分设备MTU值都是1500不会出现分片情况,但在IPSEC、GRE等技术需要增加报文长度的语境下,会导致报文最终超过1500,不修改MTU就会分片。上层协议如何感知MTU值,并发送适合长度报文,避免分片?

三、关于TCP MSS

用户业务流量都是TCP和UDP流量。TCP协议更复杂,对于单个报文长度有自己的协商计算,就是TCP MSS。关于TCP MSS上面引用的华为文档也说的很明白,TCP MSS(Maximum Segment Size)是指TCP协议所允许的从对方收到的最大报文长度,即TCP数据包每次能够传输的最大数据分段,只包含TCP Payload,不包含TCP Header和TCP Option。

TCP MSS的本质是想避免IP MTU分片的。MSS是在TCP握手时候协商的,双方均发送己方的TCP MSS值大小,然后取小的那个值作为本次会话通信的最大值。所以,这个值取决于两端设备的MTU值,一般是1460字节(1500字节-20字节IP头-20字节TCP头)。

双方协商的MSS值取决于双方的MTU值,如果中间转发设备的MTU值比较小,收发双方设置的MTU偏大会导致IP MTU分片,这种情况两端设备能发现或避免吗?在网络设备上有自动发现MTU值的功能,可以自动修改端口MTU,但很明显无法影响计算机的MTU、TCP MSS。在部分网络设备上还可以直接修改TCP协商报文中的MSS值,比如华为防火墙中的firewall tcp-mss命令,可以修改转发流量中TCP协商报文中的MSS值,使其可以符合路径中最小的值,从而让通信双方协商出较小的MSS值,而不需要修改计算机的MSS值。

四、计算机上如何判断与对端通信的最大MTU

在链接里的这篇文章里详细说明了如何测试链路MTU最小值。在计算机上执行ping命令,参数指定"不分片"和"发送大小",这里的"发送大小"不包括IP头和ICMP头大小。

对于icmp报文,其中的IP帧头是20字节,ICMP的ping请求头或应答头是8字节,加起来是28字节。所以,对于MTU是1500的接口,最大不分片能通过携带数据大小是1472(1500-28)字节大小的ping报文。通过回显可以知道当前MTU值是否能不分片的通过转发路径。

复制代码
# windows执行
ping -f -l (1500-28) 对端IP地址

# Linux执行
ping -M do -s $((1500-28)) 对端IP地址

五、不同协议对报文分片的影响

关于各协议对MTU的影响,华为专门编写了《MTU专题》(链接)的册子,里面详细说明了相关内容,实在太多太复杂。

**1. GRE协议对MTU的影响。**如果在IP协议采用GRE隧道,会在原IP报文上增加一个20字节的隧道IP头和一个4字节的GRE头,也就是总计28字节。也就是说如果路径上的设备不修改默认MTU1500,ping的负载最大只能填写1448(1472-28),否则就会分片。虽然对用户无感,但却影响转发性能。

**2. IPESC对MTU的影响。**IPSEC就更为复杂,密文用ESP协议封装,又有隧道和透明两种模式,隧道还有额外增加一个IP头。即便是透明模式,除了8字节的ESP头还有数字节的尾部。而且,加密算法的要求也会额外填充部分字节。如果采用的是ipsec客户端,可以修改ipsec服务器的接口MTU,这样双方协商时会自动取较小值。如果两端使用ipsec设备,计算机和服务器无法感知中间的ipsec存在,仍然采用默认MTU值,那么就会出现分片。

**3. MPLS对MTU的影响。**MPLS报文在二层和三层头之间,所以在计算MTU时是否包含MPLS头?不同厂商好像定义不同。按华为文档说明个人理解华为不计算MPLS头,即便加了MPLS标签的报文长度变长了,只要IP头+三层Payload小于MTU值就可以正常转发。华为文档中的转发流程图里详细说明了这个情况,同时文档也说,通过MPLS MTU可以控制分片,避免报文过大。

**4. L2TP对MTU的影响。**L2TP虽然叫二层隧道协议,但这是指L2TP协议封装了私网的二层头以上数据,也不是工作在二层。对IP承载的L2TP的,用UDP报文封装私网数据。对于封装后的L2TP报文MTU长度肯定变大了,需要分片。但是L2TP封装后需要分片的话和上面华为的流程图发生了不一致。

当我们的网络存在可能影响MTU的协议时,调整MTU可以减少分片。一种方法是修改用户计算机或服务器的MTU,修改所有用户计算机MTU太过麻烦,修改服务器只能算相对容易。另一种方法是让路径相关设备MTU值变大,但问题是路径大概率是通过运营商的,运营商设备MTU值不可控,如果是虚拟专线,运营商转发过程中是否分片我们也无法可知。