本页目录
IPv4 协议
互联网的基石协议——32 位地址空间、分片与重装、TTL 防环、DSCP/ECN 服务质量。即使 IPv6 在推进,IPv4 仍然承载着绝大部分互联网流量,它的每个字段都对应一个工程妥协。
概述
IPv4 是互联网的核心网络层协议,1981 年由 RFC 791 定义。它提供"尽力而为"的无连接数据报传输——不保证到达、不保证顺序、不保证不重复。这些保证由上层 TCP 提供。IPv4 的 32 位地址空间(43 亿地址)在 2011 年耗尽,但通过 NAT 和 CIDR 延续至今。本文聚焦 header 语义、分片/重组、PMTUD 和 QoS 标记(DSCP/ECN)——这些是理解互联网流量工程和故障诊断的基础。
IPv4 Header 逐字段
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| IHL | DSCP |ECN| Total Length |
| (4) | (6 bits)|(2)| (16 bits) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identification |Flags| Fragment Offset |
| | R|DF|MF| (13 bits, ×8) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time to Live (8) | Protocol | Header Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Address (32 bits) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Address (32 bits) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options (if IHL > 5) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Version: 4 (固定)
IHL: Internet Header Length — 4-byte words (最小 5 = 20B, 最大 15 = 60B)
IHL > 5 → 有 IP options (极少)
DSCP: DiffServ Code Point — QoS 标记 (6 bits, 替代旧 TOS field)
ECN: Explicit Congestion Notification (2 bits)
Total Length: IP packet 总长 (含 header + data, 最大 65535B)
Identification: 每个 IP datagram 的唯一 ID (用于分片重组, 复制到所有 fragment)
Flags:
bit 0: Reserved (永远是 0)
bit 1: DF (Don't Fragment) — 1 = 路由器不分片, 返回 ICMP "Frag Needed"
bit 2: MF (More Fragments) — 1 = 后续还有分片, 0 = 最后一片
Fragment Offset: 此 fragment 在原始 datagram 中的位置 (8-byte 单位)
TTL: Time to Live — 每 hop 减 1, 到 0 时丢弃并回复 ICMP Time Exceeded
Protocol: 1=ICMP, 2=IGMP, 6=TCP, 17=UDP, 47=GRE, 50=ESP, 89=OSPF
Header Checksum: 仅 IP header (TCP/UDP 自己 checksum 覆盖 payload)
Fragmentation
分片的必要性来自"路径上 MTU 可能不同"。但现代网络极力避免 IP 层分片 — PMTUD 让端点发不超过最小 MTU 的包。
分片规则:
1. 每个 fragment 有完整 IP header (复制自原始 datagram)
2. 第一个 fragment: offset=0, MF=1 (除非是唯一 fragment)
3. 中间 fragment: offset>0, MF=1
4. 最后 fragment: offset>0, MF=0
5. 每个 fragment 有相同的 Identification
6. Fragment offset 以 8 bytes 为单位 — 每个 fragment (except 最后) 的长度必须是 8 的倍数
重组:
目标收到所有 fragments → 15s timeout → 超时 = 全部丢弃
重组后的包大小: max offset + last fragment 的 Total Length
问题: 丢一个 fragment → 整个 datagram 不可用 → 重传由 L4 (TCP) 负责
PMTUD (Path MTU Discovery, RFC 1191)
原理: 发送方设 DF=1 → 中间路由器 MTU 不足 → 丢包 + ICMP "Frag Needed" (type 3, code 4)
→ ICMP 包含下一跳的 MTU → 发送方更新路由缓存 → 重发更小的包
PMTUD black hole:
ICMP 被过滤 → DF=1 包丢在路径上 → 发送方不知道 → TCP 重传 → 仍然丢 → hang
检测:
ping -M do -s 1472 1.1.1.1
如果: ping 通 (小包) 但 -s 1472 不通 → MTU black hole
一定概率: MSS clamping 不够 → 某些方向通某些不通
缓解:
TCP MSS clamping: iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
→ 即使 ICMP 被过滤, SYN 时的 MSS 被改小 → 后续数据包不大 → 不需要分片
DSCP 与 ECN
DSCP (6 bits, RFC 2474)
替代旧的 IP Precedence (3 bits), 向后兼容:
Default (CS0, 0x00): best effort
CS1-CS7: 向后兼容 IP Precedence 1-7
AF (Assured Forwarding): 4 classes × 3 drop precedence
AF11 (0x0A) AF12 AF13, AF21...AF43
→ 拥塞时低 drop probability 的包优先级高
EF (Expedited Forwarding): 0x2E → 最优先, 低延迟队列 (VoIP)
Linux: iptables -j DSCP --set-dscp 0x2e or tc filter with skbedit
ECN (2 bits, RFC 3168)
ECN 用 IP header 中 DSCP 的低 2 bits + TCP header 中的 CWR/ECE flags:
00: Not ECN-capable
10: ECT(0) — ECN-capable transport, 代码点 0
01: ECT(1) — ECN-capable transport, 代码点 1
11: CE — Congestion Experienced (路由器设置!)
流程:
发送方: ECT(0) or ECT(1) on SYN → 表示"我支持 ECN"
路由器: 拥塞检测 (队列超过阈值) → 改 ECT 为 CE (而不是丢包!)
接收方: 看到 CE → 设 TCP header ECE flag in ACK
发送方: 收到 ECE → 减速 (cwnd 减半) + 设 CWR flag → 接收方停止 ECE
ECN 比丢包的优势:
- 不丢包 → 不需要重传 → 延迟更低
- 适合数据中心 (DCTCP = data center TCP, 基于 ECN 做 congestion control)
参考
- RFC: 791, 1191, 2474, 3168
- 源码:
net/ipv4/ip_input.c(ip_rcv),net/ipv4/ip_fragment.c(分片/重组) - 工具:
ping -M do,tracepath,iptables DSCP,sysctl net.ipv4.tcp_ecn
Keywords: IPv4 header, fragmentation, DF bit, PMTUD, MTU black hole, DSCP, ECN, congestion notification