FIB(Forward Information Base) 转发信息库
inet_init()->ip_init()->ip_rt_init()->
ipv4_dst_ops.kmem_cachep
=
kmem_cache_create("ip_dst_cache", sizeof(
struct rtable), 0,
rtable结构高速缓存的创建
SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
rt_hash_table = (struct
rt_hash_bucket
*)
路由缓存的hash表创建
alloc_large_system_hash("IP route cache",
sizeof(struct rt_hash_bucket),
rhash_entries,
(totalram_pages >= 128 * 1024) ?
15 : 17,
0,
&rt_hash_log,
&rt_hash_mask,
rhash_entries ? 0 : 512 * 1024);
memset(rt_hash_table, 0, (rt_hash_mask + 1) * sizeof(struct rt_hash_bucket));
ip_fib_init()->
注册与路由相关的rtnetlink 消息以及他的处理函数,主要处理路由添加删除
rtnl_register(PF_INET, RTM_NEWROUTE, inet_rtm_newroute, NULL);
rtnl_register(PF_INET, RTM_DELROUTE, inet_rtm_delroute, NULL);
rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib);
register_pernet_subsys(&
fib_net_ops);
注册协议栈子系统,也就是路由系统。 重点--fib_net_ops
register_netdevice_notifier(&fib_netdev_notifier);
通知链注册
register_inetaddr_notifier(&fib_inetaddr_notifier);
fib_hash_init()
fib_hash_init()
该函数出现在fib_hash.c fib_trie.c两个文件中都有,系统可配置两种路由表组织算法,默认hash算法
void __init fib_hash_init(void)
{
fn_hash_kmem = kmem_cache_create("ip_fib_hash", sizeof(
struct fib_node),
fib_node高速缓存创建
0, SLAB_PANIC, NULL);
fn_alias_kmem = kmem_cache_create("ip_fib_alias", sizeof(
struct fib_alias),
fib_alias高速缓存创建
0, SLAB_PANIC, NULL);
}
主要数据结构:
struct
fib_node
{ 代表一个路由指向的子网
struct hlist_node fn_hash;
hash节点
struct list_head fn_alias;
路由别名
__be32 fn_key;
子网地址
struct fib_alias fn_embedded_alias;
内嵌的路由别名
};
struct fib_alias {
struct list_head fa_list;
struct fib_info *fa_info;
路由信息结构保存着如何处理数据包
u8 fa_tos;
TOS
u8 fa_type;
路由类型
u8 fa_scope;
路由范围
u8 fa_state;
状态标志
#ifdef CONFIG_IP_FIB_TRIE
struct rcu_head rcu;
#endif
};
fib_net_ops:
static struct pernet_operations fib_net_ops = {
.init =
fib_net_init,
.exit = fib_net_exit,
};
fib_net_init()
{
ip_fib_net_init(net);
nl_fib_lookup_init(net);
netlink初始化相关
fib_proc_init(net);
初始化proc文件系统
}
static int __net_init
ip_fib_net_init(struct net *net)
{
int err;
unsigned int i;
net->ipv4.
fib_table_hash
= kzalloc(
sizeof(struct hlist_head)*
FIB_TABLE_HASHSZ, GFP_KERNEL);
申请256大小的hash表
if (net->ipv4.fib_table_hash == NULL)
return -ENOMEM;
for (i = 0; i < FIB_TABLE_HASHSZ; i++)
INIT_HLIST_HEAD(&net->ipv4.fib_table_hash[i]);
初始化每个hash表的冲突链
err =
fib4_rules_init(net);
有了256个表,就得提一提Linux的查找路由表的规则, 也就是策略路由ip rule add/del ...
if (err < 0)
goto fail;
return 0;
fail:
kfree(net->ipv4.fib_table_hash);
return err;
}
fib4_rules_init() 有两个,如果打开多路由表的宏时,CONFIG_IP_MULTIPLE_TABLES
我们看fib_rules.c中的
int __net_init
fib4_rules_init(struct net *net)
{
int err;
struct fib_rules_ops *ops;
给ops分配空间,并以fib4_rules_ops_template初始化ops
ops = kmemdup(&fib4_rules_ops_template, sizeof(*ops), GFP_KERNEL);
if (ops == NULL)
return -ENOMEM;
INIT_LIST_HEAD(&ops->rules_list);
ops->fro_net = net;
fib_rules_register(ops);
把协议族不同的路由表规则链起来 通过list串到net的rules_ops
list_add_tail_rcu(&ops->list, &net->rules_ops);
err =
fib_default_rules_init(ops);
if (err < 0)
goto fail;
net->ipv4.rules_ops = ops;
return 0;
fail:
/* also cleans all rules already added */
fib_rules_unregister(ops);
kfree(ops);
return err;
}
static struct fib_rules_ops
fib4_rules_ops_template
= {
.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,
.flush_cache = fib4_rule_flush_cache,
.nlgroup = RTNLGRP_IPV4_RULE,
.policy = fib4_rule_policy,
.owner = THIS_MODULE,
};
fib_default_rules_init()
创建三个最基本的路由表local,main,default的规则表
static int fib_default_rules_init(struct fib_rules_ops *ops)
{
int err;
err =
fib_default_rule_add(ops, 0,
RT_TABLE_LOCAL, FIB_RULE_PERMANENT);
if (err < 0)
return err;
err = fib_default_rule_add(ops, 0x7FFE,
RT_TABLE_MAIN, 0);
if (err < 0)
return err;
err = fib_default_rule_add(ops, 0x7FFF,
RT_TABLE_DEFAULT, 0);
if (err < 0)
return err;
return 0;
}
int
fib_default_rule_add(struct fib_rules_ops *ops,u32 pref, u32 table, u32 flags)
{
struct fib_rule *r;
r = kzalloc(ops->rule_size, GFP_KERNEL);
申请fib rule结构
if (r == NULL)
return -ENOMEM;
atomic_set(&r->refcnt, 1);
r->action = FR_ACT_TO_TBL;
r->pref = pref;
r->table = table;
r->flags = flags;
r->fr_net = hold_net(ops->fro_net);
/* The lock is not required here, the list in unreacheable
* at the moment this function is called */
list_add_tail(&r->list, &ops->rules_list);
加入fib_rules_ops的rules_list中
return 0;
}
主要数据结构
路由规则函数表的结构定义
struct fib_rules_ops
{
int family; 协议栈
struct list_head list;
链入net的net->rules_ops链中
int rule_size;
规则结构长度
int addr_size;
地址长度
int unresolved_rules;
int nr_goto_rules;
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 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 fib_rule_hdr *);
u32 (*default_pref)(struct fib_rules_ops *ops);
查找优先级函数指针
size_t (*nlmsg_payload)(struct fib_rule *);
统计负载数据能力函数指针
/* Called after modifications to the rules set, must flush
* the route cache if one exists. */
void (*flush_cache)(struct fib_rules_ops *ops);
修改规则队列后,必须刷新缓存的函数指针
int nlgroup;
const struct nla_policy *policy;
struct list_head rules_list; 针对各个路由表的规则链表
struct module *owner;
struct net *fro_net; net与ops之间的关系
};
struct fib_rule
{
struct list_head list;
atomic_t refcnt;
引用计数
int ifindex;
网络设备id
char ifname[IFNAMSIZ];
用于保存网络设备名
u32 mark;
用于过滤作用
u32 mark_mask;
掩码
u32 pref;
优先级
u32 flags;
标志位
u32 table;
路由函数表id
u8 action;
动作标识
u32 target;
struct fib_rule * ctarget;
当前规则
struct rcu_head rcu;
struct net * fr_net;
net结构指针
};
上述几个结构的关系
如果没有打开CONFIG_IP_MULTIPLE_TABLES宏时,我们看fib_frontend.c
static int __net_init
fib4_rules_init(struct net *net)
{
struct fib_table *local_table, *main_table;
local_table =
fib_hash_table(RT_TABLE_LOCAL);
创建本地路由函数表
return -ENOMEM;
main_table =
fib_hash_table(RT_TABLE_MAIN);
创建主路由函数表
if (main_table == NULL)
goto fail;
hlist_add_head_rcu(&local_table->tb_hlist,
插入统一管理队列中
&
net->ipv4.fib_table_hash[TABLE_LOCAL_INDEX]);
这里就是
ip_fib_net_init中申请的那个256大小的hash表
hlist_add_head_rcu(&main_table->tb_hlist,
&net->ipv4.fib_table_hash[TABLE_MAIN_INDEX]);
return 0;
fail:
kfree(local_table);
return -ENOMEM;
}
struct fib_table *
fib_hash_table(u32 id)
{
struct
fib_table *tb;
tb = kmalloc(sizeof(
struct fib_table) + sizeof
(struct fn_hash),
这里又冒出了个两个新fib相关的结构
GFP_KERNEL);
if (tb == NULL)
return NULL;
tb->tb_id = id;
tb->tb_default = -1;
tb->tb_lookup = fn_hash_lookup;
tb->tb_insert = fn_hash_insert;
tb->tb_delete = fn_hash_delete;
tb->tb_flush = fn_hash_flush;
tb->tb_select_default = fn_hash_select_default;
tb->tb_dump = fn_hash_dump;
memset(tb->tb_data, 0, sizeof(struct fn_hash));
return tb;
}