《TCP/IP詳解卷2:實現》筆記--Radix樹路由表

由IP完成的路由選擇是一種選路機制,它通過搜索路由表來確定從哪個接口把分組發送出去,它與選路策略不一樣,選路策略

是一組規則的集合,這些規則用來確定哪些路由可以編入到路由表中,Net/3內核實現選路機制,而選路守護進程,典型地如

routed或gated,實現選路策略。

1.路由表結構

下圖是某主機上的路由表。


對於Flags列需要簡單說明下。

G  該路由通向一個網關(路由器),這種路由被稱爲間接路由。如果沒有設置本標誌,則表明路由的目的地與本機直接相連,

稱爲直接路由。

H  該路由通往一臺主機,也就是說,目的地址是一個完整的主機地址。如果沒有設置本標誌,則路由通往一個網絡,目的地址

是一個網絡地址:一個網絡號,或一個網絡號與子網號的組合。

S  該路由是靜態的。

C  該路由可被克隆以產生新的路由。在本路由表中有兩條路由設置了這個標誌:一條是到本地以太網140.252.13.32的路由,

ARP通過克隆該路由創建到以太網中其他特定主機的路由;另一條是到多播組224的路由,克隆該路由可以創建到特定多播

組(如224.0.0.1)的路由。

L  該路由含有鏈路層地址。本標誌應用於單播地址和多播地址。由ARP從以太網路由克隆而得到的所有主機路由都設置了本標誌。

R  環回驅動器(爲設有本標誌的路由而設計的普通接口)將拒絕所有使用該路由的數據報。

Net/3路由表採用Patricia樹結構來表示主機地址和網絡地址。待查找的地址和樹中的地址都看成比特序列。這樣就可以用相同

的函數來查找和維護不同類型的數。

查找路由表的目的就是爲了找到一個最能匹配給定目標的特定地址。我們稱這個給定的目標位查找鍵(search key)。所謂

最能匹配的地址,也就是說,一個能夠匹配的主機地址要優於一個能夠匹配的網絡地址;而一個能夠匹配的網絡地址要優於

默認地址。

每條路由表項都有一個對應的網絡掩碼,儘管在主機路由中沒有存儲掩碼,但它隱含了一個全1比特的掩碼。我們對查找鍵和

路由表項的掩碼進行邏輯與運算,如果得到的值與該路由表項的目的地址相同,則稱該路由表項是匹配的。對於某個給定的

查找鍵,我們會從路由表中找到多條這樣的匹配路由。

下圖給出了上面路由表的內部結構。


標有end的兩個陰影框是該書結構中帶有特殊標誌的葉節點,該標誌代表樹的端點。左邊的那個擁有一個全0鍵,而右邊的

擁有一個全1鍵,左邊的兩個標有end和default的框疊在一起,這兩個框有特殊的意義,它們與重複鍵有關。

方角框被稱爲內部結點或簡稱爲結點,圓角框被稱爲葉子。每一個內部結點對應於測試查找鍵的一個比特位,其左右各有

一個分支。每一個葉子對應於一個主機地址或者對應於一個網絡地址。如果在葉子下面有一個十六進制數,那麼這個葉子

就對應於一個網絡地址,該十六進程數就是葉子的網絡掩碼。如果在葉子下面沒有十六進制的掩碼,那麼這個葉子就是一個

主機地址,其隱含的掩碼是0xffffffff。

有一些內部節點也含有網絡掩碼,這些掩碼在回溯過程中使用。

比特比較式運用在插口地址結構上的,因此,在上圖給出的比特位置是從插口地址結構中的起始位置開始算的。下圖給出了

sockaddr_in結構中的比特位置。


下圖爲路由表中各個IP地址的比特表示形式。


下面舉一些例子來說明路由表的查找過程是如何完成的。

1.與主機地址匹配的例子

