前面已经分析了FIB表中的单位:路由表,路由哈希表,路由域,路由节点,路由别名,路由信息。拿到一张具体的路由表,根据其提供的成员方法tb_lookup,可以为一个具体的目的地址查询到一条路由。tb_lookup的函数定义如下:
int fn_hash_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
tb是一张路由表的指针,由调用者指定(根据路由策略),flp指定目的地址(只要填成员dn_u.ip4_u.daddr即可),res是查询结果,struct fib_result的定义如下:
struct fib_result {
unsigned char prefixlen;
unsigned char nh_sel;
unsigned char type;
unsigned char scope;
#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
__u32 network;
__u32 netmask;
#endif
struct fib_info *fi;
#ifdef CONFIG_IP_MULTIPLE_TABLES
struct fib_rule *r;
#endif
};
prefixlen是网络地址长度,nh_sel为路由信息中下一跳的数量(有多路径时大于1)。
fn_hash_lookup先根据tb找到路由哈希表(tb->tb_data),然后根据flp指定的目的地址找到具体的路由域中的路由节点
(遍历fb_hash->fn_zone_list链表,拿目的地址跟路由域的成员fz_mask生成key,再到路由域的哈希表中去匹配路由节
点)。
匹配到具体的路由节点后,调用函数fib_semantic_match寻找路由节点中的路由别名,最后生成查询结果。找到具体的路由别名后,其成员fa_state置FA_S_ACCESSED。
下面看几个具体的例子,试验环境的eth0接口的IP地址是172.16.48.2,以目的地址172.16.48.2在RT_TABLE_LOCAL表中查询路由,得到的结果如下:
struct fib_result{
.prefixlen = 32;
.nh_sel = 0;
.type = RTN_LOCAL;
.scope = RT_SCOPE_HOST;
struct fib_info{
.flags = 0;
.protocol = RTPROT_KERNEL;
.prefsrc = 172.16.48.2;
.priority = 0;
.nhs = 1;
struct fib_nh{
dev name: eth0
flags: 0
scope: RT_SCOPE_NOWHERE
gw: 0.0.0.0
}
}
}
显然,这是预期的信息:使用接口eth0,本地接收。
同样的查询,如果在RT_TABLE_MAIN中做,就会有不同的结果,前面讲过,main表中存放的是除本地接口地址,广播地址,NAT地址之外的没有指明所属表的路由。下面是其查询结果:
struct fib_result{
.prefixlen = 24;
.nh_sel = 0;
.type = RTN_UNICAST;
.scope = RT_SCOPE_LINK;
struct fib_info{
.flags = 0;
.protocol = RTPROT_KERNEL;
.prefsrc = 172.16.48.2;
.priority = 0;
.nhs = 1;
struct fib_nh{
dev name: eth0
flags: 0
scope: RT_SCOPE_HOST
gw: 0.0.0.0
}
}
}
显然这不是预期的结果。路由规则保证了对于任何一次路由查询,总会先查local表,再查main表,所以可以避免上述现象的发生。
阅读(1104) | 评论(0) | 转发(1) |