LwIP 协议栈源码详解 ——TCP/IP 协议的实现(八: ARP 表 )

7 ARP 表 


其实这段结合《卷一》看比较易懂!不过的看的代码版本和原作者有结构上的不同。


        讲过了包括 LWIP 的移植要点、内存管理、数据包管理、网络接口管理等等。
        ARP,全称 Address Resolution Protocol,译作地址解析协议,是位于 TCP/IP 协议栈底
层的协议。任何网络的通信都是基于底层硬件链路的,底层的数据链路有着自己的一套寻址
机制,在以太网中,往往是通过一个 48 位的 MAC 地址来标示不同的网络通信设备的。而
TCP/IP 协议的上层是使用 IP 地址作为各个主机间通信寻址机制的。当源主机上层要向目标
主机发送数据时,它只知道目标主机的 IP 地址,此时,源主机需要将该 IP 地址转换为目的
主机对应的 MAC 地址,这样才能在数据链路上选择正确的通道将数据传送出去,这就是
ARP 的作用。哎,复杂了!
        协议里面的一段描述可能更明了:在 ARP 背后有一个基ᴀ概念,那就是每个网络接口
有一个硬件地址(一个48 bit 的值,标识不同的以太网或令牌环网络接口),在硬件层次上
进行的数据帧交换必须有正确的硬件接口地址。但是, TCP/IP 有自己的地址: 32bit 的 IP 地
址。知道主机的 I P 地址并不能让内核发送一帧数据给主机。内核(如以太网驱动程序)必
须知道目的端的硬件地址才能发送数据。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 里面设
置。为什么要用数据包缓冲队列指针,随后慢慢道来。ipaddr 和 ethaddr 字段就是分别用于
存储 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 数据包到达底层链路

时会被加上以太网数据包头发送出去,最终呈现在链路上的数据报头格式如下图,



以太网包头中的前两个字段是以太网的目的 MAC 地址和源 MAC 地址,在前面一章已
经有讲解。目的地址为全1 的特殊地址是广播地址。在 ARP 表项建立前,源主机只知道目
的主机的 IP 地址,并不知道其 MAC 地址,所以在数据链路上,源主机只有通过广播的方
式将 ARP 请求数据包发送出去。电缆上的所有以太网接口都要接收广播的数据包,并检测
数据包是否是发给自己的,这点通过对照目的 IP 地址来实现,如果是发给自己的,目的主
机需要回复一个 ARP 应答数据包给源主机,以告诉源主机自己的 MAC 地址。
两个字节长的以太网帧类型表示后面数据的类型。对于 ARP 请求或应答数据包来说,
该字段的值为 0x0806,对于 IP 数据包来说,该字段的值为 0x0800。
        以太网数据报头说完,来说 ARP 数据报头。
        硬件类型字段表示硬件地址的类型,它的值为1 即表示以太网 MAC 地址,长度为 6
个字节。协议类型字段表示要映射的协议地址类型。它的值为 0x0800 即表示要映射为 IP 地
址。它的值与包৿ I P 数据报的以太网数据帧头中的类型字段的值相同。
接下来的两个 1 字节的字段,硬件地址长度和协议地址长度分别指出硬件地址和协议地
址的长度,以字节为单位。对于以太网上 A R P 请求或应答来说,它们的值分别为 6 和 4。
操作字段 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()是防止编译器字对齐
的宏定义,讲过了的。 
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值