linux网络协议栈分析笔记12-路由2-FIB1
来源:互联网 发布:html5仿淘宝手机商城 编辑:程序博客网 时间:2024/05/29 04:00
上一章我们看到了通过fib_lookup去查找了路由信息,这一章我们就看看fib到底是什么
FIB(Forward Information Base) 转发信息库
inet_init()->ip_init()->ip_rt_init()->
register_inetaddr_notifier(&fib_inetaddr_notifier);
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_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;
}
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);
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));
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_DELROUTE, inet_rtm_delroute, NULL);rtnl_register(PF_INET, RTM_NEWROUTE, inet_rtm_newroute, NULL);
rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib);
register_netdevice_notifier(&fib_netdev_notifier); 通知链注册register_pernet_subsys(&fib_net_ops); 注册协议栈子系统,也就是路由系统。 重点--fib_net_ops
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高速缓存创建
{
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高速缓存创建
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 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
};
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,
};
.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文件系统
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);
{
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;
}
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;
}
{
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,
};
.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 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之间的关系
};
{
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结构指针
};
{
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]);
{
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;
}
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;
}
主要数据结构
struct fib_table { fib_table给路由表提供了查询路由信息的方法
struct hlist_node tb_hlist; hash节点
u32 tb_id; 标示符
int tb_default;
int (*tb_lookup)(struct fib_table *tb, const struct flowi *flp, struct fib_result *res); 查询
int (*tb_insert)(struct fib_table *, struct fib_config *); 插入
int (*tb_delete)(struct fib_table *, struct fib_config *); 删除
int (*tb_dump)(struct fib_table *table, struct sk_buff *skb, 路由转发
struct netlink_callback *cb);
int (*tb_flush)(struct fib_table *table);
void (*tb_select_default)(struct fib_table *table, 选择默认路由
const struct flowi *flp, struct fib_result *res);
unsigned char tb_data[0];
};
struct hlist_node tb_hlist; hash节点
u32 tb_id; 标示符
int tb_default;
int (*tb_lookup)(struct fib_table *tb, const struct flowi *flp, struct fib_result *res); 查询
int (*tb_insert)(struct fib_table *, struct fib_config *); 插入
int (*tb_delete)(struct fib_table *, struct fib_config *); 删除
int (*tb_dump)(struct fib_table *table, struct sk_buff *skb, 路由转发
struct netlink_callback *cb);
int (*tb_flush)(struct fib_table *table);
void (*tb_select_default)(struct fib_table *table, 选择默认路由
const struct flowi *flp, struct fib_result *res);
unsigned char tb_data[0];
};
struct fn_hash { 路由区队列结构定义
struct fn_zone *fn_zones[33]; 路由区队列
struct fn_zone *fn_zone_list; 指向第一个路由区表
};
struct fn_zone *fn_zones[33]; 路由区队列
struct fn_zone *fn_zone_list; 指向第一个路由区表
};
struct fn_zone { 路由区结构定义
struct fn_zone *fz_next; /* Next not empty zone */ 指向下一个非空路由区结构
struct hlist_head *fz_hash; /* Hash table pointer */ hash队列
int fz_nent; /* Number of entries */ 包含的路由项个数
int fz_divisor; /* Hash divisor */ hash头数量
u32 fz_hashmask; /* (fz_divisor - 1) */ hash头的掩码
#define FZ_HASHMASK(fz) ((fz)->fz_hashmask)
int fz_order; /* Zone order */ 子网掩码位数
__be32 fz_mask; 子网掩码
#define FZ_MASK(fz) ((fz)->fz_mask)
};
struct fn_zone *fz_next; /* Next not empty zone */ 指向下一个非空路由区结构
struct hlist_head *fz_hash; /* Hash table pointer */ hash队列
int fz_nent; /* Number of entries */ 包含的路由项个数
int fz_divisor; /* Hash divisor */ hash头数量
u32 fz_hashmask; /* (fz_divisor - 1) */ hash头的掩码
#define FZ_HASHMASK(fz) ((fz)->fz_hashmask)
int fz_order; /* Zone order */ 子网掩码位数
__be32 fz_mask; 子网掩码
#define FZ_MASK(fz) ((fz)->fz_mask)
};
从fib相关的初始化来看,冒出了相当多的数据结构,看都看晕了,
我们下面就从处理操作等角度来看看这些结构是如何使用,并达到什么样的路由操作目的
- linux网络协议栈分析笔记12-路由2-FIB1
- linux网络协议栈分析笔记13-路由3-FIB2
- linux网络协议栈分析笔记14-路由4-FIB3
- linux网络协议栈分析笔记11-路由1-路由缓存
- 网络层路由系统(linux网络协议栈笔记)
- linux网络协议栈(五)网络层 (2)路由基本原理
- linux网络协议栈分析笔记2-网桥1
- linux网络协议栈分析笔记3-网桥2
- 网络配置过程分析(linux网络协议栈笔记)
- linux网络协议栈(五)网络层 (4)路由表
- linux网络协议栈(五)网络层 (5)策略路由
- linux网络协议栈分析笔记1-接入部分
- linux网络协议栈分析笔记4-网桥3
- linux网络协议栈分析笔记7-VLAN的处理
- linux网络协议栈分析笔记6-IP层的处理2
- linux网络协议栈分析笔记9-arp邻居子系统2
- 《网络协议》路由协议
- 网络配置过程分析二(linux网络协议栈笔记)
- valueOf()
- OAF实现客户化查询 .
- 安装eclipse插件
- [verilog]用文件初始化ROM
- HDU1283:最简单的计算机
- linux网络协议栈分析笔记12-路由2-FIB1
- 搜索题目推荐及解题报告
- Linux Mint Debain 2013.3.4版 硬盘安装笔记
- SAP BADI的实现3-使用BADI过滤器
- 取每个分类N条数据 sql
- 陷阱,中断和异常
- JSP_SERVLET_PAGE
- 梦想之路(四):自制IOC之二
- linux网络协议栈分析笔记13-路由3-FIB2