假定查找鍵是地址140.252.13.35。32爲1,33爲0,36爲1,57爲0,62爲1,63爲1。因此查找在140.252.13.35的葉子處

終止。查找鍵與路由表鍵完全匹配。

2.與網絡地址匹配的例子

假定查找鍵是127.0.0.2。32爲0,33爲1,63爲0,因此,查找在標有127.0.0.0的葉子處終止。查找鍵和路由表並沒有完全

匹配,因此,需要進一步看它是不是一個能夠匹配的網絡地址。對查找鍵和網絡掩碼0xff000000進行邏輯與運算,得到的

結果與該路由表鍵相同,即認爲該路由表項能夠匹配。

3.與默認地址匹配的例子

假定查找鍵是10.1.2.3。32爲0,33爲0,因此,查找標有end和default並帶有重複鍵的葉子處終止。在這兩個葉子中重複的

路由表鍵是0.0.0.0。查找鍵與路由表鍵值沒有完全匹配,因此,需要進一步看它是不是一個能夠匹配的網絡地址。這種匹配

運算要對每個含網絡掩碼的重複鍵都試一遍。第一個鍵沒有網絡掩碼,可以跳過不查。第二個鍵有一個0x00000000的掩碼。

查找鍵和這個掩碼的邏輯與運算,所得結果和路由表鍵0相等,即認爲該路由表項能夠匹配。這樣默認路由表就能用作匹配

路由。

3.帶回溯和克隆、並與主機地址相匹配的例子

假定查找鍵是224.0.0.5。32爲1,33爲1,35爲0,63爲1,因此,查找在標有224.0.0.1的葉子處結束。路由表的鍵值和查找關鍵字

並不相等,並且該路由表項不包含網絡掩碼,因此要進行回溯。

回溯向上移動一層,達到63對應的節點,節點含有掩碼0xff000000(如果沒有掩碼則繼續往上回溯),因此對查找鍵和該掩碼

進行邏輯與運算,產生一個新的查找鍵224.0.0.0。再從這個結點開始一次新的查找。在新的查找鍵中63爲0,於是沿左分支

到達標有224.0.0.0的葉子。這個路由表鍵和邏輯與運算得到的查找鍵相匹配,因此這個路由表項是匹配的。

該路由表設置了克隆標誌,因此,以224.0.0.5爲地址創建一個新的葉子。新的路由表項是:


下圖從比特35對應的結點開始,給出了上面路由表樹右邊部分的新的排列。無論何時向樹中添加新的葉子,都需要兩個結點:

一個作爲葉子,另一個作爲測試某一位比特的內部結點。新創建的表項就返回給查找225.0.0.5的調用者。



下圖描述了所有涉及到的數據結構。


我們解釋下圖中的幾個要點。

rf_tables是指向radix_node_head結構的指針數組。每一個地址族都有一個數組與之對應。rt_tables[AF_INET]指向Internet

路由表樹的頂點。

radix_node_head結構包含三個radix_node結構。這三個結構式在初始化路由樹時創建的,中間的是樹的頂點。它對於上面

路由樹的bit32的結點框。三個radix_node結構中的第一個是路由樹中最左邊的葉子(與默認路由共享的重複),第三個結構

是最右邊的葉子。在一個空的路由表中,就只包含三個radix_node結構。

全局變量mask_rnhead也指向一個radix_node_head結構。它是包含了所有掩碼的一棵獨立樹的首部結構。上面的路由樹給出

了八個掩碼可知,有一個掩碼重複了四次,有兩個掩碼重複了一次。通過把掩碼放在一棵單獨的樹中,可以做到對每一個掩碼

只需要維護它的一個備份即可。

路由表樹是用rtentry結構創建的,上圖中有兩個rtentry結構。每一個rtentry結構包含兩個radix_node結構,因爲每次向樹中插入

一個新的路由時,都需要兩個結點:一個是內部結點,對應於某一位測試比特;另一個是葉子,對應於一個主機路由或一個網絡

