Linuxkernel路由機(jī)制分析_第1頁(yè)
Linuxkernel路由機(jī)制分析_第2頁(yè)
Linuxkernel路由機(jī)制分析_第3頁(yè)
Linuxkernel路由機(jī)制分析_第4頁(yè)
Linuxkernel路由機(jī)制分析_第5頁(yè)
已閱讀5頁(yè),還剩15頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、Linux kernel路由機(jī)制分析 目錄(?)-1. 一前言2. 二概述1. 基于策略的路由2. 路由策略數(shù)據(jù)庫(kù)3. 相關(guān)代碼3. 三路由部分結(jié)構(gòu)1. 總體結(jié)構(gòu)2.3. IP接口部分結(jié)構(gòu)4. 路由策略數(shù)據(jù)庫(kù)部分結(jié)構(gòu)5. 接口部分結(jié)構(gòu)4. 四主要路由流程分析5. 五一些細(xì)節(jié)問(wèn)題1. 關(guān)于路由中的錯(cuò)誤處理2. 策略性路由NAT功能的實(shí)現(xiàn)6. 六總結(jié)一前言我對(duì)linux2.4.18的相關(guān)代碼進(jìn)行了閱讀,從關(guān)鍵的幾個(gè)接口函數(shù)入手,進(jìn)而理清了整個(gè)路由部分的主要脈胳,理解了一些細(xì)節(jié)問(wèn)題的處理,但還是有些問(wèn)題還沒(méi)有完全搞清楚。路由部分代碼主要在linux代碼樹的/net/ipv4/下面:對(duì)于下面報(bào)告內(nèi)容的

2、組織,我想通過(guò)由整體到部分到細(xì)節(jié)的順序,盡量把我閱讀代碼學(xué)習(xí)到的所有的知識(shí)做一個(gè)有層次有條理的總結(jié)。二概述1. 基于策略的路由目前在計(jì)算機(jī)網(wǎng)絡(luò)中使用的傳統(tǒng)路由算法都是根據(jù)IP包目的地址進(jìn)行路由選擇.然而在現(xiàn)實(shí)應(yīng)用中經(jīng)常有這樣的需求:進(jìn)行路由選擇時(shí)不僅僅根據(jù)數(shù)據(jù)報(bào)的目的地址,而且根據(jù)數(shù)據(jù)報(bào)的其他一些特性如:源地址、IP協(xié)議、傳輸層端口,甚至是數(shù)據(jù)包的負(fù)載部分內(nèi)容,這種類型的路由選擇被稱作基于策略的路由。2. 路由策略數(shù)據(jù)庫(kù)在Linux中,從2.1版本的內(nèi)核開始就實(shí)現(xiàn)了對(duì)基于策略的路由的支持,它是通過(guò)使用路由策略數(shù)據(jù)庫(kù)(RPDB,routing policy database)替代傳統(tǒng)的、基于目的

3、地址的路由表來(lái)實(shí)現(xiàn)的。RPDB通過(guò)包含的一些規(guī)則和多張路由表來(lái)選定合適的IP路由。這些規(guī)則可能會(huì)包含很多各種不同類型的鍵值(key),因此這些規(guī)則沒(méi)有默認(rèn)的特定次序,規(guī)則查找次序或規(guī)則優(yōu)先級(jí)都是由網(wǎng)絡(luò)或系統(tǒng)管理員設(shè)定的。如下圖所示,Linux的RPDB是一個(gè)由數(shù)字優(yōu)先級(jí)值進(jìn)行排序的線性規(guī)則列表。RPDB能匹配數(shù)據(jù)報(bào)源地址、目的地址、TOS、進(jìn)入接口和fwmark值等。每個(gè)路由策略規(guī)則由一個(gè)選擇器和一個(gè)動(dòng)作指示組成。RPDB按照優(yōu)先級(jí)遞增的順序被掃描,RPDB包含的每條規(guī)則的選擇器被應(yīng)用于數(shù)據(jù)報(bào)的源地址、目的地址、進(jìn)入接口、TOS和fwmark值。若數(shù)據(jù)報(bào)匹配該規(guī)則對(duì)應(yīng)于該規(guī)則的動(dòng)作被執(zhí)行。若動(dòng)

