NetCalcLab

MTU、MSS 与封装开销

隧道究竟给真实数据留了多少空间:MTU 与 MSS 背后的首部算术、路径 MTU 发现为何会静默失败,以及如何为 GRE、VXLAN 与 GTP-U 确定 MSS。

MTU 与 MSS 不是一回事

很容易把 MTU 和 MSS 当成同一个数字的两种叫法。它们不是,而这种混淆造成了相当大一部分隧道性能问题。MTU 是链路的属性:这条链路能承载的最大帧。标准以太网是 1500 字节,这也是超大 ping 过不了一台配置不当的网络设备的原因。

MSS 是 TCP 连接的属性:任一端愿意放进单个报文段的最大载荷。它不是链路设置,也不是由 MTU 协商出来的 —— 每一端通告自己能够接收的 MSS,并根据自己知道的 MTU 减去相应首部来得出这个值。

普通以太网路径上由 MTU 推出 MSS
MSS = MTU − IP 首部 − TCP 首部

IPv4:1500 − 20 − 20 = 1460 字节
IPv6:1500 − 40 − 20 = 1440 字节

1460 这个数字太常见了,值得直接记住。如果你在一条正常工作的连接上看到远低于它的值,说明有东西在加首部 —— 而这正是本页要讲的全部内容。

每一层首部都在吃掉载荷

MTU 是在最外层测量的,因此链路帧与应用数据之间的每一个首部字节,都会减少能装下的数据量。普通路径上是 1500 字节里的 40 字节开销,约 2.7%。一旦加上隧道,这个数字会迅速攀升。

最常叠加的几层及其首部大小
层基础大小标准说明
Ethernet II14 BIEEE 802.36 + 6 + 2;4 字节 FCS 通常被网卡剥掉
802.1Q VLAN 标签+4 BIEEE 802.1Q一层标签;QinQ 再加 4 字节
IPv420 BRFC 791带选项时首部最多可到 60 字节
IPv640 BRFC 8200固定长度;可选数据走扩展首部
TCP20 BRFC 9293时间戳与 SACK 通常再加 12 字节
UDP8 BRFC 768固定长度
GRE4 BRFC 2784校验和、key、sequence 各加 4 字节
VXLAN8 BRFC 7348承载在 UDP 之内;通常叠在 50 字节的开销之上
GTP-U8 B3GPP TS 29.281E、S、PN 标志各加 4 字节
PPPoE8 BRFC 25166 字节 PPPoE + 2 字节 PPP 协议
IPsec ESP(隧道模式)约 50–73 BRFC 4303SPI + 序列号 + IV + 填充 + ICV
MPLS每个标签 4 BRFC 3032典型 L3VPN 用两个标签

最后两行正是 IPsec 与 MPLS 站点经常需要下调 MTU 的原因。一个使用 AES-CBC 加 SHA-256 完整性校验的 ESP 隧道,光它自己就要加约 73 字节,还没算外层 IP 首部。

一个完整的隧道计算

以一条承载私有站点流量、跑在公网上的 GRE 隧道为例。线上跑的数据包是公网的以太网帧,私有网络的数据包是它里面的载荷。从外往里算:

GRE over IPv4 over Ethernet,外层 MTU 1500 字节

外层以太网   14 B
外层 IPv4        20 B
GRE 首部           4 B
内层 IPv4        20 B
TCP 首部         20 B
─────────────────────────
开销合计         78 B
内层 MSS    1500 − 78 = 1422 B

所以这条路径正确的 MSS 是 1422 字节,而不是 1460。使用默认 1460 的主机构造出的数据包,会比隧道能容纳的大 38 字节。如果 PMTUD 工作正常,路由器会回送一条携带更小 MTU 的 ICMP 消息,主机随之调整。而如果 ICMP 被过滤 —— 这很常见 —— 这些包会被静默丢弃,连接在每一次大于单个报文段的传输上都会卡住。

用同样的算术看 VXLAN,就明白为什么 overlay 网络常把内层 MTU 设为 1450:以太网、IPv4、UDP、VXLAN,再加内层的以太网、IPv4 与 TCP 首部,合计 14 + 20 + 8 + 8 + 14 + 20 + 20 = 104 字节,在外层 MTU 1500 下留给内层 TCP 载荷的就是 1396 字节。

路径 MTU 发现,以及它是怎么失效的

PMTUD 本应让上述事情全部自动完成。发送方把 Don't Fragment 位置 1,并按自己认为路径能支持的尺寸发包。当某台路由器发现下一跳的 MTU 更小时,它应当丢弃该包并回送一条 ICMP 消息 —— “需要分片”,并携带更小的 MTU。发送方据此减小尺寸后重试。

