作者: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方式的路由表查找过程就已结束。
