网络子系统70_路由缓存操作

//	刷新路由缓存
//	参数:
//		delay, 刷新操作的延迟时间

//	函数主要任务:
//		1.重新计算路由刷新定时器的到期时间
//		2.如果delay=0,则立即刷新缓存
//		3.激活定时器,使用最近的刷新延迟作为到期时间
1.1 void rt_cache_flush(int delay)
{
	unsigned long now = jiffies;
	//用户态
	int user_mode = !in_softirq();

	if (delay < 0)
		delay = ip_rt_min_delay;

	spin_lock_bh(&rt_flush_lock);
	//删除之前激活的定时器
	//重新计算定时器该到期的时间
	if (del_timer(&rt_flush_timer) && delay > 0 && rt_deadline) {
		long tmo = (long)(rt_deadline - now);
		if (user_mode && tmo < ip_rt_max_delay-ip_rt_min_delay)
			tmo = 0;
		
		if (delay > tmo)
			delay = tmo;
	}
	//立即刷新路由缓存
	if (delay <= 0) {
		spin_unlock_bh(&rt_flush_lock);
		rt_run_flush(0);
		return;
	}
	//rt_deadline表示路由缓存必须被刷新的期限
	if (rt_deadline == 0)
		rt_deadline = now + ip_rt_max_delay;
	//激活缓存刷新定时器,最近到期的时间
	mod_timer(&rt_flush_timer, now+delay);
	spin_unlock_bh(&rt_flush_lock);
}
// 	刷新路由缓存
//		释放所有路由缓存

//	调用路径:rt_cache_flush->rt_run_flush
//	注:此函数同时为刷新定时器函数
1.2 static void rt_run_flush(unsigned long dummy)
{
	int i;
	struct rtable *rth, *next;
	rt_deadline = 0;

	get_random_bytes(&rt_hash_rnd, 4);
	//从缓存最后一个bucket开始遍历
	for (i = rt_hash_mask; i >= 0; i--) {
		spin_lock_bh(&rt_hash_table[i].lock);
		//将冲突链表保存在本地,置链表null
		rth = rt_hash_table[i].chain;
		if (rth)
			rt_hash_table[i].chain = NULL;
		spin_unlock_bh(&rt_hash_table[i].lock);

		for (; rth; rth = next) {
			next = rth->u.rt_next;
			//释放缓存
			rt_free(rth);
		}
	}
}
//	释放缓存
//	调用路径:rt_cache_flush->rt_run_flush->rt_free->dst_free
//	注:
//		dst->obsolete:
//			0,表示该结构有效而且可以被使用
//			2,表示该结构将被删除因而不能被使用
//		   -1,被IPsec使用
1.3 static inline void dst_free(struct dst_entry * dst)
{	
	//表示dst已经在dst_garbage_list链表上
	if (dst->obsolete > 1)
		return;
	//引用计数为0
	if (!atomic_read(&dst->__refcnt)) {
		//释放dst对l2帧头缓存,邻居项的引用
		dst = dst_destroy(dst);
		if (!dst)
			return;
	}
	//将dst加入到dst_garbage_list链表,通过垃圾回收机制进行回收
	__dst_free(dst);
}

//	插入新路由缓存
//	参数:
//		rt,新建的路由缓存
//		rp,导致创建新缓存的skb->dst
//		hash,新建缓存的hash值

//	函数主要任务:
//		1.遍历缓存,如果缓存已经被添加,则将缓存移动到bucket的链表头,退出
//		2.每次新插入路由缓存,都尝试释放一个合适的路由缓存,从而平衡路由缓存容量
//		3.绑定路由缓存到邻居子系统
//			3.1 如果绑定失败是由于邻居子系统无法分配新的邻居项
//			3.2 则对路由缓存进行同步垃圾回收
//			3.3 因为路由缓存会持有邻居项的引用,通过释放路由缓存,释放邻居项
//		4.将邻居项缓存插入到缓存链表

