Linux 路由 学习笔记 之五 策略规则相关的数据结构以及ipv4策略规则的初始化

前面分析路由查找时,已经捎带提到了策略规则,本节开始就要全面分析策略规则的内容了。也分析了这么多的内核代码,基本上对一个功能模块的几个主要内容也算是比较熟悉了。对于我们开发而言,一定要重视数据结构,当我们分析新的子功能或者开发新的子功能时,一定要好好的构思数据结构,因为数据结构的好坏,某种程度上就决定了代码的好坏。

因此在开始分析策略规则的子模块时,照例需要先分析策略规则相关的数据结构。

策略规则起到什么作用呢?

添加策略规则,主要是用来和路由表一起作用,实现策略路由的功能。简而言之,就是输入或输出的数据包,通过策略规则,通过指定的路由表的路由项而把数据从相应的接口发送出去,从而实现策略路由的功能。

 

1.数据结构

 

1.1 fib_rule

该数据结构即为抽象一个策略规则,下面分析下这个数据结构

/*

策略规则对应的数据结构

*/

struct fib_rule

{

/*将策略规则链接在一起*/

struct list_head list;

/*引用计数*/

atomic_t refcnt;

/*接口的index*/

int ifindex;

/*接口的名称*/

char ifname[IFNAMSIZ];

/*mark值以及mark的掩码值*/

u32 mark;

u32 mark_mask;

/*优先级,值越小优先级越大*/

u32 pref;

u32 flags;

/*路由表的id*/

u32 table;

/*fib ruleaction规则,包括FR_ACT_TO_TBL*/

u8 action;

struct rcu_head rcu;

};

 

对于一个策略规则来说,肯定需要与其他的策略规则连接在一起,此处则是使用链表来实现的。接着还需要有引用计数以及action,指示匹配该策略规则后的下一步操作是什么;还有接口名称、接口indexmark值、路由表id(这个才是最主要的)等。

 

1.2 fib_rules_ops

该数据结构是策略规则中协议相关的操作函数的结构体,对于v4v6,其相应的处理函数会有所不同

 

/*

策略规则的操作相关的数据结构

 

*/

struct fib_rules_ops

{

/*对应的协议簇,对于ipv4AF_INET*/

int family;

/*主要是将注册到系统的fib_rules_ops链接到链表rules_ops*/

struct list_head list;

/*一个策略规则所占用的内存大小*/

int rule_size;

/*协议相关的地址的长度*/

int addr_size;

/*协议相关的action函数,即是策略规则匹配后,所调用的action函数,执行后续的操作,一般是获取到相应的路由表,查找符合要求的路由项*/

int (*action)(struct fib_rule *,

  struct flowi *, int,

  struct fib_lookup_arg *);

/*协议相关的规则匹配函数,对于策略规则的匹配,首先是通用匹配,待通用匹配完成后,则会调用该函数,进行协议相关参数(源、目的地址等)的匹配*/

int (*match)(struct fib_rule *,

 struct flowi *, int);

/*协议相关的配置函数*/

int (*configure)(struct fib_rule *,

     struct sk_buff *,

     struct nlmsghdr *,

     struct fib_rule_hdr *,

     struct nlattr **);

int (*compare)(struct fib_rule *,

   struct fib_rule_hdr *,

   struct nlattr **);

int (*fill)(struct fib_rule *, struct sk_buff *,

struct nlmsghdr *,

struct fib_rule_hdr *);

u32 (*default_pref)(void);

size_t (*nlmsg_payload)(struct fib_rule *);

/*下面两个是netlink相关的参数*/

int nlgroup;

struct nla_policy *policy;

/*链表用于将该协议簇已添加的所有fib_rule规则链接在一起*/

struct list_head *rules_list;

 

struct module *owner;

};

 

1.3 策略规则的action类型

 

/*fib ruleaction类型,FR_ACT_TO_TBL即该fib rule与路由表关联*/

enum

