TCP/IP学习(41)——Kernel中路由表的实现(4)
2013-10-17 09:11:18
本文的copyleft归gfree.wind@gmail.com所有,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。
作者:gfree.wind@gmail.com
博客:linuxfocus.blog.chinaunix.net
作者: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方式的路由表查找过程就已结束。