//	注:
//		1.当插入一个新的路由缓存时,尝试释放一个旧的路由缓存来平衡容量。
//		2.候选项:
//			2.1 引用计数=0
//			2.2 得分在同一个bucket中最小
//		3.释放条件:
//			3.1 有候选项
//			3.2 当前bucket链表长度大于平均bucket长度

//		4.ip_rt_gc_elasticity用于描述bucket的平均长度
2.1 static int rt_intern_hash(unsigned hash, struct rtable *rt, struct rtable **rp)
{
	struct rtable	*rth, **rthp;
	unsigned long	now;
	struct rtable *cand, **candp;
	u32 		min_score;
	int		chain_length;
	//当前上下文环境
	int attempts = !in_softirq();

restart:
	chain_length = 0;
	//最小的分
	min_score = ~(u32)0;
	cand = NULL;
	candp = NULL;
	now = jiffies;

	rthp = &rt_hash_table[hash].chain;
	//关下半部,获取锁
	spin_lock_bh(&rt_hash_table[hash].lock);
	while ((rth = *rthp) != NULL) {
		//该缓存已经被添加
		//移动该缓存到bucket链表头
		if (compare_keys(&rth->fl, &rt->fl)) {
			//将缓存移动到bucket链表头
			*rthp = rth->u.rt_next;
			rcu_assign_pointer(rth->u.rt_next,
					   rt_hash_table[hash].chain);
			rcu_assign_pointer(rt_hash_table[hash].chain, rth);

			rth->u.dst.__use++;
			dst_hold(&rth->u.dst);
			rth->u.dst.lastuse = now;
			spin_unlock_bh(&rt_hash_table[hash].lock);

			rt_drop(rt);
			*rp = rth;
			return 0;
		}
		//在同一个bucket中选择删除候选项
		//删除候选项只考虑引用计数=0的选项
		if (!atomic_read(&rth->u.dst.__refcnt)) {
			//按照缓存是否适合删除,给缓存评分
			u32 score = rt_score(rth);
			//寻找最小得分				
			if (score <= min_score) {
				cand = rth;
				candp = rthp;
				min_score = score;
			}
		}
		//当前冲突链的长度
		chain_length++;
		rthp = &rth->u.rt_next;
	}

	if (cand) {
		//在bucket链表超过平均长度,释放适合删除的缓存
		if (chain_length > ip_rt_gc_elasticity) {
			*candp = cand->u.rt_next;
			rt_free(cand);
		}
	}
	//绑定单播输出路由到邻居子系统
	if (rt->rt_type == RTN_UNICAST || rt->fl.iif == 0) {
		//绑定路由到邻居子系统,由邻居子系统负责完成l3->l2地址的映射
		int err = arp_bind_neighbour(&rt->u.dst);
		if (err) {
			spin_unlock_bh(&rt_hash_table[hash].lock);
			//绑定路由缓存可能会触发创建新的邻居项
			//当邻居子系统无法释放内存时,尝试释放路由缓存
			//因为路由缓存会持有邻居子系统的引用
			if (attempts-- > 0) {
				int saved_elasticity = ip_rt_gc_elasticity;
				int saved_int = ip_rt_gc_min_interval;
				ip_rt_gc_elasticity	= 1;
				ip_rt_gc_min_interval	= 0;
				//同步回收路由缓存
				rt_garbage_collect();
				ip_rt_gc_min_interval	= saved_int;
				ip_rt_gc_elasticity	= saved_elasticity;
				goto restart;
			}

			rt_drop(rt);
			return -ENOBUFS;
		}
	}
	//将路由项插入到路由缓存hash表
	rt->u.rt_next = rt_hash_table[hash].chain;
	rt_hash_table[hash].chain = rt;
	spin_unlock_bh(&rt_hash_table[hash].lock);
	*rp = rt;
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值