4、作成功返回,則規(guī)則輸出將是一個(gè)有效的路由或是路由查找失敗指示;否則查找RPDB的下一條規(guī)則。規(guī)則的動(dòng)作通常是查一張與之對(duì)應(yīng)的路由表,但也可以是如下幾種:REJECT(丟棄),PROHIBIT或決UNRECHABLE(丟棄并向源地址發(fā)送ICMP包),NAT(源地址網(wǎng)絡(luò)地址轉(zhuǎn)換)等。路由表項(xiàng)的類型除了表示指出下一跳的相關(guān)信息外,還可以表示:BLACKHOLE(丟棄),PROHIBIT或UNREACHABL(丟棄并向源地址發(fā)送ICMP包)E,NAT(目的地址網(wǎng)絡(luò)地址轉(zhuǎn)換)等。由圖中所示,系統(tǒng)默認(rèn)已經(jīng)實(shí)現(xiàn)了三個(gè)策略(本地策略、主策略和默認(rèn)策略),與之對(duì)應(yīng)的是三張默認(rèn)路由表(本地路由表、主路由表和默認(rèn)路

5、由表)3. 相關(guān)代碼我們主要分析了內(nèi)核關(guān)于路由部分的代碼,主要如下:linux/net/ipv4/*route.c提供了路由部分給IP層調(diào)用的接口。fib_rules.c提供對(duì)路由策略數(shù)據(jù)庫(kù)的查找接口,并維護(hù)策略表。fib_hash.c 對(duì)路由表的查找,維護(hù)等。fib_semantics.c路由表的語(yǔ)義操作,維護(hù)路由項(xiàng)信息表(fib_info_list)。fib_frontend.c提供對(duì)路由表進(jìn)行操作的接口。linux/include/net/*route.h路由cache中相關(guān)的一些數(shù)據(jù)結(jié)構(gòu)。ip_fib.h定義了路由部分很多重要的結(jié)構(gòu)。neighbour.hstruct neighbou

6、r的定義。dst.h對(duì)路由cache結(jié)點(diǎn)中dst_entry結(jié)構(gòu)的定義。linux/net/core/*dst.c對(duì)路由cache結(jié)點(diǎn)分配等動(dòng)作。eighbour結(jié)構(gòu)相關(guān)操作。三路由部分結(jié)構(gòu)1. 總體結(jié)構(gòu)內(nèi)核路由部分代碼實(shí)際上是ipv4協(xié)議棧的一部分,它被ip層的代碼所調(diào)用。主要的調(diào)用時(shí)機(jī)有兩個(gè):一個(gè)是IP包輸出時(shí),需要確定由哪個(gè)端口出去;另一個(gè)是IP包輸入時(shí),需要確定是發(fā)給本機(jī)還是選擇一個(gè)端口發(fā)送出去。整個(gè)路由系統(tǒng)可以分成三部分:IP層調(diào)用接口,路由策略數(shù)據(jù)庫(kù),和前后端接口。1 IP層調(diào)用接口主要是提供一組調(diào)用接口給IP層代碼,這些接口最終完成了整個(gè)的路由工作。為了提

7、高效率,這部分代碼維護(hù)了一個(gè)路由策略數(shù)據(jù)庫(kù)的緩存或者叫cache,這部分代碼另一個(gè)主要功能就是維護(hù)這個(gè)緩存了。這部分的代碼主要在route.c文件中。2 路由策略數(shù)據(jù)庫(kù)部分主要包括一個(gè)策略庫(kù)和多張路由表,還有一些相關(guān)的操作它們的函數(shù)。當(dāng)路由緩存沒(méi)有命中的情況下,就要由這部分完成最后的查找工作。這部分的代碼主要在fib_rules.c,fib_hash.c,fib_semantics.c中。3 前底端接口部分主要是給用戶提供的一些對(duì)路由策略數(shù)據(jù)庫(kù)增刪改的操作函數(shù),對(duì)/proc接口的實(shí)現(xiàn),以及一些定時(shí)器的操作。這部分代碼主要在fib_frontend.c中,還有一些分散在其它文件中。2. IP接口

8、部分結(jié)構(gòu)這部分即是route.c的內(nèi)容,主要定義了路由cache還有提供給IP層調(diào)用的幾個(gè)接口函數(shù)。我們先來(lái)介紹一下路由cache的定義:static struct rt_hash_bucket *rt_hash_table;這個(gè)rt_hash_table即是路由cache,它是一個(gè)rt_hash_bucket結(jié)構(gòu):struct rt_hash_bucket struct rtable *chain; rwlock_t lock;struct rtable的結(jié)構(gòu)定義如下:struct rtable union struct dst_entry dst; struct rtable *rt_ne

9、xt; u; unsigned rt_flags; unsigned rt_type; _u32 rt_dst; _u32 rt_src; int rt_iif; _u32 rt_gateway; struct rt_key key; _u32 rt_spec_dst; struct inet_peer *peer;#ifdef CONFIG_IP_ROUTE_NAT _u32 rt_src_map; _u32 rt_dst_map;#endif;struct rt_key _u32 dst; _u32 src; int iif; int oif; _u8 tos; _u8 scope; 實(shí)際

10、上這個(gè)rt_hash_table就是一張hash table。每個(gè)hash值相同的結(jié)點(diǎn)都掛在一個(gè)list上即struct rt_hash_bucket的chain成員,它的lock成員用于對(duì)這個(gè)list進(jìn)行加鎖以實(shí)現(xiàn)臨界資源的互斥訪問(wèn)。每個(gè)結(jié)點(diǎn)是一個(gè)rtable結(jié)構(gòu),這個(gè)結(jié)構(gòu)比較重要,實(shí)際上路由查詢的最終結(jié)果就是把一個(gè)對(duì)應(yīng)的rtable結(jié)構(gòu)的地址賦給skb->dst。這個(gè)結(jié)構(gòu)的域key就是hash表檢索時(shí)所用來(lái)比較的關(guān)鍵字,這個(gè)結(jié)構(gòu)包含了dst(目標(biāo)地址),src(源地址),iif(入端口),oif(出端口),tos(服務(wù)類型),scope(目標(biāo)地址的范圍),這些也就是查找路由緩存時(shí)所要

11、匹配的值,即如果這些都匹配了,那么說(shuō)明cache命中,否則還要繼續(xù)檢索。下面這個(gè)圖顯示了路由緩存的完整結(jié)構(gòu):這一部分主要提供了兩個(gè)供IP層調(diào)用的入口函數(shù):int ip_route_input( struct sk_buff* skb, u32 dst, u32 src, u8 tos, struct net_device *dev );int ip_route_output( struct rtable *rp, u32 daddr, u32 saddr, u32 tos, int oif )其中ip_route_input函數(shù)即是在處理從網(wǎng)絡(luò)上進(jìn)來(lái)的IP包時(shí)調(diào)用的路由函數(shù),它的結(jié)果主要有兩個(gè)

12、:即如果是本地包則傳給上層協(xié)議層,如果不是則選則一個(gè)出端口再發(fā)送出去。函數(shù)的參數(shù)有5個(gè):skb表示ip包的緩沖區(qū),dst目的地址,src源地址,tos表示IP包服務(wù)類型,dev表示入端口。函數(shù)返回值指示錯(cuò)誤,如果成功查到路由,函數(shù)返回后,skb->dst會(huì)被賦值。與之相對(duì)ip_route_output函數(shù)則是處理本機(jī)發(fā)出的IP包時(shí)調(diào)用的路由函數(shù),它的結(jié)果只是為其選擇一個(gè)下一跳以及出端口。參數(shù)也是5個(gè):rp是個(gè)輸出參數(shù),返回時(shí)*rp指向一個(gè)返回的rtable結(jié)構(gòu)的路由結(jié)點(diǎn);daddr目的地址,saddr源地址,tos服務(wù)類型,oif出接口。函數(shù)返回值指示錯(cuò)誤。這一部分其它一些比較重要的函數(shù)

13、有:ip_route_input_slow:當(dāng)ip_route_input查cache不命中時(shí)調(diào)用此函數(shù),此函數(shù)進(jìn)而調(diào)用路由策略數(shù)據(jù)庫(kù)的查詢接口進(jìn)行查詢,然后更新路由cache。ip_route_output_slow:當(dāng)ip_route_output查cahe不命中是調(diào)用此函數(shù),此函數(shù)進(jìn)而調(diào)用路由策略數(shù)據(jù)庫(kù)的查詢接口進(jìn)行查詢,然后更新路由cache。rt_intern_hash:將新rtable結(jié)構(gòu)的結(jié)點(diǎn)插入到路由緩存中。rt_garbage_collect:對(duì)路由緩存進(jìn)和垃圾收集。3. 路由策略數(shù)據(jù)庫(kù)部分結(jié)構(gòu)這一部分主要包括策略表及路由表的定義,以及查詢等操作。策略表static stru

14、ct fib_rule *fib_rules = &local_rule;fib_rules即是策略表,它是一個(gè)fib_rule結(jié)構(gòu):struct fib_rule struct fib_rule *r_next; atomic_t r_clntref; u32 r_preference; unsigned char r_table; unsigned char r_action; unsigned char r_dst_len; unsigned char r_src_len; u32 r_src; u32 r_srcmask; u32 r_dst; u32 r_dstmask; u

15、32 r_srcmap; u8 r_flags; u8 r_tos; int r_ifindex; char r_ifnameIFNAMSIZ; int r_dead;整個(gè)策略表的結(jié)構(gòu)如下圖:這個(gè)策略表實(shí)際上就是一個(gè)單鏈表,整個(gè)單鏈表按策略的優(yōu)先級(jí)由高到低的順序排列,表頭指針即是fib_rule。每個(gè)策略是一個(gè)fib_rule結(jié)構(gòu)。這個(gè)結(jié)構(gòu)有幾個(gè)重要的域:r_preference 這個(gè)策略的優(yōu)先級(jí)。r_table 這個(gè)策略對(duì)應(yīng)的路由表,它是路由表索引表fib_tables的一個(gè)索引值。r_action 策略的動(dòng)作,如單播,丟棄,NAT等。r_src,r_srcmask,r_dst,r_dstm

16、ask,r_tos等策略的選擇器,即描述什么樣的IP包匹配這條策略。系統(tǒng)默認(rèn)已經(jīng)定義了三個(gè)策略:static struct fib_rule default_rule = r_clntref: ATOMIC_INIT(2), r_preference: 0x7FFF, r_table: RT_TABLE_DEFAULT, r_action: RTN_UNICAST,;static struct fib_rule main_rule = r_next: &default_rule, r_clntref: ATOMIC_INIT(2), r_preference: 0x7FFE, r_ta

17、ble: RT_TABLE_MAIN, r_action: RTN_UNICAST,;static struct fib_rule local_rule = r_next: &main_rule, r_clntref: ATOMIC_INIT(2), r_table: RT_TABLE_LOCAL, r_action: RTN_UNICAST,;可以看到這三個(gè)策略(本地策略,主策略,默認(rèn)策略)按照優(yōu)先級(jí)的由高到低的次序排列,它們的選擇器都是0,即表示匹配所有類型的IP包。它們的動(dòng)作都是單播就表示都是查對(duì)應(yīng)的路由表。它們分別對(duì)應(yīng)三張路由表(本地路由表,主路由表,默認(rèn)路由表)。其意義就是對(duì)

18、于一個(gè)IP包,系統(tǒng)總是按本地路由表->主路由表->默認(rèn)路由表的次序進(jìn)行查找的。路由表定義如下:struct fib_table *local_table;struct fib_table *main_table;struct fib_table *fib_tablesRT_TABLE_MAX+1;它的數(shù)據(jù)結(jié)構(gòu)是:struct fib_table unsigned char tb_id; unsigned tb_stamp; int (*tb_lookup)(struct fib_table *tb, const struct rt_key *key, struct fib_resu

19、lt *res); int (*tb_insert)(); int (*tb_delete)(); int (*tb_dump)(); int (*tb_flush)(struct fib_table *table); int (*tb_get_info)(); void (*tb_select_default)(); unsigned char tb_data0;fib_table是系統(tǒng)中所有路由表的索引數(shù)組。系統(tǒng)另外定義了兩個(gè)路由表指針local_table和main_table,分別指向默認(rèn)定義的兩個(gè)路由表。在前面我們?cè)榻B系統(tǒng)定義了三張路由表,還有一張即是默認(rèn)路由表,實(shí)際上它只是一張空

20、表,一般并沒(méi)有用到。實(shí)際上,fib_table結(jié)構(gòu)只是一個(gè)路由表結(jié)構(gòu)中最上層的一個(gè)結(jié)構(gòu),它下面還很多的層次,下面這張圖描繪了整個(gè)路由表的數(shù)據(jù)結(jié)構(gòu):整個(gè)結(jié)構(gòu)看起來(lái)比較復(fù)雜,我們可以把它分成4個(gè)層次來(lái)看:第一個(gè)層次是fib_table和fn_hash結(jié)構(gòu)。實(shí)際上,fn_hash結(jié)構(gòu)即是fib_table的tb_data域。這一層主要是包括一個(gè)路由表所對(duì)應(yīng)的標(biāo)識(shí)符(tb_id),操作函數(shù)指針(tb_looup等),以及對(duì)所有路由項(xiàng)的一個(gè)總索引(fn_hash結(jié)構(gòu))。最為重要的就是這個(gè)索引,一個(gè)路由表把它所有的路由項(xiàng)劃分成33個(gè)區(qū)域,劃分的原則即是子網(wǎng)掩碼的長(zhǎng)度(從0到32),這33個(gè)區(qū)域分別對(duì)應(yīng)著f

21、n_hash結(jié)構(gòu)中的fz_zone0到fz_zone32。之所以這么劃分的原因就因?yàn)椋酚傻谋淼牟檎乙獜淖罹_到最不精確,也就是說(shuō)要從掩碼最長(zhǎng)的路由項(xiàng)查起。第二個(gè)層次是fn_zone結(jié)構(gòu)。每個(gè)fn_zone代表了一個(gè)區(qū)域,由于并不是33個(gè)區(qū)域都會(huì)同時(shí)存在,一般往往只有常用到的掩碼長(zhǎng)度(如0,16,24,32位)對(duì)應(yīng)的區(qū)域才存在,所以所有存在的區(qū)域按從大到小的順序被鏈成一個(gè)list,從而提高查找的效率。這人fn_zone結(jié)構(gòu)中最重要的就是fz_hash域了,它指向了一個(gè)hash table,這個(gè)hash table組織了這個(gè)區(qū)域下的所有路由項(xiàng)。第三個(gè)層次是代表路由項(xiàng)的fn_node結(jié)構(gòu)。它是ha

22、sh table的結(jié)點(diǎn),其中fn_key域即是hash查找的關(guān)鍵字,它實(shí)際上就是路由項(xiàng)的目標(biāo)網(wǎng)絡(luò)號(hào)。這個(gè)結(jié)構(gòu)的提供了路由查找的結(jié)果信息,fn_type這個(gè)域指示了這個(gè)路由項(xiàng)的含義:?jiǎn)尾マD(zhuǎn)發(fā),本地,丟棄,NAT等等。對(duì)于大多數(shù)情況,路由項(xiàng)都是單播轉(zhuǎn)發(fā)類型的,這時(shí)關(guān)于下一跳的信息就入在fn_info中了,它指向一個(gè)fib_info結(jié)構(gòu)。第四個(gè)層次即是fib_info結(jié)構(gòu)。因?yàn)楹芏嗟穆酚身?xiàng)具有相同的下一跳信息,即fn_node與fib_info結(jié)構(gòu)是多對(duì)一的關(guān)系。所以fn_node中只存放一個(gè)指向fib_info的指針fn_info。所有fib_info結(jié)構(gòu)被單獨(dú)管理,它們被組織成一個(gè)雙向鏈表,表頭

23、為fib_info_list。關(guān)于下一跳的具體信息由fib_nh數(shù)組指示,它是一個(gè)數(shù)組意味著一個(gè)下一跳決策可以對(duì)應(yīng)著多個(gè)物理的下一跳,這是linux支持的一個(gè)MULITPATH功能。處理函數(shù)這部分的處理函數(shù)中最為重要的就是對(duì)路由策略數(shù)據(jù)庫(kù)的查找函數(shù)fib_lookup,以及對(duì)單個(gè)路由表進(jìn)行查找的fn_hash_lookup函數(shù)。fib_lookup的定義:int fib_lookup(const struct rt_key *key, struct fib_result *res)這個(gè)函數(shù)的工作就是對(duì)整個(gè)路由策略數(shù)據(jù)庫(kù)進(jìn)行查找,它會(huì)在需要的時(shí)候調(diào)用fn_hash_lookup查找特定的路由表。

24、函數(shù)有兩個(gè)參數(shù),key是查找的關(guān)鍵字,它與路由緩存查找時(shí)的key是一致的。res是輸出參數(shù),函數(shù)返回后如果成功則在res存入查找結(jié)果。函數(shù)的返回值用來(lái)指示錯(cuò)誤。static intfn_hash_lookup(struct fib_table *tb, const struct rt_key *key, struct fib_result *res)這個(gè)函數(shù)的即是對(duì)路由進(jìn)行查找。參數(shù)有3個(gè),tb指示待查的路由表,key查找關(guān)鍵字,res指向的結(jié)構(gòu)存放查找的結(jié)果。函數(shù)返回值指示錯(cuò)誤。4. 接口部分結(jié)構(gòu)這一部分主要實(shí)現(xiàn)以下幾個(gè)功能:1對(duì)路由表,策略表進(jìn)行增加項(xiàng),刪除項(xiàng),創(chuàng)建表,表空路由緩存等操作。

25、2為路由策略數(shù)據(jù)庫(kù),路由緩存提供/proc接口。3設(shè)置定時(shí)器,以定時(shí)對(duì)路由緩存進(jìn)行清理工作。四主要路由流程分析前面已經(jīng)介紹過(guò),IP層會(huì)在輸入和輸出兩個(gè)時(shí)候去調(diào)用路由部分代碼。輸入路由過(guò)程更為復(fù)雜一些也更具代表性,所以我們下面主要分析一下IP包輸入時(shí)的路由流程。下圖描述了這個(gè)流程:當(dāng)有數(shù)據(jù)到達(dá)網(wǎng)絡(luò)設(shè)備的時(shí)候,會(huì)產(chǎn)生一個(gè)中斷,中斷處理函數(shù)會(huì)調(diào)用驅(qū)動(dòng)層的net_rx函數(shù),net_rx進(jìn)而產(chǎn)生個(gè)軟中斷進(jìn)入net_rx_action函數(shù),進(jìn)而如是發(fā)現(xiàn)這個(gè)數(shù)據(jù)幀是IP包的話,它就調(diào)用IP協(xié)議層的ip_rcv函數(shù),它進(jìn)而又調(diào)用ip_rcv_finish函數(shù)。在這個(gè)函數(shù),它調(diào)用路由代碼的IP接口函數(shù)ip_ro

26、ute_input進(jìn)行路由??梢钥吹絺鬟f給路由代碼的參數(shù)有5個(gè):skb IP包緩沖區(qū),iph->daddr IP包的目的地址,iph->saddr IP包源地址,iph->tos 服務(wù)類型,dev 輸入的網(wǎng)絡(luò)設(shè)備。當(dāng)這個(gè)ip_route_input函數(shù)返回時(shí),就意味著路由工作已經(jīng)結(jié)束,如果返回值是0,那么就說(shuō)明已經(jīng)成功找到了路由。那么這個(gè)路由查詢結(jié)果放在哪里呢?它就在skb->dst,它指向的就是查到的路由緩存中的一個(gè)結(jié)點(diǎn)。下邊通過(guò)調(diào)用skb->dst->input(skb)就可以對(duì)這個(gè)IP進(jìn)行處理了。這個(gè)input是路由緩存結(jié)點(diǎn)中的一個(gè)函數(shù)指針,如果這個(gè)路

27、由項(xiàng)表示轉(zhuǎn)發(fā)的,那么這個(gè)指針實(shí)際上指向的是ip_local_deliver,而如果是傳送給本地的,那么指向的是ip_forward。ip_local_deliver會(huì)將這個(gè)IP包進(jìn)一步傳給上層協(xié)議層處理,ip_forward則會(huì)再將這個(gè)IP包從網(wǎng)絡(luò)設(shè)備發(fā)送出去。我們?cè)賮?lái)看一下路由的具體流程。首先調(diào)用的是ip_route_input,它的任務(wù)主要是查路由緩存,如果找到了那么它給skb->dst賦值并返回,如是沒(méi)找到,它會(huì)調(diào)用ip_route_input_slow去查詢路由策略數(shù)據(jù)庫(kù)。下面是經(jīng)過(guò)簡(jiǎn)化的代碼和注釋:int ip_route_input(struct sk_buff *skb,

28、u32 daddr, u32 saddr, u8 tos, struct net_device *dev)int iif = dev->ifindex;hash = rt_hash_code(daddr, saddr (iif << 5), tos);/*遍歷hash table */for (rth = rt_hash_tablehash.chain; rth; rth = rth->u.rt_next ) /* 只有這五個(gè)量都匹配才算命中,要比較這么多量是因?yàn)樵诨诓呗缘穆酚芍校幸粋€(gè)量不同就有可能選擇不同的策略。*/if ( rth->key.dst = d

29、addr && rth->key.src = saddr && rth->key.iif = iif && rth->key.oif = 0 && rth->key.tos = tos ) rth-> = jiffies;dst_hold(&rth->u.dst);rth->+;/*關(guān)鍵的一步,為dst為賦值*/skb->dst = (struct dst_entry*)rth;return 0;/*如果緩存查不到,那么調(diào)用這個(gè)函數(shù)*/return ip_route_inpu

