lwip---(八)ARP層流程

  前面一節重點說了ARP緩存表以及如何對其進行相關操作,關於ARP,一共想說三個函數,前面已經講過了兩個。

  最後要講的一個函數是update_arp_entry,該函數用於更新ARP緩存表中的表項或者在緩存表中插入一個新的表項。該函數會在收到一個IP數據包或ARP數據包後被調用。該函數原型如下,

static err_t

update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags)

  其中重要的兩個參數ipaddrethaddr分別對應的ip地址和mac地址,函數利用這兩個地址去更新或插入ARP表項。由於這個函數代碼量較小,這裏就列出源碼來講解,注意這個源碼是經過處理的,已經去掉了編譯選項、源碼註釋、調試輸出信息等非重點部分。

static err_t
update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags)
{
   
   
	s8_t i;                                     // 兩個變量,不解釋
	u8_t k;
	i = find_entry(ipaddr, flags);              // 查找或新建一個ARP表項,返回其索引值
	if (i < 0)  return (err_t)i;                // 如果爲不合法的索引值,則更新緩存表失敗
	arp_table[i].state = ETHARP_STATE_STABLE;   // 否則將對應表項狀態改爲stable
	arp_table[i].netif = netif;                 // 記錄下網絡接口
	
	k = ETHARP_HWADDR_LEN;                      // 這一段是更新緩存表項中的MAC地址
	
	while (k > 0) {
   
   
		k--;
		arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];
	}
	
	arp_table[i].ctime = 0;                    // 生存時間值置0
	
#if ARP_QUEUEING                               //該ARP表項上有未發送的隊列,則把這些隊列發送出去
	
	while (arp_table[i].q != NULL) {
   
              // 只要緩衝鏈表中海有數據則循環
		struct pbuf *p;
		struct etharp_q_entry *q = arp_table[i].q;                            // 記錄下緩衝鏈表表頭
		arp_table[i].q = q->next;              // 緩衝鏈表表頭指向下一個節點
		p = q->p;                              // 取得記錄下的緩衝鏈表表頭指向的數據包
		memp_free(MEMP_ARP_QUEUE, q);          // 釋放記錄下的緩衝鏈表表頭
		etharp_send_ip(netif, p, (struct eth_addr*)(netif->hwaddr), ethaddr); // 發送數據包
		pbuf_free(p);                          // 釋放數據包緩存空間
	}
	
