//为分片确定正确的ipq结构
// 定位5元组
// 1.<id, 源ip, 目的ip, l4协议> 可通过ip报文获取
// 2.user 通过ip_defrag给出,指出重组是由谁发起的,最常见的时IP_DEFRAG_LOCAL_DELIVER,当重组的入口分包要传递给本地时
// ipq中所有分片最迟完成重组的时间为30HZ
1.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元组进行hash
unsigned int hash = ipqhashfn(id, saddr, daddr, protocol);
struct ipq *qp; read_lock(&ipfrag_lock);
//选择正确的bucket
for(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);//递增ipq的引用计数,当skb被添加到frags链表之后,会通过ipq_put递减该计数
read_unlock(&ipfrag_lock);
return qp;
}
}
read_unlock(&ipfrag_lock);
//该4元组的第一个分片,创建新的ipq
return ip_frag_create(hash, iph, user);
} //调用路径:ip_find->ip_frag_create
// 新ip分片到达时,根据4元组创建一个ipq
1.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;
} //调用路径:ip_frag_create->ip_frag_intern
// 将ipq插入到hash表中
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 = 30HZ
if (!mod_timer(&qp->timer, jiffies + sysctl_ipfrag_time))//对一个不活跃的定时器修改到期时间
atomic_inc(&qp->refcnt);//增加引用计数,表示定时器对其的引用 atomic_inc(&qp->refcnt);//增加引用计数,表示hash表对其的引用
if((qp->next = ipq_hash[hash]) != NULL)
qp->next->pprev = &qp->next;
ipq_hash[hash] = qp;//将ipq插入到hash表中
qp->pprev = &ipq_hash[hash];
INIT_LIST_HEAD(&qp->lru_list);//将新加入的ipq加入到lru尾
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表中unlink
ipq_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结构
}

网络子系统54_ip协议分片重组_定位ipq的更多相关文章

  1. 网络子系统55_ip协议分片重组_加入ipq

    //ip分片加入到正确的ipq结构 //调用路径:ip_defrag->ip_frag_queue // 处理过程: // 1.正在被释放的ipq,不处理新加入的分片(ipq正在被释放由last ...

  2. 网络子系统53_ip协议分片重组_内存阈值

    //调用路径:ip_defrag->ip_evictor // 分片重组时,可使用内存上下限: // 1.sysctl_ipfrag_high_thresh 可用内存上限 // 2.sysctl ...

  3. 网络子系统42_ip协议处理函数_数据帧的接收

    //向协议栈注册l3处理函数 1.1 void dev_add_pack(struct packet_type *pt) { int hash; //ptype_all ptype_base共用一把锁 ...

  4. 网络子系统48_ip协议数据帧的发送

    //ip协议与l4协议接口,l4通过此接口向下l3传递数据帧 //函数主要任务: // 1.通过路由子系统路由封包 // 2.填充l3报头 // 3.ip分片 // 4.计算校验和 // 5.衔接邻居 ...

  5. 网络子系统45_ip协议tos处理

    //ip报头tos字段,一个字节 // 二进制位:[0 1 2] [3] [4] [5] [6] [7] // 1.[0 1 2] 表示优先级: // 000 路由 // 001 优先级 // 010 ...

  6. 网络子系统46_ip协议数据帧的转发

    //调用路径ip_rcv->ip_rcv_finish->dst_input->(skb->dst->input) //ip_forward以回调函数的形式,保存在skb ...

  7. Linux 网络子系统之网络协议接口层(一)

    Linux 网络设备驱动之网络协议接口层介绍. 网络协议接口层最主要的功能是给上层协议提供透明的数据包发送和接收接口. 当上层ARP或IP需要发送数据包时,它将调用网络协议接口层的dev_queue_ ...

  8. Linux内核笔记--网络子系统初探

    内核版本:linux-2.6.11 本文对Linux网络子系统的收发包的流程进行一个大致梳理,以流水账的形式记录从应用层write一个socket开始到这些数据被应用层read出来的这个过程中linu ...

  9. IP分片重组的分析和常见碎片攻击 v0.2

    IP分片重组的分析和常见碎片攻击 v0.2http://www.nsfocus.net/index.php?act=magazine&do=view&mid=584 作者:yawl ( ...

随机推荐

  1. UVa 11235 (RMQ) Frequent values

    范围最值问题,O(nlogn)的预处理,O(1)的查询. 这个题就是先对这些数列进行游程编码,重复的元素只记录下重复的次数. 对于所查询的[L, R]如果它完全覆盖了某些连续的重复片段,那么查询的就是 ...

  2. HDU 1397 Goldbach's Conjecture【素数打表】

    题意:给出n,问满足a+b=n且a,b都为素数的有多少对 将素数打表,再枚举 #include<iostream> #include<cstdio> #include<c ...

  3. 移动开发之浅析cocos2d-x的中文支持问题

    题记:这阵子一直在学习cocos2d-x,其跨平台的特性确实让人舒爽,引擎的框架概念也很成熟,虽然相应的第三方工具略显单薄,但也无愧是一件移动开发的利器啊,有兴趣的朋友有时间就多了解吧. 使用引擎的过 ...

  4. Android启动activity的4种模式(standard、singleTop、singleTask、singleINstance)

    在AndroidManifest.xml中配置activity时,android:launchMode属性会指定启动activity的模式,有四种: standard singleTop single ...

  5. CKEditor如何统计文字数量

    今天在修改v5后台的比赛系统时,发现文本框需要限制输入字数.我们这个系统用的是3.6.3版本的,前台代码是这样的 <script> //编辑器 CKEDITOR.replace('matc ...

  6. Linux下GPIO驱动

    编写驱动程序,首先要了解是什么类型的设备.linux下的设备分为三类,分别为:字符设备,块设备和网络设备.字符设备类型是根据是否以字符流为数据的交换方式,大部分设备都是字符设备,如键盘,串口等,块设备 ...

  7. Android下载速度计算

    long startTime = System.currentTimeMillis(); // 开始下载时获取开始时间 long curTime = System.currentTimeMillis( ...

  8. Selenium IDE验证点

    Selenium IDE验证点 我们还开发了测试用例需要检查一个Web页面的属性.这需要维护和验证命令.有两种方法可以验证点到任何脚本 插入记录模式中的任何验证点单击“右键”元素,并选择“Show a ...

  9. ARM指令协处理器处理指令

    ARM支持16个协处理器,在程序执行过程中,每个协处理器忽略属于ARM处理器和其他协处理器指令,当一个协处理器硬件不能执行属于她的协处理器指令时,就会产生一个未定义的异常中断,在异常中断处理程序中,可 ...

  10. 利用原生JavaScript获取样式的方式小结

    来源:http://www.ido321.com/930.html ps:是获取样式,不是设置样式.若没有给元素设置样式值,则返回浏览器给予的默认值.(论坛整理) 1.element.style:只能 ...