linux内核 策略路由之添加

4.3策略规则的添加
        对于策略规则的添加,也可以抽象出通用规则接口函数,然后根据传参进入协议相关的策略规则的接口函数;
4.3.1 通用规则的添加
        在规则初始化时,会注册添加函数fib_nl_newrule
        rtnl_register(PF_UNSPEC, RTM_NEWRULE, fib_nl_newrule, NULL);
        接下来,分析创建规则fib_nl_newrule函数
功能:
        (1)根据应用层传递的协议类型,找到相应的fib_rules_ops变量;
        (2)解析应用层传入的数据;
        (3)针对源IP和目的IP,有效性检查
        (4)分配新的fib_rule缓存,并对优先级、接口index、接口名称、mark值、action等赋值;
        (5)调用协议对应的configure函数,对fib_rule的源IP、目的IP、掩码、tos进行配置;
        (6)将fib_rule添加到rule_lists中,并通过netlink通知其他进程。
static int fib_nl_newrule(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, *r, *last = NULL;
    struct nlattr *tb[FRA_MAX+1];
    int err = -EINVAL, unresolved = 0;

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

    //根据应用层传递的协议类型,找到相应的fib_rules_ops变量
    //ipv4对应的是fib4_rules_ops
    ops = lookup_rules_ops(net, frh->family);
    if (ops == NULL) {
        err = -EAFNOSUPPORT;
        goto errout;
    }
    //解析应用层传入的数据nlh,放入tb中。
    err = nlmsg_parse(nlh, sizeof(*frh), tb, FRA_MAX, ops->policy);
    if (err < 0)
        goto errout;

    //有效性检查,针对源IP和目的IP
    err = validate_rulemsg(frh, tb, ops);
    if (err < 0)
        goto errout;

    //分配新的fib_rule缓存
    rule = kzalloc(ops->rule_size, GFP_KERNEL);
    if (rule == NULL) {
        err = -ENOMEM;
        goto errout;
    }
    rule->fr_net = hold_net(net);//增加rule->net的引用计数

    if (tb[FRA_PRIORITY])
        rule->pref = nla_get_u32(tb[FRA_PRIORITY]);//设置优先级

    if (tb[FRA_IFNAME]) {
        struct net_device *dev;

        rule->ifindex = -1;//接口index
        nla_strlcpy(rule->ifname, tb[FRA_IFNAME], IFNAMSIZ);//接口名称
        dev = __dev_get_by_name(net, rule->ifname);//通过接口名找dev
        if (dev)
            rule->ifindex = dev->ifindex;//将dev的index赋值给rule接口index
    }

    if (tb[FRA_FWMARK]) {
        rule->mark = nla_get_u32(tb[FRA_FWMARK]);//mark值
        if (rule->mark)
            /* compatibility: if the mark value is non-zero all bits
             * are compared unless a mask is explicitly specified.
             */
            rule->mark_mask = 0xFFFFFFFF;
    }

    if (tb[FRA_FWMASK])
        rule->mark_mask = nla_get_u32(tb[FRA_FWMASK]);//mark掩码值

    //设置规则action,table id,实现规则与路由表的关联
    rule->action = frh->action;
    rule->flags = frh->flags;
    rule->table = frh_get_table(frh, tb);

    //获取默认优先级为除0外的最高优先级  ??怎么理解
    if (!rule->pref && ops->default_pref)
        rule->pref = ops->default_pref(ops);

    err = -EINVAL;
    if (tb[FRA_GOTO]) {
        if (rule->action != FR_ACT_GOTO)
            goto errout_free;

        rule->target = nla_get_u32(tb[FRA_GOTO]);
        /* Backward jumps are prohibited to avoid endless loops */
        if (rule->target <= rule->pref)
            goto errout_free;

        list_for_each_entry(r, &ops->rules_list, list) {
            if (r->pref == rule->target) {
                rule->ctarget = r;
                break;
            }
        }

        if (rule->ctarget == NULL)
            unresolved = 1;
    } else if (rule->action == FR_ACT_GOTO)
        goto errout_free;

    //调用协议对应的configure函数,这里就是协议相关的添加
    err = ops->configure(rule, skb, frh, tb);
    if (err < 0)
        goto errout_free;

    //找到第一个pref比新创建的fib_rule的pref值大的 fib_rule
    //然后将新创建的fib_rule添到该规则之前
    //若没有找到,则添加到已有规则链表之后
    list_for_each_entry(r, &ops->rules_list, list) {
        if (r->pref > rule->pref)
            break;
        last = r;
    }

    fib_rule_get(rule);//增加fib_rule的引用计数

    if (ops->unresolved_rules) {
        /*
         * There are unresolved goto rules in the list, check if
         * any of them are pointing to this new rule.
         */
        list_for_each_entry(r, &ops->rules_list, list) {
            if (r->action == FR_ACT_GOTO &&
                r->target == rule->pref) {
                BUG_ON(r->ctarget != NULL);
                rcu_assign_pointer(r->ctarget, rule);
                if (--ops->unresolved_rules == 0)
                    break;
            }
        }
    }

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

    if (unresolved)
        ops->unresolved_rules++;
    //根据优先级,将fib_rule添到rules_list链表中
    if (last)
        list_add_rcu(&rule->list, &last->list);
    else
        list_add_rcu(&rule->list, &ops->rules_list);

    //通过netlink通知其他进程
    notify_rule_change(RTM_NEWRULE, rule, ops, nlh, NETLINK_CB(skb).pid);
    flush_route_cache(ops);//刷新路由缓存
    rules_ops_put(ops);//将一个特定模块module的引用计数减1
    return 0;

errout_free:
    release_net(rule->fr_net);//减少rule->net的引用计数
    kfree(rule);
errout:
    rules_ops_put(ops);
    return err;
}

