lwIP ARP協議分析1

1. ARP:

從功能上來說,arp可以簡單的分成兩個部分:

a. 當我要向目的ip發送一個數據包的時候,需要通過arp實現ip到物理地址(一般爲mac地址)的映射------------》ethernet_output函數

b. 處理輸入包,更新arp緩存,如果是ip包後遞交給ip層,如果是arp包,對於不同的arp操作做相應的相應------------》etharp_input函數。

2011-6-13-20-55

 

 

ethernet_input函數:

以太網的幀類型可以是:IP,ARP 甚至可以是pppoe, wlan等。這裏主要分爲IP, ARP(注意:ip arp在以太網的幀類型中是並列的,所以在input這個函數中分爲ip,arp兩大部分)

對於ip類型的:主要工作就是看是否開啓了ETHARP_TRUST_IP_MAC這個選項,如果開啓了就是要用這個幀中的信息來更新arp緩衝(利用幀首部的源mac地址和幀數據中ip報文中的源ip地址),然後丟棄以太網幀首部傳遞給ip層(即ip_input)。

對於arp類型的:同樣先更新arp緩存,然後判斷arp報文的操作類型,在lwip中對於arp數據包實現了兩種操作:(rarp請求,rarp響應已經幾乎淘汰了)

a.arp請求:首先判斷這個包是不是給本機的,如果是給本機的,在原有包的基礎上重組一個迴應包併發出(注意此處並沒有重新分配一個pbuf,而是借用了原來的緩衝結構)。如果不是本機的忽略。、

b.arp迴應:主要的工作是更新arp緩存,但是這一步已經在arp包剛進來的時候就處理了,所以這裏不需要再重複做,這裏有一些dhcp的東東,暫時還未涉及到。

這裏無論是ip類型,還是arp類型,都會更新arp緩存,也就是我們的

update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags),其中netif是對應的網絡接口,ipaddr和ethaddr分別是對應的ip地址和mac地址。這個函數中會去更新arp緩存,並且把這個arp表項的等待的隊列通過發送函數發送出去()。

update_arp_entry:先通過調用find_entry找到對應ipaddr對應的表項——>設置相應的arp選項的成員(主要是state,netif, ethaddr, cttime)——>如果定義了arp_queue的話,並且這個arp表項上有未發送隊列的話,把這些隊列發送出去。其中find_entry這個函數蠻重要的,下面解釋下這個函數的流程。

find_entry:

1. lwip有一個比較巧妙的地方,它並不是衝上去就是就把arp緩存中所有的表項搜索一遍,而是做了一個假設,假設這次的表項索引還是上一次的,if so ,we are really fast!(因爲在很多情況下就是這樣的)

2. 首先搜索分成三類,empty,suspending,stable。第一個是對狀態爲empty的檢查,arp表項中第一個狀態爲empty的索引號,第二個對狀態爲suspend的檢查,分成三部分,首先判斷是否恰好爲此次想要的ip對應的索引,如果是直接返回;不是的話又分這個索引是有queue還是沒有queue,分別記錄這兩種類型中cttime最大的一個索引,第三個是對狀態爲stable的檢查,分成兩部分,首先判斷是否恰好爲此次想要的ip對應的索引,如果是直接返回;不是的話,記錄狀態爲stable中cttime最大的(時間戳,最老的)。

因此這部分,主要做了兩件事:

●如果arp緩存中有現成的索引,則直接返回(狀態時suspend和stable);

●通過索引記錄幾個重要的參數:a. arp表項中第一個狀態爲empty的索引號 b. arp表項中最老的狀態爲suspend的有queue的索引號 c. arp表項中最老的狀態爲suspend的沒有queue的索引號 d. arp表項中最老的狀態爲stable的索引號。這些參數是在arp緩存沒有現成索引號時,會根據優先級來對這四個參數來選擇或刪除表項。優先級等級一次爲:empty——》oldest stable——》oldest pending without queue——》oldest pending with queue

3. arp沒有現存的緩存,而狀態又不是empty的選項,意味着需要在裏面刪除現有的arp選項,這裏則需要調用snmp_delete****,由於snmp的東東暫時還未看到,這裏就不詳細講了。

4. 最後更新表項的一些成員,有狀態,時間戳,索引緩存

ethernet_output函數:

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

廣播包:判斷目的ip地址是不是爲全1,或者是全0(老版本中使用的),如果是廣播包則目的ip的mac地址不需要查詢arp緩存或者發送arprequest,mac地址爲全一,即0xff,0xff,0xff,0xff,0xff,0xff。

多播包:判斷目的ip地址是不是d類地址,即eXXXX,如果是多播的話,mac地址也是確定的,即將ip地址的低23位映射到mac地址爲01-00-5e-00-00-00的低23位上。

單播包:要比較目的ip和本地ip地址,看是否是局域網內的,不是局域網內的,則調用默認網關的地址,然後再統一調用etharp_query(netif, ipaddr, q);函數

而廣播包和多播包則無需調用etharp_query(netif, ipaddr, q);函數,因爲已經得到了明確的mac地址,基本只需要添加以太網幀首部然後發送即可。

etharp_query:大概流程如下:

a. 先通過ipaddr利用函數find_entry找到arp緩存中的索引號

b. 根據索引號就能得到arp的對應項,此時根據項的state分成三大類,

empty:說明原來表項中是沒有這個arp緩存的,所以把表項狀態切換爲pending併發送arp_requst包,把待發送的數據放在這個entry(表項)的隊列上,系統在input的時候解析了這個ip後會發送(具體可以看前面input中的講解);

pending:說明這個ip原來就有了,我們再重新發一次arp_request,同樣把待發送數據放在隊列上;

stable:說明在arp緩存中ip地址已經有了解析的mac地址,此時又分成兩類,一類是數據包不爲空,則直接調用etharp_send_ip函數發送;第二類是如果數據包爲空,則說明是一個request包,還是調用arp_request

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