网络子系统54_ip协议分片重组_定位ipq
来源:互联网 发布:韦德数据统计 编辑:程序博客网 时间:2024/06/05 19:00
//为分片确定正确的ipq结构//通过5元组定位ipq,成功后,递增ipq引用计数,返回ipq//定位5元组 //1.<id, 源ip, 目的ip, l4协议> 可通过ip报文获取//2.user 通过ip_defrag给出,指出重组是由谁发起的,最常见的时IP_DEFRAG_LOCAL_DELIVER,当重组的入口分包要传递给本地时//ipq中所有分片最迟完成重组的时间为30HZ1.1 static inline struct ipq *ip_find(struct iphdr *iph, u32 user){//定位4元组__u16 id = iph->id;__u32 saddr = iph->saddr;__u32 daddr = iph->daddr;__u8 protocol = iph->protocol;//对4元组进行hashunsigned int hash = ipqhashfn(id, saddr, daddr, protocol);struct ipq *qp;read_lock(&ipfrag_lock);//选择正确的bucketfor(qp = ipq_hash[hash]; qp; qp = qp->next) {if(qp->id == id&& qp->saddr == saddr&& qp->daddr == daddr&& qp->protocol == protocol && qp->user == user) {atomic_inc(&qp->refcnt);read_unlock(&ipfrag_lock);return qp;}}read_unlock(&ipfrag_lock);//该4元组的第一个分片,创建新的ipqreturn ip_frag_create(hash, iph, user);}//调用路径:ip_find->ip_frag_create//新ip分片到达时,根据5元组创建一个ipq1.2 static struct ipq *ip_frag_create(unsigned hash, struct iphdr *iph, u32 user){struct ipq *qp;if ((qp = frag_alloc_queue()) == NULL)//SLAB缓存goto out_nomem;//5元组qp->protocol = iph->protocol;qp->last_in = 0;qp->id = iph->id;qp->saddr = iph->saddr;qp->daddr = iph->daddr;//重组的发起者qp->user = user;//新ipq还没有任何分片与之关联qp->len = 0;qp->meat = 0;qp->fragments = NULL;qp->iif = 0;//入口设备init_timer(&qp->timer);//定时器,当一定时间范围内,重组没有完成,则释放与之关联的内存qp->timer.data = (unsigned long) qp;qp->timer.function = ip_expire;spin_lock_init(&qp->lock);atomic_set(&qp->refcnt, 1);return ip_frag_intern(hash, qp);//将ipq插入到hash表中out_nomem:NETDEBUG(if (net_ratelimit()) printk(KERN_ERR "ip_frag_create: no memory left !\n"));return NULL;}//将ipq插入到hash表中//调用路径:ip_frag_create->ip_frag_intern//函数主要任务://1.修改定时器的到期时间,在一段时间内没有接收到新的分片,则释放所有接收到的分片。//2.将ipq插入到hash表//3.将ipq插入到lru链表1.3 static struct ipq *ip_frag_intern(unsigned int hash, struct ipq *qp_in){struct ipq *qp;write_lock(&ipfrag_lock);qp = qp_in;//sysctl_ipfrag_time = 30HZif (!mod_timer(&qp->timer, jiffies + sysctl_ipfrag_time))//ipq所有封包延迟定时器atomic_inc(&qp->refcnt);//增加引用计数,表示定时器对其的引用//表示hash表对其的引用atomic_inc(&qp->refcnt);if((qp->next = ipq_hash[hash]) != NULL)qp->next->pprev = &qp->next;ipq_hash[hash] = qp;//将ipq插入到hash表中qp->pprev = &ipq_hash[hash];//将新加入的ipq加入到lru尾INIT_LIST_HEAD(&qp->lru_list);list_add_tail(&qp->lru_list, &ipq_lru_list);ip_frag_nqueues++;write_unlock(&ipfrag_lock);return qp;}//ipq中所有分片的到期时间//接收到的ip分片不能永久的存在内存中,如果在一定时间范围内,没有为其完成重组,则需要释放所有分片占用的内存//1.删除定时器//2.从hash表中unlink//3.使用分片的入口设备向发送方发送icmp消息,告诉对方过期//4.释放ipq中的所有分片,释放ipq结构1.4 static void ip_expire(unsigned long arg){struct ipq *qp = (struct ipq *) arg;spin_lock(&qp->lock);if (qp->last_in & COMPLETE)goto out;//删除定时器,从ipq hash表中unlinkipq_kill(qp);if ((qp->last_in&FIRST_IN) && qp->fragments != NULL) {struct sk_buff *head = qp->fragments;if ((head->dev = dev_get_by_index(qp->iif)) != NULL) {icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);//发送ICMP消息dev_put(head->dev);}}out:spin_unlock(&qp->lock);ipq_put(qp, NULL);//释放与ipq关联的所有分片,释放ipq结构}