4.3.1.1 查找fib_rule对应的ops
功能

        根据协议簇 在链表rules_ops中查找符合要求的fib_rules_ops类型的变量;
        对于IPV4,变量为fib4_rules_ops。
static struct fib_rules_ops *lookup_rules_ops(struct net *net, int family)
{
    struct fib_rules_ops *ops;

    rcu_read_lock();
    list_for_each_entry_rcu(ops, &net->rules_ops, list) {
        if (ops->family == family) {
            if (!try_module_get(ops->owner))
                ops = NULL;
            rcu_read_unlock();
            return ops;
        }
    }
    rcu_read_unlock();

    return NULL;
}

4.3.2 协议相关规则的配置
        此处以IPV4协议类型为例,

功能:

        ipv4的配置函数,根据应用层传参,设置fib4_rule变量参数:源IP、目的IP、掩码、路由表ID、tos;

static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
                   struct fib_rule_hdr *frh,
                   struct nlattr **tb)//    tb 添加策略规则的可选属性
{
    struct net *net = sock_net(skb->sk);
    int err = -EINVAL;
    struct fib4_rule *rule4 = (struct fib4_rule *) rule;

    if (frh->tos & ~IPTOS_TOS_MASK)
        goto errout;

    //若应用层没有设置路由表ID,则创建一个新的,并赋值给rule->table
    if (rule->table == RT_TABLE_UNSPEC) {
        if (rule->action == FR_ACT_TO_TBL) {
            struct fib_table *table;

            table = fib_empty_table(net);
            if (table == NULL) {
                err = -ENOBUFS;
                goto errout;
            }

            rule->table = table->tb_id;
        }
    }

    if (frh->src_len)
        rule4->src = nla_get_be32(tb[FRA_SRC]);

    if (frh->dst_len)
        rule4->dst = nla_get_be32(tb[FRA_DST]);

#ifdef CONFIG_NET_CLS_ROUTE
    if (tb[FRA_FLOW])
        rule4->tclassid = nla_get_u32(tb[FRA_FLOW]);
#endif

    rule4->src_len = frh->src_len;
    rule4->srcmask = inet_make_mask(rule4->src_len);
    rule4->dst_len = frh->dst_len;
    rule4->dstmask = inet_make_mask(rule4->dst_len);
    rule4->tos = frh->tos;

    err = 0;
errout:
    return err;
}

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