规则的添加
在规则初始化时,会注册添加函数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)
{
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;
//根据应用层传递的协议类型family af_inet ,找到相应的fib_rules_ops变量
/*/ipv4对应的是 fib4_rules_ops
根据协议簇 在链表rules_ops中查找符合要求的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;
err = validate_rulemsg(frh, tb, ops);//有效性检查,针对源IP和目的IP
if (err < 0)
goto errout;
rule = kzalloc(ops->rule_size, GFP_KERNEL);//分配新的fib_rule缓存
if (rule == NULL) {
err = -ENOMEM;
goto errout;
}
rule->fr_net = net;//增加rule->net的引用计数
rule->pref = tb[FRA_PRIORITY] ? nla_get_u32(tb[FRA_PRIORITY])
: fib_default_rule_pref(ops);//设置优先级
if (tb[FRA_IIFNAME]) {
struct net_device *dev;
rule->iifindex = -1;//入接口index
nla_strlcpy(rule->iifname, tb[FRA_IIFNAME], IFNAMSIZ);
dev = __dev_get_by_name(net, rule->iifname);//通过接口名找dev
if (dev)
rule->iifindex = dev->ifindex;//将dev的index赋值给rule接口index
}
if (tb[FRA_OIFNAME]) {
struct net_device *dev;
rule->oifindex = -1;//和入接口一样 设置
nla_strlcpy(rule->oifname, tb[FRA_OIFNAME], IFNAMSIZ);
dev = __dev_get_by_name(net, rule->oifname);
if (dev)
rule->oifindex = dev->ifindex;
}
if (tb[FRA_FWMARK]) {
rule->mark = nla_get_u32(tb[FRA_FWMARK]);//mark值
if (rule->mark)//mark值
/* compatibility: if the mark value is non-zero all bits
* are compared unless a mask is explicitly specified.
*/
rule->mark_mask = 0xFFFFFFFF;//默认 mark掩码值
}
if (tb[FRA_FWMASK])
rule->mark_mask = nla_get_u32(tb[FRA_FWMASK]);
if (tb[FRA_TUN_ID])
rule->tun_id = nla_get_be64(tb[FRA_TUN_ID]);
//设置规则action,table id,实现规则与路由表的关联
rule->action = frh->action;
rule->flags = frh->flags;
rule->table = frh_get_table(frh, tb);
if (tb[FRA_SUPPRESS_PREFIXLEN])
rule->suppress_prefixlen = nla_get_u32(tb[FRA_SUPPRESS_PREFIXLEN]);
else
rule->suppress_prefixlen = -1;
if (tb[FRA_SUPPRESS_IFGROUP])
rule->suppress_ifgroup = nla_get_u32(tb[FRA_SUPPRESS_IFGROUP]);
else
rule->suppress_ifgroup = -1;
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) {
RCU_INIT_POINTER(rule->ctarget, r);
break;
}
}
if (rcu_dereference_protected(rule->ctarget, 1) == NULL)
unresolved = 1;
} else if (rule->action == FR_ACT_GOTO)
goto errout_free;
//调用协议对应的configure函数,这里就是协议相关的添加
err = ops->configure(rule, skb, frh, tb);
//ipv4的配置函数,根据应用层传参,设置fib4_rule变量参数:源IP、目的IP、掩码、路由表ID、tos
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 (last) //根据优先级,将fib_rule添到rules_list链表中
list_add_rcu(&rule->list, &last->list);
else
list_add_rcu(&rule->list, &ops->rules_list);
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 &&
rtnl_dereference(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++;
if (rule->tun_id)
ip_tunnel_need_metadata();
//通过netlink通知其他进程
notify_rule_change(RTM_NEWRULE, rule, ops, nlh, NETLINK_CB(skb).portid);
flush_route_cache(ops);//刷新路由缓存
rules_ops_put(ops);
return 0;
errout_free:
kfree(rule);
errout:
rules_ops_put(ops);
return err;
}
策略路由查找
策略规则的查找函数fib_rules_lookup
功能:
(1)遍历rules_list链表;
(2)调用fib_rule_match进行规则匹配
(3)调用函数指针action,进行路由表项的查找;
(4)将arg->rule指向该规则的首地址。
int fib_rules_lookup(struct fib_rules_ops *ops, struct flowi *fl,
int flags, struct fib_lookup_arg *arg)
{
struct fib_rule *rule;
int err;
rcu_read_lock();
list_for_each_entry_rcu(rule, &ops->rules_list, list) {//遍历ops->rules_list的所有fib_rule节点;比如 ipv4-rules
jumped:
pr_info("family:%d tableid:%d pref:0X%x src:%pI4--->dst:%pI4\n", ops->family, rule->table, rule->pref,
&(fl->u.ip4.saddr), &(fl->u.ip4.daddr));
pr_info("rule iiindex:%d oifindex:%d mark:0x%x mark_mask:0x%x flags:%d targer:%d action:%d\n",
rule->iifindex, rule->oifindex, rule->mark, rule->mark_mask, rule->flags, rule->target,
rule->action);
/*对于传入的fib_rule变量与传入的路由查找键值flowi变量比较
//判断输入接口index是否相等;mark是否相等
/源IP、目的IP是否相等
//如果tos 非0; tos是否相等
//协议规则的匹配,ipv4调用fib4_rule_match
*/
if (!fib_rule_match(rule, ops, fl, flags)) //规则匹配
continue;
pr_info("family:%d tableid:%d pref:0X%x action:%d\n", ops->family, rule->table, rule->pref, rule->action);
if (rule->action == FR_ACT_GOTO) {
struct fib_rule *target;
target = rcu_dereference(rule->ctarget);
if (target == NULL) {
continue;
} else {
rule = target;
goto jumped;
}
} else if (rule->action == FR_ACT_NOP)
continue;
else
err = ops->action(rule, fl, flags, arg);//fib4_rule_action 查找对应的路由表项
//获取到相应的路由表 以及 查找符合要求的路由项;其逻辑/是/根据id值,获取相应的路由表,然后在tb 中查找fib 结果
pr_info("action:%d err:%d \n", rule->action, err);
if (!err && ops->suppress && ops->suppress(rule, arg))
continue;
if (err != -EAGAIN) {
struct fib_result * res = arg->result;
struct fib_info *pfib = res->fi;
pr_info("prefixlen:%d nh_sel:%d type:%d scope:%d tb_id:%d prefsrc:%pI4 priority:%d oifname:%s nexthop:%pI4 \n",
res->prefixlen, res->nh_sel, res->type, res->scope, res->table->tb_id,
&pfib->fib_prefsrc, pfib->fib_priority, pfib->fib_nh[0].nh_dev->name, &pfib->fib_nh[0].nh_gw);
if ((arg->flags & FIB_LOOKUP_NOREF) ||
likely(atomic_inc_not_zero(&rule->refcnt))) {
arg->rule = rule;
goto out;
}
break;
}
}
err = -ESRCH;
out:
rcu_read_unlock();
return err;
}
EXPORT_SYMBOL_GPL(fib_rules_lookup);
http代理服务器(3-4-7层代理)-网络事件库公共组件、内核kernel驱动 摄像头驱动 tcpip网络协议栈、netfilter、bridge 好像看过!!!!
但行好事 莫问前程
--身高体重180的胖子