通常,只要主机认为数据包由于太大而被丢弃,就会发生路径最大传输单元发现 (PMTUD)。
这可能是为了响应需要 ICMP 分段(类型 3,代码 4)的响应,明确指示数据包已被丢弃。在典型的实践中,所有 IPv4 数据包都设置了“不分段”(DF) 标志,因此任何超过 MTU 的数据包都将引发此类响应。IPv6 根本不支持分片。
一些路由器或主机防火墙经常丢弃所有 ICMP,因为幼稚的管理员认为 ICMP 是一种安全风险。或者,某些链路聚合方案可能会中断 ICMP 交付。RFC4821 中提出了一种不依赖于 ICMP 的发现 MTU 的替代机制。
tracepath
是我最喜欢的用于探测 MTU 的 Linux 工具。以下是 LAN 上具有 9001 MTU 的主机的示例,但它必须通过 IPsec VPN 才能到达 10.33.32.157:
$ tracepath -n 10.33.32.157
1?: [LOCALHOST] pmtu 9001
1: 10.1.22.1 0.122ms pmtu 1500
1: 169.254.3.1 1.343ms pmtu 1422
1: 10.255.254.61 23.790ms
2: no reply
^C [this host won't return an ICMP port unreachable, so tracepath won't terminate]
可以通过以下方式观察 ICMP 错误tcpdump
:
$ sudo tcpdump -p -ni eth0 'icmp and icmp[0] == 3 and icmp[1] == 4'
14:46:57.313690 IP 10.1.22.1 > 10.1.22.194: ICMP 10.33.32.157 unreachable - need to frag (mtu 1500), length 36
14:46:57.315080 IP 169.254.3.1 > 10.1.22.194: ICMP 10.33.32.157 unreachable - need to frag (mtu 1422), length 556
MTU 发现被缓存。在 Linux 中,这可以被观察和刷新ip
(注意自 Linux 3.6 以来的变化):
$ ip route get 10.33.32.157
10.33.32.157 via 10.1.22.1 dev eth0 src 10.1.22.194
cache expires 591sec mtu 1422
$ sudo ip route flush cache
$ ip route get 10.33.32.157
10.33.32.157 via 10.1.22.1 dev eth0 src 10.1.22.194
cache
对于 TCP,作为连接设置的一部分,可以避免超过 MTU。每端发送的 SYN 中包括最大段大小 (MSS)。TCP头(20个字节不包括选项)和IP头(20个字节)意味着MSS和MTU之间相差40个字节。
这是传输大文件时这两个主机之间的连接设置示例scp
:
$ sudo tcpdump -p -ni eth0 'host 10.33.32.157 and tcp[13]&2 == 2'
IP 10.1.22.194.45853 > 10.33.32.157.22: Flags [S], seq 634040018, win 26883, options [mss 8961,sackOK,TS val 10952240 ecr 0,nop,wscale 7], length 0
IP 10.33.32.157.22 > 10.1.22.194.45853: Flags [S.], seq 1371736848, ack 634040019, win 26847, options [mss 1379,sackOK,TS val 10824267 ecr 10952240,nop,wscale 7], length 0
在第一个数据包中,本地主机建议的 MSS 为 8961。这是配置的 9001 MTU,少 40 个字节。返回的 SYN/ACK 的 MSS 为 1379,这意味着 MTU 为 1419。我碰巧知道在这个网络中远程主机也发送了 8961,但该值已被路由器修改,因为它知道该路径包括互联网路径( MTU 1500) 来自 IPsec 隧道的开销。该路由器还将我们发送的 8961 的 MSS 修改为在另一台主机上显示为 1419。这称为MSS 钳位。
所以从某种意义上说,PMTUD 一直在发生。在实践中,如果 MSS 限制到位并且所有流量都通过 TCP 发生,或者如果没有任何路由器的 MTU 小于端点上配置的 MTU,它实际上可能永远不会发生。即使没有 MSS 限制,它也可能很少发生,当缓存过期时。