写在前面
上一篇把链路层讲完了:同一子网里,靠 MAC 地址 + 以太网帧 + 交换机 + ARP,两台设备就能把数据搬过去。但 MAC 只管"一跳",跨网、跨子网、从北京到纽约,链路层就无能为力了。
升级到网络层,主角登场:IP(Internet Protocol)。这一篇先不谈地址怎么划分、路由怎么走(那是下一篇的事),而是把 IP 协议本身讲透——它的设计哲学、IPv4 数据报头部每一个字段、TTL 怎么防环路、分片怎么和 MTU 较劲,最后带一眼 IPv6 的概貌。
一、IP 的设计哲学:尽力而为
IP 的脾性可以用三个词概括:无连接、不可靠、尽力而为 。
- 无连接(connectionless):发包前不先建电路、不先握手,抬手就发;
- 不可靠(unreliable):不保证送达、不保证顺序、不保证不重复;
- 尽力而为(best-effort):会尽量投递,但出了问题不负责善后——丢了就丢了,乱序就乱序。
这听起来很糟,其实是有意为之。可靠性、顺序、去重这些复杂活,IP 全部甩给上层(一般是 TCP)去干。IP 只负责一件事:看目的地址,把包往目的方向推一跳。这样网络层保持极简、极快,复杂逻辑只在端点上做——这正是互联网能"大而糙地"扩到全球的秘诀。
顺带一提 ICMP(Internet Control Message Protocol),它是 IP 的"信使"。IP 自己不报告错误,遇到问题(TTL 超时、目的不可达、需要分片但 DF 置位)就回一个 ICMP 报文告诉源端。日常用的 ping、traceroute 都靠它。
二、IPv4 数据报头部
IP 层的 PDU 叫数据报(datagram)。一个 IPv4 数据报由头部 + 载荷组成,头部固定部分 20 字节,最长 60 字节(带选项)。RFC 791 定义的头部布局:
| |
逐字段拆解:
| 字段 | 位宽 | 说明 |
|---|---|---|
| Version | 4 位 | IP 版本,IPv4 这里是 4 |
| IHL | 4 位 | 头长,以 4 字节为单位。最小 5(=20 字节,无选项),最大 15(=60 字节)。它决定了载荷从哪个字节开始 |
| DSCP | 6 位 | 差分服务码点,用于 QoS 打标记优先级 |
| ECN | 2 位 | 显式拥塞通告,路由器用它给端点"我拥塞了"的信号 |
| Total Length | 16 位 | 整个数据报(头部 + 载荷)的字节数,理论最大 65535 |
| Identification | 16 位 | 标识符,分片重组时用来认"这几片本来是一家" |
| Flags | 3 位 | bit0 保留(置 0);bit1 DF(Don’t Fragment);bit2 MF(More Fragments) |
| Fragment Offset | 13 位 | 本片在原数据报中的位置,以 8 字节为单位 |
| TTL | 8 位 | 生存时间,每经一跳减 1 |
| Protocol | 8 位 | 上层协议号,告诉对面"载荷交给谁"(见下表) |
| Header Checksum | 16 位 | 只校验头部,不校验载荷 |
| Source IP | 32 位 | 源地址 |
| Destination IP | 32 位 | 目的地址 |
| Options | 可变 | 几乎不用,多数路径会忽略或直接丢 |
Protocol 字段 常见取值(IANA 维护完整列表):
| 协议号 | 协议 |
|---|---|
| 1 | ICMP |
| 2 | IGMP |
| 6 | TCP |
| 17 | UDP |
| 41 | IPv6 封装 |
| 47 | GRE |
| 50 | ESP(IPsec) |
| 51 | AH(IPsec) |
| 58 | ICMPv6 |
| 89 | OSPF |
几个容易记错的点:
- IHL 数的是 4 字节单位,不是字节。所以
5代表 20 字节、15代表 60 字节,别和 Total Length 搞混; - Header Checksum 只管头部,载荷的完整性交给上层(TCP 有自己的校验和、UDP 在 IPv4 里校验和可选但实际都开);
- Options 基本退出历史舞台:带选项的包常被路径上的设备丢弃或特殊处理,安全设备尤其敏感。
三、TTL:防环路的保险丝
TTL(Time To Live)名字像"时间",其实是跳数。规则极简:
- 源端给个初值(常见 64、128 或 255,因系统而异);
- 每经过一台路由器,TTL 减 1;
- 减到 0 还没到目的地,路由器丢弃该包,并回一个 ICMP Time Exceeded 给源。
它的核心使命是防止环路包永远转圈。要是没有 TTL,一个配错路由的包可能在两台路由器之间无限循环,把链路带宽吃光。
不同系统的默认 TTL 不一样,常被拿来粗略判断对端系统(不完全可靠,可被改):
| 系统 | 常见默认 TTL |
|---|---|
| Linux / macOS | 64 |
| Windows | 128 |
| 网络设备(路由器等) | 255 |
这正是
traceroute(Windows 下叫tracert)的原理:故意发 TTL = 1、2、3 … 的探测包,每一跳的路由器因为 TTL 超时回 ICMP Time Exceeded,把返回的 ICMP 源地址记下来,就描出了整条路径。
四、分片与 MTU
上一篇说过,以太网的 MTU = 1500 字节(载荷上限)。可 IP 数据报最长能到 65535 字节。当 IP 包大于出口链路的 MTU 时,就要分片(fragmentation):路由器把载荷切成几片,每片都套上一个完整的 IP 头,各自独立转发。
分片相关三个字段一起用:
- Identification:原数据报被切出来的所有分片,共用同一个 Identification,让目的端能认出"这几片是一家的";
- MF(More Fragments):除最后一片外都是
1,最后一片是0——告诉目的端"分片到这就齐了"; - Fragment Offset:本片数据在原载荷中的偏移,以 8 字节为单位。
重组(reassembly)只在目的端做,中间路由器不重组。目的端靠 (源 IP, 目的 IP, Protocol, Identification) 四元组把同一组的分片归到一起,按 Offset 拼回去;MF = 0 的那片到齐、且中间没有空洞,就算拼完。
为什么 Offset 以 8 字节为单位?因为 13 位的 Offset 域,乘以 8 才能覆盖 16 位的最大长度:2^13 × 8 = 65536,正好够表示最大 65535 字节的数据报。这也意味着每片的载荷长度必须是 8 的倍数(最后一片除外)。
DF 标志与 PMTUD:DF = 1 表示"不要分片"。如果路由器发现包超过 MTU 又被置了 DF,它会丢弃该包,并回一个 ICMP “需要分片” 报文(Fragmentation Needed),把"下游 MTU 是多少"也带上。源端收到后调小包重发——这就是 PMTUD(Path MTU Discovery,路径 MTU 发现)的核心。现代网络强烈推荐用 PMTUD + DF = 1 来避免分片,原因下面说。
分片为什么能避则避:
- 一片丢,全丢:任一分片在路上丢了,整个数据报就拼不齐,上层(TCP)只能整体重传,放大了丢包代价;
- 防火墙难处理:分片后第一条之外的片没有 L4 头部,安全策略和 NAT 很难判断,历史上是著名的绕过手法;
- 重组负担在目的端:占用内存、可能被用来打"重组炸弹"。
所以实践里:应用尽量别发超大包、TCP 配合 PMTUD、UDP 应用自己控制报文大小,能不分片就不分。
五、IPv6 概览
IPv4 地址(32 位)早不够用了,IPv6 把地址扩到 128 位,号称"给每粒沙子都分一个地址"。但 IPv6 不只是"地址变长",它对头部做了大幅简化。IPv6 基本头部固定 40 字节,没有选项、没有头部校验和、分片相关字段也从基本头里挪走了:
| |
字段对照 IPv4 看更清楚:
| IPv6 字段 | 位宽 | 对应 IPv4 / 说明 |
|---|---|---|
| Version | 4 位 | 这里是 6 |
| Traffic Class | 8 位 | 对应 IPv4 的 DSCP + ECN |
| Flow Label | 20 位 | IPv6 新增,标识一条流,便于做 QoS |
| Payload Length | 16 位 | 只算载荷,不含 40 字节基本头(IPv4 的 Total Length 是含头的) |
| Next Header | 8 位 | 对应 IPv4 的 Protocol,但还能指向扩展头链(见下) |
| Hop Limit | 8 位 | 对应 TTL,名字更准确(每跳减 1) |
| Source / Dest Address | 各 128 位 | 16 字节的 IPv6 地址 |
IPv6 相对 IPv4 的几个关键变化:
头部更简、转发更快。固定 40 字节、没有头部校验和(校验交给上层和链路层 FCS),路由器转发时不用每跳重算校验和,转发效率更高。
扩展头链代替 Options。IPv6 把可选功能(逐跳选项、路由、分片、IPsec 的 ESP/AH、目的选项)做成一条扩展头链,用 Next Header 一个接一个串起来,最后才接上层协议。基本头永远在前、固定 40 字节,路由器只需看基本头就能转发,绝大多数扩展头只有目的端(或指定节点)才处理。
中间路由不再分片。IPv6 规定路由器不负责分片,只有源端能分(通过分片扩展头)。如果路由器发现包超过下游 MTU,直接丢弃并回 ICMPv6 Packet Too Big,源端据此调小重发(PMTUD)。IPv6 还规定每条链路最低 MTU = 1280 字节,低于这个值必须做适配。
Hop Limit 取代 TTL,机制完全一样(每跳减 1、到 0 丢弃),只是换了个更诚实的名字。
NDP 取代 ARP。IPv6 没有 ARP 协议,地址解析改由 NDP(Neighbor Discovery Protocol,邻居发现协议,RFC 4861)完成——它基于 ICMPv6,用组播(而非广播)来查询邻居的链路层地址。好处是:不再有 ARP 那种全链路广播风暴,也顺带把 ARP 欺骗的老坑换成了新的安全模型(NDP 有 SEND 等机制可加固)。
小结
- IP 是无连接、不可靠、尽力而为的网络层协议,可靠性交给上层(TCP);
- IPv4 头部固定 20 字节(可扩到 60),关键字段:Version / IHL(4 字节单位)/ Total Length / TTL / Protocol / 头部校验和 / 源 / 目的 IP,分片靠 Identification + Flags + Fragment Offset 三个字段;
- TTL 每跳减 1,到 0 丢弃并回 ICMP Time Exceeded,是防环路的保险丝,也是
traceroute的原理; - 当 IPv4 数据报长度超过出口链路 MTU 且没有禁止分片时,源主机或中间路由器可能分片;重组只在目的端进行。现代实践倾向用 DF = 1 + PMTUD 避免分片(一片丢则全丢、安全设备难处理);
- IPv6 头部固定 40 字节、无校验和、扩展头链代替选项、中间路由不分片、最低 MTU 1280、Hop Limit 取代 TTL、NDP 取代 ARP。
下一篇,我们正式进入 IP 地址的世界——TCP/IP(四):IP 地址、子网划分与路由 :地址分类、子网掩码与 CIDR、私有地址、路由表怎么选下一跳。
参考: