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

来源:互联网 发布:杭州动漫周边淘宝店 编辑:程序博客网 时间:2024/06/04 17:45
//刷新路由缓存//参数://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);//将冲突链表保存在本地,置链表nullrth = 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;//引用计数为0if (!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 longnow;struct rtable *cand, **candp;u32 min_score;intchain_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;}