lwip---(六)ARP表

  ARP,全稱Address Resolution Protocol,譯作地址解析協議,是位於TCP/IP協議棧底層的協議任何網絡的通信都是基於底層硬件鏈路的,底層的數據鏈路有着自己的一套尋址機制,在以太網中,往往是通過一個48位的MAC地址來標示不同的網絡通信設備的TCP/IP協議的上層是使用IP地址作爲各個主機間通信尋址機制的。當源主機上層要向目標主機發送數據時,它只知道目標主機的IP地址,此時,源主機需要將該IP地址轉換爲目的主機對應的MAC地址,這樣才能在數據鏈路上選擇正確的通道將數據傳送出去,這就是ARP的作用。

  協議裏面的一段描述可能更明瞭:在ARP背後有一個基本概念,那就是每個網絡接口有一個硬件地址(一個 48 bit的值,標識不同的以太網或令牌環網絡接口),在硬件層次上進行的數據幀交換必須有正確的硬件接口地址。但是,TCP/IP有自己的地址:32bit的IP地址。知道主機的IP地址並不能讓內核發送一幀數據給主機。內核(如以太網驅動程序)必須知道目的端的硬件地址才能發送數據。ARP的功能是在32 bit的I P地址和採用不同網絡技術的硬件地址之間提供動態映射ARP協議基本功能就是通過目標設備的IP地址,查詢目標設備的MAC地址,以保證通信的進行

  ARP協議實現的核心是ARP緩存表ARP的實質就是對緩存表的建立、更新、查詢等操作。ARP緩存表是由一個個的**緩存表項(entry)**組成的,LWIP中描述緩存表項的數據結構叫etharp_entry,上源代碼:

struct etharp_entry {
   
   
#if ARP_QUEUEING
	struct etharp_q_entry *q;     // 數據包緩衝隊列指針

#endif
	struct ip_addr ipaddr;        // 目標IP地址
	struct eth_addr ethaddr;      //  MAC地址
	enum etharp_state state;      // 描述該entry的狀態
	u8_t ctime;                   // 描述該entry的時間信息
	struct netif *netif;          // 相應網絡接口信息
};

  ARP_QUEUEING編譯選項表示是否允許緩存表項有數據包緩衝隊列,在opt.h裏面設置。爲什麼要用數據包緩衝隊列指針,隨後慢慢道來。ipaddrethaddr字段就是分別用於存儲IP地址MAC地址的,它們是ARP緩存表項的核心部分了。state是個枚舉類型,它表示該緩存表項的狀態,一個表項有三個可能的狀態,我們用枚舉型etharp_state進行描述。

enum etharp_state {
   
   
	ETHARP_STATE_EMPTY = 0,
	ETHARP_STATE_PENDING,
	ETHARP_STATE_STABLE
};

  LWIP內核通過數組的方式來創建ARP緩存表,如下,

static struct etharp_entry arp_table[ARP_TABLE_SIZE];

  初始化緩存表中的各個緩存表項都處於初始狀態,沒有記錄任何信息,此時每個表項都處於ETHARP_STATE_EMPTY狀態,ETHARP_STATE_PENDING狀態表示該表項處於不穩定狀態,很可能的情況是,該表項只記錄到了IP地址,但是還未記錄到對應該IP地址MAC地址,此時就該表項就處於ETHARP_STATE_PENDING狀態。在該狀態下,LWIP內核會發出一個廣播ARP請求到數據鏈路上,以讓對應IP地址的主機迴應其MAC地址,當源主機接收到MAC地址時,它就更新對應的ARP表項。當ARP表項得到更新後,它就完全記錄了一對IP地址和MAC地址,此時該表項就處於ETHARP_STATE_STABLE狀態。注意當某表項處在PENDING狀態時,要發往該表項中IP地址處的數據包會被連接在表項對應的數據包緩衝隊列上,當等到該表項穩定後,這些數據包纔會被髮送出去。這就是爲什麼每個表項需要有數據包緩衝隊列指針了。

  ctime字段記錄表項處於某個狀態的時間當某表項的ctime值大於規定的表項最大生存值時,該表項會被內核刪除。在第一講中,我們就說到了關於LWIP的超時事件,要使用ARP功能,就必須設置一個ARP超時事件,該超時事件的基本功能就是對每個表項的ctime字段值加1,然後刪除那些生存時間大於最大生存值的表項

  好了,下面講講能夠正確建立ARP緩存的基礎:ARP數據包。要在源主機上建立關於目標主機的IP地址與MAC地址對應表項,則源主機和目的主機間的基本信息交互是必須的,簡單的說就是,源主機如何告訴目的主機:我需要你的MAC地址;而目的主機如何回覆:這就是我的MAC地址。ARP數據包,這就派上用場了。

  ARP數據包可以分爲ARP請求數據包ARP應答數據包ARP數據包到達底層鏈路時會被加上以太網數據包頭髮送出去,最終呈現在鏈路上的數據報頭格式如下圖,

