预分片是根据Tunnel RT Cache PMTU(在没有PMTUD的情况下,从Tunnel Interface MTU继承),而不是Tunnel SA MTU。
6.2/6.4/7.0版本中,Tunnel SA MTU的计算都是正确、精准的。在物理口MTU为默认1500时:
Tunnel Interface MTU总会根据Tunnel SA MTU变化(相等),所以,在6.2版本中,预分片在任何算法组合、non-NAT-T/NAT-T环境组合下,都可以正确避免FortiGate生成超过FortiGate物理口MTU的ESP/UESP报文而被物理口分片。Tunnel SA MTU计算正确,但Tunnel Interface MTU被固定为1438,这导致在以下算法下,预分片后,FortiGate仍会生成超过物理口MTU的ESP/UESP报文而被物理口分片。
Tunnel SA MTU计算正确,但Tunnel Interface MTU被固定为1420,这导致在以下算法下,预分片后,FortiGate仍会生成超过物理口MTU的ESP/UESP报文而被物理口分片。
实验证明,从6.4开始,Tunnel Interface MTU已经不再自动根据算法/NAT-T情况计算,在物理口MTU固定的情况下,被固定为一个值(除非手动Override Tunnel MTU),只是这个固定值在以上算法组合中大于Tunnel SA MTU,产生ESP分片问题。
<aside> 💡 为什么要改?未找到Mantis,怀疑和Hub-Spoke模式下,Spoke有Shortcut的情况下,OSPF协商Flapping有关,Mantis ID 599667,待继续研究。 In 6.2, The root cause of the OSPF flapping is because that th mtu of spoke2 interface is kept changing from 1438 and 1422. The parent tunnel(spoke2)'s mtu is 1438 as there is no NAT between hub and spoke2. The mtu of child tunnel(spoke2_0) between spoke1 and spoke2 is 1422 as there is NAT on spoke1. With net-device disabled, the child(spoke2_0) will set interface's mtu to 1422(in function ipsec_att_set_mtu). However, the parent(spoke2) will try to set it to 1438. The solution is to search the smallest mtu of all children and spoke itself and set it as the interface's mtu when net-device disabled.
</aside>
net-device开启的情况:
也就是说,在Tunnel SA MTU计算正确的前提下,开启预分片,如果不想让ESP/UDP-ESP报文从FortiGate物理口发出时被分片,Tunnel Interface MTU可以≤ Tunnel SA MTU,但不能>Tunnel SA MTU。
在6.4/7.0版本中,问题的解决办法是Override Tunnel接口的MTU,改为和Tunnel SA MTU一致或更小,请参考Override MTU of Tunnel Interface。
FortiGate在处理分片包时,并不是线性的将分片包直接转发,而是先将分片重组(在等待所有分片到达的timeout时间内)后(需要等待全部分片到达后做策略匹配),再根据原始分片中的最大长度和出接口MTU两者中的最小值进行再分片(如果出接口的MTU大于等于原始分片的最大长度,则不对分片作处理,如果出接口的MTU小于原始分片的最大长度,则按照出接口的MTU进行分片处理)。
<aside> 💡 参考Mantis ID 0218818,Refer to IPv6 refragmentation in FortiOS to refrag assembled IPv4 packet according to the minimum of the max len of the original fragments and the egress interface mtu.
</aside>