作者:gfree.wind@gmail.com
博客:linuxfocus.blog.chinaunix.net
在昨天的查找函数中,还有一个函数没有学习,即check_leaf。
- /* should be called with rcu_read_lock */
-
static int check_leaf(struct fib_table *tb, struct trie *t, struct leaf *l,
-
t_key key, const struct flowi4 *flp,
-
struct fib_result *res, int fib_flags)
-
{
-
struct leaf_info *li;
- /*
- 得到叶子节点的hlist_head.
- 所谓的hlist_head其实只是list_head的变种,只为了节省一个指针的空间。
- 其它的hlist_head的操作也类似于list_head的同等操作。
- */
-
struct hlist_head *hhead = &l->list;
-
struct hlist_node *node;
/* 遍历hlist */
-
hlist_for_each_entry_rcu(li, node, hhead, hlist) {
/*struct leaf_info为hlist_node真正的数据 */
/* 对于同一route,但其它参数不同如TOS等,这时使用fib_alias区分。*/
-
struct fib_alias *fa;
-
int plen = li->plen;
-
__be32 mask = inet_make_mask(plen);
/* 比较目的地址 */
-
if (l->key != (key & ntohl(mask)))
-
continue;
-
-
list_for_each_entry_rcu(fa, &li->falh, fa_list) {
- /* 获得route的info */
-
struct fib_info *fi = fa->fa_info;
-
int nhsel, err;
/* 比较route的info,如tos,scope等*/
-
if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos)
-
continue;
- if (fa->fa_info->fib_scope < flp->flowi4_scope)
-
continue;
-
fib_alias_accessed(fa);
-
err = fib_props[fa->fa_type].error;
-
if (err) {
-
#ifdef CONFIG_IP_FIB_TRIE_STATS
-
t->stats.semantic_match_passed++;
-
#endif
-
return err;
-
}
-
if (fi->fib_flags & RTNH_F_DEAD)
-
continue;
/*
遍历该route的所有下一跳。
一般情况下,route只有一个下一跳地址。但是如果enable了multiple path的话,一个route信息就
可以有多个下一跳地址。
*/
-
for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) {
-
const struct fib_nh *nh = &fi->fib_nh[nhsel];
/* 该下一跳不可用 */
-
if (nh->nh_flags & RTNH_F_DEAD)
-
continue;
/* 出口dev不匹配 */
-
if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif)
-
continue;
-
-
#ifdef CONFIG_IP_FIB_TRIE_STATS
-
t->stats.semantic_match_passed++;
-
#endif
/* ok。找到了一个合适的路由 */
-
res->prefixlen = plen;
-
res->nh_sel = nhsel;
-
res->type = fa->fa_type;
-
res->scope = fa->fa_info->fib_scope;
-
res->fi = fi;
-
res->table = tb;
-
res->fa_head = &li->falh;
-
if (!(fib_flags & FIB_LOOKUP_NOREF))
-
atomic_inc(&res->fi->fib_clntref);
-
return 0;
-
}
-
}
-
-
#ifdef CONFIG_IP_FIB_TRIE_STATS
-
t->stats.semantic_match_miss++;
-
#endif
-
}
-
-
return 1;
- }
学习完这个函数,trie方式的路由表查找过程就已结束。