核心版本:2.6.34
前篇路由表
說明了路由表的結構及路由表的建立。下面是一些路由表的使用的細枝末節,作補充說明。
路由可以分為兩部分:路由快取(rt_hash_table)和路由表()
路由快取顧名思義就是加速路由查詢的,路由快取的插入是由核心控制的,而非人為的插入,與之相對比的是路由表是人為插入的,而非核心插入的。在核心中,路由快取組織成rt_hash_table的結構。
下面是一段ip層協議的**段[net/ipv4/route.c],傳入ip層的協議在查詢路由時先在路由快取中查詢,如果已存在,則skb_dst_set(skb, &rth->u.dst)並返回;否則在路由表中查詢。
[cpp]view plain
copy
hash = rt_hash(daddr, saddr, iif, rt_genid(net));
rcu_read_lock();
for(rth = rcu_dereference(rt_hash_table[hash].chain); rth;
rth = rcu_dereference(rth->u.dst.rt_next))
rt_cache_stat_inc(in_hlist_search);
} rcu_read_unlock();
在ip_route_input()中查詢完陸由快取後會處理組播位址,如果是組播位址,則下面判斷會成功:ipv4_is_multicast(daddr)。
然後執行ip_route_input_mc(),它的主要作用就是生成路由快取項rth,並插入快取。rth的生成與初始化只給出了input函式的,其它略去了,可以看出組播報文會通過ip_local_deliver()繼續向上傳遞。
[cpp]view plain
copy
rth->u.dst.input= ip_local_deliver;
hash = rt_hash(daddr, saddr, dev->ifindex, rt_genid(dev_net(dev)));
return
rt_intern_hash(hash, rth, null, skb, dev->ifindex);
路由表又可以分為兩個:rt_table_local和rt_table_main
rt_table_local儲存目的位址是本機的路由表項,這些目的位址就是為各個網絡卡配置的ip位址;
rt_table_main儲存到其它主機的路由表項;
顯然,rt_table_main路由表只有當主機作為路由器時才有作用,一般主機該表是空的,因為主機不具有**資料報的功能。rt_table_local對主機就足夠了,為各個網絡卡配置的ip位址都會加入rt_table_local中,如為eth1配置了1.2.3.4的位址,則rt_table_local中會存在1.2.3.4的路由項。只有本地的網絡卡位址會被加入,比如lo、eth1。ip模組在初始化時ip_init() -> ip_rt_init() - > ip_fib_init()會註冊notifier機制,當為網絡卡位址配置時會執行fib_netdev_notifier和fib_inetaddr_notifier,使更改反映到rt_table_local中。
[cpp]view plain
copy
register_netdevice_notifier(&fib_netdev_notifier);
register_inetaddr_notifier(&fib_inetaddr_notifier);
而當在路由快取中沒有查詢到快取項時,會進行路由表查詢,還是以ip層協議中的**段為例[net/ipv4/route.c],fib_lookup()會在main和local兩張表中進行查詢。
[cpp]view plain
copy
if((err = fib_lookup(net, &fl, &res)) != 0)
如果主機配置成了支援**,則無論在路由表中找到與否,都會生成這次查詢的乙個快取,包括源ip、目的ip、接收的網絡卡,插入路由快取中:
[cpp]view plain
copy
hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net));
err = rt_intern_hash(hash, rth, null, skb, fl.iif);
不同的是,如果在路由表中查詢失敗,即資料報不是發往本機,也不能被本機**,則會設定插入路由快取的快取項u.dst.input=ip_error,而u.dst.input即為ip層處理完後向上傳遞的函式,而ip_error()會丟棄資料報,被傳送相應的icmp錯誤報文。不在路由表中的路由項也要插入路由快取,這可以看作路由學習功能,下次就可以直接在路由快取中找到。
[cpp]view plain
copy
rth->u.dst.input= ip_error;
rth->u.dst.error= -err;
rth->rt_flags &= ~rtcf_local;
但如果主機不支援**,即沒有路由功能,則只有在找到時才會新增路由快取項,都不會生成路由快取項。這是因為在local表中沒有找到,表明資料報不是發往本機的,此時快取這樣的路由項對於主機的資料報傳輸沒有一點意義。它只需要知道哪些資料報是發給它的,其餘的一律不管!
路由查詢整合起來,就是由ip_route_input()引入,然後依次進行路由快取和路由表查詢,並對路由快取進行更新。路由快取在每個資料報到來時都可能發生更新,但路由表則不一樣,只能通過rtm機制更新,local表是在網絡卡配置時更新的,main表則是由人工插入的(inet_rtm_newroute)。
ip_route_input()
- 路由快取查詢
- 路由表查詢:ip_route_input_slow() -> fib_lookup()
Linux核心分析 網路 四 路由表
路由表 在核心中存在路由表 fib table hash 和路由快取表 rt hash table 路由快取表主要是為了加速路由的查詢,每次路由查詢都會先查詢路由快取,再查詢路由表。這和 cache 是乙個道理,快取儲存最近使用過的路由項,容量小,查詢快速 路由表儲存所有路由項,容量大,查詢慢。首先...
linux核心分析四
使用庫函式api和c 中嵌入彙編 兩種方式使用同乙個系統呼叫,理解系統呼叫的工作機制。api 第一層是指libc中定義的api,這些api封裝了系統呼叫,使用int 0x80觸發乙個系統呼叫中斷 當然,並非所有的api都使用了系統呼叫,如完成數學加減運算的api就沒有使用系統呼叫 也有可能某個api...
Linux核心工程導論 網路 路由 路由原理
ip層通過路由將資料報送達該送達的目的位址,這就要求在整個網路中建立正確的路由表。路由表的內容是記錄要到達 下一跳需要發到 可以是埠可以是ip 如此整個網路在單個節點只知道自己區域性 資訊的情況下就能正確的 路由表的原理簡單,難的是維護。如何在全網路形成這樣一張大表,如果在網路變動的時候全網的表快速...