写点什么

MTU 带来的问题

用户头像
BUG侦探
关注
发布于: 2021 年 06 月 10 日
MTU带来的问题

背景

割接旧专线流量到带有 GRE 隧道的新专线的时候,发现部分用户电脑浏览网站异常,网站页面会出现偶尔无法正常浏览的现象。因为新专线唯一区别是带有 GRE 隧道,所以重点分析 GRE 问题。

GRE

GRE(General Routing Encapsulation,通用路由封装),可以对某些网络层协议的数据报文进行封装,使这些被封装的数据报文能够在另一个网络层协议中传输。

GRE 提供了将一种协议的报文封装在另一种协议报文中的机制,是一种三层隧道封装技术,使报文可以通过 GRE 隧道透明的传输,解决异种网络的传输问题。



GRE 是三层技术,是对原始 IP 报文进行了封装,那么是不是因为新专线传输的数据包比旧专线的大,引起了异常?

影响数据包大小的有几个地方:MTU 和 MSS。

MTU

MTU( Maximum Transmission Unit),最大传输单元。用来限制一个数据包的大小,相当于一个最高阀值,不能超过它。我们使用的以太网的网络层 MTU 是 1500 字节。



网络是个复杂的环境,MTU 不一定都是 1500 字节,例如以太网标准是 1500 字节,如果在以太网上使用了隧道技术,则相应 MTU 会减少,例如 GRE 隧道,因为原始 IP 数据包增加了一个 GRE 头和新的 IP 头,那么 MTU 就要减少到 1476。

GRE 隧道接口为啥要减少 mtu?因为以太网标准是 1500,数据包过 GRE 隧道,加上 GRE 隧道报文头,要保持不超过 1500,否则在标准以太网内无法传输,自然要压缩过 GRE 隧道前的数据报长度。GRE 隧道接口直接说自己 mtu 就支持 1476,你们原始数据包自己看着办吧。



分片与重组

如果发送的数据很大,以太网 MTU 就只有 1500 字节,或者网络中间链路的 MTU 小于 1500 字节,怎么办?

当 IP 数据报太大时,就要采用分片技术,以保证数据帧不大于网络的 MTU,必须把该数据报分割成多个不大于以太网接口的数据报才能发送。数据到达目的服务器以后,再把这些零碎的数据包进行重组成一个完成的数据包,再交给上层应用。

比如,发快递,快递公司规定他们的一个包裹最多能承受 1500 克的重量,如果发送方发送 15000 克的物品,那么快递公司就要把这些物品进行拆分到 10 个包裹里面进行发送,到目的地以后再把这 10 个包裹进行打包,还原成原来 15000 克的物品,再交给接收方。

如果传输过程中,一个分片(快递的一个包裹)丢了,怎么办?

如果 IP 层对一个数据包进行了分片,只要有一个分片丢失了,只能依赖于传输层进行重传,结果是所有的分片都要重传一遍。IP 分片会大大降低传输层传送数据的成功率,所以应尽量避免分片(很多应用程序就是这么干的,发送的数据包 IP 头“标志”字段“Do not Fragment”标志被置 1,不允许分片!当然了,网络设备遇到这种情况,不分片无法传输,分片吧,数据包不让,咋办?丢掉这个左右为难的数据包是唯一出路)。



如何避免分片

服务器如何知道自己要传输的数据封装每个 IP 数据包的大小呢,如果以太网中间链路的 MTU 小于 1500,服务器又不知道,怎么解决这个问题?

MSS(Maximum Segment Size,最大报文段长度)表示 TCP 传往另一端的最大块数据的长度。当一个连接建立时,连接的双方都要通告各自的 MSS。



当需要通讯的两台设备 TCP 握手阶段,会发送自己支持的 MSS 大小,默认本地服务器 MTU 是 1500 的时候,MSS 会协商成 1460(1460+20 字节 TCP 头+20 字节 IP 头=1500 字节)

MSS 只是解决源主机、目的主机第一跳 MTU 问题,这样保证第一跳不分片,但是这种方式不能克服路径中有更小的 MTU 而造成的分片,就是说,如果数据传输过程中间链路的 MTU 小于 1500,怎么办?

PMTU(Path MTU Discovery),PMTU 被用于动态确定从数据包源到目的地路径上的最小 MTU。

实现方式:使用 ICMP 协议里有 type 字段、code 字段,发送 type=3,code=4,MTU=XXX 的消息,当这个 ICMP 消息到达 IP 包的源主机,源主机将配置正确的 MTU。



GRE 带来的问题

GRE 是在原始 IP 包前又封装了一个 GRE 头(4 字节)和新的 IP 头(20 字节),为了新封装的数据包不超过以太网标准 MTU 1500 字节,他会把自己的 MTU 自动减小,GRE 接口 MTU 是 1500 - 24 = 1476