30、t_slow(skb, daddr, saddr, tos, dev);ip_route_input_slow函數(shù)的主要任務(wù)是去調(diào)用路由策略數(shù)據(jù)庫(kù)的查找函數(shù)fib_lookup進(jìn)行查找,然后更新路由緩存。因?yàn)檫@個(gè)函數(shù)很長(zhǎng),我們用下面的流程圖來(lái)表示一些主要的流程:當(dāng)調(diào)用過(guò)fib_lookup后,函數(shù)會(huì)根據(jù)查找的結(jié)構(gòu)進(jìn)行不同的處理。一般情況是轉(zhuǎn)發(fā)或者本地,這兩種的情況都會(huì)先分配一個(gè)新的路由緩存結(jié)點(diǎn),填充適當(dāng)?shù)闹等缓蟛迦氲骄彺嬷校粌烧叩牟煌饕谟?,設(shè)置dst.input函數(shù)分別為ip_forward或ip_local_deliver,轉(zhuǎn)發(fā)的情況還要綁定關(guān)于下一跳信息的neighbour(這個(gè)結(jié)構(gòu)主

31、要用來(lái)得到網(wǎng)段上鄰居的物理地址)。除了轉(zhuǎn)發(fā)或本地還有可能是其它情況,比如有錯(cuò)誤,沒(méi)查到,丟棄,NAT等。fib_lookup函數(shù)是路由策略數(shù)據(jù)庫(kù)的查詢接口,它首先查找策略表,找到一條匹配的策略,然后再執(zhí)行該策略所對(duì)應(yīng)的動(dòng)作,動(dòng)作一般來(lái)說(shuō)就是要查找對(duì)應(yīng)的一張路由表,所以接下來(lái)會(huì)調(diào)用fn_hash_lookup函數(shù)進(jìn)行處理。下面是這個(gè)函數(shù)的簡(jiǎn)化后的代碼和相關(guān)注釋:fib_lookup(const struct rt_key *key, struct fib_result *res) /*循環(huán)遍歷策略表*/for (r = fib_rules; r; r=r->r_next) /*如果有一項(xiàng)不

32、符,繼續(xù)查找下一個(gè)*/if ( (saddrr->r_src) & r->r_srcmask) | (daddrr->r_dst) & r->r_dstmask) | (r->r_tos && r->r_tos != key->tos) | (r->r_ifindex && r->r_ifindex != key->iif) )continue;/*判斷策略的動(dòng)作*/switch (r->r_action) case RTN_UNICAST:case RTN_NAT:policy