路由。

存在於每一個UDP和TCP插口中的協議控制塊PCB中包含了一個指向rtentry結構的route結構。每次發送一個IP數據報時,UDP

和TCP輸出函數都傳遞一個指向PCB中route結構的指針,作爲調用ip_output的參數。使用相同路由的PCB都指向相同的路由

表項。


2.選路插口

下圖給出了12種不同類型的選路消息。消息類型位於rt_msghdr結構中的rtm_type字段。



3.函數調用

下圖顯示了各選路函數之間的關係。


rtalloc函數是由Internet協議調用的,用於查找到達指定目的地的路由。圖中還給出了在選路域中創建插口的五個典型程序。

arp處理ARP高速緩存,該ARP高速緩存被存儲在Net/3的IP路由表中。

gated和routed是選路守護進程,他們與其他路由器進行通信,當選路環境發生變化時,對內核的路由表進行操作。

route通常是由啓動腳本或系統管理員執行的一個程序,用於添加或刪除路由。

rwhod在啓動時會調用一個選路sysctl來測定連接的接口。


4.Radix結點數據結構

每一個路由表的表頭都是一個radix_node_head結構,而選路數中所有的節點都是radix_node結構。radix_node_head結構如

下圖所示:

rnh_treetop指向路由數頂端的radix_node結構,可以看到radix_node_head結構的最後一項分配了三個radix_node結構,

其中中間的那個被初始化爲樹的頂點。

從rnh_addaddr到rnh_walktree是七個函數指針,它們所指向的函數被調用以完成對樹的操作。下圖中,rn_inithead僅初始

化其中的四個指針,剩下的未被使用。

下圖給出了組成樹中結點的radix_node結構。

前5個成員是內部結點和葉子結點都有的成員,後面是一個union:如果結點是葉子,那麼它定義了三個成員;如果是內部

結點,那麼它定義了另外不同的三個成員。

rn_mklist是該節點掩碼鏈表的表頭。

rn_p指向該節點的父結點。

如果rn_b值大於等於0,那麼該結點爲內部結點,否則爲葉子。對於內部結點來說,rn_b就是要測試的比特位置。對於葉子

結點來說,rn_b是負的,它的值等於-1減去網絡掩碼索引。該索引是指壓那麼中出現的第一個零的比特位置。下圖給出了

掩碼的索引。


內部結點rn_bmask是個單字節的掩碼,用於檢測相應的比特位是0還是1。在葉子中它的值爲0

下圖給出了rn_flags的三個值。


對於葉子而言,rn_key指向插口地址結構,rn_mask指向保存掩碼的插口地址結構。如果rn_mask爲空,則其掩碼爲隱含的

全1值(即,該路由指向某個主機而不是某個網絡)。


5.選路結構

訪問內核路由信息的關鍵之處是:

1.rtalloc函數,用於查找通往目的地的路由。

2.route結構,它的值由rtalloc函數填寫。

3.route結構所指向的rtentry結構。

在UDP和TCP中使用的協議控制塊(PCB),其中包含了一個route結構。


ro_dst被定義成一個一般的插口地址結構,但對於internet協議而言,它就是一個sockaddr_in結構。

下圖給出了rtentry結構的定義。


結構中包含了兩個radix_node結構,每次向路由樹中添加一個新葉子的同時也要添加一個內部結點,rt_nodes[0]爲葉子,

rt_nodes[1]爲內部結點。

下圖給出了存儲在rt_flags中各種常量以及netstat輸出的相應Flags字符。


如果設置了RTF_GATEWAY標誌,那麼rt_gateway所含的插口地址結構的指針就指向網絡的地址。同樣,rt_gwroute就指向

該網關的rtentry。

rt_refcnt是一個計數器,保存正在包含該結構的引用數目。

當分配該結構存儲空間時,rt_use被初始化爲0,每次利用該路由輸出一份IP數據報時,其值會隨之遞增。

rt_ifp和rt_ifa分別指接口結構和接口地址結構。

rt_llinfo指針允許鏈路層協議在路由表中存儲該協議專用的結構指針。在介紹ARP時會描述如何使用該指針。

下圖給出了rtentry結構中含有的rt_metrics結構。


在TCP中會使用該結構中的六個成員。在ARP中會使用rmx_expire作爲每一個ARP路由項的定時器。


6.初始化:route_init和rtable_init函數

下圖給出了各協議族中與domain結構相關的字段。


PF_ROUTE域是唯一具有初始化函數的域。同樣,只有那些需要路由表的域纔有dom_rtattach函數,並且該函數總是rn_inithead。

選路域和Unix域並不需要路由表。

dom_rtoffset成員是以比特爲單位的選路過程中被檢測的第一個比特的偏移量(從域的插口地址結構的起始處開始計算)。

dom_maxrtkey給出了該結構的字節長度。

下圖列出了路由表初始化過程所包含的步驟。


在系統初始化時,內核的main函數將調用一次domaininit函數,ADDDOMAIN宏用於創建一個domain結構的鏈表,並調用

每個域的dom_init函數。


7.初始化:rn_init和rn_inithead函數

函數rn_init只被route_init調用一次,用於初始化radix函數使用的一些全局變量。

調用rn_inithead,初始化地址掩碼路由樹的首部,並使全局變量mask_rnhead指向radix_node_head結構。

下圖爲Internet協議創建的radix_node_head結構。


這三個radix_node結構組成了一棵樹:中間的結構是樹的頂點,第一個結構式樹的最左邊的葉子,左後一個結構是樹的最

右邊的葉子,這三個結點的父指針都指向中間的那個結點。

最左邊結點的鍵是全0(rn_zeros),最右邊結點的鍵是全1(rn_ones)。

這三個結點都設置了RNF_ROOT標誌,這說明它們都是構成樹的原始結點之一。它們也是唯一具有該標誌的結點。


8.重複鍵和掩碼列表

下面介紹radix_node結構中的兩個字段:一個是rn_dupedkey,它構成了附加的含重複鍵的radix_node結構鏈表;另一個

是rn_mklist,它是含網絡掩碼的radix_mask結構鏈表的開始。在上面的路由樹中最左邊標有end和default兩個框,這就是

重複鍵。最左邊設有RNF_ROOT標誌的結點有一個爲全0比特的鍵,但是它和默認路由的鍵相同。

下圖給出了兩個具有全0比特重複鍵的結點。


圖中最上面的結點即爲路由樹的頂點。接下來的兩個結點是葉子(他們的rn_b爲負值),其中第一個葉子的rn_dupedkey

成員指向第二個結點。

第一個葉子是rnh_nodes[0]結構,該結構是樹的左邊標有end的結點,它設有RNF_ROOT標誌。它的鍵被rn_inithead設爲

rn_zeros。

第二個葉子是默認路由表項。它的rn_key指向0.0.0.0的sockaddr_in結構,並具有一個全0的掩碼。

最後一個是radix_mask結構,樹的頂結點和默認路由對應的葉子都指向這個結構,這個列表時樹的頂結點的掩碼列表,在

查找網絡掩碼時,回溯算法將使用它。radix_mask結構列表和內部結點一起確定了運用於從該結點開始的子樹的掩碼。

應該注意:具有相同值得掩碼之間可以共享,但是具有相同值的鍵之間不能共享。


9.rn_match函數

在Internet協議中,它被稱爲rnh_matchaddr函數。它將被rtallocl函數調用(而rtallocl函數將被rtalloc函數調用),具體

算法如下:

1.從樹的頂端開始搜索,直到到達與查找鍵比特相應的葉子,檢測該葉子,看能夠得到一個精確的匹配。

2.檢測該葉節點,看是否能夠得到匹配的網絡地址。

3.回溯。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章