linux内核 路由fib表之删除

2.2.4 路由删除
        应用层通过SIOCDELRT删除路由项,一般调用ip_rt_ioctl或者inet_rtm_delroute。
        这里我们通过inet_rtm_delroute来学习。
static int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{
    struct net *net = sock_net(skb->sk);
    struct fib_config cfg;
    struct fib_table *tb;
    int err;
    //将netlink传递的用户空间信息输出到config中
    err = rtm_to_fib_config(net, skb, nlh, &cfg);
    if (err < 0)
        goto errout;

    tb = fib_get_table(net, cfg.fc_table);//找到要对应的路由表
    if (tb == NULL) {
        err = -ESRCH;
        goto errout;
    }

    err = tb->tb_delete(tb, &cfg);//调用fn_hash_delete删除表项
errout:
    return err;
}
2.2.4.1路由表项删除
        接下来,学习fn_hash_delete函数
功能:
        1)根据目的地址,找对应的fn_zone->fib_node->fib_alias
        2)遍历fib_alias链表找到精确要删除的路由表项
        3)删除并释放fib_alias->fib_node
        4)刷新路由缓存,通知用户空间。

程序流程图:


static int fn_hash_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)
    {
            DEBUG_V4Route("%s-->can't find fn_zone dst_len:%d\n",__FUNCTION__,cfg->fc_dst_len);
            return -ESRCH;
    }
        

    key = 0;
    if (cfg->fc_dst) {
        if (cfg->fc_dst & ~FZ_MASK(fz))
            return -EINVAL;
        key = fz_key(cfg->fc_dst, fz);//根据目的地址和fn_zone获得key值
    }

    f = fib_find_node(fz, key);//根据key和fn_zone找到fib_node

    if (!f)
        fa = NULL;
    else
        fa = fib_find_alias(&f->fn_alias, cfg->fc_tos, 0);//根据tos、优先级找到fib_alias
    if (!fa)
    {
            DEBUG_V4Route("%s-->Can't find fib_alias fa_tos:%d\n",__FUNCTION__,cfg->fc_tos);
            return -ESRCH;
    }
        

    fa_to_delete = NULL;//遍历余下的fib_alias,精确匹配要删除的路由表项
    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) {
                DEBUG_V4Route("%s-->Find fib_alias to delete fa_type:%d fa_scope:%d fib_protocol:%d\n",__FUNCTION__,\
                                                    fa->fa_type,fa->fa_scope,fi->fib_protocol);
            fa_to_delete = fa;
            break;
        }
    }

    if (fa_to_delete) {
        int kill_fn;

        fa = fa_to_delete;
        
        kill_fn = 0;
        write_lock_bh(&fib_hash_lock);
        list_del(&fa->fa_list);//从链表中删除该fib_alias
        if (list_empty(&f->fn_alias)) {//若fib_alias链表为空,则删除对应的fib_node节点
            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);
        fn_free_alias(fa, f);//释放该fib_alias
        if (kill_fn) {
            fn_free_node(f);//若fib_alias链表为空,释放对应的fib_node
            fz->fz_nent--;
        }
        //通知用户空间
        rtmsg_fib(RTM_DELROUTE, key, fa, cfg->fc_dst_len,
              tb->tb_id, &cfg->fc_nlinfo, 0);
        return 0;
    }
        DEBUG_V4Route("%s-->Cant't find fib_alias\n",__FUNCTION__);
    return -ESRCH;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值