Lwip IP包分片重組

1. 開發環境

操作系統:SylixOS

編程環境:RealEvo-IDE3.1

硬件平臺:AT9x25開發板

2. 技術實現

SylixOS系統使用的網絡協議棧是Lwip協議棧。LwipLight Weight (輕型)IP協議,有無操作系統的支持都可以運行。Lwip實現的重點是在保持TCP協議主要功能的基礎上減少對RAM 的佔用,它只需十幾KBRAM40K左右的ROM就可以運行,這使Lwip協議棧適合在低端的嵌入式系統中使用。

Lwip協議棧主要關注的是怎麼樣減少內存的使用和代碼的大小,這樣就可以讓Lwip適用於資源有限的小型平臺例如嵌入式系統。爲了簡化處理過程和內存要求,LwipAPI進行了裁減,可以不需要複製一些數據。

網絡協議棧是以層的結構來實現的。鏈路層具有最大傳輸單元MTU這個特性,它限制了數據幀的最大長度,不同的網絡類型都有一個上限值。以太網的MTU1500。如果IP層有數據包要傳,而且數據包的長度超過了MTU,那麼IP層就要對數據包進行分片(fragmentation)操作,使每一片的長度都小於或等於MTU。我們假設要傳輸一個UDP數據包,以太網的MTU1500字節,一般IP首部爲20字節,UDP首部爲8字節,數據的淨荷(payload)部分預留是1500-20-8=1472字節。如果數據部分大於1472字節,就會出現分片現象。

本篇文章主要介紹Lwip裏對收到的IP分片報文重組的實現。


 2.1      IP報文重組宏觀分析

wKioL1lHKZvwNR8yAAA_QYsVKiE425.png-wh_50

21 IP包重組框圖


IP包的重組的簡單流程如圖2-1所示

首先,Lwip協議裏會有一個單向鏈表,每個結點是一個ip_reassdata的結構體,reassdatagrams指向這個鏈表。

ip_reassdata結點用來進行分片包的重組,每個結點對應着一個完整的IP包。這個結構體裏有一個指向pbuf的成員。當一個IP報文通過ip4_input向上層傳輸時,會檢測是否屬於分片包,如果是,則需要進行分片重組。

重組時,會從reassdatagrams鏈表裏查找是否已經有ip_reassdata這個結構體了,如果有,就會改變每個分片包的報頭,這裏是通過一個ip_reass_helper結構體改變的。改變完之後,會把這個分片包根據偏移插入到ip_reassdata這個結構體後面對應的位置。如果在reassdatagrams鏈表裏查找不到對應的ip_reassdata這個結構體,那麼說明這個分片包是收到幀的第一個報文,因此會創建一個新的ip_reassdata結構體,然後再進行後續操作。插入完成後,協議棧會檢測報文是否全部接收並重組完成。如果完成,就會從reassdatagrams鏈表中把ip_reassdata結構體刪除並把重組好的報文返回給ip4_input


2.2      代碼分析

IP包的分片重組是通過ip4_reass 這個函數來完成的。判斷需要重組時都會調用這個函數,這個函數的主要內容如下:

  1. 對收到的IP報文的首部長度檢測,Lwip目前是不支持IP報文頭帶填充位的。

  2. 通過IP報文頭,獲得偏移和數據報文的長度。         

  3. lwip的一個特性:它對reassdatagrams鏈表上的pbuf的總數是有限制的,因此協議棧會判斷加上收到的這些pbuf的個數後,會不會超過這個限制。        

  4. 如果超過了,會刪除鏈表中存在時間最長的那個。         

  5. 從鏈表中尋找對當前的pbuf對應的ip_reassdata結構體。如果沒有,則會新創建一個結構體。          

  6. 現在應該已經找到一個合適的 ip_reassdata結構體了,此時會做一個判斷:如果當前的這個IP報文的偏移爲0並且此時的 ip_reassdata結構體的偏移也不等於0,那麼需要把當前的這個IP分片報文的頭部拷貝到 ip_reassdata結構體中。        

  7. 檢測當前收到的IP分片報文是不是最後一個,如果是最後一個,那麼,就更新一下當前IP分片報文對應的 ip_reassdata結構體。        

  8. 上述兩個檢測完成之後,會調用ip_reass_chain_frag_into_datagram_and_validate,找到一個合適的地方,把IP分片包插進去。      

  9. 檢測當前的報文是否組裝完成,如果完成,返回一個非0的值。否則,返回0       

  10. 上述檢測結果如果是沒有完成,則ip4_reass 直接返回。如果完成了,則會對 ip_reassdata結構體的iphdr字段做修改,包括報文總長度、校驗和,並且把iphdr字段全部拷貝到第一個分片包的頭部,這樣,整個IP包的信息就出現在第一個分片包的信息裏。        

  11. 接下來,把其他的IP分片包的的信息頭刪除,這樣一個完整的IP包就重組完成了。       

最後,調用 ip_reass_dequeue_datagramip_reassdata結構體從整個鏈表中刪除。 代碼執行到這裏,整個重組基本完成。 


3. 參考資料


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