《LwIP協(xié)議棧源碼詳解——TCP/IP協(xié)議的實現(xiàn)》ARP表

姓名:朱小鵬 ? ?學(xué)號:16010130023

轉(zhuǎn)載:

http://blog.sina.com.cn/s/blog_62a85b950101am9z.html

【嵌牛導(dǎo)讀】:ARP,全稱Address Resolution Protocol,譯作地址解析協(xié)議,是位于TCP/IP協(xié)議棧底層的協(xié)議。

【嵌牛鼻子】:ARP

【嵌牛提問】:LWIP中的ARP結(jié)構(gòu)是怎么樣的?

【嵌牛正文】:

ARP,全稱Address Resolution Protocol,譯作地址解析協(xié)議,是位于TCP/IP協(xié)議棧底層的協(xié)議。任何網(wǎng)絡(luò)的通信都是基于底層硬件鏈路的,底層的數(shù)據(jù)鏈路有著自己的一套尋址機(jī)制,在以太網(wǎng)中,往往是通過一個48位的MAC地址來標(biāo)示不同的網(wǎng)絡(luò)通信設(shè)備的。而TCP/IP協(xié)議的上層是使用IP地址作為各個主機(jī)間通信尋址機(jī)制的。當(dāng)源主機(jī)上層要向目標(biāo)主機(jī)發(fā)送數(shù)據(jù)時,它只知道目標(biāo)主機(jī)的IP地址,此時,源主機(jī)需要將該IP地址轉(zhuǎn)換為目的主機(jī)對應(yīng)的MAC地址,這樣才能在數(shù)據(jù)鏈路上選擇正確的通道將數(shù)據(jù)傳送出去,這就是ARP的作用。哎,復(fù)雜了!

協(xié)議里面的一段描述可能更明了:在ARP背后有一個基本概念,那就是每個網(wǎng)絡(luò)接口有一個硬件地址(一個48 bit的值,標(biāo)識不同的以太網(wǎng)或令牌環(huán)網(wǎng)絡(luò)接口),在硬件層次上進(jìn)行的數(shù)據(jù)幀交換必須有正確的硬件接口地址。但是,TCP/IP有自己的地址:32bit的IP地址。知道主機(jī)的I P地址并不能讓內(nèi)核發(fā)送一幀數(shù)據(jù)給主機(jī)。內(nèi)核(如以太網(wǎng)驅(qū)動程序)必須知道目的端的硬件地址才能發(fā)送數(shù)據(jù)。ARP的功能是在32 bit的I P地址和采用不同網(wǎng)絡(luò)技術(shù)的硬件地址之間提供動態(tài)映射。ARP協(xié)議的基本功能就是通過目標(biāo)設(shè)備的IP地址,查詢目標(biāo)設(shè)備的MAC地址,以保證通信的進(jìn)行。

ARP協(xié)議實現(xiàn)的核心是ARP緩存表,ARP的實質(zhì)就是對緩存表的建立、更新、查詢等操作。ARP緩存表是由一個個的緩存表項(entry)組成的,LWIP中描述緩存表項的數(shù)據(jù)結(jié)構(gòu)叫etharp_entry,上源代碼:

struct etharp_entry {

#if ARP_QUEUEING

struct etharp_q_entry *q;//數(shù)據(jù)包緩沖隊列指針

#endif

struct ip_addr ipaddr;//目標(biāo)IP地址

struct eth_addr ethaddr;//MAC地址

enum etharp_state state;//描述該entry的狀態(tài)

u8_t ctime;//描述該entry的時間信息

struct netif *netif;//相應(yīng)網(wǎng)絡(luò)接口信息

};

ARP_QUEUEING是編譯選項,表示是否允許緩存表項有數(shù)據(jù)包緩沖隊列,在opt.h里面設(shè)置。為什么要用數(shù)據(jù)包緩沖隊列指針,隨后慢慢道來。ipaddr和ethaddr字段就是分別用于存儲IP地址和MAC地址的,它們是ARP緩存表項的核心部分了。state是個枚舉類型,它表示該緩存表項的狀態(tài),一個表項有三個可能的狀態(tài),我們用枚舉型etharp_state進(jìn)行描述。

enum etharp_state {

ETHARP_STATE_EMPTY = 0,

ETHARP_STATE_PENDING,

ETHARP_STATE_STABLE

};

LWIP內(nèi)核通過數(shù)組的方式來創(chuàng)建ARP緩存表,如下,

static struct etharp_entry arp_table[ARP_TABLE_SIZE];

