《Linux高性能服务器编程》阅读笔记:
如图,当IP数据报超过帧的MTU(最大传输单元)时,它将会被分片传输。分片能发生在发送端或者中转路由器,且在传输过程中可能被多次分片。在最后的目标机器上这些分片才会被内核的的IP模块重新组装。
一个IP数据报的每个分片都具有自己的IP头部信息,它们都具有相同的标识值,但是具有不同的位偏移,且除了最后一个分片外,其他分片都将设置MF标志。此外,每个分片的IP头部的总长度字段将被设置为该分片的长度。
以太网帧的MTU是1500字节,因此它的数据部分最大为1480字节(IP头部占用20字节)。为观察IP分片的数据报,这里采用ICMP协议发送一个长度为1501字节的IP数据报,其中IP头部占用20字节,ICMP报文占据1481字节。1481字节的ICMP数据报中含8字节ICMP头部,其他1473字节为数据部分。长度为1504的IP数据报被拆分为2个IP分片:
(1) 第1个IP分片:1480字节ICMP数据报文(含8字节的ICMP头部信息) + 20 字节IP头部信息 = 1500字节的IP数据报,设置了MF位
(2) 第2个IP分片:1字节的ICMP数据报文(不含8字节的ICMP头部信息) + 20 字节的IP头部信息 = 21字节的IP数据包,没有设置MF位
分片后:
注:分片1的IP头部信息的MF(More Fragment)位被置为1,分片2的该位不设置,即为0
事实上,ICMP报文的头部长度取决于ICMP报文的类型且变化范围很大。这里以8字节为例,因为接下来的用例用到了ping程序,ping应用程序使用的ICMP回显和应答报文的头部长度都是8字节。
机器1:Ubuntu14.04 IP地址为192.168.239.136
机器2:Ubuntu11.04 IP地址为192.168.239.145
用机器1来ping机器1,每次传送1473字节的数据(这是ICMP的数据部分)以引起IP分片,用tcpdump抓取过程中双方交换的数据包:
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
1. IP (tos 0x0, ttl 64, id 52457, offset 0, flags [+], proto ICMP (1), length 1500)
192.168.239.136 > 192.168.239.145: ICMP echo request, id 4938, seq 1, length 1480
2. IP (tos 0x0, ttl 64, id 52457, offset 1480, flags [none], proto ICMP (1), length 21)
192.168.239.136 > 192.168.239.145: ip-proto-1
3. IP (tos 0x0, ttl 64, id 36694, offset 0, flags [+], proto ICMP (1), length 1500)
192.168.239.145 > 192.168.239.136: ICMP echo reply, id 4938, seq 1, length 1480
4. IP (tos 0x0, ttl 64, id 36694, offset 1480, flags [none], proto ICMP (1), length 21)
192.168.239.145 > 192.168.239.136: ip-proto-1
一条ping命令对应两个IP数据报,以第一条ping语句的IP数据报为例:
(1) 两个IP分片的标识值52457,说明它们是同一个IP数据报的分片
(2) 第1个分片的位偏移为0,第2个为1480。显然,第2个分片的位偏移实际上就是第一个分片的ICMP报文的长度
(3) 第1个分片中“flags[+]”即设置了MF标志,表示还有后续分片;第2个分片中“flags[none]”即没有设置MF位
(4) 两个IP分片的长度分别1500字节和21字节