linux网络协议栈分析笔记13-路由3-FIB2
来源:互联网 发布:百中搜优化软件 编辑:程序博客网 时间:2024/06/05 19:56
当然,我们选择路由1那章的遗留的接口进入分析
struct fib_lookup_arg arg = {
.result = res,
};
int err;
err = fib_rules_lookup(net->ipv4.rules_ops, flp, 0, &arg); 提供rules_ops进行fib rule的查找
res->r = arg.rule;
return err;
}
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) {
jumped:
if (!fib_rule_match(rule, ops, fl, flags)) 对rule类型进行match
continue;
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); 执行rule的action动作
if (err != -EAGAIN) {
fib_rule_get(rule);
arg->rule = rule;
goto out;
}
}
err = -ESRCH;
out:
rcu_read_unlock();
return err;
}
fib4_rule_match()
fib_lookup() 我们前面提到过fib初始化时,CONFIG_IP_MULTIPLE_TABLES 宏导致了两种方式的fib表初始化,
因此存在了有多路由表存在和无多路由表存在的情况,我们先看无多路由表的情况
static inline int fib_lookup(struct net *net, const struct flowi *flp,
struct fib_result *res)
{
struct fib_table *table;
table = fib_get_table(net, RT_TABLE_LOCAL); 先查LOCAL
if (!table->tb_lookup(table, flp, res))
return 0;
table = fib_get_table(net, RT_TABLE_MAIN); 再查MAIN
if (!table->tb_lookup(table, flp, res))
return 0;
return -ENETUNREACH;
}
struct fib_result *res)
{
struct fib_table *table;
table = fib_get_table(net, RT_TABLE_LOCAL); 先查LOCAL
if (!table->tb_lookup(table, flp, res))
return 0;
table = fib_get_table(net, RT_TABLE_MAIN); 再查MAIN
if (!table->tb_lookup(table, flp, res))
return 0;
return -ENETUNREACH;
}
static inline struct fib_table *fib_get_table(struct net *net, u32 id)
{
struct hlist_head *ptr;
ptr = id == RT_TABLE_LOCAL ?
&net->ipv4.fib_table_hash[TABLE_LOCAL_INDEX] :
&net->ipv4.fib_table_hash[TABLE_MAIN_INDEX];
return hlist_entry(ptr->first, struct fib_table, tb_hlist); 根据传入的id找到fib_table
}
{
struct hlist_head *ptr;
ptr = id == RT_TABLE_LOCAL ?
&net->ipv4.fib_table_hash[TABLE_LOCAL_INDEX] :
&net->ipv4.fib_table_hash[TABLE_MAIN_INDEX];
return hlist_entry(ptr->first, struct fib_table, tb_hlist); 根据传入的id找到fib_table
}
上一章的一幅图说明了这种结构
!table->tb_lookup(table, flp, res)) 即fn_hash_lookup
static int
fn_hash_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
{
int err;
struct fn_zone *fz;
struct fn_hash *t = (struct fn_hash *)tb->tb_data; 获得路由区队列
read_lock(&fib_hash_lock);
for (fz = t->fn_zone_list; fz; fz = fz->fz_next) { 扫描网络区
struct hlist_head *head;
struct hlist_node *node;
struct fib_node *f;
__be32 k = fz_key(flp->fl4_dst, fz); 取目标地址在该网络区的网络号 fl4_det&((fz)->fz_mask)
head = &fz->fz_hash[fn_hash(k, fz)]; fn_hash(k, fz)得到hash关键字 获得hash链头
hlist_for_each_entry(f, node, head, fn_hash) {
if (f->fn_key != k) 通过fn_key找到匹配的fib node节点
continue;
err = fib_semantic_match(&f->fn_alias, 进入fib semantic查找
flp, res,
fz->fz_order);
if (err <= 0)
goto out;
}
}
err = 1;
out:
read_unlock(&fib_hash_lock);
return err;
}
fn_hash_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
{
int err;
struct fn_zone *fz;
struct fn_hash *t = (struct fn_hash *)tb->tb_data; 获得路由区队列
read_lock(&fib_hash_lock);
for (fz = t->fn_zone_list; fz; fz = fz->fz_next) { 扫描网络区
struct hlist_head *head;
struct hlist_node *node;
struct fib_node *f;
__be32 k = fz_key(flp->fl4_dst, fz); 取目标地址在该网络区的网络号 fl4_det&((fz)->fz_mask)
head = &fz->fz_hash[fn_hash(k, fz)]; fn_hash(k, fz)得到hash关键字 获得hash链头
hlist_for_each_entry(f, node, head, fn_hash) {
if (f->fn_key != k) 通过fn_key找到匹配的fib node节点
continue;
err = fib_semantic_match(&f->fn_alias, 进入fib semantic查找
flp, res,
fz->fz_order);
if (err <= 0)
goto out;
}
}
err = 1;
out:
read_unlock(&fib_hash_lock);
return err;
}
int fib_semantic_match(struct list_head *head, const struct flowi *flp,
struct fib_result *res, int prefixlen) 这里head是f->fn_alias结构
{
struct fib_alias *fa;
int nh_sel = 0;
list_for_each_entry_rcu(fa, head, fa_list) {
int err;
if (fa->fa_tos &&
fa->fa_tos != flp->fl4_tos) 比较TOS
continue;
if (fa->fa_scope < flp->fl4_scope) 比较路由范围 scope
continue;
fa->fa_state |= FA_S_ACCESSED;
err = fib_props[fa->fa_type].error; 取转发类型错误码 根据错误码进行特定处理
if (err == 0) { 允许的转发类型
struct fib_info *fi = fa->fa_info;
if (fi->fib_flags & RTNH_F_DEAD) 如果该转发节点不通
continue;
switch (fa->fa_type) {
case RTN_UNICAST: 单目转发
case RTN_LOCAL: 本地转发
case RTN_BROADCAST: 广播转发
case RTN_ANYCAST: 任意转发
case RTN_MULTICAST: 多目转发
for_nexthops(fi) { 对于转发信息中的每一个转发地址 取每个fib_nh结构
if (nh->nh_flags&RTNH_F_DEAD)
continue;
if (!flp->oif || flp->oif == nh->nh_oif)
break;
}
#ifdef CONFIG_IP_ROUTE_MULTIPATH 多径路由
if (nhsel < fi->fib_nhs) {
nh_sel = nhsel;
goto out_fill_res;
}
#else
if (nhsel < 1) { 非多径路由转发地址编号必须小于1
goto out_fill_res; 跳转
}
#endif
endfor_nexthops(fi);
continue;
default:
printk(KERN_WARNING "fib_semantic_match bad type %#x\n",
fa->fa_type);
return -EINVAL;
}
}
return err;
}
return 1;
out_fill_res:
res->prefixlen = prefixlen; 填充查询结果 到了这里算是从fib中找到了路由信息
res->nh_sel = nh_sel;
res->type = fa->fa_type;
res->scope = fa->fa_scope;
res->fi = fa->fa_info;
atomic_inc(&res->fi->fib_clntref);
return 0; 成功返回
}
struct fib_result *res, int prefixlen) 这里head是f->fn_alias结构
{
struct fib_alias *fa;
int nh_sel = 0;
list_for_each_entry_rcu(fa, head, fa_list) {
int err;
if (fa->fa_tos &&
fa->fa_tos != flp->fl4_tos) 比较TOS
continue;
if (fa->fa_scope < flp->fl4_scope) 比较路由范围 scope
continue;
fa->fa_state |= FA_S_ACCESSED;
err = fib_props[fa->fa_type].error; 取转发类型错误码 根据错误码进行特定处理
if (err == 0) { 允许的转发类型
struct fib_info *fi = fa->fa_info;
if (fi->fib_flags & RTNH_F_DEAD) 如果该转发节点不通
continue;
switch (fa->fa_type) {
case RTN_UNICAST: 单目转发
case RTN_LOCAL: 本地转发
case RTN_BROADCAST: 广播转发
case RTN_ANYCAST: 任意转发
case RTN_MULTICAST: 多目转发
for_nexthops(fi) { 对于转发信息中的每一个转发地址 取每个fib_nh结构
if (nh->nh_flags&RTNH_F_DEAD)
continue;
if (!flp->oif || flp->oif == nh->nh_oif)
break;
}
#ifdef CONFIG_IP_ROUTE_MULTIPATH 多径路由
if (nhsel < fi->fib_nhs) {
nh_sel = nhsel;
goto out_fill_res;
}
#else
if (nhsel < 1) { 非多径路由转发地址编号必须小于1
goto out_fill_res; 跳转
}
#endif
endfor_nexthops(fi);
continue;
default:
printk(KERN_WARNING "fib_semantic_match bad type %#x\n",
fa->fa_type);
return -EINVAL;
}
}
return err;
}
return 1;
out_fill_res:
res->prefixlen = prefixlen; 填充查询结果 到了这里算是从fib中找到了路由信息
res->nh_sel = nh_sel;
res->type = fa->fa_type;
res->scope = fa->fa_scope;
res->fi = fa->fa_info;
atomic_inc(&res->fi->fib_clntref);
return 0; 成功返回
}
根据上面的流程,我跟踪了数据结构变量的查询过程,梳理了以下的图 当然具体每个结构的每个成员的作用,这里不再详细分析,这个都具体得深入的慢慢的研究,我们这里只梳理流程
我们再看下开启多路由表的情况
->int fib_lookup(struct net *net, struct flowi *flp, struct fib_result *res)
{struct fib_lookup_arg arg = {
.result = res,
};
int err;
err = fib_rules_lookup(net->ipv4.rules_ops, flp, 0, &arg); 提供rules_ops进行fib rule的查找
res->r = arg.rule;
return err;
}
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) {
jumped:
if (!fib_rule_match(rule, ops, fl, flags)) 对rule类型进行match
continue;
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); 执行rule的action动作
if (err != -EAGAIN) {
fib_rule_get(rule);
arg->rule = rule;
goto out;
}
}
err = -ESRCH;
out:
rcu_read_unlock();
return err;
}
这个函数又涉及了上一章的另个结构图
static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops,
struct flowi *fl, int flags)
{
int ret = 0;
if (rule->ifindex && (rule->ifindex != fl->iif)) 检测设备id
goto out;
if ((rule->mark ^ fl->mark) & rule->mark_mask) 掩码匹配
goto out;
ret = ops->match(rule, fl, flags);
out:
return (rule->flags & FIB_RULE_INVERT) ? !ret : ret;
}
struct flowi *fl, int flags)
{
int ret = 0;
if (rule->ifindex && (rule->ifindex != fl->iif)) 检测设备id
goto out;
if ((rule->mark ^ fl->mark) & rule->mark_mask) 掩码匹配
goto out;
ret = ops->match(rule, fl, flags);
out:
return (rule->flags & FIB_RULE_INVERT) ? !ret : ret;
}
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,
};
fib4_rule_match()
static int fib4_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
{
struct fib4_rule *r = (struct fib4_rule *) rule;
__be32 daddr = fl->fl4_dst;
__be32 saddr = fl->fl4_src;
if (((saddr ^ r->src) & r->srcmask) || 源地址 目的地址与路由规则进行对比
((daddr ^ r->dst) & r->dstmask))
return 0;
if (r->tos && (r->tos != fl->fl4_tos)) tos匹配
return 0;
return 1;
}
struct fib_table *fib_get_table(struct net *net, u32 id)
{
struct fib_table *tb;
struct hlist_node *node;
struct hlist_head *head;
unsigned int h;
if (id == 0)
id = RT_TABLE_MAIN;
h = id & (FIB_TABLE_HASHSZ - 1);
rcu_read_lock();
head = &net->ipv4.fib_table_hash[h]; 这里的hash table就是那个256大小的hash表
{
struct fib4_rule *r = (struct fib4_rule *) rule;
__be32 daddr = fl->fl4_dst;
__be32 saddr = fl->fl4_src;
if (((saddr ^ r->src) & r->srcmask) || 源地址 目的地址与路由规则进行对比
((daddr ^ r->dst) & r->dstmask))
return 0;
if (r->tos && (r->tos != fl->fl4_tos)) tos匹配
return 0;
return 1;
}
static int fib4_rule_action(struct fib_rule *rule, struct flowi *flp,
int flags, struct fib_lookup_arg *arg)
{
int err = -EAGAIN;
struct fib_table *tbl;
switch (rule->action) { 检查action标识码
case FR_ACT_TO_TBL:
break;
case FR_ACT_UNREACHABLE:
err = -ENETUNREACH;
goto errout;
case FR_ACT_PROHIBIT:
err = -EACCES;
goto errout;
case FR_ACT_BLACKHOLE:
default:
err = -EINVAL;
goto errout;
}
if ((tbl = fib_get_table(rule->fr_net, rule->table)) == NULL) 查找路由表函数
goto errout;
err = tbl->tb_lookup(tbl, flp, (struct fib_result *) arg->result); 使用路由表函数记性查询
if (err > 0)
err = -EAGAIN;
errout:
return err;
}
int flags, struct fib_lookup_arg *arg)
{
int err = -EAGAIN;
struct fib_table *tbl;
switch (rule->action) { 检查action标识码
case FR_ACT_TO_TBL:
break;
case FR_ACT_UNREACHABLE:
err = -ENETUNREACH;
goto errout;
case FR_ACT_PROHIBIT:
err = -EACCES;
goto errout;
case FR_ACT_BLACKHOLE:
default:
err = -EINVAL;
goto errout;
}
if ((tbl = fib_get_table(rule->fr_net, rule->table)) == NULL) 查找路由表函数
goto errout;
err = tbl->tb_lookup(tbl, flp, (struct fib_result *) arg->result); 使用路由表函数记性查询
if (err > 0)
err = -EAGAIN;
errout:
return err;
}
struct fib_table *fib_get_table(struct net *net, u32 id)
{
struct fib_table *tb;
struct hlist_node *node;
struct hlist_head *head;
unsigned int h;
if (id == 0)
id = RT_TABLE_MAIN;
h = id & (FIB_TABLE_HASHSZ - 1);
rcu_read_lock();
head = &net->ipv4.fib_table_hash[h]; 这里的hash table就是那个256大小的hash表
其中的table是通过fib_new_table创建
hlist_for_each_entry_rcu(tb, node, head, tb_hlist) {
if (tb->tb_id == id) {
rcu_read_unlock();
return tb;
}
}
rcu_read_unlock();
return NULL;
}
hlist_for_each_entry_rcu(tb, node, head, tb_hlist) {
if (tb->tb_id == id) {
rcu_read_unlock();
return tb;
}
}
rcu_read_unlock();
return NULL;
}
tbl->tb_lookup 这个就是注册的tb的lookup函数,和本文上述无开启多路由表的情况是一样的了
- linux网络协议栈分析笔记13-路由3-FIB2
- linux网络协议栈分析笔记12-路由2-FIB1
- linux网络协议栈分析笔记14-路由4-FIB3
- linux网络协议栈分析笔记11-路由1-路由缓存
- 网络层路由系统(linux网络协议栈笔记)
- linux网络协议栈分析笔记3-网桥2
- linux网络协议栈分析笔记4-网桥3
- 网络配置过程分析(linux网络协议栈笔记)
- linux网络协议栈(五)网络层 (2)路由基本原理
- linux网络协议栈(五)网络层 (4)路由表
- linux网络协议栈(五)网络层 (5)策略路由
- linux网络协议栈分析笔记1-接入部分
- linux网络协议栈分析笔记2-网桥1
- linux网络协议栈分析笔记7-VLAN的处理
- linux网络协议栈(五)网络层 (3)路由缓存表
- linux网络协议栈分析笔记10-arp邻居子系统3
- 《网络协议》路由协议
- 网络配置过程分析二(linux网络协议栈笔记)
- SAP BADI的实现3-使用BADI过滤器
- 取每个分类N条数据 sql
- 陷阱,中断和异常
- JSP_SERVLET_PAGE
- 梦想之路(四):自制IOC之二
- linux网络协议栈分析笔记13-路由3-FIB2
- PCA, PCA whitening and ZCA whitening in 2D
- Oracle常规恢复的实验测试
- windows C++ 资源形式实现多语言版本 .
- 自动将指定文件发送到指定ip的指定目录下
- 2440 nor flash启动和nand flash启动有什么区别
- OpenCV笔记14:抠图
- GPIO学习笔记
- python demo