《LwIP協議棧源碼詳解——TCP/IP協議的實現》ARP表

  以太網包頭中的前兩個字段是以太網的目的MAC地址源MAC地址,在前面一章已經有講解。目的地址爲全 1的特殊地址是廣播地址。在ARP表項建立前,源主機只知道目的主機的IP地址,並不知道其MAC地址,所以在數據鏈路上,源主機只有通過廣播的方式將ARP請求數據包發送出去。電纜上的所有以太網接口都要接收廣播的數據包,並檢測數據包是否是發給自己的,這點通過對照目的IP地址來實現,如果是發給自己的,目的主機需要回復一個ARP應答數據包給源主機,以告訴源主機自己的MAC地址

  兩個字節長的以太網幀類型表示後面數據的類型。對於ARP請求或應答數據包來說該字段的值爲0x0806對於IP數據包來說,該字段的值爲0x0800

  以太網數據報頭說完,來說ARP數據報頭。

  硬件類型字段表示硬件地址的類型,它的值爲 1即表示以太網MAC地址,長度爲6個字節。協議類型字段表示要映射的協議地址類型。它的值爲0x0800即表示要映射爲IP地址。它的值與包含IP數據報的以太網數據幀頭中的類型字段的值相同。

  接下來的兩個1字節的字段硬件地址長度協議地址長度分別指出硬件地址和協議地址的長度,以字節爲單位。對於以太網上A R P請求或應答來說,它們的值分別爲64

  操作字段op指出四種操作類型,它們是 A R P請求(值爲1)、A R P應答(值爲2)、R A R P請求(值爲3)和R A R P應答(值爲4,這裏我們只關心前兩個類型。這個字段必需的,因爲A R P請求和A R P應答的幀類型字段值是相同的。

  接下來的四個字段發送端的以太網MAC地址、發送端的I P地址、目的端的以太網MAC地址和目的端的I P地址。

  注意,這裏有一些重複信息:在以太網的數據幀報頭中和A R P請求數據幀中都有發送端的以太網MAC地址。對於一個ARP請求來說,除目的端MAC地址外的所有其他的字段都有填充值。當目的主機收到一份給自己的ARP請求報文後,它就把自己的硬件地址填進去,然後將該請求數據包的源主機信息和目的主機信息交換位置,並把操作字段op置爲2,最後把該新構建的數據包發送回去,這就是ARP響應

  最後,用源碼來看看LWIP是如何描述上面的這個數據報頭的:

struct etharp_hdr {
   
   
	PACK_STRUCT_FIELD(struct eth_hdr ethhdr);    // 14字節的以太網數據報頭
	PACK_STRUCT_FIELD(u16_t hwtype);             // 2字節的硬件類型
	PACK_STRUCT_FIELD(u16_t proto);              // 2字節的協議類型
	PACK_STRUCT_FIELD(u16_t _hwlen_protolen);    // 兩個1字節的長度字段
	PACK_STRUCT_FIELD(u16_t opcode);             // 2字節的操作字段op
	PACK_STRUCT_FIELD(struct eth_addr shwaddr);  // 6字節源MAC地址
	PACK_STRUCT_FIELD(struct ip_addr2 sipaddr);  // 4字節源IP地址
	PACK_STRUCT_FIELD(struct eth_addr dhwaddr);  // 6字節目的MAC地址
	PACK_STRUCT_FIELD(struct ip_addr2 dipaddr);  // 4字節目的IP地址
} PACK_STRUCT_STRUCT;

  和前面的各個描述完全相符。PACK_STRUCT_FIELD()防止編譯器字對齊的宏定義

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