分片:就是当一个skb包长度大于传输设备或者链路上物理设备的mtu时,会根据一定的方式进行切割,从而使报文得以发送出去。但是这里需要说明,分片又分为IP和TCP分片两种,由于tcp报文有自己的机制去分片,不需要依赖IP层分片;而对于udp或者icmp等报文,只能依赖IP层去分片。
分片与重组关系:IP协议理论上允许的最大IP数据报为65535字节(16位来表示包总长)。但是因为协议栈网络层下面的数据链路层一般允许的帧长远远小于这个值,例如以太网的MTU(即Maximum Transmission Unit,最大传输单元)通常在1500字节左右。假如我们需要传输一个字节为4600的数据,则我们需要将其分为四片。所以较大的IP数据包会被分片传递给数据链路层发送,分片的IP数据报可能会以不同的路径传输到接收主机,接收主机通过一系列的重组,将其还原为一个完整的IP数据报,再提交给上层协议处理。
IP数据报格式:
把一份IP数据报文分片以后,只有到达目的地才进行重新组装,这里的目的地是指IP报文传送的下一站,而不是最终的目的地,因此分片和重新组装的过程对传输层是透明的。
在IP报头中,16位标识、3位标志、13位段偏移就是用于IP报文的分片与重组的。其中标识字段长度为16比特,用于标识一个IP数据报。也就是说当发送端将某个较大的IP报文分片进行传输时,其中每个分片的标识字段都是相同的,代表这些分片是属于同一个数据报。段偏移字段13比特,用于指示该片在原始数据报中所处的位置。
标志字段有三位,其中第一位未使用;第二位用于指出是否要对数据报分段,称为“请勿分段(DF)”位,如果该位的值设置为1,表示该数据报不能分段。如果必须对数据报分段,而DF位又置为1,则数据报会被丢弃,并向源端发送一个ICMP差错报文;第三位用于指出当前分段后面是否还有更多的分段,如果此位置0,表示当前分段是数据报的最后一个分段。
分片函数:
ip_fragment(int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)))
首先ip_fragment必须处理如下两种情况:
<1>必须切成小块的大数据,要切割大数据就需要分配新的缓冲区,并且在大的缓冲区和小缓冲区见做内存的拷贝。
<2>不需要再分片的数据链表或数组,如果分配的缓冲区又足够的空间新增较抵层的L3头和L2头,则ip_fragment处理这些缓冲区不需要进行内存拷贝。ip层要做的就是
重组函数:
int ip_defrag(struct sk_buff *skb,u32 user)
IP分片的优点是它为上层协议提供了一个透明的传输管道,使上层协议不必关心底层硬件技术,缺点是:在传输过程中,即使丢失其中的一片数据也要重传整个数据报。