第10章 IP的分片与重装
所属:TCP/IP详解 卷2:实现 来源:TCP/IP详解 卷2:实现
本章描述IP分片与重装的实现,包括分片的原因、分片算法、重装过程和重装定时器等。
10.1 引言
什么是分片
分片(Fragmentation):
- 当IP数据报的大小超过链路的MTU时
- 把数据报分成多个小的分片
- 每个分片独立传输
- 到达目的地后再重装
分片是为了适应不同链路的MTU。
为什么需要分片
为什么需要分片:
-
不同链路的MTU不同
- 以太网MTU=1500
- SLIP MTU=296
- 其他链路可能更小
-
端到端路径MTU可能很小
- 路径上最小的MTU
- 大的分组通不过
-
IP层负责处理
- 对上层透明
- TCP/UDP不用关心
分片让大的分组能通过小MTU的链路。
分片和重装的位置
分片的位置:
- 发送主机
- 中间路由器
- 任何需要转发但MTU不够的地方
重装的位置:
- 只有目的主机
- 中间路由器不重装
- 每个分片独立选路
分片可以在中间,重装只在目的地。
10.2 分片相关的字段
IP首部中的相关字段
IP首部中与分片相关的字段:
| 字段 | 大小 | 说明 |
|---|---|---|
| 标识(ip_id) | 16位 | 数据报的唯一标识 |
| 标志(ip_off的高3位) | 3位 | 分片标志 |
| 片偏移(ip_off的低13位) | 13位 | 分片在原数据中的偏移 |
这三个字段用于分片和重装。
标志位
三个标志位:
| 位 | 名称 | 说明 |
|---|---|---|
| 第0位(最高位) | 保留位(RF) | 保留,必须为0 |
| 第1位 | 不分片(DF) | 1=不分片,0=可以分片 |
| 第2位(最低位) | 更多分片(MF) | 1=还有更多分片,0=最后一个分片 |
DF位(Don’t Fragment):
- 设置了DF位就不能分片
- MTU不够就丢弃,发ICMP不可达
- 用于路径MTU发现
MF位(More Fragments):
- 除了最后一个分片,其他都设置
- 最后一个分片MF=0
- 表示是不是最后一个
标志位控制分片的行为。
片偏移
片偏移(Fragment Offset):
- 13位
- 以8字节为单位
- 表示这个分片的数据在原数据中的偏移
- 第一个分片偏移=0
为什么以8字节为单位:
- 片偏移只有13位
- 8字节单位可以表示更大的范围
- 13位 × 8字节 = 8192字节偏移
- 加上数据,最大65535字节(IP最大长度)
片偏移以8字节为单位。
标识
标识(Identification):
- 16位
- 每个数据报一个唯一的标识
- 同一个数据报的所有分片标识相同
- 重装时用标识匹配分片
标识的生成:
- 发送时递增
- 每个数据报加1
- 循环使用
标识用于匹配同一个数据报的分片。
10.3 分片的过程
什么时候分片
触发分片的条件:
-
输出接口的MTU小于数据报大小
- 需要转发或发送
- 数据报比MTU大
-
DF位没有设置
- DF=0才能分片
- DF=1就不能分
MTU不够且DF=0就分片。
分片算法
分片的算法:
-
计算每个分片的大小
- 不超过MTU
- 减去IP首部长度
- 数据部分是8字节的倍数(除了最后一个)
-
创建各个分片
- 复制IP首部
- 复制对应的数据
- 设置片偏移
- 设置MF标志
- 重新计算检验和
-
逐个发送
- 每个分片独立发送
- 独立选路
把大的数据报分成小的分片。
分片的例子
例子:
- 原数据报:4500字节(20字节首部 + 4480字节数据)
- MTU:1500字节
- 每个分片数据:1480字节(1500-20)
- 1480是8的倍数:1480 / 8 = 185
分片结果:
| 分片 | 偏移 | 数据长度 | 总长度 | MF位 |
|---|---|---|---|---|
| 1 | 0 | 1480 | 1500 | 1 |
| 2 | 185 | 1480 | 1500 | 1 |
| 3 | 370 | 1520 | 1540 | 0 |
验证:
- 1480 + 1480 + 1520 = 4480 ✓
- 偏移1:0
- 偏移2:1480 / 8 = 185
- 偏移3:(1480+1480) / 8 = 370
除了最后一个,其他都是最大长度。
10.4 重装的过程
重装的位置
重装只在目的主机:
- 中间路由器不重装
- 每个分片独立转发
- 目的主机收集所有分片
- 收集齐了再重装
重装只在目的地,中间不重装。
重装的数据结构
重装的数据结构:
- 每个正在重装的数据报一个结构
- 包含:
- 源地址
- 目的地址
- 协议
- 标识
- 分片链表
- 定时器
- 等等
链表组织:
- 所有正在重装的链接成链表
- 按源、目的、协议、标识查找
- 匹配同一个数据报的分片
用数据结构管理正在重装的分片。
重装的步骤
重装的步骤:
-
收到分片
- 检查是不是分片(MF=1 或 偏移>0)
- 不是分片:直接上交
-
查找重装结构
- 根据源、目的、协议、标识查找
- 找到:加入对应的链表
- 没找到:创建新的重装结构
-
插入分片
- 按偏移排序
- 检查是否重叠
- 插入到正确的位置
-
检查是否完整
- 所有分片都到了吗?
- 最后一个分片到了吗?
- 有没有空隙?
-
完整则重装
- 合并所有分片
- 重建原数据报
- 上交上层
- 释放重装结构
收集所有分片,然后合并。
重装定时器
重装定时器:
- 每个重装结构有一个定时器
- 防止分片丢失导致资源泄漏
- 超时还没收齐就丢弃
- 可能发送ICMP超时报文
超时时间:
- 通常是30秒或60秒
- 不同实现可能不同
- RFC建议是60秒
定时器防止资源泄漏。
10.5 分片的问题
分片的问题
分片带来的问题:
-
性能问题
- 分片需要开销
- 重装需要开销
- 降低性能
-
可靠性问题
- 一个分片丢了,整个数据报就丢了
- 没有重传机制(IP不保证可靠)
- TCP会重传整个数据报
-
安全问题
- 分片攻击
- 重叠分片
- tiny分片攻击
-
效率问题
- 每个分片都有IP首部
- 额外的开销
- 小分片效率低
分片有很多问题,能不分就不分。
路径MTU发现
路径MTU发现(Path MTU Discovery):
- 发现路径上的最小MTU
- 发送合适大小的分组
- 避免分片
- 用DF位实现
工作原理:
- 发送分组,设置DF位
- 如果中间MTU不够,路由器丢弃,发ICMP不可达(需要分片)
- 收到ICMP后,减小MTU
- 重新发送
- 直到能通过
路径MTU发现可以避免分片。
10.6 小结
分片概述
-
什么是分片
- 大的数据报分成小的
- 适应不同的MTU
-
为什么需要
- 不同链路MTU不同
- 路径MTU可能很小
-
位置
- 分片:发送主机、路由器
- 重装:只有目的主机
分片相关字段
-
标识
- 16位
- 同一个数据报相同
- 用于匹配分片
-
标志位
- RF:保留
- DF:不分片
- MF:更多分片
-
片偏移
- 13位
- 以8字节为单位
- 数据在原数据中的偏移
分片过程
-
触发条件
- MTU不够
- DF=0
-
分片算法
- 计算分片大小
- 创建各个分片
- 设置偏移和标志
- 逐个发送
重装过程
-
重装位置
- 只有目的主机
- 中间不重装
-
重装步骤
- 收到分片
- 查找重装结构
- 插入分片
- 检查完整性
- 完整则重装
-
重装定时器
- 防止资源泄漏
- 超时丢弃
分片的问题
-
性能问题
- 分片重装开销
- 降低性能
-
可靠性问题
- 一个丢了全丢
- 效率低
-
安全问题
- 分片攻击
- 重叠分片
-
路径MTU发现
- 避免分片
- 用DF位实现
关键概念
-
分片
- 大分小
- 适应MTU
-
重装
- 小合大
- 只在目的地
-
标识、标志、偏移
- 分片的关键字段
-
重装定时器
- 防止资源泄漏
-
路径MTU发现
- 避免分片
- 更好的方式