LWIP協議棧:IP協議


1. IP協議概述

IP 協議(Internet Protocol),又稱之為網際協議,屬於網絡層。IP協議以IP地址作為唯一識別碼,負責將數據從源主機發送到目標主機。

IP 協議是一種無連接的不可靠數據報交付協議,協議本身不提供任何的錯誤檢查與恢復機制。 

1.1 IP地址

在互聯網中,每一個主機都有一個唯一的IP地址作為身份識別標志。

(1)分類編址

IP地址可分為五類:A類、B類、C類、D類、E類,其組成如下圖。

   各類IP地址的特點,如下圖。

   (2)特殊IP地址

特殊IP地址用於特殊用途,不能分配給任何一個網絡的主機使用。

受限廣播地址  網絡號、主機號全為1的地址(255.255.255.255),表示整個互聯網內的主機。但是由於路由器禁止轉發IP地址為255.255.255.255的數據包,這樣的數據包只會在局域網內廣播。
直接廣播地址  主機號全為1的地址,表示局域網內的所有主機,
多播地址  D類地址屬於多播地址,一個發送者,多個接收者。D類地址只能作為目標IP地址,不能作為源IP地址。
環回地址  A類地址中,127網段的所有地址都是環回地址,用來測試網絡協議是否正常工作。譬如,ping 127.1.1.1可以測試本地TCP/IP協議是否正常工作。
本網絡本主機  IP地址全為0的地址(0.0.0.0),表示本網絡本主機。該地址只能作為源地址,用於本機IP地址不明確的情況。

 1.2 局域網、廣域網、互聯網

局域網(Local Area Network,縮寫為 LAN),又稱內網,覆蓋局部區域的計算機網絡。

廣域網((Wide Area Network,縮寫為 WAN),又稱外網、公網,連接不同區域的計算機網絡進行通信。

互聯網,由無數個局域網,通過廣域網線路匯聚互聯形成。

局域網、廣域網、互聯網三者間關系如下圖所示。

  • 無線路由器為手機、電腦分配局域網IP(LAN-IP)。路由器的IP地址,由運營商分配(運營商的局部IP地址),該地址將被轉換為廣域網IP地址(WAN-IP)。廣域網IP地址(WAN-IP)也需要轉換為互聯網公共IP地址(Global-IP),才能進入互聯網。
  • 網絡通信的IP地址轉換過程:LAN-IP <—> WAN-IP <—> Global-IP。

1.3 網絡地址轉換

NAT(Network Address Translation),網絡地址轉換,其功能是實現局域網IP地址與廣域網IP地址之間的轉換,即完成LAN-IP <—> WAN-IP之間的轉換。

示例:

  • 具有NAT功能的路由器擁有兩個IP地址,一個內部地址,用於進行局域網內部的通信;一個外部地址,用於與廣域網進行通信,由運營商分配。
  • 具有 NAT 功能的路由器會在其內部維護一個 NAT 轉換表。當路由器收到局域網的IP數據報時,路由器會為該數據報分配一個它內部的 NAT 端口(譬如:port 6666),局域網主機IP地址(192.168.0.181:5555)與廣域網IP地址(223.166.166.66:6666)形成一個映射。從而,局域網主機能夠實現與廣域網進行通信。
  • NAT轉換中,路由器會每個連接的局域網主機分配唯一的NAT端口號,並回收失效端口號。

2. IP報文

2.1 IP報文格式

  •  版本:IP協議的版本號。IPv4的版本號為4,IPv6的版本號為6。
  • 首部長度:記錄IP首部所占的空間,單位“字”。占4bit,因此IP首部的最大長度為15*4=60Byte。
  • 服務類型(TOS):用於區分不同的IP數據包。譬如,區分一些特別要求低時延、高吞吐量或可靠性的數據包;從而便於路由器為此類IP數據包提供更合理的路徑。
  • 數據報長度:IP報文的總長度,IP首部+數據區域的長度,單位“字節”。該長度一般不超過以太網數據幀的最大長度(MTU_MAX=1500Byte),若超過,則需進行分片發送。若該長度小於MTU_MIN(46Byte),則需填充至MTU_MIN后再發送。
  • 標識:用於判斷各個IP數據報分片是否屬於同一個數據報。每發送一個IP數據報,該字段的值+1;屬於同一個IP數據報的分片,該字段的值相等。
  • 標志:占3bit。BIT(0)保留未用;BIT(1)為1表示該數據報允許進行分片處理,為0表示禁止分片處理(此時,若數據報長度超過MTU_MAX,則丟棄該數據報);BIT(2)為0表示該分片是整個數據報的最后一個分片,反之則不是。
  • 分片偏移量:表示當前分片所攜帶的數據在整個IP數據報中的偏移量,以8Byte為單位。
  • 生存時間(TTL):每當IP數據報被一個路由器處理后,該字段的值減1;當減為0時,丟棄該數據報。從而確保IP數據報不會永遠在網絡中循環(譬如由於長時間的路由選擇環路)。
  • 上層協議:表示IP數據報的數據部分應該交由哪個傳輸協議(TCP、UDP、)處理。
  • 首部校驗和:IP數據報首部的校驗和,用於幫助路由器檢測收到的IP數據報的首部是否正確。
  • 源IP地址:源主機的IP地址。
  • 目標IP地址:目標主機的IP地址。
  • 選擇:該字段不是必須組成部分。LWIP協議棧只識別選項字段,但是不會處理它的內容。
  • 數據區域:IP數據報所攜帶額數據。

P.S.:IPv4和IPv6的報文格式不同,此處記錄的為IPv4報文格式。

2.2 IP報文數據結構定義

LWIP定義了ip_hdr結構體來描述IP報文的首部,同時定義了獲取IP報文首部信息的宏定義、設置IP報文首部信息的宏定義。源碼位置:lwip_2_1_2/src/core/ipv4/ip4_frag.c

定義ip_hdr結構體時要禁止編譯器進行對齊操作,因為該結構體的很多字段都是按位進行操作的。

 1 PACK_STRUCT_BEGIN
 2 struct ip_hdr
 3 {
 4     /* 版本 / 首部長度 */
 5     PACK_STRUCT_FLD_8(u8_t _v_hl);
 6     /* 服務類型 */
 7     PACK_STRUCT_FLD_8(u8_t _tos);
 8     /* 數據報總長度 */
 9     PACK_STRUCT_FIELD(u16_t _len);
10     /* 標識字段 */
11     PACK_STRUCT_FIELD(u16_t _id);
12     /* 標志與偏移 */
13     PACK_STRUCT_FIELD(u16_t _offset);
14 #define IP_RF 0x8000U /* 保留的標志位 */
15 #define IP_DF 0x4000U /* 不分片標志位 */
16 #define IP_MF 0x2000U /* 更多分片標志 */
17 #define IP_OFFMASK 0x1fffU /* 用於分段的掩碼 */
18     /* 生存時間 */
19     PACK_STRUCT_FLD_8(u8_t _ttl);
20     /* 上層協議*/
21     PACK_STRUCT_FLD_8(u8_t _proto);
22     /* 校驗和 */
23     PACK_STRUCT_FIELD(u16_t _chksum);
24     /* 源 IP 地址與目標 IP 地址 */
25     PACK_STRUCT_FLD_S(ip4_addr_p_t src);
26     PACK_STRUCT_FLD_S(ip4_addr_p_t dest);
27 } PACK_STRUCT_STRUCT;
28 PACK_STRUCT_END
29 
30 
31 /* 獲取 IP 數據報首部各個字段信息的宏 */
32 
33 //獲取協議版本
34 #define IPH_V(hdr) ((hdr)->_v_hl >> 4)
35 //獲取首部長度(字)
36 #define IPH_HL(hdr) ((hdr)->_v_hl & 0x0f)
37 //獲取獲取首部長度字節
38 #define IPH_HL_BYTES(hdr) ((u8_t)(IPH_HL(hdr) * 4))
39 //獲取服務類型
40 #define IPH_TOS(hdr) ((hdr)->_tos)
41 //獲取數據報長度
42 #define IPH_LEN(hdr) ((hdr)->_len)
43 //獲取數據報標識
44 #define IPH_ID(hdr) ((hdr)->_id)
45 //獲取分片標志位+偏移量
46 #define IPH_OFFSET(hdr) ((hdr)->_offset)
47 //獲取偏移量大小(字節)
48 #define IPH_OFFSET_BYTES(hdr) \
49 ((u16_t)((lwip_ntohs(IPH_OFFSET(hdr)) & IP_OFFMASK) * 8U))
50 //獲取生存時間
51 #define IPH_TTL(hdr) ((hdr)->_ttl)
52 //獲取上層協議
53 #define IPH_PROTO(hdr) ((hdr)->_proto)
54 //獲取校驗和
55 #define IPH_CHKSUM(hdr) ((hdr)->_chksum)
56 
57 
58 /* 用於填寫 IP 數據報首部的宏*/
59 
60 //設置版本號跟首部長度
61 #define IPH_VHL_SET(hdr, v, hl) \
62 (hdr)->_v_hl = (u8_t)((((v) << 4) | (hl)))
63 //設置服務類型
64 #define IPH_TOS_SET(hdr, tos) (hdr)->_tos = (tos)
65 //設置數據報總長度
66 #define IPH_LEN_SET(hdr, len) (hdr)->_len = (len)
67 //設置標識
68 #define IPH_ID_SET(hdr, id) (hdr)->_id = (id)
69 //設置分片標志與偏移量
70 #define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off)
71 //設置生存時間
72 #define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl = (u8_t)(ttl)
73 //設置上層協議
74 #define IPH_PROTO_SET(hdr, proto) (hdr)->_proto = (u8_t)(proto)
75 //設置校驗和
76 #define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum)
IP報文數據結構定義

 3. IP數據報分片

(1)分片處理的原因

IP數據報被傳送至鏈路層,鏈路層將IP數據報封裝成鏈路層幀,網卡硬件將鏈路層幀發送至目標主機。一個鏈路層幀能攜帶的最大數據量稱為最大傳送單元(MTU),不同網卡硬件的MTU可能不一樣。當IP數據報的長度超過MTU,則需對其進行分片處理后,再發送。

(2)分片處理的原理

IP數據報的分片處理,是將IP數據報中的數據區域切割為若干個較小的IP數據報,並封裝成單獨的鏈路層幀后進行發送。

  • 每個分片的IP首部,除“標志”、“分片偏移量”這兩個字段,其余都一樣。
  • “分片偏移量”字段的單位是8Byte,因此分片的數據區域的長度也必須是8的整數倍。
  • 最后一個分片的標志位的BIT(2)為0,表示該分片為最后一個分片。
  • 所有分片在到達目標主機的IP層后,進行重裝,形成一個完整的IP數據包。

(3)分片處理示例

主機發送一個4000Byte的IP數據報,鏈路層MTU = 1500Byte,需要對原始IP數據報進行分片處理。

原始IP數據報(4000Byte)= IP首部(20Byte)+ 數據區域(3980Byte),對數據區域進行切割,並填寫每個分片IP首部的“標志”、“分片偏移量”字段。

第一個分片:“標志”字段BIT(2) = 1,分片偏移量為0,分片數據報長度(1500Byte)=  IP首部(20Byte)+ 數據區域(1480Byte);

第二個分片:“標志”字段BIT(2) = 1,分片偏移量為185(1480/8),分片數據報長度(1500Byte)=  IP首部(20Byte)+ 數據區域(1480Byte);

第三個分片:“標志”字段BIT(2) = 0,分片偏移量為370(185+185),分片數據報長度(1040Byte)=  IP首部(20Byte)+ 數據區域(1020Byte)。

 (4)分片處理的源碼

分片處理的源碼位於“lwip_2_1_2/src/core/ipv4/ip4_frag.c”,調用“ip4_frag()”函數對IP數據報進行分片處理並發送至目標主機。

4. IP數據報的發送與接收

IP數據報的發送與接收,源碼位於:lwip_2_1_2/src/core/ipv4/ip4.c

4.1 IP數據報的發送

  •  傳輸層需要發送數據時,將需要發送的數據傳遞到網絡層的IP協議,IP層調用“ip4_output()”函數發送IP數據報。
  • “ip4_output()”函數調用“ip4_route_src()”函數根據目標IP地址在網卡列表中選擇一個合適的網卡,匹配條件:目標IP地址與網卡地址在一個子網內,或者目標IP地址等於網卡的網關地址。再調用“ip4_output_if()”函數發送IP數據報。
  • “ip4_output_if_src()”函數調整payload指針至IP數據報首部的起始地址,填寫IP首部信息,並對IP數據報進行分類處理。若目標IP地址等於源主機的IP地址,則調用“netif_loop_output()”函數進行環回輸入;若IP數據報長度超過MTU,則調用“ip4_frag()”函數進行分片發送;否則直接調用“netif->output ”接口將IP數據報傳遞給ARP協議進行發送。

4.2 IP數據報的接收

  • 鏈路層接收到一個IP數據報,通過“ethernet_input()”函數再傳遞到“ip4_input()”函數進行處理。
  • “ip4_input()”函數首先檢查IP數據報首部的協議版本是否為IPv4,然后根據目標IP地址在本地網卡列表中尋找有效的目標網卡。若目標IP地址不等於主機地址,則通過“ip4_addr_isloopback()”函數判斷目標IP地址是否為環回地址。若匹配到目標網卡,對於分片則調用“ip4_reass()”函數進行重裝,然后將數據傳遞至指定的傳輸層協議。若沒有找到目標網卡,對於廣播包則直接刪除該數據報,對於非廣播包則可以通過“ip4_forward()”函數進行轉發。

5. 參考資料

[1] 野火《LwIP應用開發實戰指南》。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM