路由表
在核心中存在路由表
fib_table_hash
和路由快取表
rt_hash_table
。路由快取表主要是為了加速路由的查詢,每次路由查詢都會先查詢路由快取,再查詢路由表。這和
cache
是乙個道理,快取儲存最近使用過的路由項,容量小,查詢快速;路由表儲存所有路由項,容量大,查詢慢。
首先,應該先了解路由表的意義,下面是
route
命令檢視到的路由表:
destination
netmask
gateway
flags
inte***ce
metric
169.254.0.0
255.255.0.0 *
ueth0 1
192.168.123.0
255.255.255.0 *
ueth0 1
default
0.0.0.0
192.168.123.254 ug
eth0 1
一條路由其實就是告知主機要到達乙個目的位址,下一跳應該走**。比如發往
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;
當找到表項後會更新表項的最後訪問時間,並取出
dstdst_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)
,建立後的結構如圖所示:
路由快取插入條目
函式rt_intern_hash()
要插入的條目是
rt,相應雜湊值是
hash
,首先通過
hash
值找到對應的
bucket
rthp = &rt_hash_table[hash].chain;
然後對bucket
進行一遍查詢,這次查詢的目的有兩個:如果是超時的條目,則直接刪除;如果是與
rt相同鍵值的條目,則刪除並將
rt插入頭部返回。
while ((rth = *rthp) != null)
if (compare_keys(&rth->fl, &rt->fl) && compare_netns(rth, rt))
……rthp = &rth->u.dst.rt_next; }
在掃瞄一遍後,如
rt還未存在,則將其插入頭部
rt->u.dst.rt_next = rt_hash_table[hash].chain;
rcu_assign_pointer(rt_hash_table[hash].chain, rt);
如果新插入rt滿足一定條件,還要與arp鄰居表進行繫結
hint
:快取的每個
bucket
是沒有頭結點的,單向鍊錶,它所使用的插入和刪除操作是值得學習的,簡單實用。
路由快取刪除條目
rt_del()
要刪除的條目是
rt,相應雜湊值是
hash
,首先通過
hash
值找到對應的
bucket
,然後遍歷,如果條目超時,或找到
rt,則刪除它。
rthp = &rt_hash_table[hash].chain;
spin_lock_bh(rt_hash_lock_addr(hash));
ip_rt_put(rt);
while ((aux = *rthp) != null)
rthp = &aux->u.dst.rt_next; }
spin_unlock_bh(rt_hash_lock_addr(hash));
Linux核心分析 網路 四補 路由表補充
核心版本 2.6.34 前篇路由表 說明了路由表的結構及路由表的建立。下面是一些路由表的使用的細枝末節,作補充說明。路由可以分為兩部分 路由快取 rt hash table 和路由表 路由快取顧名思義就是加速路由查詢的,路由快取的插入是由核心控制的,而非人為的插入,與之相對比的是路由表是人為插入的,...
網路 路由表 IP選路
路由表的 flags 字段顯示路由狀態 a 活動的休眠閘道器檢測在路由上被啟用。本字段只適用於 aix 5.1 或更新版本。u up.h 路由至主機而不是網路。g 路由至閘道器。不帶g表示不經過路由 d 路由通過重定向動態地建立。m 路由通過重定向被修改。c 對該路由的訪問建立轉殖路由。本字段只適用...
CQTSC2016 路由表 題解
題目大意 有n個操作,分add和ask兩種。add操作就是新增乙個字串 把ipv4位址轉成32位的二進位制串,取前l位,l為掩碼 保證每次add都不相同。ask操作給出詢問串s 同樣是ipv4位址轉成32位二進位制串 和區間 l,r 對於這次ask之前的add操作,從頭開始,每add一次,s就會找已...