在NS2中,AODV路由協議主要包括以下幾個組件:
1、協議實體
2、路由表
3、定時器
(1)廣播定時器
(2)週期Hello報文廣播定時器
(3)用於鄰居管理的定時器
(4)用於路由緩存的定時器
(5)用於本地修復的定時器
(6)緩存廣播ID的定時器
4、日誌記錄器
5、路由緩存隊列
首先來看協議從接收到一個分組開始的基本流程。
當協議接收到一個分組,即recv(Packet*, Handler*)函數被調用,函數根據分組類型調用不同的處理函數進行處理。
1、如果是協議分組,則將分組的ttl值減1,並調用recvAODV(Packet*)函數進行處理。recvAODV函數再根據分組的不同類型來調用不同的函數進行處理。
(1)如果接收到的是路由請求分組,則調用recvRequest(Packet*)函數進行處理。
如果該分組由節點自身產生或已經接收過的,會被節點丟棄,並結束處理。否則,節點將緩存該分組的序列號,並將該分組發送來的路徑添加到反向路由中,轉發相應分組。然後,節點根據該分組的目的地址進行判斷並調用不同函數進行處理。
如果節點自身即爲目的節點,則調用sendReply(nsaddr_t, u_int32_t, nsaddr_t, u_int32_t, u_int32_t, double)函數進行響應。如果節點不是目的節點,但知道通往目的節點的路由,則調用sendReply函數進行響應,並在源和目的前驅列表中分別插入到源和目的的下一跳節點。否則,不能直接響應該請求,將跳數加1,並調用forward(aodv_rt_entry*, Packet*,
double)函數轉發該分組。
在sendReply函數中,節點首先查找到達目的節點(即發送路由請求分組的節點)的路由,創建並填充分組,然後調用Scheduler::instance().schedule()函數來發送該分組。
(2)如果接收到的是路由響應分組,則調用recvReply(Packet*)函數進行處理。
節點首先查詢前往分組目的節點的路由,如果不存在則新增一條路由項。然後,節點更新到該目的節點的路由項,併發送所有相關分組。
如果節點爲目的節點則更新路由發現延遲併發送所有相關的分組。如果節點不是目的節點,但知道通往目的節點的路由,則將跳數加1,調用forward函數轉發該分組,並修改響應的前驅列表。如果節點不是目的節點,也不知道通往目的節點的路由,則丟棄該分組。
(3)如果接收到的是路由錯誤分組,則調用recvError(Packet*)函數進行處理。
節點首先清除所有受到影響的路由項,丟棄所有受影響的分組。然後,如果前驅節點中存在會受該路由錯誤影響的分組,則調用sendError(Packet*, bool)函數轉發該分組。
sendError函數創建並填充分組,然後調用Scheduler::instance().schedule()函數來發送該分組。
(4)如果接收到的是Hello消息分組,則調用recvHello(Packet*)函數進行處理。
節點會將該鄰居的信息添加到鄰居列表中(或更新該鄰居的信息)。
2、如果是數據分組,則節點丟棄已經發送過或者ttl爲0的分組,並結束處理。如果分組是由上層協議產生的,則節點添加IP報頭。隨後,節點根據目的路由進行不同處理。
(1)如果目的節點路由未知,則調用rt_resolve(Packet*)函數進行路由解析和轉發。
如果目的節點路由在路由表中存在,則直接調用forward函數進行轉發。如果分組是由節點自身產生的,則將分組保存到緩衝隊列中,並調用 sendRequest(nsaddr_t)函數查詢目的路由。如果目的路由已知,但正在進行本地修復,則將分組保存到緩衝隊列中。否則,丟棄該分組,並調用sendError函數報錯。
(2)如果目的節點路由已知,則調用forward進行轉發。
節點丟棄ttl爲0的分組,並根據分組類型決定下一步操作。
如果接收到的是數據分組,且自身爲目的節點,則通過調用PortClassifier對象的recv(Packet*, Handle*)函數將分組交遞給高層協議,並結束處理。否則,節點設置分組屬性,並調用Scheduler::instance().schedule (Handler*, Event*, double)函數來發送分組。其中,Handler爲基類中的屬性target_(會根據腳本中的設置指向相應的協議實體),Event爲要發送的分組即可。
以上就是在節點收到分組後的一個處理過程。接下來看看各個定時器所做的工作。
1、廣播定時器BroadcastTimer在到時後調用id_purge()函數刪除廣播項中已超時的項目,並通過調用Scheduler:: instance().schedule()函數來設置下次被調用的時間(Handler爲this指針,Event爲類屬性intr)。
2、週期Hello報文廣播定時器HelloTimer在到時後調用sendHello()函數向鄰居創建併發送Hello消息,並調用schedule()函數來設置下次被調用的時間。
3、鄰居管理定時器NeighborTimer在到時後調用nb_purge()函數來清除鄰居列表中已超時的鄰居項,並調用schedule()來設置下次被調用的時間。nb_purge會調用nt_delete(nsaddr_t)函數來清除超時的鄰居項,其又會調用 handle_link_failure(nsaddr_t)函數來處理由於鄰居節點被刪除而引起的路由變化。
4、路由緩存定時器RouteCacheTimer在到時後調用rt_purge()函數來清除路由表中已超時的路由項,並丟棄相關的分組,再調用schedule()來設置下次被調用的時間。
5、本地修復定時器LocalRepairTimer在調用後根據傳遞的分組的目的地址關閉相應的路由項。
6、緩存廣播ID定時器BroadcastID用來保存廣播分組的ID。
此外,路由表、日誌記錄和隊列三個類就相對比較簡單了,都只實現了一些非常基本的功能,在此就不做介紹了
1、AODV簡介
AODV是由Nokia研究中心的Charles E.Perkins和加利福尼亞大學Santa Barbara的Elizabeth M.Belding-Roryer以及Cincinnati大學Samir R.Das等共同開發,已經被 IETF MANET工作組於2003年7月正式公佈爲自組網路由協議的RFc標準。AODV實質上就是DSR和DSDV的綜合,它借用了DSR中路由發現和路由維護的基礎程序,及DSDV的逐跳(Hop-by-Hop)路由、目的節點序列號和路由維護階段的週期更新機制,以DSDV爲基礎,結合DSR中的按需路由思想並加以改進。
AODV在每個中間節點隱式保存了路由請求和應答的結果,並利用擴展環搜索的辦法來限制搜索發現過的目的節點的範圍。AODV支持組播功能,支持QoS,而且AODV中可以使用IP地址,實現同Internet連接,但是不支持單向信道。和DSDV保存完整的路由表不同的是,AODV通過建立基於按需路由來減少路由廣播的次數,這是AODV對DSDV的重要改進。和DSR相比,AODV的好處在於源路由並不需要包括在每一個數據分組中,這樣會使路由協議的開銷有所降低。AODV是一個純粹的按需路由系統,那些不在路徑內的節點不保存路由信息,也不參與路由表的交換。AODV協議可以實現在移動終端間動態的、自發的路由,使移動終端很快獲得通向所需目的的路由,同時又不用維護當前沒有使用的路由信息,並且還能很快對斷鏈的拓撲變化做出反應。AODV的操作是無環路的,在避免了通常Bellman-ford算法的無窮計數問題的同時,還提供了很快的收斂速度。AODV的路由表中每個項都使用了目的序列號(Destination Sequence Number)。目的序列號是目的節點創建,並在發給發起節點的路由信息中使用的。使用目的序列號可以避免環路的發生。
當源節點需要和目的節點通信時,如果在路由表中已經存在了對應的路由時,AODV不會進行任何操作。當源節點需要和新的目的通信時,它就會發起路由發現過程,通過廣播RREQ信息來查找相應路由。當這個RREQ到達目的節點本身,或者是一個擁有足夠新的到目的節點路由的中間節點時,路由就可以確定了。所謂“足夠新”就是通過目的序列號來判斷的。目的節點或中間節點通過原路返回一個RREP信息來向源節點確定路由的可用性。在維護路由表的過程中,當路由不再被使用時,節點就會從路由表中刪除相應的項。同時,節點會監視一個活動路由(activeroute,有限跳的,可用於數據轉發的路由表)中,下一跳節點的狀況。當發現有鏈路斷開的情況時,節點就會使用RERR通知上游的節點,而上游的節點就會使用該RERR分組拷貝通知更上游的節點。在RERR消息中,指明瞭由於斷鏈而導致無法達到目的節點。每個節點都保留了一個“前驅列表”(precursor list)來幫助完成錯誤報告的功能,這個列表中保存了把自己作爲到當前不可達節點的下一跳的相鄰節點(可以通過記錄RERR很容易地獲得)。在路由表中,針對每一個表項,需要記錄相應的的特徵內容。其中,序列號是防止路由環路的關鍵所在。當發生斷鏈時,通過增加序列號和度量值(跳數)來使路由表項無效。
在RREP轉發回源節點的過程中,沿着這條路徑上的每一個.節點都將建立到目的節點的同向路由,也就是記錄下RREP是從哪一個鄰居節點來的地址,然後更新有關源和目的路由的定時器信息以及記錄下RREP中目的節點的最新序列號。對於那些建立了反向路由,但RREP分組並沒有經過的節點,它們中建立的反向路由將會在一定時間(Active-Route-Timeout)後自動變爲無效。收到RREP分組的節點將會對到某一個源節點的第一個RREP分組進行轉發,對於其後收到的到同一個源的RREP分組,只有當後到的RREP分組中包含了更高的目的序列號或雖然有相同的目的序列號但所經過的跳數較少時,節點才一會重新更新路由信息,以及把這個RREP分組轉發出去。這種方法有效地抑制了向源節點轉發的RREP分組數,而且確保了最新及最快的路由信息。源節點將在收到第一個RREP分組後,就開始向目的節點發送數據分組。如果以後源節點瞭解到的更新的路由,它就會更新自己的路由信息。
移動節點爲每一個相關的目的節點維護了一個路由表。每一個路由表包含以下一些信息:目的地址、下一跳地址、跳數、目的序列號及路由項的生存時間。路由表在每一次被用來傳送一個分組時,它的生存時間都要重新開始計算,也就是用當前時間加上Aetive-Route-Timeout。如果一個移動節點被提供了到達某一個目的節點的新路由,那麼它就會把這個新路由的目的序列號與自己路由表中己有的目的序列號做比較,並將目的序列號大的作爲到達目的節點的路由表。如果目的序列號相同,則採用到目的節點所經過的節點數(跳數)最少的那個路由。
一旦一個節點的下一跳節點變得不可達,這時它就要向利用該損壞鏈路的活躍上游節點發送未被請求的RREP(RERR)分組,這個RREP(RERR)分組帶有一個新的序列號(即在目的序列號上加1),並將跳數值設置爲二。收到這個RREP(RERR)分組的節點再依次將RREP(RERR)分組轉發到它們各自的活躍鄰居,這個過程持續到所有的與損壞鏈路有關的活躍節點都被通知到爲止。源節點在收到斷鏈的通知後,如果它還要與目的節點聯繫,它就需要再次發起新的路由發現過程。這時,它將會廣播一個RREQ分組,這個RREQ分組中的目的序列號要在源節點已知的最新目的序列號之上加1,以確保那些還不知道目的節點最新位置的中間節點對這個RREQ分組做出響應,從而能保證建立一條新的、有效的路由。
http://hi.baidu.com/jerry_916/blog/item/91342237a4e7402d0b55a963.html