失效模式在于:ICMP 经常被防火墙拦截,可能是出于安全考虑有意为之,也可能是限速带来的附带损伤。当这条消息永远到不了,发送方会继续用超大包, 而每一个都被丢弃,连接看起来就是卡死。这就是 PMTUD 黑洞,它的表现有非常明确的特征:

指向 MTU 或 MSS 问题的症状
症状它暗示什么
ping 和 DNS 正常,大文件传输卡住典型的 PMTUD 黑洞 —— 小包过得去,满尺寸的包过不去
SSH 能连上,登录后卡死横幅信息装得下,密钥交换装不下
HTTPS 握手完成,页面永远加载不出来握手报文段很小,数据报文段不小
局域网正常,走隧道就失败隧道开销降低了路径 MTU,而没有人调整 MSS
时好时坏,某些目的地更严重只有部分路径的 MTU 更小,或只有部分路径过滤了 ICMP
一个方向正常,反方向卡住不对称的 PMTUD 失效 —— 两个方向要分别排查

最快的诊断方法是发一个带 Don't Fragment 的超大 ping,然后对载荷大小做二分查找,直到能通为止。在隧道上这样测出的应当就是真实的路径 MTU,可以拿它和两端所认为的值对比。

MSS 钳制,以及 PMTUD 不可靠时的选择

在不能指望 PMTUD 的地方,通常的做法是 MSS 钳制。路径上的某台路由器改写 SYN 与 SYN-ACK 报文中的 MSS 字段,这样两端会立刻使用一个装得下的值,完全不需要去发现什么。这在 PPPoE 链路上很常见:8 字节的 PPPoE 首部把有效 MTU 降到 1492,MSS 降到 1452。

MSS 钳制有几个值得了解的限制。它只影响握手经过钳制设备的那些连接,所以对于处在不在路径上的路由器后面的主机毫无作用。它也不会去改动一条已经建立的连接。而且由于它改写了两端协商一致的字段,它可能掩盖真正的配置错误,而不是修复它。

替代方案包括:在两端显式设置 MSS;把隧道的接口 MTU 调低,让算术自然成立;或者 —— 对 IPv6 而言 —— 尊重"PMTUD 是强制要求"这一点,确保 ICMPv6 类型 2 消息永远不会被过滤。

实用规则

  • 按最外层 MTU 来定 MSS,而不是按 1500。把你实际使用的首部逐个加起来。MTU / MSS 计算器会逐层完成这个算术。
  • 绝不要整体屏蔽 ICMP。如果必须过滤,至少要放行入方向的 fragmentation-needed(类型 3、代码 4)—— 屏蔽它会让所有终结在你身后的路径的 PMTUD 全部失效。对 IPv6 则要放行 Packet Too Big(类型 2)。
  • 记住 1460 只对普通 IPv4 以太网路径成立。IPv6 是 1440,PPPoE 是 1452,任何带隧道的路径都还要更小。
  • 隧道的实际代价往往高于首部算术的估算。GRE over IPsec 叠起来可以吃掉一百多字节,把 1500 字节的路径压到 MSS 接近 1330。
  • 两个方向都要检查。不对称路由意味着回程路径的 MTU 可能不同,而 MSS 是按方向分别通告的。

按路径类型查 MSS

常见路径配置下主机应当使用的 MSS。除特别说明外,均基于 1500 字节的以太网 MTU。

各封装方式对应的正确 MSS
路径开销MSS(IPv4)MSS(IPv6)
以太网 + IPv4/IPv6 + TCP40 B / 60 B14601440
以太网 + TCP 选项(12 B)52 B / 72 B14481428
PPPoE(MTU 1492)34 B / 54 B14521432
以太网 + IPv4 + GRE + IPv4/IPv6 + TCP58 B / 78 B14221402
以太网 + IPv4 + UDP + VXLAN + 内层以太网 + IPv4/IPv6 + TCP84 B / 104 B13961376
以太网 + IPv4 + UDP + VXLAN,内层 MTU 145050 B / 70 B13701350
以太网 + IPv4 + ESP(隧道模式)+ IPv4/IPv6 + TCP约 112 B / 约 132 B约 1338约 1318
以太网 + IPv4 + GRE + ESP + IPv4/IPv6 + TCP约 140 B约 1310约 1290
以太网 + GTP-U + IPv4 + TCP62 B1418—
巨帧(MTU 9000),普通 IPv440 B89608940