一个很严重的问题,GRE 隧道把自己的 MTU 减小到了 1476,这时候服务器又不知道网络传输链路上最小 MTU 情况,还认为 MTU 是 1500,并传输数据,这个时候,应用程序如果不让分片,数据包到达 GRE 接口的时候,就会产生问题,最终数据包被丢弃。

如果服务器利用 MSS,能发现 GRE 隧道的 MTU,这样是不是就可以解决问题了?

带 GRE 隧道的服务器 MSS:MSS = MTU(1500byte) - IP 首部(20byte) - GRE 头部(24byte) - TCP 首部(20byte) = 1436byte

服务器 MSS 应该是 1436,才会避免分片。

那么如果一个正常通讯的两台服务器,割接过程中,链路 MTU 变小,会发生什么?

答案是服务器初始协商的 MTU 是 1500,后续数据就是按 1500 进行通讯,如果中间链路 MTU 变小,较小 MTU 接口会丢弃报文,并向发送源服务器发送一条 type=3,code=4 的 ICMP 消息,告诉发送源,自己接口能支持的 MTU 是什么,希望后续报文按该 MTU 进行发送。




PMTU 就完全解决了 MTU 问题?

以太网默认 MTU 是 1500,所以不配置隧道情况下,服务器交互协商的 MSS,可以正常在以太网链路上传输。如果流量穿越较小 MTU 链路,则非常依靠 PMTU 机制。

PMTU 太依赖 ICMP 消息,在实际生产环境中,防火墙、杀毒软件等对 ICMP 消息有不同的处理策略,如果安全策略把 PMTUD 的 ICMP 给过滤掉,那么主机将无法知道网络链路 MTU 情况,直接影响 TCP/UDP 网络通讯。

故障排查

模拟测试,搭建模拟环境,模拟环境使用的设备型号、网络结构、调度配置等按现场网络搭建,如下图。



使用 1 台服务器代替 Client,然后对远端的服务器进行模拟访问,可以正常接收 GRE 隧道接口发出的 ICMP(type=3,code=4,MTU=XXX)消息,后续的通讯也正常,符合之前 GRE 产生诸多问题的分析。

验证该结构 GRE 隧道流量转发没有问题。



服务器做 Client,可以正常接收 GRE 隧道,因为丢弃大于接口 MTU 的报文后发送的 ICMP(type=3,code=4,MTU=XXX)消息,之后 Client 端更新了自己的 MSS,后续发送的报文正常,那么是什么原因引起的普通电脑浏览网页异常呢?

后来发现,普通电脑默认是开启防火墙的,有拒绝 ICMP 策略,开始尝试使用带防火墙策略的电脑进行测试



测试发现当 TCP 建立连接的时候,用正常的 MTU 协商 MSS,TCP 建立连接后,发送的大包有重传,造成数据震荡。

结论:结合以上分析,查看网络途径没有异常,使用服务器代替 Client 端模拟与远端服务器通讯,没有发现异常。经与 IT 核对,发现普通电脑默认开启了防火墙策略,ICMP 也被策略禁止了。防火墙策略阻止了 ICMP 消息,当 ICMP(type=3,code=4,MTU=XXX)消息到达电脑后因策略原因无法正常被系统识别,主机无法更新 MSS,继续按 MTU 1500 发送数据,数据包到达 GRE 隧道接口后,大于 GRE 隧道接口 MTU 的报文被丢弃,小包正常转发,所以部分还能正常通信,部分异常。

解决思路

方法 1:所有电脑都配置防火墙允许 ICMP。

可实施性:上百台的电脑要修改防火墙策略,维护成本较高,也不方便维护,如果个别电脑自己安装一些安全软件,无法控制。

方法 2:生产网接口 MTU 全部调大,这样即使网络内有 IP 隧道,也可以保证接口 MTU 不小于 1500,数据包还是可以正常传输。可实施性:生产网要修改接口 MTU 是个大工程,因隧道的中间链路涉及跨机房的 IDC 设备,直线路径有 5+设备,且为数通核心级别设备,如调整则建议全部 IDC 设备调整,涉及设备量上千+,且会对线上生产流量造成影响。

方法 3:避免专线使用 IP 隧道技术。可实施性:网络操作复杂度增加,客户侧参与度降低,客户侧正常发送数据即可。

结合实际环境,最终选择了方法 3,使用无 IP 隧道专线,后续已经割接生产流量到新专线上,没有发生因 MTU 引发的故障。

发布于: 2021 年 06 月 10 日阅读数: 62
用户头像

BUG侦探

关注

还未添加个人签名 2021.06.08 加入

专注于发掘程序员/工程师的有趣灵魂,对工作中的思路与总结进行闪光播报。

评论 (1 条评论)

发布
用户头像
方案4:开启强制分片功能,忽略DF标志位
2021 年 06 月 11 日 15:07
回复
没有更多了
MTU带来的问题