linux内核 策略路由之添加

来源:互联网 发布:淘宝不能好评返现了 编辑:程序博客网 时间:2024/06/06 01:34
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;}

0 0
原创粉丝点击