《TCP/IP詳解卷2:實現》筆記--選路請求和選路訊息
核心的各種協議並不直接使用前面提供的函式來訪問選路樹,而是呼叫幾個函式: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。