报文为什么要分片
一个链路层数据报能承载的最大数据量称为最大传送单元(MTU)。 因为IP数据报被封装在链路层数据报中,故链路层的MTU严格地限制着IP数据报的长度, 而且在IP数据报的源与目的地路径上的各段链路可能使用不同的链路层协议,有不同的MTU. 例如,以太网的MTU为1500字节,而许多广域网的MTU不超过576字节。
当IP数据报的总长度大于链路MTU时, 就需要将IP数据报中的数据分装在两个或更多个较小的IP数据报中, 这些较小的数据报叫做片。
ipv6 分片报文
ipv4 分片报文
IPv4分片的特点
一般来说我们都知道MTU是1500字节,因此超过1500字节的数据就需要进行ip分片。 1、分片由IPv4头部中的标识(Identification)、分片偏移(Fragment offiet)和更多分片(More Fragments, MF)字段控制,分片的标识(Identification)都是同样的而且分片偏移(Fragment offiet)是以8字节为单位的偏移。 2、分片:源和目的端口号的UDP(协议)头部只出现在第一个分片里 3、重组:IP分片在目的地的网络层被重新组装。 目的主机使用IP首部中的标识、标志和片偏移字段来完成对片的重组。 同样的标识和不同的偏移让接收方可以对分片进行重组, 当MF = 0的分片被接收到时,重组程序才能确定原始数据报的长度, 它等于分片偏移字段的值(乘以8)加上当前分片IPv4总长度字段的值。。
标识(Identification):
当创建一个 IP数据报时,源主机为该数据报加上一个标识号。 当一个路由器需要将一个数据报分片时,形成的每个数据报(即片)都具有相同的原始数据报的标识号。 当目的主机收到来自同一发送主机的一批数据报时,它可以通过检查数据报的标识号以确定哪些数据报是属于同一个原始数据报的片。
更多分片(More Fragments, MF)
IP首部中的标志位有3个比特,但只有后2个比特有意义,分别是MF位和DF位(Don’t Fragment),标志指明该数据报后面是否还有更多的分组。 只有当DF=0时,该IP数据报才可以被分片。 MF则用来告知目的主机该IP数据报是否为原始数据报的最后一个片。 当MF=1时,表示相应的原始数据报还有后续的片; 当MF=0时,表示该数据报是相应原始数据报的最后-一个片。 目的主机在对片进行重组时,使用片偏移字段来确定片应放在原始IP数据报的哪个位置。
分片偏移(Fragment offiet)
偏移量是用来记录每个分片所在的位置, 偏移量=相对分片报文长度/8; 假设一共传输3800字节,mtu为1400字节,由于固定ip首部为20字节, 因此实际传输长度为1420字节,所以只需要传输三次,1400+1400+1000, 那么第一片偏移为0,第二片偏移=1400/8=175,第三次偏移=2800/8=350.
分片偏移量计算。
例: 考虑向一条具有1500字节的MTU的链路发送一个8000字节的数据报(首部20字节,数据部分7980字节), 假定初始化数据报具有序列号321,这将会生成多少个片?它们的特征是什么?
答: 因为IP数据报首部占20字节,因此在每个分片中片的大小是1500-20=1480个字节, 故原始数据报中7980字节数据必须被分配到7980/1480=6个片中。 所以7980字节数据必须被分配到6个独立的片中(每个片也是一一个IP数据报)。 由于偏移值的单位是8字节,所以除了最后一个片外,其他所有片中的有效数据载荷都是8的倍数。 每个片的标识号都为321.前5个片的MF=1(还有分片),最后一个片的MF=0(表示最后一个分片)
例:分片报文实例分析
1、首片
2,中间片
灰底的Fragment offset:1480 那行对应的十六进制码是蓝底的0X20b9, 刚开始很疑惑为何十进制的1480对应的是0x20b9,怎么算都不对啊,不知道读者您是不是遇到了这样的疑惑!
参考RFC791中相关字段的说明 才明白原来这个1480指的是偏移的实际字节而不是 fragment offset字段中比特位对应的十进制数值。 该字段的是以8个“八比特组”为单位的,所以1480在该字段的值是除以8之后的185,换算成二进制就是0 0000 1011 1001,因为前面还有个值为001的3比特的Flag字段,所以加上Flag字段后其二进制值是0010 0000 10111001,换算成二进制就是20b9。请自己算算吧。弄不明白的需要先掌握数据包结构及进制等基础了。
3、最后一片
从Wireshark抓包来看IP分片
例:下图是一个长度为3000字节的udp包(包括了udp包头的8个字节)。
原始数据报要加上ipv4包头为3020字节,它超过了MTU的限制,因此发送的时候会进行分片。
第一个分片中实际传送了1472字节的udp数据和8字节udp包头。 此时偏移为0,因为接下来还有数据包要发因此MF置为1
第二个分片传送1480字节的udp数据,因为第一个分片已经传送了1480,因此这里的偏移为1480/8 = 185,因为接下来还有数据包要发因此MF置为1
最后一个分片传送剩下的40字节数据,并将MF置为0,此时接收方可以通过370*8+60来算出原始数据报的长度,因此也知道了udp包的大小为3000字节(减掉ip包头的20字节)。
wireshark中的抓到的报文(wireshark默认设置)
我们发现它和我们上一节讲的不太一样,UDP包按理应该是第一个出现,之后跟着一串分片后的IPv4包。而打开上面截图里所有的IPv4包我们发现它们的MF标志全都是1,且最后的udp包的length明显大于了MTU。
这是因为wireshark的首选项中自动开启了重组分片数据的选项。这个默认开启的选项能直接帮我们重组原udp数据包并用它替换了MF=0的那个IPv4数据包,因此在开启该选项时我们是找不到MF=0的数据包的。
我们打开第一个UDP包,它的数据如下: 我们可以知道虽然它包头中的长度给出的Length为8537(包含8个字节包头,实际数据为8529字节),但是真实的Data里只有1472字节,1472+8(UDP包头)+20(IP包头) = MTU。我们再看这一组最后一个IPv4包: 我们可以看到它的MF=0,因此计算925*8+1157 = 8557,这是原始的数据报文,减掉20字节的IP包头,恰好为8537字节。与UDP包中所给的Length值一样。
|