Chinaunix首页 | 论坛 | 博客
  • 博客访问: 643817
  • 博文数量: 155
  • 博客积分: 5688
  • 博客等级: 大校
  • 技术积分: 2134
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-15 15:12
文章分类

全部博文(155)

文章存档

2011年(58)

2010年(97)

分类: LINUX

2010-10-01 22:51:45

声明:本文为原创
#####请转贴时保留以下内容######
作者GTT
本文档归属http://oldtown.cublog.cn/.转载请注明出处!
请提出宝贵意见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实例相关
联的下一跳信息。
 
 
 

阅读(2139) | 评论(0) | 转发(3) |
给主人留下些什么吧!~~