IPv6 MTU 和路径 MTU 发现:避免分片问题
了解路径 MTU 发现在 IPv6 中的工作原理,为什么路由器不能对数据包进行分片,以及如何排查与 MTU 相关的连接问题。
数据包分片是那些你不注意它就不会出问题,一出问题就会导致一切崩溃的问题之一。
为什么 MTU 在 IPv6 中更重要#
IPv6 完全移除了基于路由器的分片。在 IPv4 中,如果路由器收到一个对于下一跳来说太大的数据包,它可以对其进行分片。IPv6 路由器不能这样做——它们会丢弃数据包并向源发送 ICMPv6"数据包过大"消息。
源主机负责所有分片。这个设计决定提高了路由器性能并简化了协议,但它将负担转移到了端点上,使得路径 MTU 发现(PMTUD)变得至关重要。
如果 PMTUD 失败,你的连接会神秘地挂起。TCP 握手完成,但数据传输停滞。HTTP 请求超时。SSH 会话在身份验证后冻结。这些都是典型的 MTU 黑洞症状。
IPv6 最小 MTU#
所有 IPv6 链路必须支持至少 1280 字节。这是最小 MTU,不可协商。如果你的链路无法处理 1280 字节的数据包,它就不符合 IPv6 标准。
大多数网络使用 1500 字节(标准以太网 MTU),这为 40 字节的 IPv6 头部加上 1460 字节的有效载荷提供了空间。这相当于 IPv4 的典型 TCP MSS 1460。
隧道和封装协议会减少可用的 MTU。如果你运行 IPv6-in-IPv4(6in4)、6to4 或 ISATAP,你会因为外部头部而损失字节。VPN、IPsec、GRE 和 VXLAN 都会消耗 MTU 空间。
你会遇到的常见 MTU 值:
- 1500:标准以太网
- 1480:PPPoE(PPP 开销损失 8 字节)
- 1460:6in4 隧道(IPv4 头部损失 20 字节)
- 1420:PPPoE 上的 6in4
- 1280:最小 IPv6 MTU,回退值
- 9000:巨型帧(数据中心网络)
路径 MTU 发现的工作原理#
PMTUD 确定可以在源和目标之间遍历路径而不进行分片的最大数据包大小。
过程很简单:
- 主机使用当前 MTU 发送数据包
- 如果路径上的路由器具有较小的 MTU,它会丢弃数据包
- 路由器向源发送 ICMPv6 类型 2"数据包过大"消息
- 消息包含下一跳的 MTU
- 主机减小其路径 MTU 并重新发送
- 过程重复,直到数据包遍历整个路径
"数据包过大"消息(ICMPv6 类型 2,代码 0)在消息有效载荷中包含 MTU 值。这告诉源数据包可以有多大,而不仅仅是它们太大了。
ICMPv6 消息如下所示:
ICMPv6 Packet Too Big:
Type: 2
Code: 0
MTU: 1280
[Original packet headers up to minimum MTU]主机维护一个路径 MTU 缓存,其条目通常在 10 分钟后过期(RFC 8201 建议)。如果网络路径发生变化,过时的缓存条目可能会导致问题,直到它们过期。
PMTUD 黑洞#
当 ICMPv6 类型 2 消息被阻止时,系统会崩溃。这会创建"PMTUD 黑洞",数据包会悄无声息地消失。
常见原因:
过度热心的防火墙:管理员有时会阻止所有 ICMP 流量,将其视为安全风险。这是错误的。ICMPv6 是 IPv6 操作的组成部分,不是像 ping 这样的可选诊断协议。
状态检查问题:一些防火墙不能正确地将 ICMPv6 错误消息与现有连接关联,将它们作为未经请求的流量丢弃。
速率限制:安全设备可能会限制 ICMPv6 的速率,在繁忙期间丢弃合法的 PMTUD 消息。
NAT64 网关:如果网关不能正确转换 ICMP 消息,IPv6 和 IPv4 之间的转换可能会丢失 PMTUD 信息。
PMTUD 黑洞的症状:
- TCP 连接建立(SYN、SYN-ACK、ACK 完成)
- 小数据包工作(DNS 查询、SSH 登录横幅)
- 大数据包失败(文件传输、带正文的 HTTP POST、身份验证后的 SSH 交互会话)
- 没有错误消息,只有超时
- 问题看起来是间歇性的(取决于数据包大小)
诊断 MTU 问题#
从 ping 开始。发送特定大小的数据包以测试路径 MTU:
# 使用 1280 字节测试(最小 MTU)
ping6 -M do -s 1232 2001:db8::1
# 使用 1500 字节测试(标准以太网)
ping6 -M do -s 1452 2001:db8::1
# 使用 1280 字节有效载荷测试
ping6 -c 5 -s 1280 2001:db8::1-M do 标志禁止分片(不分片)。-s 参数指定有效载荷大小——为 ICMPv6 头部添加 8 字节,为 IPv6 头部添加 40 字节以获得总数据包大小。
如果 1452 字节失败但 1232 成功,你的路径 MTU 在 1280 和 1500 之间。二分查找以找到确切值:
# 尝试 1400
ping6 -M do -s 1352 2001:db8::1
# 尝试 1450
ping6 -M do -s 1402 2001:db8::1使用 traceroute 识别 MTU 更改的位置:
traceroute6 -n 2001:db8::1然后单独测试每个跳的 MTU。大数据包开始失败的跳是你的问题点。
对于 TCP 连接,观察实际行为:
# 捕获数据包
tcpdump -i eth0 -n 'ip6 and (icmp6 or tcp)'寻找:
- 初始握手后的 TCP 重传
- ICMPv6 类型 2 消息(如果 PMTUD 正常工作应该出现)
- 缺少 ICMPv6 类型 2(表示阻塞或黑洞)
现代工具可以自动化这一点。MTR 将 traceroute 与数据包大小测试相结合:
# 使用 1400 字节数据包测试
mtr -6 -s 1400 2001:db8::1TCP MSS 限制#
MSS(最大段大小)是 TCP 选项,它告诉另一端每个段可以发送多少数据。MSS = MTU - IP 头部 - TCP 头部。
对于 IPv6:MSS = MTU - 40(IPv6)- 20(TCP)= MTU - 60
使用标准 1500 字节 MTU:MSS = 1440
MSS 限制强制 TCP 连接使用较低的 MSS 值,在不依赖 PMTUD 的情况下解决 MTU 问题。这在终止隧道或 PPPoE 连接的路由器上很常见。
在 Linux 上配置 MSS 限制:
# 将 IPv6 的 MSS 限制为 1280
ip6tables -t mangle -A FORWARD \
-p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --set-mss 1220值 1220 考虑了 1280 MTU 减去 60 字节的头部。
对于 1492 MTU 的 PPPoE:
ip6tables -t mangle -A FORWARD \
-p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --set-mss 1432MSS 限制仅影响 TCP。UDP、SCTP 和其他协议仍然依赖 PMTUD 或应用层分片。
防火墙配置#
你的防火墙必须允许 ICMPv6 类型 2 消息才能使 PMTUD 正常工作。这对于生产 IPv6 网络来说是不可协商的。
IPv6 操作所需的最小 ICMPv6 类型:
- 类型 1:目标不可达
- 类型 2:数据包过大(PMTUD)
- 类型 3:时间超过
- 类型 4:参数问题
- 类型 133-137:邻居发现协议
PMTUD 的 iptables 规则:
# 允许 ICMPv6 数据包过大
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 2 -j ACCEPT
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type 2 -j ACCEPT
ip6tables -A FORWARD -p ipv6-icmp --icmpv6-type 2 -j ACCEPT更好的方法——允许所有必要的 ICMPv6:
# 允许已建立的 ICMPv6
ip6tables -A INPUT -p ipv6-icmp -m state --state ESTABLISHED,RELATED -j ACCEPT
# 允许必要的 ICMPv6 类型
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 1 -j ACCEPT # Destination Unreachable
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 2 -j ACCEPT # Packet Too Big
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 3 -j ACCEPT # Time Exceeded
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 4 -j ACCEPT # Parameter Problem
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 128 -j ACCEPT # Echo Request
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 129 -j ACCEPT # Echo Reply
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 133 -j ACCEPT # Router Solicitation
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 134 -j ACCEPT # Router Advertisement
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 135 -j ACCEPT # Neighbor Solicitation
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 136 -j ACCEPT # Neighbor Advertisement速率限制是可以接受的,但要设置宽松的限制:
# 允许带速率限制的 ICMPv6
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 2 \
-m limit --limit 10/sec --limit-burst 20 -j ACCEPT永远不要完全阻止 ICMPv6。这不是安全风险——这是协议要求。
隧道 MTU 注意事项#
隧道通过封装头部的开销减少有效 MTU。
常见隧道类型和开销:
| 隧道类型 | 开销 | 有效 MTU(来自 1500) |
|---|---|---|
| 6in4 | 20 字节 | 1480 |
| 6to4 | 20 字节 | 1480 |
| 6rd | 20 字节 | 1480 |
| ISATAP | 20 字节 | 1480 |
| GRE | 24 字节 | 1476 |
| IPsec | 50-70 字节 | 1430-1450 |
| WireGuard | 60 字节 | 1420 |
| OpenVPN | 40-80 字节 | 1420-1460 |
明确配置隧道 MTU 以避免问题:
# 6in4 隧道
ip tunnel add tun6in4 mode sit remote 203.0.113.1 local 198.51.100.1
ip link set tun6in4 mtu 1480
ip link set tun6in4 up对于 WireGuard:
[Interface]
MTU = 1420一些隧道协议支持 MTU 发现,但显式配置更可靠。
巨型帧和数据中心#
数据中心网络通常使用 9000 字节 MTU(巨型帧)来提高批量传输的吞吐量。
在接口上启用巨型帧:
ip link set eth0 mtu 9000确保路径中的所有交换机和路由器都支持巨型帧。一个具有 1500 字节 MTU 的设备将成为瓶颈。
PMTUD 仍然适用。如果数据包离开你的巨型帧网络前往互联网,它必须减少到 1500 或更少。
测试和验证#
验证主机的 MTU 配置:
ip -6 link show查找每个接口上的 MTU 值。
检查当前路径 MTU 缓存:
ip -6 route get 2001:db8::1输出显示该目标的缓存 MTU。
使用不同的数据包大小测试端到端连接:
for size in 1232 1352 1402 1452; do
echo "Testing $size bytes:"
ping6 -M do -s $size -c 3 2001:db8::1
done使用 netcat 测试 TCP MSS 协商:
# 服务器
nc -6 -l 8080
# 客户端
nc -6 2001:db8::1 8080使用 tcpdump 捕获数据包并验证 SYN 数据包中的 MSS 值。
常见场景和修复#
问题:网页加载缓慢,图像失败 原因:由于防火墙阻止 ICMPv6 类型 2 导致的 PMTUD 黑洞 修复:配置防火墙以允许 ICMPv6 类型 2
问题:SSH 连接但登录后冻结 原因:MTU 太大,PMTUD 不工作 修复:减小客户端接口上的 MTU 或在路由器上启用 MSS 限制
问题:VPN 适用于小传输,大文件失败 原因:隧道 MTU 配置不正确 修复:减小隧道 MTU 以考虑封装开销
问题:IPv6 在本地网络上工作,通过互联网失败 原因:上游路由器具有较小的 MTU,没有正确通告 修复:联系 ISP 或将本地 MTU 减小到 1280(最小值)
问题:某些目标工作,其他失败 原因:路径特定的 MTU 问题 修复:使用 ping 测试以识别工作的 MTU,相应地配置接口
最佳实践#
- 始终在防火墙中允许 ICMPv6 类型 2
- 明确配置隧道 MTU,而不是依赖自动检测
- 使用最小 MTU(1280)测试以确保基线连接
- 在隧道端点和 PPPoE 连接上使用 MSS 限制
- 在故障排除期间使用数据包捕获监控 PMTUD 失败
- 记录每一层的网络 MTU(物理、隧道、应用)
- 在有疑问时设置保守的 MTU 值(1280 始终有效)
相关文章#
- ICMPv6 详解 - 了解 IPv6 的控制协议
- IPv6 防火墙配置 - 在不破坏功能的情况下保护 IPv6
- IPv6 故障排除 - 调试常见的 IPv6 连接问题