之前的文章中我们讨论过,一旦IP数据报大小超过MTU的限制,就会被分片(如果在IP头部设置禁止分片标志将返回ICMP错误),具体看MTU对IP协议的影响。之前我们用图片的方式形象地描述了是如何分片的,下面我们用tcpdump抓个包看看IP协议究竟是怎么分片的。
IP头部中有三个字段用来描述分片和分片之后在接收端的重组:16位数据报标识,3位标志和13位片偏移。一个IP数据报的每个分片都有自己的IP头部,它们具有相同的标识值,但具有不同的片偏移。并且除了最后一个分片外,其他分片都将设置(MF)标志。另外,需要注意的一点是,每个分片的IP头部的总长度被设置为该分片的总长度。
以太网帧的MTU为1500字节,因此它能够接受的IP数据报的数据部分最多是1480字节(头部占20字节)。在下面测试的时候,我们用IP数据报封装一个长度为1481字节的ICMP报文(包括8字节的ICMP头部,所以其数据部分长度为1473字节),则该数据报在使用以太网帧传输时必须被分片,如下图
![](https://i-blog.csdnimg.cn/blog_migrate/8509113088b6376c8e6bb8da458f5482.png)
注意ICMP报文头部大小不一定是8字节,具体的根据报文类型而定。这里因为下面要用到ping命令,ping命令使用的ICMP回显和应答报文的头部长度是8字节。
我们开启两台虚拟机,在一台虚拟机上ping另一台虚拟机,每次传送1473字节的数据(ICMP报文的数据部分)来强制引起分片,并用tcpdump抓取这一过程中双方交换的数据包。具体命令如下
sudo tcpdump -ntv -i ens33 icmp //只抓取ICMP报文
ping 192.168.224.138 -s 1473 //-s选项指定每次发送1473字节的数据 192.168.224.138是另一台虚拟机的IP地址
我们看下输出的IP数据报的头两个分片
![](https://i-blog.csdnimg.cn/blog_migrate/b2aedd248f60647830e645b0825d41f3.png)
-
这两个分片的标识都是48147
-
第一个分片的偏移值为0
-
第二个分片的偏移值为1480,显然第二个分片的片偏移值实际上也是第一个分片的ICMP报文长度(8字节头部+1472字节数据),如果有第三个分片,第三个分片的偏移应该就是2960(1480*2)
-
第一个分片输出flags[+],标识还有后续分片,第二分片输出flags[none],标识已经没有后续分片了
-
这两个分片的长度一个是1500一个是21,和我们上面分析的一样。