背景
割接旧专线流量到带有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引发的故障。