
ip分片与重组的分析与整理.doc
16页IP分片与重组的分析与整理二2009-11-04 15:27Linux下IP――分片与重组 1 原理 2 1.1 为一个数据包片再次分片 2 1.2 数据包重组 2 1.2.1 数据结构 2 1.2.2 互斥操作 2 1.2.3 在链表中加入一个数据包片 2 1.2.4 溢出时的丢弃 2 1.3 测试是否组成一个完整的数据包 2 1.3.1 将数据包片组装成完整的数据包 2 1.4 数据包片链表的维护管理 2 2 Linux下的实现 3 2.1 IP分片 3 2.1.1 ip_fragment(非UDP使用) 3 2.1.1.1 典型调用者 3 2.1.2 UDP的分片(待续) 7 2.2 IP重组 7 2.2.1 ip_defrag 7 2.2.1.1 典型调用者 7 2.2.1.2 关键数据结构(2.4系列) 7 2.2.1.2.1 ipfrag(不再使用了) 7 2.2.1.2.2 ipq 8 2.2.1.2.3 FRAG_CB 9 2.2.1.2.4 ipfrag_skb_cb 9 2.2.1.2.5 inet_skb_parm 9 2.2.1.3 函数说明 10 2.2.1.4 ip_evictor 11 2.2.1.5 ip_find 12 2.2.1.6 ip_frag_create 12 2.2.1.7 ip_frag_intern 12 2.2.1.8 ip_frag_queue(hash, iph) 12 2.2.1.9 ip_frag_reasm 16 1 原理 1.1 为一个数据包片再次分片 为数据包分片和位数据包片再次分片之间的细微差别就在于网关处理MF比特的不同。
但一个网关为原来为分片的数据包分片时,除了末尾的数据包片,它 将其余所有分片上的MF比特都置为一,最后一片为0然而,当网关为一个非末尾的数据包片再次分片时,它会把生成的所有子分片中的MF比特全部设置为1, 因为所有这些子分片都不可能是整个数据包的末尾的数据包片 对于分片,需要拷贝IP首部和选项,以及数据而选项的拷贝要注意:根据协议标准,某些选项只应当出现在的一个数据包片中,而其他一些则必须出现在所有的数据包中 1.2 数据包重组 1.2.1 数据结构 为了使数据包的重组效率更高,用于保存数据包的数据结构必须能够做到: l 为构成某一个特定数据包的一组数据包片快速定位; l 在一组数据包片中快速插入新的数据包片; l 有效地判断一个完整的数据包是否已经全部抵达; l 具有数据包片超时机制,并且,如果在重组完成之前定时器溢出,则删除数据包片 1.2.2 互斥操作 重组程序代码使用了一个互斥信号量 1.2.3 在链表中加入一个数据包片 线性查找??? 1.2.4 溢出时的丢弃 分片列表空间以全满的情况下:丢弃对应的数据包的所有分片 1.3 测试是否组成一个完整的数据包 1.3.1 将数据包片组装成完整的数据包 1.4 数据包片链表的维护管理 为了使丢失数据包片的数据包不再浪费存储资源 ,并防止因为标示符字段的重新使用而给IP带来混乱,但已经不可能再受到剩余数据包片时,IP必须定期检查数据包片列表。
2 Linux下的实现 2.1 IP分片 如何提高分片处理的效率 2.1.1 ip_fragment(非UDP使用) 2.1.1.1 典型调用者 ip_sendà ip_fragment(skb, ip_finish_output);一般从转发来 ip_queue_xmit2à ip_fragment(skb, skb->dst->output)一般从TCP来 /* * This IP datagram is too large to be sent in one piece. Break it up into * smaller pieces (each of size equal to IP header plus * a block of the data of the original IP data part) that will yet fit in a * single device frame, and queue such a frame for sending. * * Yes this is inefficient, feel free to submit a quicker one. */ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) { struct iphdr *iph; unsigned char *raw; unsigned char *ptr; struct net_device *dev; struct sk_buff *skb2; unsigned int mtu, hlen, left, len; int offset; int not_last_frag; struct rtable *rt = (struct rtable*)skb->dst; int err = 0; dev = rt->u.dst.dev;出口路由设备 /* * Point into the IP datagram header. */ raw = skb->nh.raw; iph = (struct iphdr*)raw;取IP头 /* * Setup starting values. */ hlen = iph->ihl * 4; left = ntohs(iph->tot_len) - hlen; /* Space per frame */IP包总长度减去IP头长度――需要分片的数据长度 mtu = rt->u.dst.pmtu - hlen; /* Size of data space */MTU减去IP头长度――除去IP头的分片长度 ptr = raw + hlen; /* Where to start from */取数据区指针 /* * Fragment the datagram. */ offset = (ntohs(iph->frag_off) & IP_OFFSET) << 3;取出偏移位(13位),并乘8算出总字节数――算出该包的偏移字节数 not_last_frag = iph->frag_off & htons(IP_MF);取出MF位(第14位) /* * Keep copying data until we run out. */ while(left > 0) { len = left; /* IF: it doesn't fit, use 'mtu' - the data space left */ if (len > mtu) len = mtu; /* IF: we are not sending upto and including the packet end then align the next start on an eight byte boundary */ if (len < left) { len &= ~7;取8字节的整数倍 } /* * Allocate buffer. */ if ((skb2 = alloc_skb(len+hlen+dev->hard_header_len+15,GFP_ATOMIC)) == NULL) { 分片长+IP头长+帧头长 NETDEBUG(printk(KERN_INFO "IP: frag: no memory for new fragment!\n")); err = -ENOMEM; goto fail; } /* * Set up data on packet */ 填充分片 skb2->pkt_type = skb->pkt_type; skb2->priority = skb->priority; skb_reserve(skb2, (dev->hard_header_len+15)&~15); skb_put(skb2, len + hlen); skb2->nh.raw = skb2->data; 网络层 skb2->h.raw = skb2->data + hlen;传输层 /* * Charge the memory for the fragment to any owner * it might possess */ if (skb->sk) skb_set_owner_w(skb2, skb->sk); skb2->dst = dst_clone(skb->dst); 目的地址 skb2->dev = skb->dev; 出口设备 /* * Copy the packet header into the new buffer. */ memcpy(skb2->nh.raw, raw, hlen); 拷贝IP头 /* * Copy a block of the IP datagram. */ memcpy(skb2->h.raw, ptr, len); 拷贝数据包(只有分片长度MTU大小) left -= len; 减小总的包长度 /* * Fill in the new header fields. */ iph = skb2->nh.iph; iph->frag_off = htons((offset >> 3)); 这表明分片是从IP包的开头开始(从头开始分片) /* ANK: dirty, but effective trick. Upgrade options only if * the segment to be fragmented was THE FIRST (otherwise, * options are already fixed) and make it ONCE * on the initial skb, so that all the following fragments * will inherit fixed options. */ if (offset == 0) 表明该IP包是第一次分片要在第一片中填入一些不允许在其他分片中出现的选项 ip_options_fragment(skb); /* * Added AC : If we are fragmenting a fragment that's not the * last fragment then keep MF on each bit 多重分片 */ if (left > 0 || not_last_frag) iph->frag_off |= htons(IP_MF); 设置MF位1 ptr += len; 移动IP包数据指针 offset += len; 移动分片指针 #ifdef CONFIG_NETFILTER /* Connection association is same as pre-frag packet */ skb2。
