路由表
在核心中存在路由表fib_table_hash和路由緩衝表rt_hash_table。路由緩衝表主要是為了加速路由的尋找, 每次路由查詢都會先尋找路由緩衝,再尋找路由表。這和cache是一個道理,緩衝儲存最近使用過的路由項,容量小,尋找快速 ;路由表格儲存體所有路由項,容量大,尋找慢。
首先,應該先瞭解路由表的意義,下面是route命令查看到的路由表:
一條路由其實就是告知主 機要到達一個目的地址,下一跳應該走哪裡。比如發往192.168.22.3報文通過查路由表,會得到下一跳為192.168.123.254,再 將其發送出去。在路由表項中,還有一個很重要的屬性-scope,它代表了到目的網路的距離。
路由scope可取值: RT_SCOPE_UNIVERSE, RT_SCOPE_LINK, RT_SCOPE_HOST
在報文的轉寄過程中,顯然是每次轉寄都要使到達目的網路的距離 要越來越小或不變,否則根本到達不了目的網路。上面提到的scope很好的實現這個功能,在尋找路由表中,表項的scope一定是 更小或相等的scope(比如RT_SCOPE_LINK,則表項scope只能為RT_SCOPE_LINK或RT_SCOPE_HOST)。
路由緩衝
路由 緩衝用於加速路由的尋找,當收到報文或發送報文時,首先會查詢路由緩衝,在核心中被組織成hash表,就是rt_hash_table。
static struct rt_hash_bucket *rt_hash_table __read_mostly; [net/ipv4/route.c]
通過 ip_route_input()進行查詢,首先是快取作業時,通過[src_ip, dst_ip, iif,rt_genid]計算出hash值
hash = rt_hash (daddr, saddr, iif, rt_genid(net));
此時rt_hash_table[hash].chain就是要操作的緩衝表項的鏈表,比如遍曆該鏈 表
for (rth = rt_hash_table[hash].chain; rth; rth = rth->u.dst.rt_next)
因此,在緩衝中尋找一個表 項,首先計算出hash值,取出這組表項,然後遍曆鏈表,找出指定的表項,這裡需要完全符合[src_ip, dst_ip, iif, tos, mark, net],實際上struct rtable中有專門的屬性用於緩衝的尋找索引值– struct flowi。
/* Cache lookup keys */
struct flowi fl;
當找到表項後會更新表項的最後訪問時間,並取出dst
dst_use (&rth->u.dst, jiffies);
skb_dst_set(skb, &rth->u.dst);
路由緩衝的建立
inet_init () -> ip_init() -> ip_rt_init()
rt_hash_table = (struct rt_hash_bucket *)
alloc_large_system_hash("IP route cache",
sizeof(struct rt_hash_bucket),
rhash_entries,
(totalram_pages >= 128 * 1024) ?
15 : 17,
0,
&rt_hash_log,
&rt_hash_mask,
rhash_entries ? 0 : 512 * 1024);
其中 rt_hash_mask表示表的大小,rt_hash_log = log(rt_hash_mask),建立後的結構如圖所示: