內核的各種協議並不直接使用前面提供的函數來訪問選路樹,而是調用幾個函數:rtalloc和rtallocl是完成路由表查詢的兩個
函數;rtrequest函數用於添加和刪除路由表項;另外大多數接口在接口連接或斷開時都會調用函數rtinit。
選路消息在兩個方向上傳遞信息。進程(route命令)或守護進程(routed或gated)把選路消息寫入選路插口,以使內核添加
路由、刪除路由或者修改現有的路由。當有時間發生時,如接口斷開、收到重定向等,內核也會發送選路消息。進程通過選路
插口來讀取它們感興趣的內容。
內核還提供了另一種訪問路由表的接口,即系統的sysctl調用。
1.rtalloc和rtalloc1函數
通常,路由表的查找通過調查rtalloc和rtalloc1函數來實現的。rtalloc調用rtalloc1,rtalloc1調用rnh_matchaddr函數,對於
Internet地址來說,該函數就是rn_match函數。
rtalloc1的大概處理流程如下:
調用rn_match,如果符合下列三個條件,則查找成功。
1)存在該協議族的路由表。
2)rn_match返回一個非空指針;並且
3)匹配的radix_node結構沒有設置RNF_ROOT標誌。
如果查找成功,則指向匹配的radix_node結構的指針保存在rt中。如果調用的第二個參數非0,而且匹配的路由表設有
RTF_CLONING標誌,則調用rtrequest函數發送RTM_RESOLVE命令來創建一個新的rtentry結構,該結構是查詢結果的
克隆。
2.宏RTFREE和rtfree函數
宏RTFREE,僅在引用計數小於等於1時才調用rtfree函數;否則,它僅完成引用計數的遞減。
3.rtrequest函數
rtrequest函數是添加和刪除路由表項的關鍵點。下圖給出了調用它的一些其他函數。
rtrequest是一個switch語句,每個case對應一個命令:RTM_ADD、RTM_DELETE和RTM_RESOLVE。
對於RTM_DELETE命令:
1.從選路樹中刪除路由
2.刪除對網絡路由表項的引用。
3.調用接口請求函數。如果該表項定義了ifa_rtrequest函數,就調用該函數。ARP會使用該函數。
4.返回指針或刪除引用。如果調用者需要選路樹中被刪除的rtentry結構指針,則返回該指針,但此時不能釋放該表項,調用
這必須使用完該表項後調用rtfree來刪除它。
對於RTM_RESOLVE命令:
只有rtalloc1能夠攜帶此命令參數調用本函數。也只有在從一個設有RTF_CLONING標誌的表項中克隆一個新的表項時,
rtalloc1才這麼用。
這個命令將跳轉到makeroute標記處繼續執行。
對於RTM_ADD命令:
定位相應的接口。查找適當的本地接口,並返回指向該接口的ifaddr結構的指針。
進入makeroute標記處執行。
makeroute的大概處理流程如下:
1.爲路由表項分配存儲器。分配rtentry結構。
2.分配並複製網關地址。
3.複製目的地址。
4.往選路樹中添加表項(rtentry結構)。
5.保存接口指針。遞增ifaddr結構的引用計數,並保存ifaddr和ifnet結構的指針。
6.爲新克隆的路由複製度量。如果是RTM_RESOLVE,則把被克隆的表項中的整個度量結構複製到新的表項裏。如果是
RTM_ADD,則調用者可在函數返回後設置該度量值。
7.調用接口請求函數。如果爲該表項定義了ifa_rtrequest函數,則調用該函數。
8.返回指正並遞增引用計數。如果調用者需要改新結構的指針,在返回該指針,並將該引用計數值從0遞增到1。
4.rtinit函數
Internet協議添加或刪除相關接口的路由時,對rtinit的調用有四個。
1.在設置點到點接口的目的地址時,in_control調用rtinit兩次。第一次調用指定RTM_DELETE命令,以刪除所有現存的到
該目的地址的路由,第二次調用指定RTM_ADD命令,以添加新路由。
2.in_ifinit調用rtinit爲廣播網絡添加一條網絡路由或爲點到點鏈路添加一條主機路由。如果是給以太網接口添加的路由。
3.in_ifscrub調用rtinit,以刪除一個接口現存的路由。
函數的大概處理流程如下:
1.爲路由獲取目的地址。如果是一個到達某主機的路由,則目的地址是點到點鏈路的另一端。否則,我們處理的就是一個
網絡路由,其目的地址是接口的單播地址。
2.如果要刪除路由,則必須在路由表中查找該目的地址,並得到它的路由表。
3.調用rt_request執行RTM_ADD或者RTM_DELETE命令。
4.如果刪除成功,則產生一個選路消息。
5.如果添加成功但是新路由表項接口的ifaddr指針不等於調用參數,則表明有差錯產生。做如下步驟:向控制檯輸出一條
出錯消息;如果rt_request獲得到的rtentry中ifa_rtrequest函數(rt->ifa->ifa_rtrequest),就以RTM_DELETE爲參數調用
它。如果函數的參數中ifa定義了ifa_rtrequest函數,就以RTM_ADD爲參數調用它。最後產生選路消息。
5.rtredirct函數
當收到一個ICMP重定向後,icmp_input調用rtredirect及pfctlinput。後一個函數又調用udp_cltinput和tcp_ctlinput,這兩個
函數遍歷所有的UDP和TCP協議控制塊(PCB)。如果PCB連接到一個外部地址,而到該外部地址的方向已經被改變,並且
該PCB持有到那個外部地址的路由,則調用rtfree釋放該路由。下一次使用這些控制塊發送外部地址的IP數據報時,就會調用
rtalloc,並在路由表中查找該目的地址,很可能會找到一條新的路由。
rtredirect函數的作用是驗證重定向中的信息,並立即更新路由表,產生選路插口消息。該函數的大概處理流程如下:
1.新路由必須直接相連,否則該重定向失效。
2.查找目的地址的路由表項並驗證重定向。調用rtalloc1在路由表中查找到目的地址的路由。驗證重定向時,下列條件必須爲
真:
必須未設置RTF_DONE標誌。
rtalloc必須已經找到一個到dst的路由表項。
發送重定向的路由器的地址必須等於當前爲目的地址設置的rt_gateway.
新網關的接口必須等於當前爲目的地址設置的接口,也就是說,新網關必須和當前網關在同一網絡上。
新網關不能把到這個主機的路由改變到自己,也就是說,不能存在與gateway相等的有單播地址或廣播地址的連接着的接口。
3.創建新的主機路由。如果到達目的地址的當前路由是一個網絡路由,並且重定向是主機重定向而不是網絡重定向,那麼就爲
該目的地址建立一個主機路由(調用rtrequest,RTM_ADD),而不必去管現存的網絡路由。
4.改變現存的主機路由。當到達目的地址的當前路由已經是一個主機路由時,不需要創建新的表項,而是修改現存的表項。
5.由rt_missmsg產生一個選路插口消息。
6.選路消息的結構
選路消息有一個定長的首部和至多8個插口地址結構組成。該定長首部是下列三種結構中的一個:
rt_msghdr
if_msghdr
ifa_msghdr
選路消息三種首部結構的前三個成員的數據類型及其含義是相同的,分別爲:消息的長度,版本和類型。每中結構都都有
一個成員來編碼首部之後8個可能的插口地址:rtm_addr、ifm_addrs和ifam_addrs成員,它們都是一個比特掩碼。
下圖給出了最常用的結構,rt_msghdr。
RTM_IFINFO消息使用了下圖的if_msghdr結構。
RTM_NEWADDR和RTM_DELADDR消息使用了下圖的ifa_msghdr結構。
三個變量rtm_addrs、ifm_addrs和ifam_addrs都是比特掩碼,它們定義了首部之後的插口地址結構,下圖給出了比特掩碼
用到的一些常量。
內核用上圖的數組下標來引用rt_addrinfo結構,如下圖所示。
如果rti_addrs成員中設置了RTA_GATEWAY比特,則rti_info[RTA_GATEWAY]成員就是含網關地址的插口地址結構的指針。
7.rt_missmsg函數
rt_missmsg函數使用了rt_addrinfo結構,並調用rt_msg1在mbuf鏈中爲進程創建了相應的變長消息,之後調用raw_input將
該mbuf鏈傳遞給所有相關的選路插口。函數的處理流程如下:
1.在mbuf中創建消息。rt_msg1在mbuf鏈中創建相應的消息,並返回該鏈的指針,下圖爲rt_msg1創建的一個mbuf鏈。
2.完成消息的創建。設置rt_msghdr的其他成員。
3.設置消息的協議,調用raw_input。
8.rt_ifmsg函數
在if_up和if_down中都調用了rt_ifmsg。在接口連接或斷開時,該函數被用來產生一個選路插口消息。函數的大概處理流程
如下:
1.調用rt_msg1函數在mbuf鏈中創建消息。
2.完成消息的創建。設置if_msghdr接口中其他成員。
3.設置消息的協議,調用raw_input。
9.rt_newaddrmsg函數
在接口上添加或者刪除一個地址時,rtinit要以RTM_ADD或者RTM_DELETE爲參數調用rt_newaddrmsg。函數的大概處理
流程如下:
1.調用rt_msg1函數在mbuf鏈中創建消息。
2.完成消息的創建。設置ifa_msghdr接口中其他成員。
3.設置消息的協議,調用raw_input。