{

FR_ACT_UNSPEC,

FR_ACT_TO_TBL, /* Pass to fixed table */

FR_ACT_RES1,

FR_ACT_RES2,

FR_ACT_RES3,

FR_ACT_RES4,

FR_ACT_BLACKHOLE, /* Drop without notification */

FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */

FR_ACT_PROHIBIT, /* Drop with EACCES */

__FR_ACT_MAX,

};

我们一般用到的是FR_ACT_TO_TBL,即匹配后的规则,即会进入到相应的路由表,继续进行路由项的匹配。

1.4 fib4_rule

 

ipv4协议相关的fib rule结构,该结构包含了

struct fib_rule 类型的成员变量,同时增加了源ip地址、目的

ip地址、tosipv4相关的成员判断

 

struct fib4_rule

{

struct fib_rule common;

u8 dst_len;

u8 src_len;

u8 tos;

__be32 src;

__be32 srcmask;

__be32 dst;

__be32 dstmask;

#ifdef CONFIG_NET_CLS_ROUTE

u32 tclassid;

#endif

};

 

2.策略规则的初始化

对于策略规则的初始化,主要是包括两个方面

通用策略规则的初始化

协议相关的策略规则的初始化

 

2.1 通用策略规则的初始化

对于通用策略规则,主要是就是注册通知链而已。

/*

注册通知链

*/

static int __init fib_rules_init(void)

{

return register_netdevice_notifier(&fib_rules_notifier);

}

 

static struct notifier_block fib_rules_notifier = {

.notifier_call = fib_rules_event,

};

 

该通知链仅处理NETDEV_REGISTERNETDEV_UNREGISTER这两个事件通知,主要是在设备注册时,即是遍历策略规则,对于匹配的规则,则会将该策略规则的ifindex进行赋值;而当设备注销时,则会遍历策略规则,对于匹配的规则,则会将该策略规则的ifindex的值设置为-1

static int fib_rules_event(struct notifier_block *this, unsigned long event,

    void *ptr)

{

struct net_device *dev = ptr;

struct fib_rules_ops *ops;

 

ASSERT_RTNL();

rcu_read_lock();

 

switch (event) {

case NETDEV_REGISTER:

list_for_each_entry(ops, &rules_ops, list)

attach_rules(ops->rules_list, dev);

break;

 

case NETDEV_UNREGISTER:

list_for_each_entry(ops, &rules_ops, list)

detach_rules(ops->rules_list, dev);

break;

}

 

rcu_read_unlock();

 

return NOTIFY_DONE;

}

 

2.2 协议相关的策略规则的初始化

本文以ipv4为主,此处就分析ipv4相关的策略规则的的初始化

2.2.1 fib4_rules_init

这个函数主要也就是实现两个功能,增加localmaindefault3个策略规则,并添加到fib4_rules_ops.rules_list中;然后就是将fib4_rules_ops注册到系统中,添加到链表rules_ops

 

功能:ipv4协议的fib rule的初始化函数

1.分别将默认的3fib rule规则添加到全局链表fib4_rules的链尾

2.调用函数fib_rules_registeripv4对应的fib 规则的操作变量fib4_rules_ops添加

   到系统的链表rules_ops

void __init fib4_rules_init(void)

{

list_add_tail(&local_rule.common.list, &fib4_rules);

list_add_tail(&main_rule.common.list, &fib4_rules);

list_add_tail(&default_rule.common.list, &fib4_rules);

 

fib_rules_register(&fib4_rules_ops);

}

 

2.2.2 localmaindefault等默认规则的定义

默认创建3fib_rule规则,而fib rule规则添加到相应协议簇

fib_rules_opslist链表中时,是根据pref的优先级来进行添加

到,pref的值越小,而优先级越大。

而在ipv4fib rule的初始化中,首先建立了default_rulemain_rulelocal_rule

并分别添加到fib4_rules_ops.list中,因此以后添加的ipv4 fib rule规则,即使

优先级最大,也是在local_rule规则之后。

 

因此,在使用策略路由查找时,首先就会匹配local_rule规则,即进入

local路由表中进行路由匹配,其次才会匹配其他的fib rule规则

 

