IPv6 只有源端能分片,中间路由器遇到太大的包只能回「包太大」。 所以每条链路的 MTU 必须至少 1280,否则 IPv6 根本跑不起来。
4.5.2 讲了 IPv4 的分片,这一节讲 IPv6 改成了什么样。 4.5.3 的 PMTUD 在 IPv6 里是「必需」而不是「优化」,原因就在这里。
一、只有源端能分
IPv6 把「中间路由器分片」这件事彻底删了。 要分片,只有发送方自己分;中间设备过不去,只能回一个 ICMPv6「包太大」。
| 项 | IPv4 | IPv6 |
|---|---|---|
| 源端分片 | 可以 | 可以 |
| 路由器分片 | 可以 | 禁止 |
| 过不去时 | 切了继续发 | 回 ICMPv6 报错 |
第三行是这次改动的全部意义:从「偷偷切」变成「明确报错」。 报错意味着源端一定会知道,而「偷偷切」意味着源端永远不知道自己的包被切成了几片。 这个改动让路由器的工作变简单了: 不用维护重组缓冲区,不用等片到齐,转发路径上少了一整类状态。 代价是「源端必须自己搞清楚路径 MTU」——所以 PMTUD 从「优化」变成了「必需」。
二、分片扩展首部
IPv6 的分片信息放在「分片扩展首部」里,长度固定 8 字节。 它只在需要分片时出现,不分片就没有。
| 字段 | 长度 | 作用 |
|---|---|---|
| 下一个首部 | 1 字节 | 指向下一层 |
| 保留 | 1 字节 | 填 0 |
| 片偏移 | 13 位 | 单位 8 字节 |
| M 标志 | 1 位 | 后面还有没有 |
| 标识 | 32 位 | 同一组的编号 |
第五行那个 32 位标识比 IPv4 宽: IPv4 只有 16 位,包一多就容易重号;IPv6 给到 32 位,撞号概率大大降低。 这是「顺手改好」的一个细节。 「只在需要时出现」是扩展首部机制的好处:不分片的包完全不带这 8 字节, 而 IPv4 的「标识、标志、片偏移」是每个包都占着位置。
三、1280 这条底线
因为路由器不能分片,链路的 MTU 就必须「自己扛得住」。 规范把底线定在 1280 字节:任何一条能跑 IPv6 的链路,都必须能传 1280 字节的包。
| 链路 | MTU | 能不能跑 IPv6 |
|---|---|---|
| 以太网 | 1500 | 能 |
| PPPoE | 1492 | 能 |
| 某些隧道 | 可能低于 1280 | 要特殊处理 |
第三行是实际会遇到的问题:隧道封装会吃掉几十字节,套两层就可能低于 1280。 这时只能「在隧道入口就把包切到 1280 以下」, 或者干脆在隧道里再分片——后者很别扭,但有时没别的办法。 所以「1280」不是一个随便定的数:它要「比以太网小得多(容得下封装开销)」, 又要「比 576(IPv4 的老底线)大得多(效率不至于太差)」。
四、和 IPv4 的取舍对比
两种设计各有代价,值得摆在一起看:
| 维度 | IPv4 的做法 | IPv6 的做法 |
|---|---|---|
| 路由器负担 | 要能分片、要缓存 | 不碰分片 |
| 源端知情权 | 常常不知情 | 一定知情 |
| 实现复杂度 | 分布在所有设备 | 集中在两端 |
| 老设备兼容 | 天然兼容 | 要求链路达标 |
第二行是这次改动的核心价值:「谁发包谁负责」比「路上谁都能改」更符合工程直觉。 IPv4 的分片像是「邮局替你拆包裹」——拆了你还不知道,丢了也算你的。 第四行是 IPv6 的「隐性门槛」:它要求「链路必须达标」, 所以老网络升级 IPv6 时,第一件事往往是「量一遍 MTU」。 这也是 IPv6 部署比想象中慢的原因之一。
五、动手 Demo:IPv6 只在源端分片
先算「分片时每片能装多少」,再把 4000 字节切一遍。 注意 1448 和 1460 的差:分片要多带 8 字节的扩展首部。
mtu, data = 1500, 4000
per = (mtu - 40 - 8) // 8 * 8
off = 0
while data > 0:
take = min(per, data)
data -= take
print(take, off, 1 if data else 0)
off += take // 8
实跑输出:
--------------------------------------------------------------------
IPv6 只在源端分片
--------------------------------------------------------------------
**IPv6 把「中间路由器分片」这件事取消了**:
**要分,只有发送方自己分;中间设备遇到太大的包,只能回一个「包太大」。**
**这一刀砍掉了路由器最讨厌的一类工作。**
**先看一片能装多少数据**:
链路 MTU 分片时每片数据 不分片时每片数据
-------------------------------------------------
1500 1448 1460
1280 1232 1240
9000 8952 8960
**第二列比第三列少 8**——**因为分片时要多带一个 8 字节的「分片扩展首部」。**
**拿 4000 字节数据在 MTU 1500 上切**:
片号 数据长度 偏移(8 字节) M 标志
------------------------------------------------
1 1448 0 1
2 1448 181 1
3 1104 362 0
**3 片拼出 4000 字节**,**每片都不超过 1500**(数据加 40 加 8)。
**「路由器不分片」带来一个硬约束**:**链路的 MTU 必须至少 1280**,
**否则 IPv6 根本跑不起来**——**这也是为什么所有 IPv6 的规范都把 1280 写成「最低要求」。**
**对比一下 IPv4**:
**IPv4 允许中间路由器分片,看着「更宽容」,实际更糟**——
**因为分片在中间发生,源端不知道,重传的代价全由接收方承担。**
**IPv6 把这件事推回源端,是「让该负责的人负责」。**
1448 这个数要会算:1500 减 40(IPv6 头)再减 8(分片首部)得 1452, 向下取到 8 的倍数就是 1448。 而 IPv4 那边是 1480——同样 1500 的链路,IPv6 每片少装 32 字节。 这个差不是小事:分片场景下 IPv6 要切更多片,掉一片全丢的风险更高。 所以「IPv6 更快」这句话要加限定:首部处理更快,但分片场景反而更费。 最后那张对比表里「实现复杂度」这一行最值得想:IPv4 把复杂度摊给了所有路由器, 所以「任何一台设备都要能分片」;IPv6 把它收回到两端,路由器可以做得更简单更快。 这是「端到端原则」的一次回归。
30 秒实验
- 算一下:MTU 1280 时,IPv6 分片每片最多装多少数据?
- 想一下:为什么 IPv6 的最低 MTU 定在 1280 而不是 1500?
- 想一下:隧道场景为什么容易出 MTU 问题?
常见误区
- 以为「IPv6 完全不能分片」。 源端可以分,只是路由器不许分。
- 以为「IPv6 的 MTU 底线和 IPv4 一样」。 不同,IPv4 是 68,IPv6 是 1280。
- 以为「IPv6 头短所以一定更快」。 分片场景反而更费,因为每片要多带 8 字节。
自测三问(点开对答案)
1. IPv6 谁可以分片? —— **只有源端可以**,中间路由器不许分片。 2. 路由器遇到过大的包怎么办? —— **回一个 ICMPv6「包太大」消息**,让源端自己调整。 3. IPv6 要求链路的最小 MTU 是多少? —— **1280 字节**,达不到就跑不了 IPv6。下一节逐字段看 IPv4 首部:那 20 个字节里到底装了什么。
- ☐ (本节完,下一节 4.7 IPv4首部)