这些数值按最小首部计算。你每开启一个选项 —— TCP 时间戳、IPsec 完整性校验、更多 MPLS 标签、第二层 VLAN 标签 —— MSS 都会进一步下降。

值得记住的 MTU 与 MSS 数值

参考值
量数值出处
标准以太网 MTU1500 字节IEEE 802.3 / 事实上的互联网标准
含首部与 FCS 的以太网帧1522 字节(带 VLAN 为 1526)14 + 1500 + 4,再加 4 字节标签
默认 IPv4 TCP MSS1460 字节1500 − 20 − 20
默认 IPv6 TCP MSS1440 字节1500 − 40 − 20
主机必须接受的 IPv4 最小 MTU576 字节RFC 791
IPv6 最小 MTU1280 字节RFC 8200 —— 路由器从不分片
PPPoE MTU1492 字节1500 − 8 字节 PPPoE 首部
IPv4 首部最大值60 字节IHL = 15 × 4
TCP 首部最大值60 字节数据偏移 = 15 × 4
巨帧 MTU9000 字节常见的数据中心约定,并非互联网标准

相关:MTU / MSS 计算器、TCP 吞吐计算器、TCP 吞吐与带宽时延积、带宽计算器。

常见问题

MTU 和 MSS 有什么区别?

MTU 是链路能承载的最大帧或数据包,在第 2 层或第 3 层测量 —— 标准以太网是 1500 字节。MSS 是发送方可以放进单个报文段的最大 TCP 载荷,由 MTU 减去 IP 与 TCP 首部得出。在普通的 1500 字节以太网路径上跑 IPv4 与 TCP 时,MSS = 1500 − 20 − 20 = 1460 字节。MTU 是链路的属性;MSS 是两个 TCP 端点之间的约定。

隧道为什么会破坏 TCP 连接?

隧道在原数据包外面加上了自己的首部,使封装后的包比原来更大。如果隧道的外层 MTU 是 1500 字节,那么能装下的内层包就小于 1500 —— 于是认为路径 MTU 是 1500 的主机会发出装不下的包,隧道要么把它们分片,要么直接丢弃。丢包的表现是连接能建立、但在大批量传输时卡住,也就是经典的「ping 通、网页打不开」。

怎么计算隧道路径上正确的 MSS?

把外层链路帧到 TCP 载荷之间的每一个首部加起来,再用外层 MTU 减去这个总和。以以太网 + IPv4 + GRE + IPv4 + TCP 为例:14 + 20 + 4 + 20 + 20 = 78 字节,所以内层 MSS 是 1500 − 78 = 1422 字节。无论哪种隧道类型,算法都一样 —— 变的只是首部清单。MTU / MSS 计算器会按你实际使用的选项逐层完成计算。

MSS 钳制是什么?

MSS 钳制是指路径上的路由器在经过时改写 TCP 握手过程中的 MSS 值,强制两端使用能装下路径的更小报文段尺寸。它用于路径 MTU 发现无法工作的场合 —— 最常见的是 PPPoE 链路、某些隧道,以及 ICMP 被过滤的环境。它是一种权宜手段而不是修复:只对握手经过钳制路由器的连接有效,对已经进行中的流毫无作用。

路径 MTU 发现是什么?

PMTUD 的做法是发送带 Don't Fragment 位的数据包。当路径上某台路由器因为下一跳 MTU 更小而无法转发时,它会丢弃该包并回送一条携带更小 MTU 的 ICMP「需要分片」消息。发送方随即将包减小。只要没人屏蔽 ICMP,它就工作得很好 —— 而一旦被屏蔽,发送方永远不知道存在更小的 MTU,连接就会卡死。这就是为什么 PMTUD 黑洞如此常见、又如此难以诊断。

为什么 IPv6 不在路由器上分片?

IPv6 彻底取消了路由器分片:只有发送主机可以分片,路由器绝不代劳。IPv6 要求的最小 MTU 是 1280 字节,因此 PMTUD 从可选变成了强制。实际后果是:40 字节的 IPv6 首部让 MSS 相比 IPv4 少 20 字节;而某条路径降低了 MTU 却没有把 ICMPv6 Packet Too Big 消息送达时,连接会直接断开,而不是性能下降。

干脆把所有地方的 MTU 都调大行不行?

只有当路径上每一台设备都支持时才可行。9000 字节的巨帧在数据中心内很常见,但几乎不可能端到端跨广域网使用;一旦不匹配,就会制造出你原本想避开的 PMTUD 黑洞。在可控网络内提高 MTU 是值得的;在一条你无法完全掌控的路径上假定存在更大 MTU 则不可取。