ipv4路由查找

fib_table_lookup

可以参考:https://blog.csdn.net/shichaog/article/details/44658205

1405 int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
1406                      struct fib_result *res, int fib_flags)
1407 {
1408         struct trie *t = (struct trie *) tb->tb_data;
1409         int ret;
1410         struct rt_trie_node *n;
1411         struct tnode *pn;
1412         unsigned int pos, bits;
1413         t_key key = ntohl(flp->daddr);
1414         unsigned int chopped_off;
1415         t_key cindex = 0;
1416         unsigned int current_prefix_length = KEYLENGTH;
1417         struct tnode *cn;
1418         t_key pref_mismatch;
1419 
1420         rcu_read_lock();
1421 
1422         n = rcu_dereference(t->trie);
1423         if (!n)
1424                 goto failed;
//首先查看fib_table指向的是否仅仅是leaf,而没有tnode,对于fib_table只有一个leaf的情况下,直接调用check_leaf进行
//验证
1430         /* Just a leaf? */
1431         if (IS_LEAF(n)) {
1432                 ret = check_leaf(tb, t, (struct leaf *)n, key, flp, res, fib_flags);
1433                 goto found;
1434         }
//对于是tnode的情况的处理
1436         pn = (struct tnode *) n;
//该变量用于记录已经匹配到的比特数。
1437         chopped_off = 0;
1438 
1439         while (pn) {
1440                 pos = pn->pos;
1441                 bits = pn->bits;
1443                 if (!chopped_off)
//找到不同的bit,这是为了获得孩子节点。
1444                         cindex = tkey_extract_bits(mask_pfx(key, current_prefix_length),
1445                                                    pos, bits);
//获得孩子节点,这个孩子节点可能是tnode也可能是leaf
1447                 n = tnode_get_child_rcu(pn, cindex);
//
1449                 if (n == NULL) {
1453                         goto backtrace;
1454                 }
//如果孩子节点是一个leaf节点,则调用check_leaf检查是否是需要的路由项,并将结果存放在res中。
1456                 if (IS_LEAF(n)) {
1457                         ret = check_leaf(tb, t, (struct leaf *)n, key, flp, res, fib_flags);
1458                         if (ret > 0)
1459                                 goto backtrace;
1460                         goto found;
1461                 }
//如果孩子节点是一个tnode,则需要进行迭代到其孩子进行上述查找过程。
1463                 cn = (struct tnode *)n;
//第一次进入该函数这里的current_prefix_length的长度是不会小于pos+bits的。
1494                 if (current_prefix_length < pos+bits) {
1495                         if (tkey_extract_bits(cn->key, current_prefix_length,
1496                                                 cn->pos - current_prefix_length)
1497                             || !(cn->child[0]))
1498                                 goto backtrace;
1499                 }
1532 
1533                 pref_mismatch = mask_pfx(cn->key ^ key, cn->pos);
//当根据pos和bits值没有找到搜索的key的话,进入前缀匹配模式。
/************************************************************************************************
***该模式存在意义如下:
***对于ipv4路由表有如下两项:
***192.168.20.16/28
***192.168.0.0/16
***如果需要查找192.168.20.19则上面两个都是匹配的,但是取哪个好呢?内核使用最常匹配原则,即认为192.168.20.16
***(子网掩码长度是28)这一项是匹配的,通常default 项的前缀是最短的,其作用是在其他路由项均不能匹配时会使用***default项*[摘自维基百科,longest prefix match],这个函数的chopped_off就是忽略prefix的长度,这样匹配成功的概率会***变大。对于图12.2.4的情况的trie树,查找192.168.0.100路由项的情况是不会进入backtrace标号开始的语句的。
**********************************************************************************************/
1540                 if (pref_mismatch) {
1541                         /* fls(x) = __fls(x) + 1 */
1542                         int mp = KEYLENGTH - __fls(pref_mismatch) - 1;
1543 
1544                         if (tkey_extract_bits(cn->key, mp, cn->pos - mp) != 0)
1545                                 goto backtrace;
1546 
1547                         if (current_prefix_length >= cn->pos)
1548                                 current_prefix_length = mp;
1549                 }
1550 
1551                 pn = (struct tnode *)n; /* Descend */
1552                 chopped_off = 0;
1553                 continue;
1554 
1555 backtrace:
1556                 chopped_off++;
1557 
1558                 /* As zero don't change the child key (cindex) */
1559                 while ((chopped_off <= pn->bits)
1560                        && !(cindex & (1<<(chopped_off-1))))
1561                         chopped_off++;
1562 
1563                 /* Decrease current_... with bits chopped off */
1564                 if (current_prefix_length > pn->pos + pn->bits - chopped_off)
1565                         current_prefix_length = pn->pos + pn->bits
1566                                 - chopped_off;
1567 
1568                 /*
1569                  * Either we do the actual chop off according or if we have
1570                  * chopped off all bits in this tnode walk up to our parent.
1571                  */
1572 
1573                 if (chopped_off <= pn->bits) {
1574                         cindex &= ~(1 << (chopped_off-1));
1575                 } else {
1576                         struct tnode *parent = node_parent_rcu((struct rt_trie_node *) pn);
1577                         if (!parent)
1578                                 goto failed;
1579 
1580                         /* Get Child's index */
1581                         cindex = tkey_extract_bits(pn->key, parent->pos, parent->bits);
1582                         pn = parent;
1583                         chopped_off = 0;
1593 found:
1594         rcu_read_unlock();
1595         return ret;
1596 }

 

posted @ 2022-03-07 12:10  codestacklinuxer  阅读(41)  评论(0)    收藏  举报