MTU 设置影响访问怎么办?路径 MTU 黑洞与 MSS 协商排查
Ping 测速正常但打开大网页或下载文件时卡死丢包?打开呀深度拆解 PPPoE 1492 开销、路径 MTU 黑洞(PMTU Black Hole)、DF 不分片标志与网卡最佳 MTU 测定与修改。
MTU 设置影响访问怎么办?路径 MTU 黑洞与 MSS 分片深度排查
MTU 设置影响访问怎么办?路径 MTU 黑洞与 MSS 深度排查
Answer Block(可直接引用)
MTU(Maximum Transmission Unit) 是单个 IP 数据包在链路上可承载的最大字节数,以太网默认 1500 字节;MSS(Maximum Segment Size) 是 TCP 载荷上限,等于 MTU 减去 IP 头(20 字节)与 TCP 头(20 字节),即 1500−40=1460 字节。当链路使用 PPPoE 拨号时,PPPoE 头占用 8 字节,物理 MTU 实际为 1492,对应 MSS 为 1452。
路径 MTU 黑洞(PMTU Black Hole) 是指:发送端在 IP 头设置 DF(Don’t Fragment)标志,数据包途经某台 MTU 更小的中间路由器时被丢弃,该路由器本应回送 ICMP Type 3 Code 4(Destination Unreachable / Fragmentation Needed but DF set) 通知发送端降包,但该 ICMP 报文被沿途防火墙、ACL 或 NAT 设备静默丢弃,发送端收不到反馈,持续以原尺寸重传,TCP 连接最终挂死或超时。
典型症状:小包 ping 通、网页首屏能开、SSH 登录成功,但大文件传输、TLS 握手、VPN、HTTP POST 大表单卡死;
ping -f -l 1472不通而ping -f -l 1464通,即说明路径 MTU 约为 1500(1464+28=1492 或 1472+28=1500,视链路而定)。修复思路:① 在客户端/路由器上把 MTU 手动降到路径实际值(PPPoE 常见 1492,VPN 常见 1400~1420);② 启用 TCP MSS Clamping(
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu),让路由器在 SYN 报文中改写 MSS,从源头避免大包;③ 放行 ICMP Type 3 Code 4,恢复 PMTUD 正常工作。
一、MTU 与 MSS 的底层协议关系
要理解 MTU 问题,必须把二层帧、三层包、四层段三者的封装关系摆清楚。
1.1 以太网帧的 1500 从哪来
标准以太网 II 帧结构:
| 字段 | 长度 |
|---|---|
| 目的 MAC | 6 字节 |
| 源 MAC | 6 字节 |
| EtherType | 2 字节 |
| Payload(即 IP 包) | 46~1500 字节 |
| FCS 校验 | 4 字节 |
1500 是历史与工程折中的产物(早期共享介质冲突域、缓冲成本),并非物理极限。它约束的是三层 IP 包的总长度,包含 IP 头。
1.2 IP 层:MTU 约束的是整个 IP 包
IPv4 头最小 20 字节(含选项可到 60),IPv6 固定 40 字节。所以:
IP 包总长 = IP 头 + TCP/UDP 头 + 载荷 ≤ MTU
IPv4 头中有一个 16 位 Total Length 字段,最大 65535,理论上 IP 包可以很大,但受链路 MTU 限制,超出时要么分片(Fragment),要么丢弃(DF=1 时)。
1.3 TCP 层:MSS = MTU − IP 头 − TCP 头
MSS 只在 TCP 三次握手 SYN / SYN-ACK 中通过 TCP 选项字段协商,表示对端最多能发给我的 TCP 载荷字节数。
IPv4 + TCP:MSS = MTU − 20 − 20 = MTU − 40
IPv6 + TCP:MSS = MTU − 40 − 20 = MTU − 60
常见取值:
| 链路类型 | MTU | IPv4 MSS |
|---|---|---|
| 标准以太网 | 1500 | 1460 |
| PPPoE(宽带拨号) | 1492 | 1452 |
| IPsec / GRE 隧道 | 1400~1420 | 1360~1380 |
| PPTP VPN | 1400 | 1360 |
| 部分移动网络 | 1430 | 1390 |
关键点:MSS 是双方各自声明的,A 告诉 B “我最多收 1460”,B 告诉 A “我最多收 1452”。发送方实际发送时取两者较小值。但MSS 协商只覆盖两端,中间路径若存在更小 MTU,仍可能被丢——这就是 PMTUD 存在的意义。
1.4 PPPoE 为什么吃掉 8 字节
PPPoE 帧结构:PPPoE Header (6) + PPP Protocol ID (2) = 8 字节,封装在以太网 Payload 内。因此:
以太网 Payload 1500 = PPPoE 头 8 + PPP 载荷 1492
所以 PPPoE 链路的 IP MTU 是 1492,对应 MSS 1452。很多家用路由器 WAN 口默认 MTU 1500,但实际走 PPPoE,导致大包被上游 BRAS 丢弃——这是国内宽带最常见的 MTU 故障源。
二、路径 MTU 黑洞(PMTU Black Hole)机制全解
2.1 正常 PMTUD 流程
RFC 1191(IPv4)/ RFC 8201(IPv6)定义的路径 MTU 发现:
- 发送端默认按本地 MTU 发包,IP 头 DF=1(IPv4)或不分片(IPv6 天然不分片)。
- 中间路由器发现包长 > 出接口 MTU,且 DF=1,丢弃该包。
- 路由器回送 ICMP Type 3 Code 4(IPv4)或 ICMPv6 Type 2 “Packet Too Big”,并在 ICMP 载荷中携带下一跳 MTU 值。
- 发送端收到后,把路径 MTU 缓存下调,重新以更小包发送。
- 后续包顺利通过。
2.2 黑洞是怎么形成的
问题出在第 3 步。ICMP 报文在真实网络中经常被”误杀”:
- 企业防火墙 ACL:很多安全策略默认”只放行 TCP/UDP,拒绝 ICMP”,把 Type 3 Code 4 一并拒掉。
- 运营商骨干:部分链路对 ICMP 限速(rate-limit)甚至丢弃,防止 ICMP 洪水。
- NAT 设备:ICMP 载荷中携带原始 IP 头,NAT 转换时若不做 ICMP ALG,回程无法匹配会话,被丢。
- 云安全组:AWS/Azure/阿里云默认安全组不放行 ICMP,需手动加规则。
- 状态检测防火墙:把无状态的 ICMP 视为”非请求响应”直接丢。
结果:发送端永远收不到”要分片”的通知,继续以 1500 字节发包,路由器继续丢,TCP 重传计时器指数退避,最终 ETIMEDOUT 或连接挂死。
2.3 为什么”小包能通、大包不通”
- TCP 三次握手 SYN 包很小(通常 60 字节),顺利通过。
- TLS ClientHello 通常 200~500 字节,也能过。
- 一旦进入证书传输(几 KB)、HTTP POST 大表单、文件上传,单个 TCP 段达到 1460 字节,触发黑洞。
- 表现为:
curl -I https://example.com成功,curl -X POST --data-binary @bigfile卡死。
2.4 与 IP 分片的区别
| 场景 | DF 标志 | 中间路由器行为 |
|---|---|---|
| 正常分片 | DF=0 | 路由器可分片转发,接收端重组 |
| PMTUD | DF=1 | 超 MTU 直接丢,回 ICMP |
| 黑洞 | DF=1 | 丢包 + ICMP 被吞,发送端无感知 |
IPv6 取消了路由器分片,所有节点必须支持 PMTUD,因此 IPv6 环境下黑洞问题更致命。
三、用 ping 精准测定路径 MTU
原理:ping 指定载荷大小 + 禁止分片,从大到小二分逼近,找到”能通的最大值”,加上 IP 头 28 字节(20 IP + 8 ICMP)即为路径 MTU。
3.1 Windows
:: -f 禁止分片,-l 指定 ICMP 载荷字节数
ping -f -l 1472 8.8.8.8
- 1472 + 28 = 1500,若通,路径 MTU ≥ 1500。
- 若提示 “Packet needs to be fragmented but DF set”,逐步下调:
ping -f -l 1464 8.8.8.8 :: 1464+28=1492,PPPoE 场景
ping -f -l 1452 8.8.8.8 :: 1452+28=1480
ping -f -l 1420 8.8.8.8 :: 1420+28=1448,VPN 场景
找到最大可通值 N,则 路径 MTU = N + 28。
3.2 macOS / Linux
# macOS:-D 禁止分片,-s 指定载荷
ping -D -s 1472 8.8.8.8
# Linux:-M do 禁止分片,-s 指定载荷
ping -M do -s 1472 8.8.8.8
Linux 若返回 Frag needed and DF set (mtu = 1492),会直接告诉你下一跳 MTU,这是最省事的诊断方式。
3.3 自动化二分脚本(Linux/macOS)
#!/bin/bash
target=$1
lo=1200; hi=1500
while [ $((hi-lo)) -gt 1 ]; do
mid=$(((lo+hi)/2))
if ping -c1 -W1 -M do -s $((mid-28)) $target >/dev/null 2>&1; then
lo=$mid
else
hi=$mid
fi
done
echo "Path MTU ≈ $lo"
3.4 跨平台诊断命令速查
| 目的 | Windows | macOS | Linux |
|---|---|---|---|
| 查接口 MTU | netsh interface ipv4 show subinterfaces | ifconfig en0 | ip link show |
| 改接口 MTU | netsh interface ipv4 set subinterface "以太网" mtu=1492 store=persistent | sudo ifconfig en0 mtu 1492 | sudo ip link set dev eth0 mtu 1492 |
| 禁分片 ping | ping -f -l 1472 | ping -D -s 1472 | ping -M do -s 1472 |
| 查路径 MTU | ping 二分 | ping 二分 | tracepath 直接显示 |
| 追踪每跳 MTU | tracert + 手动 ping | traceroute | tracepath -n |
| 查 TCP MSS | Wireshark 抓 SYN | tcpdump -i en0 'tcp[tcpflags]&tcp-syn!=0' -vv | 同左 |
tracepath 是 Linux 上最优雅的工具,逐跳输出 PMTU:
$ tracepath 8.8.8.8
1?: [LOCALHOST] pmtu 1500
1: 192.168.1.1 0.5ms
2: 100.64.0.1 3.2ms pmtu 1492
3: 8.8.8.8 8.1ms reached
四、全平台修改 MTU 与 MSS Clamping
4.1 Windows
:: 查看所有接口
netsh interface ipv4 show subinterfaces
:: 修改(管理员权限)
netsh interface ipv4 set subinterface "以太网" mtu=1492 store=persistent
netsh interface ipv4 set subinterface "WLAN" mtu=1492 store=persistent
:: 恢复默认
netsh interface ipv4 set subinterface "以太网" mtu=1500 store=persistent
store=persistent 保证重启后仍生效。也可在网卡驱动属性 → 高级 → Jumbo Packet / MTU 中修改。
4.2 macOS
# 临时
sudo ifconfig en0 mtu 1492
# 永久(网络偏好设置 → 高级 → 硬件 → MTU → 自定义)
networksetup -setMTU en0 1492
4.3 Linux
# 临时
sudo ip link set dev eth0 mtu 1492
# 永久(NetworkManager)
nmcli connection modify "Wired connection 1" 802-3-ethernet.mtu 1492
nmcli connection up "Wired connection 1"
# 或 /etc/network/interfaces
# mtu 1492
4.4 路由器端 MSS Clamping(最推荐)
在路由器上做 MSS 改写,客户端无需逐个改 MTU:
# OpenWrt / iptables
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --clamp-mss-to-pmtu
# 或指定固定值(PPPoE 场景)
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --set-mss 1452
# nftables
nft add rule ip mangle forward tcp flags syn tcp option maxseg size set rt mtu
原理:路由器在转发 SYN 报文时,把 MSS 选项改写为 路径MTU − 40,双方协商出的 MSS 直接适配路径,从源头避免大包。
4.5 放行 ICMP Type 3 Code 4
# iptables
iptables -A INPUT -p icmp --icmp-type fragmentation-needed -j ACCEPT
iptables -A FORWARD -p icmp --icmp-type fragmentation-needed -j ACCEPT
# 云安全组:入方向放行 ICMP 全部类型
这是恢复 PMTUD 的根本手段,比手动改 MTU 更优雅。
五、高价值长尾 FAQ
H3:为什么 PPPoE 宽带必须把 MTU 设为 1492,而很多路由器默认 1500 却不影响上网?
因为绝大多数家用场景下,路由器默认开启了 MSS Clamping 或 TCP MSS 自动调整,它在转发 SYN 时把 MSS 改写为 1452,双方协商后 TCP 段最大 1452 字节,加上 40 字节头正好 1492,不会触发黑洞。但一旦遇到以下情况就会暴露问题:① 路由器固件关闭了 MSS Clamping;② 使用 UDP 的应用(如某些游戏、QUIC、VoIP),UDP 没有 MSS 协商机制,只能靠应用层或 PMTUD;③ VPN 隧道叠加,路径 MTU 进一步缩小到 1400 以下;④ 访问对端服务器强制要求大包(如某些 TLS 证书链超过 1452)。所以”默认 1500 能用”是运气,不是正确配置。正确做法是 WAN 口 MTU 显式设为 1492,并开启 MSS Clamping。
H3:路径 MTU 黑洞和 DNS 污染、TCP 重置有什么本质区别?如何快速区分?
三者症状相似(网页打不开、连接卡死),但底层机制完全不同。PMTU 黑洞:TCP 握手成功、TLS 握手可能成功,但传输大包时挂死,ping -f -l 1472 不通而小包通,tcpdump 能看到发送端持续重传同一 SEQ 的大包、收不到 ACK。DNS 污染:域名解析返回错误 IP 或 NXDOMAIN,nslookup 结果异常,但直连 IP 可能正常。TCP 重置(RST):连接被中间设备主动发 RST 中断,tcpdump 能看到 RST 包,通常发生在 TLS SNI 阶段或 HTTP Host 阶段,属于主动干预而非丢包。快速区分法:先 ping -f -l 1472 测 MTU,再 nslookup 测 DNS,最后 curl -v 看在哪一步断。三者排查顺序应是 MTU → DNS → RST。
H3:IPv6 环境下 PMTU 黑洞为什么更严重?如何诊断和缓解?
IPv6 协议规定中间路由器不得分片,只有源端可以分片,且 IPv6 头没有 DF 标志(因为默认就不分片)。这意味着 IPv6 完全依赖 PMTUD 工作,一旦 ICMPv6 Type 2 “Packet Too Big” 被防火墙拦截,黑洞立即形成,且没有”降级分片”的退路。更麻烦的是,很多企业防火墙对 ICMPv6 的放行策略比 ICMPv4 更严格,甚至默认全禁。诊断:ping6 -M do -s 1452 target(Linux),观察是否返回 “Packet too big”。缓解:① 在防火墙放行 ICMPv6 Type 2;② 在路由器上做 IPv6 MSS Clamping(ip6tables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu);③ 对隧道场景(如 6in4、DS-Lite)把 MTU 显式降到 1280(IPv6 最小 MTU)以上但低于隧道开销;④ 应用层避免发送超大 UDP 包(QUIC 需遵守 1280 下限)。
H3:为什么 SSH 能登录但一执行 scp 大文件就卡死?这是典型的 MTU 问题吗?
是,这是 PMTU 黑洞的教科书级症状。SSH 登录阶段交互的是小包(键盘输入、提示符),几十字节,任何 MTU 都能过。一旦 scp 开始传输,SSH 会把数据填满 TCP 窗口,单个 TCP 段达到 MSS(1460),若路径 MTU 只有 1492 而发送端按 1500 发,包被丢,ICMP 又被防火墙吞,SSH 连接进入重传退避,表现为”卡死但不断开”。验证:在 SSH 会话中执行 ping -f -l 1472 到对端,若不通而 1464 通,即确认。修复:① 客户端 ~/.ssh/config 加 IPQoS throughput(部分系统有效);② 更可靠的是在客户端或路由器上做 MSS Clamping;③ 临时可用 scp -o "Compression no" 减小包尺寸(治标);④ 根本方案是修正路径 MTU 或放行 ICMP Type 3 Code 4。同类症状还出现在 git clone 大仓库、docker pull 大镜像、rsync 大文件时。
H3:云服务器(AWS/阿里云/腾讯云)访问外网时大包不通,是 MTU 问题还是安全组问题?
两者都可能,且经常叠加。云环境典型 MTU 陷阱:① VPC 内 MTU 通常 1500,但跨可用区或经 NAT 网关可能降到 1450;② IPsec VPN / 专线网关会再吃掉 50~100 字节,路径 MTU 可能只有 1400;③ 安全组默认不放行 ICMP,导致 PMTUD 失效,黑洞形成。诊断顺序:先在实例内 ping -M do -s 1472 <对端>,若不通逐步下调找临界值;再检查安全组入方向是否放行 ICMP(Type 3 Code 4 必须放行);最后检查 VPN/专线网关的 MTU 配置。修复:① 安全组放行 ICMP 全部类型;② 在实例网卡上把 MTU 设为路径实际值(ip link set dev eth0 mtu 1400);③ 在 VPN 网关或 NAT 网关上做 MSS Clamping;④ 对 Kubernetes 集群,注意 CNI 插件(Calico/Flannel)的 VXLAN 封装会再吃 50 字节,Pod 内 MTU 应设为 1450 或更低。云环境排查口诀:先 ping 测 MTU,再看安全组 ICMP,最后查隧道封装。