初始化緩存表中的各個緩存表項都處于初始狀態(tài),沒有記錄任何信息,此時每個表項都處于ETHARP_STATE_EMPTY狀態(tài),ETHARP_STATE_PENDING狀態(tài)表示該表項處于不穩(wěn)定狀態(tài),很可能的情況是,該表項只記錄到了IP地址,但是還為記錄到對應(yīng)該IP地址的MAC地址,此時就該表項就處于ETHARP_STATE_PENDING狀態(tài)。在該狀態(tài)下,LWIP內(nèi)核會發(fā)出一個廣播ARP請求到數(shù)據(jù)鏈路上,以讓對應(yīng)IP地址的主機(jī)回應(yīng)其MAC地址,當(dāng)源主機(jī)接收到MAC地址時,它就更新對應(yīng)的ARP表項。當(dāng)ARP表項得到更新后,它就完全記錄了一對IP地址和MAC地址,此時該表項就處于ETHARP_STATE_STABLE狀態(tài)。注意當(dāng)某表項處在PENDING狀態(tài)時,要發(fā)往該表項中IP地址處的數(shù)據(jù)包會被連接在表項對應(yīng)的數(shù)據(jù)包緩沖隊列上,當(dāng)?shù)鹊皆摫眄椃€(wěn)定后,這些數(shù)據(jù)包才會被發(fā)送出去。這就是為什么每個表項需要有數(shù)據(jù)包緩沖隊列指針了。

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

好了,下面講講能夠正確建立ARP緩存的基礎(chǔ):ARP數(shù)據(jù)包。要在源主機(jī)上建立關(guān)于目標(biāo)主機(jī)的IP地址與MAC地址對應(yīng)表項,則源主機(jī)和目的主機(jī)間的基本信息交互是必須的,簡單的說就是,源主機(jī)如何告訴目的主機(jī):我需要你的MAC地址;而目的主機(jī)如何回復(fù):這就是我的MAC地址。ARP數(shù)據(jù)包,這就派上用場了。

ARP數(shù)據(jù)包可以分為ARP請求數(shù)據(jù)包和ARP應(yīng)答數(shù)據(jù)包,ARP數(shù)據(jù)包到達(dá)底層鏈路時會被加上以太網(wǎng)數(shù)據(jù)包頭發(fā)送出去,最終呈現(xiàn)在鏈路上的數(shù)據(jù)報頭格式如下圖,

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

兩個字節(jié)長的以太網(wǎng)幀類型表示后面數(shù)據(jù)的類型。對于ARP請求或應(yīng)答數(shù)據(jù)包來說,該字段的值為0x0806,對于IP數(shù)據(jù)包來說,該字段的值為0x0800。

以太網(wǎng)數(shù)據(jù)報頭說完,來說ARP數(shù)據(jù)報頭。

硬件類型字段表示硬件地址的類型,它的值為1即表示以太網(wǎng)MAC地址,長度為6個字節(jié)。協(xié)議類型字段表示要映射的協(xié)議地址類型。它的值為0x0800即表示要映射為IP地址。它的值與包含I P數(shù)據(jù)報的以太網(wǎng)數(shù)據(jù)幀頭中的類型字段的值相同。

接下來的兩個1字節(jié)的字段,硬件地址長度和協(xié)議地址長度分別指出硬件地址和協(xié)議地址的長度,以字節(jié)為單位。對于以太網(wǎng)上A R P請求或應(yīng)答來說,它們的值分別為6和4。

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

接下來的四個字段是發(fā)送端的以太網(wǎng)MAC地址、發(fā)送端的I P地址、目的端的以太網(wǎng)MAC地址和目的端的I P地址。

注意,這里有一些重復(fù)信息:在以太網(wǎng)的數(shù)據(jù)幀報頭中和A R P請求數(shù)據(jù)幀中都有發(fā)送端的以太網(wǎng)MAC地址。對于一個ARP請求來說,除目的端MAC地址外的所有其他的字段都有填充值。當(dāng)目的主機(jī)收到一份給自己的ARP請求報文后,它就把自己的硬件地址填進(jìn)去,然后將該請求數(shù)據(jù)包的源主機(jī)信息和目的主機(jī)信息交換位置,并把操作字段op置為2,最后把該新構(gòu)建的數(shù)據(jù)包發(fā)送回去,這就是ARP響應(yīng)。

最后,用源碼來看看LWIP是如何描述上面的這個數(shù)據(jù)報頭的:

struct etharp_hdr {

PACK_STRUCT_FIELD(struct eth_hdr ethhdr);// 14字節(jié)的以太網(wǎng)數(shù)據(jù)報頭

PACK_STRUCT_FIELD(u16_t hwtype);// 2字節(jié)的硬件類型

PACK_STRUCT_FIELD(u16_t proto);// 2字節(jié)的協(xié)議類型

PACK_STRUCT_FIELD(u16_t _hwlen_protolen);//兩個1字節(jié)的長度字段

PACK_STRUCT_FIELD(u16_t opcode);// 2字節(jié)的操作字段op

PACK_STRUCT_FIELD(struct eth_addr shwaddr);// 6字節(jié)源MAC地址

PACK_STRUCT_FIELD(struct ip_addr2 sipaddr);// 4字節(jié)源IP地址

PACK_STRUCT_FIELD(struct eth_addr dhwaddr);// 6字節(jié)目的MAC地址

PACK_STRUCT_FIELD(struct ip_addr2 dipaddr);// 4字節(jié)目的IP地址

} PACK_STRUCT_STRUCT;

不唐僧了,和前面的各個描述完全相符。PACK_STRUCT_FIELD()是防止編譯器字對齊的宏定義,講過了的。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容