以下3个默认ipv4 fib rule是没有设置匹配条件的,即只要遍历到

下面3ipv4 fib rule规则,即会匹配。

 

static struct fib4_rule default_rule = {

.common = {

.refcnt = ATOMIC_INIT(2),

.pref = 0x7FFF,

.table = RT_TABLE_DEFAULT,

.action = FR_ACT_TO_TBL,

},

};

 

static struct fib4_rule main_rule = {

.common = {

.refcnt = ATOMIC_INIT(2),

.pref = 0x7FFE,

.table = RT_TABLE_MAIN,

.action = FR_ACT_TO_TBL,

},

};

 

static struct fib4_rule local_rule = {

.common = {

.refcnt = ATOMIC_INIT(2),

.table = RT_TABLE_LOCAL,

.action = FR_ACT_TO_TBL,

.flags = FIB_RULE_PERMANENT,

},

};

2.2.3 ipv4相关的fib_rule_ops的定义以及注册

ipv4对应的struct fib_rules_ops 变量,其中为ipv4 fib rulematchactionconfigurecompare、等函数指针进行赋值;规定了ipv4fib rule链表为fib4_rules

 

static struct fib_rules_ops fib4_rules_ops = {

.family = AF_INET,

.rule_size = sizeof(struct fib4_rule),

.addr_size = sizeof(u32),

.action = fib4_rule_action,

.match = fib4_rule_match,

.configure = fib4_rule_configure,

.compare = fib4_rule_compare,

.fill = fib4_rule_fill,

.default_pref = fib4_rule_default_pref,

.nlmsg_payload = fib4_rule_nlmsg_payload,

.nlgroup = RTNLGRP_IPV4_RULE,

.policy = fib4_rule_policy,

.rules_list = &fib4_rules,

.owner = THIS_MODULE,

};

 

 

既然讲到了fib_rule_ops的注册,那就分析下相应的注销与注册函数吧,这两个函数也是通用的函数,因此其定义是放在通用策略规则相关的fib_rule.c

2.2.3.1 fib_rules_register

功能:fib_rules_ops注册到全局链表rules_ops中去

1.对传入的struct fib_rules_ops变量的成员进行合理性检查包括rule_size是否符合要求,matchconfigurecompare等函数指针是否为NULL

2.只有符合1中的合理性检查后,才会将传入的struct fib_rules_ops变量添加到

    全局链表rules_ops

int fib_rules_register(struct fib_rules_ops *ops)

{

int err = -EEXIST;

struct fib_rules_ops *o;

 

if (ops->rule_size < sizeof(struct fib_rule))

return -EINVAL;

 

if (ops->match == NULL || ops->configure == NULL ||

    ops->compare == NULL || ops->fill == NULL ||

    ops->action == NULL)

return -EINVAL;

 

spin_lock(&rules_mod_lock);

/*判断全局链表rules_ops中是否存在相同协议簇的struct fib_rules_ops变量,

若存在,则不再添加,程序返回*/

list_for_each_entry(o, &rules_ops, list)

if (ops->family == o->family)

goto errout;

 

list_add_tail_rcu(&ops->list, &rules_ops);

err = 0;

errout:

spin_unlock(&rules_mod_lock);

 

return err;

}

 

2.2.3.2 fib_rules_unregister

功能:fib_rules_ops从全局链表rules_ops中删除,并删除该fib_rules_opsdrules_list链表中的所有fib rule规则(这主要是通过函数cleanup_ops实现)

 

int fib_rules_unregister(struct fib_rules_ops *ops)

{

int err = 0;

struct fib_rules_ops *o;

 

spin_lock(&rules_mod_lock);

list_for_each_entry(o, &rules_ops, list) {

if (o == ops) {

list_del_rcu(&o->list);

cleanup_ops(ops);

goto out;

}

}

 

err = -ENOENT;

out:

spin_unlock(&rules_mod_lock);

 

synchronize_rcu();

 

return err;

}

 

 

至此,将策略规则的初始化基本分析完了,后面开始分析策略规则的添加、删除、查找等功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值