1. ARP協議簡介
-
ARP(Address Resolution Protocol),地址解析協議。ARP協議處於網絡層,其主要功能就是通過目標設備的 IP 地址,查詢目標設備的 MAC 地址,從而進行網絡通信。
-
網絡層中,源主機和目標主機依賴於IP地址進行通信。而鏈路層又有自己的尋址尋址機制(如,以太網依賴於MAC地址進行通信)。ARP的作用在於將IP地址轉換為MAC地址,從而連接網絡層與鏈路層,使得上層可以通過IP地址進行網絡通信。
-
ARP協議的基本運作過程如下:
2. ARP緩存表
2.1 ARP緩存表的定義
每台主機或路由器在其內存中都存儲着一個ARP緩存表,表中記錄着了<IP 地址,MAC 地址>對,反映着目標主機的IP地址與MAC地址的映射關系。
1 /*lwip/src/netif/etharp.c*/ 2 3 enum etharp_state { 4 ETHARP_STATE_EMPTY = 0, //空狀態,表示該表項為空 5 ETHARP_STATE_PENDING, //掛起狀態,表示該表項還未收到目標主機的ARP應答 6 ETHARP_STATE_STABLE, //可用狀態,表示該表項可用 7 ETHARP_STATE_STABLE_REREQUESTING_1,//過渡狀態 8 ETHARP_STATE_STABLE_REREQUESTING_2 //過渡狀態 9 #if ETHARP_SUPPORT_STATIC_ENTRIES 10 , ETHARP_STATE_STATIC 11 #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ 12 }; 13 14 struct etharp_entry { 15 #if ARP_QUEUEING 16 /* 指向此ARP表項上掛起的數據包隊列*/ 17 struct etharp_q_entry *q; 18 #else /* ARP_QUEUEING */ 19 /*指向此ARP表項上掛起的單個數據包 */ 20 struct pbuf *q; 21 #endif /* ARP_QUEUEING */ 22 ip_addr_t ipaddr; //目標主機的IP地址 23 struct netif *netif; //目標主機的網卡信息 24 struct eth_addr ethaddr;//目標主機的MAC地址 25 u8_t state; //此表項的狀態 26 u8_t ctime; //此表項的生存時間 27 }; 28 29 static struct etharp_entry arp_table[ARP_TABLE_SIZE]; //LWIP協議棧的ARP緩存表
- 表項的數據包指針q:指針q指向需要發送至該目標主機的數據包。struct etharp_q_entry *q指向一個數據包隊列,struct pbuf *q指向單個數據包。
- 表項的生存時間ctime:每個表項都包含一個ctime變量,表示該表項的生存時間。當達到指定的生存時間,該表項會被刪除。
2.2 緩存表的動態處理
ARP協議的核心就是對緩存表的動態處理。因為IP地址可能是動態的,所以ARP緩存表必須動態更新。
ARP協議中,通過發送ARP請求包、接收ARP應答包、ARP緩存表超時處理來實現緩存表的動態更新。
(1)發送ARP請求包
發送數據時,若不存在目標主機的表項,則新建一個表項,並發送ARP請求包;若存在目標主機的表項,對處於ETHARP_STATE_STABLE的表項,會再次發送ARP請求包,以確認目標主機依然在工作狀態。詳見4. ARP協議工作流程。
(2)接收ARP應答包
接收到ARP應答包時,將ARP應答包包含的<IP 地址,MAC 地址>對添加到緩存表。詳見4. ARP協議工作流程。
(3)ARP緩存表超時處理
緩存表的超時處理。周期性(1S)調用 etharp_tmr()函數,動態更新緩存表項的生存時間,以及它的狀態。
在ARP緩存表的動態更新過程中,其表現狀態變化過程如下:
3. ARP報文
ARP協議的請求與應答同時通過ARP報文來實現的。ARP的報文將被封裝在以太網幀中進行發送。
3.1 以太網幀結構
(1)MAC地址
MAC Address(Media Access Control Address),亦稱為 EHA(Ethernet Hardware Address)、硬件地址、物理地址(Physical Address)、鏈路地址。MAC的值被固化在網卡的ROM中,以唯一標識該網卡。MAC地址長度為 6字節,其前 3個字節(組 織唯一標志符)表示廠家的代碼,后 3個字節(擴展標識符)由廠家自行分配。 目標 MAC地址可以分成三類,單播地址、多播地址和廣播地址。
- 單播地址:即目標主機的MAC地址,發送數據至特定的目標主機。
- 多播地址:MAC的第一個字節的bit0為1,發送數據至多個目標主機。
- 廣播地址:MAC地址為全1,即FF-FF-FF-FF-FF-FF,發送數據至同一子網內的所有主機。
(2)以太網幀結構
在鏈路層中,數據被封裝為以太網幀結構進行發送。以太網幀結構如下:
前同步碼:它的作用是實現物理層幀輸入輸出的同步,其值都是 10101010(0x55,大端模式)。
- 幀開始符:表示着以 太網幀的開始,其值都是 10101011(0xD5, 大端模式)。
- 目標MAC地址:接收設備的MAC地址。
- 源MAC地址:發送設備的MAC地址。
- 類型:表示網絡協議的類型。一台給定的主機可以支持多種網絡層協議,不同的應用采用不同的協議。因此,當以太網幀到達網卡中,網卡需要知道它應該將數據字段的內容傳遞給哪個網絡層協議。如 IP 協議、ARP協議等。
- 數據:包含需要被發送的數據(如IP數據包、ARP數據包)。以太網的最大傳輸單元 (MTU)是1500字節,若數據包超過1500字節,則需要分片傳輸;若數據包小於46字節,則需要填充至46字節再發送。
- CRC:以太網的差錯校驗信息。
P.S.:當“類型”字段的值小於 1518時,它表示后面數據字段的數據長度,當大於1518的時候才表示遞交給哪個協議。
3.2 ARP報文結構
(1)ARP報文格式如下:
- 硬件類型:目標網卡的硬件類型,表明ARP報文可以在哪種類型的網絡上傳輸。1表示以太網地址。
- 協議類型:硬件地址要映射的協議地址類型。映射IP地址時的值為0x0800.
- 硬件地址長度:即MAC地址的長度(以太網的MAC地址長度為6)。
- 協議地址長度:即IP地址的長度。
- 操作類型:指定本次ARP報文的類型。1:ARP請求報文;0:ARP響應報文。
- 源MAC地址:發送設備的MAC地址。
- 源IP地址:發送設備的IP地址。
- 目標MAC地址:接收設備的MAC地址。在ARP請求報文中,目標MAC地址未知,MAC字段的值為全0(即00-00-00-00-00-00)。
- 目標IP地址:接收設備的IP地址。
(2)ARP幀格式:
ARP報文將被傳輸到鏈路層,加上以太網的幀頭,形成ARP幀,再通過鏈路層發送出去。ARP幀的格式如下:
- 目標MAC地址:接收設備的MAC地址。在ARP請求報文中,它的目標為網絡上的所有主機,目標MAC字段的值為FF-FF-FF-FF-FF-FF(廣播地址)。
- 源MAC地址:發送設備的MAC地址。
- 幀類型:標識幀封裝的上層協議。此處封裝的為ARP協議,它的值為0x0806。
(3)幀格式的定義

1 /*lwip2.1.2/src/include/lwip/port/ethernet.h*/ 2 #define ETH_HWADDR_LEN 6 //以太網地址長度 3 4 struct eth_addr //以太網地址結構體 5 { 6 PACK_STRUCT_FLD_8(u8_t addr[ETH_HWADDR_LEN]); 7 } PACK_STRUCT_STRUCT; 8 9 struct eth_hdr //以太網首部 9 10 { 11 PACK_STRUCT_FLD_S(struct eth_addr dest); //以太網目標 MAC 地址 12 PACK_STRUCT_FLD_S(struct eth_addr src); //以太網源 MAC 地址 13 PACK_STRUCT_FIELD(u16_t type); //幀類型 14 } PACK_STRUCT_STRUCT; 15 16 17 /*lwip2.1.2/src/include/lwip/port/etharp.h*/ 18 struct etharp_hdr //ARP 報文 19 { 20 PACK_STRUCT_FIELD(u16_t hwtype); //硬件類型 21 PACK_STRUCT_FIELD(u16_t proto); //協議類型 22 PACK_STRUCT_FLD_8(u8_t hwlen); //硬件地址長度 23 PACK_STRUCT_FLD_8(u8_t protolen); //協議地址長度 24 PACK_STRUCT_FIELD(u16_t opcode); //op 字段 25 /* 以上是 ARP 報文首部 */ 26 27 PACK_STRUCT_FLD_S(struct eth_addr shwaddr); //源 MAC 地址 28 PACK_STRUCT_FLD_S(struct ip4_addr_wordaligned sipaddr);//源 ip 地址 29 PACK_STRUCT_FLD_S(struct eth_addr dhwaddr); //目標 MAC 地址 30 PACK_STRUCT_FLD_S(struct ip4_addr_wordaligned dipaddr);//目標 ip 地址 31 } PACK_STRUCT_STRUCT; 32 33 enum etharp_opcode //op 字段操作 34 { 35 ARP_REQUEST = 1, //請求包 33 36 ARP_REPLY = 2 //應答包 34 37 };
4. ARP協議工作流程
(1)數據包接收流程說明:
- 硬件網卡接收到數據之后,會調用ethernet_input()函數來處理接收到的數據包。ethernet_input()函數根據數據包中的以太網首部的幀類型進行分別處理;當幀類型為IP協議,則該數據包為IP數據包,調用ip4_input()函數進行處理;當幀類型為ARP協議,則該數據包為ARP數據包,調用 etharp_input()函數進行處理。
- etharp_input()函數對ARP數據包進行處理。首先調用 etharp_update_arp_entry()更新ARP緩存表。然后判斷ARP數據包類型。如果是ARP請求包,且是發送給本機的,則調用 etharp_raw()函數發送ARP應答包;如果不是發送給本機的ARP請求包,則丟棄。
- etharp_update_arp_entry()對ARP緩存表進行更新。首先查找或創建ARP表項,設置新建表項的信息。然后檢查改表項是否含有未發送的數據包,若存在,則調用ethernet_output()函數發送該表項上的數據。
(2) 數據包接收流程說明:
- 上層調用etharp_output()函數來發送IP數據包。對於廣播、多播數據包,調用ethernet_output()函數直接發送數據包。對於單播數據包,若源主機與目標主機不在同一個子網,則修改IP地址為網關地址;然后遍歷ARP緩存表,如果存在與目標IP地址對應的表項,且表項狀態>=ETHARP_STATE_STABLE,則調用 etharp_output_to_arp_index()函數發送IP數據包;若不存在,則調用etharp_query()函數。
- etharp_output_to_arp_index()函數用來發送IP數據包。(此時表項狀態必須>=ETHARP_STATE_STABLE)首先,更新該表項信息,確認目標主機是否在工作狀態。當表項還有15s到期,調用(etharp_request()函數以廣播方式發送ARP數據包;當表項還有30秒到期,調用etharp_request_dst()函數以單播方式發送ARP請求包。若表項有效期大於30s,則調用ethernet_output()函數發送IP數據包。
- 當ARP表中沒有與目標IP地址對應的表項,或表項的狀態為ETHARP_STATE_PENDING,則etharp_query()函數被調用。etharp_query()函數首先調用 etharp_find_entry()函數查詢或創建新的表項,當該表項為新建表項,或該表項的數據隊列為空時,調用etharp_request()函數發送ARP請求。然后判斷表項的狀態,當表項狀態>=ETHARP_STATE_STABLE,則調用ethernet_output函數發送數據包;當表項狀態為ETHARP_STATE_PENDING,則將數據包插入該表項的數據包隊列。
5. 參考資料
[1] 野火《LwIP應用開發實戰指南》。