linux内核 策略路由之删除

4.5 策略规则的删除
        策略规则一般是通过应用层手动添加的,没有垃圾回收机制,只能通过手动删除操作。

功能:

        (1)根据应用层传递的协议类型,获取相对应的fib_rule_ops

        (2)对应用层传参进行解析;
        (3)遍历rule_list链表,删除匹配的fib_rule
static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
{
    struct net *net = sock_net(skb->sk);
    struct fib_rule_hdr *frh = nlmsg_data(nlh);
    struct fib_rules_ops *ops = NULL;
    struct fib_rule *rule, *tmp;
    struct nlattr *tb[FRA_MAX+1];
    int err = -EINVAL;

    if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh)))
        goto errout;

    ops = lookup_rules_ops(net, frh->family);//获取协议相关的fib_rule_ops
    if (ops == NULL) {
        err = -EAFNOSUPPORT;
        goto errout;
    }

    err = nlmsg_parse(nlh, sizeof(*frh), tb, FRA_MAX, ops->policy);//解析传参
    if (err < 0)
        goto errout;

    err = validate_rulemsg(frh, tb, ops);
    if (err < 0)
        goto errout;

    list_for_each_entry(rule, &ops->rules_list, list) {
        if (frh->action && (frh->action != rule->action))
            continue;

        if (frh->table && (frh_get_table(frh, tb) != rule->table))
            continue;

        if (tb[FRA_PRIORITY] &&
            (rule->pref != nla_get_u32(tb[FRA_PRIORITY])))
            continue;

        if (tb[FRA_IFNAME] &&
            nla_strcmp(tb[FRA_IFNAME], rule->ifname))
            continue;

        if (tb[FRA_FWMARK] &&
            (rule->mark != nla_get_u32(tb[FRA_FWMARK])))
            continue;

        if (tb[FRA_FWMASK] &&
            (rule->mark_mask != nla_get_u32(tb[FRA_FWMASK])))
            continue;

        if (!ops->compare(rule, frh, tb))
            continue;

        if (rule->flags & FIB_RULE_PERMANENT) {
            err = -EPERM;
            goto errout;
        }

        list_del_rcu(&rule->list);//删掉rule

        if (rule->action == FR_ACT_GOTO)
            ops->nr_goto_rules--;

        /*
         * Check if this rule is a target to any of them. If so,
         * disable them. As this operation is eventually very
         * expensive, it is only performed if goto rules have
         * actually been added.
         */
        if (ops->nr_goto_rules > 0) {
            list_for_each_entry(tmp, &ops->rules_list, list) {
                if (tmp->ctarget == rule) {
                    rcu_assign_pointer(tmp->ctarget, NULL);
                    ops->unresolved_rules++;
                }
            }
        }

        synchronize_rcu();
        notify_rule_change(RTM_DELRULE, rule, ops, nlh,
                   NETLINK_CB(skb).pid);
        fib_rule_put(rule);//减去引用计数,并决定是否释放该fib_rule占用的缓存
        flush_route_cache(ops);
        rules_ops_put(ops);
        return 0;
    }

    err = -ENOENT;
errout:
    rules_ops_put(ops);
    return err;
}


你可能感兴趣的:(linux,网络协议)