#endif
	return ERR_OK;
}

  從源程序中可以看出,update_arp_entry的流程如下:先通過調用find_entry找到對應ipaddr對應的表項,並設置相應的arp表項的成員(主要是state, netif, ethaddr, cttime),最後如果定義了ARP_QUEUEING,並且這個arp表項上有未發送的數據包的話,則把這些數據全部發送出去。雖然比較囉嗦,但是還是我們還是根據不同的ipaddr經過find_entry執行後,來看看update_arp_entry運行的幾種不同情況。

  首先可以肯定的是,update_arp_entry的兩個參數ipaddrethaddr必是互相匹配的,因爲它們是從源主機發來的IP包或ARP包中解析出來的,代表了源主機的MAC地址和IP地址。find_entry利用ipaddr作爲參數執行後,返回一個ARP表項索引。如果該表項處於empty狀態,那麼該表項現在一定是新創建的,此時設置該表項爲stable狀態並設置該表項其他字段值後即結束。如果該表項是處於pending狀態,由於此時已經有了和ipaddr匹配的MAC地址返回,所以該表項也被設置爲stable狀態並同時設置該表項其他字段值。如果該表項是處於stable狀態,其實此時只需要將ctime的值復位即可,但是LWIP爲了節省代碼量,它還是選擇像上面的情況一樣做相同的處理,這樣雖然有些步驟是多餘的,但並不影響函數功能。最後都會檢查該表項是否還有數據需要發送,如果有,則將所有數據包發送出去。

  現在是時候從宏觀上來看看到底ARP是怎麼一個工作流程,以及它在整個LWIP協議棧當中發揮的重要作用。。

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

  該圖簡潔明瞭的解釋了基本所有LWIP的數據包接收與發送的全過程。我們可以看到幾個熟悉的身影:etharp_query、etharp_request、update_arp_entry。在前面已經講過了的!

  ARP從功能上來說可以簡單的分成兩個部分:當有數據包輸入時,更新arp表,如果是ip包則遞交給ip層,如果是arp包,則針對不同的arp包類型做相應的響應;當向目的ip發送一個數據包的時候,需要通過arp實現ip到MAC地址的映射,必要時,需要發送廣播數據包獲得目標機器的MAC地址。

  LWIP利用netif.input指向的函數接收以太網數據包,通常這個函數是ethernet_input。注意,這裏並不是說ethernet_input直接與底層硬件交互接收數據包,而是更底層的函數接收到數據包後將數據包遞交給ethernet_inputethernet_input再對其進行處理。

  以太網的幀類型可以是:IP,ARP,甚至可以是pppoewlan等。這裏主要分析IP和ARP兩種類型的數據包。ethernet_input根據以太網首部的類型字段判斷收到的數據包的類型,如果是IP包,則將該包遞交給etharp_ip_input,如果是ARP包,則將該包遞交給etharp_arp_input

  對於ip類型的數據包,etharp_ip_input首先檢查是否開啓了ETHARP_TRUST_IP_MAC這個選項,如果開啓了就是要用這個幀中的信息和update_arp_entry函數來更新arp表(利用幀首部的源mac地址和幀數據中ip報文中的源ip地址),然後丟棄以太網幀首部,將IP報文通過ip_input函數遞交給ip層。

  對於arp類型的數據包,etharp_arp_input函數首先利用數據包頭信息更新arp表的內容,

  然後再判斷該ARP數據包的類型,如果是ARP請求包,則首先判斷這個包是不是給自己的,如果是給自己的,則在原有包的基礎上重組一個ARP應答包發送出去(注意此處並沒有重新分配一個pbuf,而是借用了原來的緩衝結構)。如果不是給自己的,則直接忽略。如果是ARP應答包,主要的工作就是更新arp表,但是這一步已經在arp包剛進來的時候就處理了,所以這裏不需要再重複做,這樣ARP包的處理也完畢。

  LWIP利用netif.output指向的函數發送IP數據包,通常這個函數是etharp_output。注意,這裏並不是說etharp_output直接與底層硬件交互發送數據包,而是將數據包做相應的處理,最終遞交給netif.linkoutput函數來發送的。

  etharp_output函數接收IP層要發送的數據包,並將數據包發送出去。由於是發送ip數據包,所以函數一開始需要增加緩衝區大小,大小爲以太網的數據首部的大小。然後檢查ip地址,可以分爲廣播包,多播包,單播包(單播包又分爲是局域網內部還是局域網外面)。

  廣播包:判斷目的IP地址是不是爲全1,或者是全0(老版本中使用的),如果是廣播包則目的IP的MAC地址不需要查詢arp表,直接將MAC地址設置爲全1發送即可,即MAC六個字節值爲0xff,0xff,0xff,0xff,0xff,0xff

  多播包:判斷目的ip地址是不是d類地址,即0xexxxxxxx,如果是多播的話,mac地址也是確定的,即將MAC地址01-00-5e-00-00-00的低23位設置爲IP地址的低23位。對於以上的兩種數據包,etharp_output直接調用函數etharp_send_ip將數據包發送出去。

  單播包:要比較目的IP和本地IP地址,看是否是局域網內的,不是局域網內的,則將目的IP地址設置爲默認網關的地址,然後再統一調用etharp_query函數將數據包發送出去,注意這些數據包在這種情況下可能被連接在相關ARP表項的發送鏈表上,等待發送。

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