0.0.1. 综述
fib tie是一个多叉树。其原理可以简化为:
根据前缀每一位是0还是1, 决定走左子树还是右子树。
绝大部分路由树,都没有那么多条目路由,所以再优化下,
- 多个联系节点只有一个子树,如
仅有两条路由:8.8.2.0/24和8.8.3.0/24, 前面16+6位都完全一样。
- 多级子树转换成一个节点下多个孩子。
仅有5条路由:
1 2 3 4 5
| 8.8.4.0/24 8.8.5.0/24 8.8.6.0/24 8.8.7.0/24 8.8.8.0/24
|
这就催生了Fib compress tree的产生。

0.0.1.1. fib Trie 节点类型
- Trie:是个多叉树。
- Tnode/key vector: 每个树节点是个,包含两个关键信息
- 前缀: 前缀相同继续找孩子。前缀不同,则回溯。
- 孩子: 前缀相同,根据指定区域位的值,继续在子树里查找。
- Leaf:
- 每个叶子节点是路由终点,但不是对应路由条目。
- 每个叶子节点有一个FA节点链在一起的list链。
- Fib alias:
- Fib info: 与fib alias一一对应?
- Fib nh:
- 对应每条路由下的每个下一跳。
- ECMP场景下,会有多个下一跳。

0.0.1.2. Fib Trie 查找逻辑:
- 根据目的IP地址,从Trie树根节点开始查找。
- 遍历每个节点
- 如果前缀不相同,回溯上级节点,查找其他膝兄弟节点
- 如果前缀相同, 查找孩子节点(子树)
- 到达叶子节点:
遍历FA, 查找最长路径匹配。
TODO:
0.0.2. 节点类型
0.0.2.1. trie
1 2 3 4 5 6
| 167 struct trie { 168 struct key_vector kv[1]; 169 #ifdef CONFIG_IP_FIB_TRIE_STATS 170 struct trie_use_stats __percpu *stats; 171 #endif 172 };
|
fib trie的入口节点,自带一个根节点kv[1]。
1
| struct key_vector kv[1];
|
0.0.2.2. tnode
1 2 3 4 5 6 7 8
| 134 struct tnode { 135 struct rcu_head rcu; 136 t_key empty_children; /* KEYLENGTH bits needed */ 137 t_key full_children; /* KEYLENGTH bits needed */ 138 struct key_vector __rcu *parent; 139 struct key_vector kv[1]; 140 #define tn_bits kv[0].bits 141 };
|
【AI总结】tnode 是 key_vector 的”管理外壳”。
empty_children 和 full_children 这两个计数器实时追踪子节点的填充状态,
让 resize() 能快速判断是否需要 inflate(扩大扇出)、halve(缩小扇出)或 collapse(合并节点)。
查找热路径完全绕开 tnode,只在 key_vector 层面操作。
注:只有中间节点有tnode, Leaf节点是纯key_vector.
0.0.2.3. key_vector
1 2 3 4 5 6 7 8 9 10 11 12
| 121 struct key_vector { 122 t_key key; 123 unsigned char pos; /* 2log(KEYLENGTH) bits needed */ 124 unsigned char bits; /* 2log(KEYLENGTH) bits needed */ 125 unsigned char slen; 126 union { 127 /* This list pointer if valid if (pos | bits) == 0 (LEAF) */ 128 struct hlist_head leaf; 129 /* This array is valid if (pos | bits) > 0 (TNODE) */ 130 DECLARE_FLEX_ARRAY(struct key_vector __rcu *, tnode); 131 }; 132 };
|
key_vector 是fib路由的核心数据结构。
【中间节点】
- key:路由前缀
- pos+bits:从pos开始的bits, 根据数值/下标,去key_vector数组里去找child/子树
- slen:子树中最大的后缀长度 (32-plen) max(pos, 子树中最大的 slen)
- struct key_vector *tnode:

【叶子】
- Leaf链接相同前缀的所有路由Fib alias。
- pos = 0
- bit = 0
- slen:挂载路由的最大(fa_slen)
0.0.2.4. fib_alias
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| struct fib_alias { struct hlist_node fa_list; struct fib_info *fa_info; dscp_t fa_dscp; u8 fa_type; u8 fa_state; u8 fa_slen; u32 tb_id; s16 fa_default; u8 offload; u8 trap; u8 offload_failed; struct rcu_head rcu; };
|
例:一个Leaf下有三条不同掩码和table的路由。
1 2 3
| 192.168.1.1/32, local表 192.168.1.0/24, main表 192.168.0.0/16, main表
|
fa_slen从小到大排序(前缀越长越靠前),查找时优先匹配最长前缀。
1 2 3 4 5 6 7 8 9 10 11 12
| Leaf (key_vector, bits=0) │ └── leaf (hlist_head) │ ├── fib_alias [fa_slen=0, tb_id=255] ──→ fib_info ──→ fib_nh[] │ (192.168.1.1/32, local表) │ ├── fib_alias [fa_slen=8, tb_id=254] ──→ fib_info ──→ fib_nh[] │ (192.168.1.0/24, main表) │ └── fib_alias [fa_slen=16, tb_id=254] ──→ fib_info ──→ fib_nh[] (192.168.0.0/16, main表)
|
fa_state:
目前就是一个 1-bit 的 “脏标记”.
核心目的是:在路由变更时,避免对从未使用过的路由执行不必要的缓存刷新。
目前只用了 bit 0(FA_S_ACCESSED)。
0.0.2.5. fib_info
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| struct fib_info { struct hlist_node fib_hash; struct hlist_node fib_lhash; struct list_head nh_list; struct net *fib_net; refcount_t fib_treeref; refcount_t fib_clntref; unsigned int fib_flags; unsigned char fib_dead; unsigned char fib_protocol; unsigned char fib_scope; unsigned char fib_type; __be32 fib_prefsrc; u32 fib_tb_id; u32 fib_priority; struct dst_metrics *fib_metrics; #define fib_mtu fib_metrics->metrics[RTAX_MTU-1] #define fib_window fib_metrics->metrics[RTAX_WINDOW-1] #define fib_rtt fib_metrics->metrics[RTAX_RTT-1] #define fib_advmss fib_metrics->metrics[RTAX_ADVMSS-1] int fib_nhs; bool fib_nh_is_v6; bool nh_updated; bool pfsrc_removed; struct nexthop *nh; struct rcu_head rcu; struct fib_nh fib_nh[]; };
|
0.0.2.6. fib_nh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| 107 struct fib_nh { 108 struct fib_nh_common nh_common; 109 struct hlist_node nh_hash; 110 struct fib_info *nh_parent; 111 #ifdef CONFIG_IP_ROUTE_CLASSID 112 __u32 nh_tclassid; 113 #endif 114 __be32 nh_saddr; 115 int nh_saddr_genid; 116 #define fib_nh_family nh_common.nhc_family 117 #define fib_nh_dev nh_common.nhc_dev 118 #define fib_nh_dev_tracker nh_common.nhc_dev_tracker 119 #define fib_nh_oif nh_common.nhc_oif 120 #define fib_nh_flags nh_common.nhc_flags 121 #define fib_nh_lws nh_common.nhc_lwtstate 122 #define fib_nh_scope nh_common.nhc_scope 123 #define fib_nh_gw_family nh_common.nhc_gw_family 124 #define fib_nh_gw4 nh_common.nhc_gw.ipv4 125 #define fib_nh_gw6 nh_common.nhc_gw.ipv6 126 #define fib_nh_weight nh_common.nhc_weight 127 #define fib_nh_upper_bound nh_common.nhc_upper_bound 128 };
|