33、= r;break;default:case RTN_BLACKHOLE:read_unlock(&fib_rules_lock);return -EINVAL;/*得到策略所對(duì)應(yīng)的路由表*/if (tb = fib_get_table(r->r_table) = NULL) continue;/*查找路由表*/err = tb->tb_lookup(tb, key, res);/*返回0表示查找成功*/if (err = 0) res->r = policy; return 0; /*如果有錯(cuò)誤,則返回錯(cuò)誤號(hào),如果是-EAGAIN或正數(shù)則查下一策略*/if (err

34、 < 0 && err != -EAGAIN) return err;return -ENETUNREACH;fn_hash_lookup函數(shù)的主要功能即是對(duì)路由表的查找。如下:int fn_hash_lookup(struct fib_table *tb, const struct rt_key *key, struct fib_result *res)/*從大到小遍歷區(qū)域*/for (fz = t->fn_zone_list; fz; fz = fz->fz_next) fn_key_t k = fz_key(key->dst, fz);/*遍歷一區(qū)

35、域內(nèi)的hash table */for (f = fz_chain(k, fz); f; f = f->fn_next) if (!fn_key_eq(k, f->fn_key) if (fn_key_leq(k, f->fn_key) break;else continue;/*找到匹配的路由項(xiàng)*/if (f->fn_state&FN_S_ZOMBIE) continue;/*進(jìn)行語(yǔ)義上的檢查和設(shè)置如果是單播,把fib_info賦給res 如果是其它,相應(yīng)作一些處理*/err = fib_semantic_match(f->fn_type, FIB_IN

36、FO(f), key, res);/*沒(méi)有錯(cuò)誤的情況*/if (err = 0) res->type = f->fn_type;res->prefixlen = fz->fz_order;goto out;if (err < 0) goto out;/*如果沒(méi)有找到匹配的路由項(xiàng),返回正值表示上層函數(shù)處理下一個(gè)策略*/err = 1;out: return err;五一些細(xì)節(jié)問(wèn)題1. 關(guān)于路由中的錯(cuò)誤處理這里的錯(cuò)誤是指找不到路由項(xiàng),還包括丟棄、禁止、不可到達(dá)等情況。這些情況產(chǎn)生的原因可能是因?yàn)槁酚杀碇姓也坏较鄳?yīng)的項(xiàng)或是用戶設(shè)置了相應(yīng)的策略或路由項(xiàng)對(duì)特定IP包進(jìn)行丟棄

37、等處理。在這種情況下fib_lookup會(huì)返回一個(gè)錯(cuò)誤值,如-ENETUNREACH,-BLACKHOLE等。接著在ip_route_input_slow中 if (err = fib_lookup(&key, &res) != 0) if (!IN_DEV_FORWARD(in_dev) goto e_inval; goto no_route; 即會(huì)跳到no_route處:no_route:rt_cache_statsmp_processor_id().in_no_route+;spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);res.type = RTN_UNREACHABLE;goto local_input;它把res.type標(biāo)記成RTN_UNREACHABLE然后跳到本地包情況的處理代碼,先是更新路由緩存,然后遇到如下代碼: if (res.type = RTN_UNREACHABLE) rth->u.dst.input= ip_error; rth->u.dst.error= -err; rth->rt_flags &= RTCF_LOCAL; rth->rt_type = re

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論