声明:本文为原创
#####请转贴时保留以下内容######
作者:GTT
请提出宝贵意见Mail:mtloveft@hotmail.com
Linux Version:2.6.33
提示:本文是介绍linux 如何实现ipv4路由!
删除一条路由表项是通过fib_table_delete方法的,跟路由表项追加相比,
这个方法只有删除一个目的,所以程序就简单很多。
source code 如下
int fib_table_delete(struct fib_table *tb, struct fib_config *cfg) { struct fn_hash *table = (struct fn_hash *)tb->tb_data; struct fib_node *f; struct fib_alias *fa, *fa_to_delete; struct fn_zone *fz; __be32 key;
if (cfg->fc_dst_len > 32) return -EINVAL;//判断网络掩码长度 //取得对应网络掩码长度的fn_zone,不存在则退出。 if ((fz = table->fn_zones[cfg->fc_dst_len]) == NULL) return -ESRCH;
key = 0; if (cfg->fc_dst) { if (cfg->fc_dst & ~FZ_MASK(fz)) return -EINVAL; key = fz_key(cfg->fc_dst, fz);//根据地址和网络掩码构造搜索key
}
f = fib_find_node(fz, key);//根据上面计算的key查找fib_node if (!f) fa = NULL; else fa = fib_find_alias(&f->fn_alias, cfg->fc_tos, 0);//查找fib_alaias
if (!fa) return -ESRCH;
fa_to_delete = NULL; fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list); list_for_each_entry_continue(fa, &f->fn_alias, fa_list) { struct fib_info *fi = fa->fa_info;
if (fa->fa_tos != cfg->fc_tos) break;
if ((!cfg->fc_type || fa->fa_type == cfg->fc_type) && (cfg->fc_scope == RT_SCOPE_NOWHERE || fa->fa_scope == cfg->fc_scope) && (!cfg->fc_protocol || fi->fib_protocol == cfg->fc_protocol) && fib_nh_match(cfg, fi) == 0) { fa_to_delete = fa;//第一个合法的fib_alaias break; } }
if (fa_to_delete) { int kill_fn;
fa = fa_to_delete; rtmsg_fib(RTM_DELROUTE, key, fa, cfg->fc_dst_len, tb->tb_id, &cfg->fc_nlinfo, 0);//发送Netlink广播
kill_fn = 0; write_lock_bh(&fib_hash_lock); list_del(&fa->fa_list);//
if (list_empty(&f->fn_alias)) { hlist_del(&f->fn_hash);//
kill_fn = 1; } fib_hash_genid++; write_unlock_bh(&fib_hash_lock); //该路 由已经被用 if (fa->fa_state & FA_S_ACCESSED) rt_cache_flush(cfg->fc_nlinfo.nl_net, -1);//flush路由缓存
fn_free_alias(fa, f);//释放fib_alaias
//删除 的是最后一个fib_alias实例 if (kill_fn) { fn_free_node(f);//释放fib_node fz->fz_nent--;//路由表项数减少 } return 0; } return -ESRCH; }
|
fib_table_delete首先构造搜索key,然后用它来查找待删除的表项是否还存在。当查找到
fib_alias结构时,就删除它并通过Netlink广播通知感兴趣的子系统,如果该路由表项已经被
使用(即设置了FA_S_ACCESSED标志)则flush路由缓存表。
删除一个fib_alias实例可能删除一个fib_info实例和一个fib_node实例:
● 当一个待删除的fib_alias为相关联的fib_node实例的最后一个实例时,也删除该fib_node实例。
● 当相关联的fib_info实例的引用计数fib_treeref为空时,由于不再需要而被删除。
更具体地讲,fn_free_alias释放匹配的fib_alias实例时,调用fib_release_info接口递减与之
相关联的fib_info实例中的引用计数fib_treeref。当该引用计数为0时,从所有的hash
表中摘除该fib_info实例,设置fib_dead标志标记该fib_info实例状态为dead,在
fib_info_put中通过free_fib_info接口释放它。从hash表中也删除与该fib_info实例相关
联的下一跳信息。
阅读(856) | 评论(0) | 转发(0) |