zoukankan      html  css  js  c++  java
  • LWIP协议栈:ARP协议

    1. ARP协议简介

    • ARP(Address Resolution Protocol),地址解析协议。ARP协议处于网络层,其主要功能就是通过目标设备的 IP 地址,查询目标设备的 MAC 地址,从而进行网络通信。

    • 网络层中,源主机和目标主机依赖于IP地址进行通信。而链路层又有自己的寻址寻址机制(如,以太网依赖于MAC地址进行通信)。ARP的作用在于将IP地址转换为MAC地址,从而连接网络层与链路层,使得上层可以通过IP地址进行网络通信。

    • ARP协议的基本运作过程如下:

    2. ARP缓存表

    2.1 ARP缓存表的定义 

    每台主机或路由器在其内存中都存储着一个ARP缓存表,表中记录着了<IP 地址,MAC 地址>对,反映着目标主机的IP地址与MAC地址的映射关系。

    LwIP协议栈中,使用一个 arp_table 数组描述 ARP 缓存表,数组的内容是表项的内容。
     1 /*lwip/src/netif/etharp.c*/
     2 
     3 enum etharp_state {
     4    ETHARP_STATE_EMPTY = 0,            //空状态,表示该表项为空
     5    ETHARP_STATE_PENDING,              //挂起状态,表示该表项还未收到目标主机的ARP应答
     6    ETHARP_STATE_STABLE,               //可用状态,表示该表项可用
     7    ETHARP_STATE_STABLE_REREQUESTING_1,//过渡状态
     8    ETHARP_STATE_STABLE_REREQUESTING_2 //过渡状态
     9  #if ETHARP_SUPPORT_STATIC_ENTRIES
    10    , ETHARP_STATE_STATIC
    11  #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
    12 };
    13 
    14 struct etharp_entry {
    15 #if ARP_QUEUEING
    16    /* 指向此ARP表项上挂起的数据包队列*/
    17    struct etharp_q_entry *q;
    18  #else /* ARP_QUEUEING */
    19    /*指向此ARP表项上挂起的单个数据包 */
    20    struct pbuf *q;
    21  #endif /* ARP_QUEUEING */
    22    ip_addr_t ipaddr;       //目标主机的IP地址
    23    struct netif *netif;    //目标主机的网卡信息
    24    struct eth_addr ethaddr;//目标主机的MAC地址
    25    u8_t state;             //此表项的状态
    26    u8_t ctime;             //此表项的生存时间
    27  };
    28 
    29 static struct etharp_entry arp_table[ARP_TABLE_SIZE]; //LWIP协议栈的ARP缓存表
    • 表项的数据包指针q:指针q指向需要发送至该目标主机的数据包。struct etharp_q_entry *q指向一个数据包队列,struct pbuf *q指向单个数据包。
    • 表项的生存时间ctime:每个表项都包含一个ctime变量,表示该表项的生存时间。当达到指定的生存时间,该表项会被删除。

    2.2 缓存表的动态处理

    ARP协议的核心就是对缓存表的动态处理。因为IP地址可能是动态的,所以ARP缓存表必须动态更新。

    ARP协议中,通过发送ARP请求包、接收ARP应答包、ARP缓存表超时处理来实现缓存表的动态更新。

    (1)发送ARP请求包

    发送数据时,若不存在目标主机的表项,则新建一个表项,并发送ARP请求包;若存在目标主机的表项,对处于ETHARP_STATE_STABLE的表项,会再次发送ARP请求包,以确认目标主机依然在工作状态。详见4. ARP协议工作流程。

    (2)接收ARP应答包

    接收到ARP应答包时,将ARP应答包包含的<IP 地址,MAC 地址>对添加到缓存表。详见4. ARP协议工作流程。

    (3)ARP缓存表超时处理

    缓存表的超时处理。周期性(1S)调用 etharp_tmr()函数,动态更新缓存表项的生存时间,以及它的状态。

    在ARP缓存表的动态更新过程中,其表现状态变化过程如下:

    3. ARP报文

    ARP协议的请求与应答同时通过ARP报文来实现的。ARP的报文将被封装在以太网帧中进行发送。

    3.1 以太网帧结构

    (1)MAC地址

    MAC Address(Media Access Control Address),亦称为 EHA(Ethernet Hardware Address)、硬件地址、物理地址(Physical Address)、链路地址。MAC的值被固化在网卡的ROM中,以唯一标识该网卡。MAC地址长度为 6字节,其前 3个字节(组 织唯一标志符)表示厂家的代码,后 3个字节(扩展标识符)由厂家自行分配。 目标 MAC地址可以分成三类,单播地址、多播地址和广播地址。

    • 单播地址:即目标主机的MAC地址,发送数据至特定的目标主机。
    • 多播地址:MAC的第一个字节的bit0为1,发送数据至多个目标主机。
    • 广播地址:MAC地址为全1,即FF-FF-FF-FF-FF-FF,发送数据至同一子网内的所有主机。

    (2)以太网帧结构 

    在链路层中,数据被封装为以太网帧结构进行发送。以太网帧结构如下:

      前同步码:它的作用是实现物理层帧输入输出的同步,其值都是 10101010(0x55,大端模式)。

    • 帧开始符:表示着以 太网帧的开始,其值都是 10101011(0xD5, 大端模式)。
    • 目标MAC地址:接收设备的MAC地址。
    • 源MAC地址:发送设备的MAC地址。
    • 类型:表示网络协议的类型。一台给定的主机可以支持多种网络层协议,不同的应用采用不同的协议。因此,当以太网帧到达网卡中,网卡需要知道它应该将数据字段的内容传递给哪个网络层协议。如 IP 协议、ARP协议等。 
    • 数据:包含需要被发送的数据(如IP数据包、ARP数据包)。以太网的最大传输单元 (MTU)是1500字节,若数据包超过1500字节,则需要分片传输;若数据包小于46字节,则需要填充至46字节再发送。
    • CRC:以太网的差错校验信息。 

    P.S.:当“类型”字段的值小于 1518时,它表示后面数据字段的数据长度,当大于1518的时候才表示递交给哪个协议。 

    3.2 ARP报文结构

    (1)ARP报文格式如下:

    • 硬件类型:目标网卡的硬件类型,表明ARP报文可以在哪种类型的网络上传输。1表示以太网地址。
    • 协议类型:硬件地址要映射的协议地址类型。映射IP地址时的值为0x0800.
    • 硬件地址长度:即MAC地址的长度(以太网的MAC地址长度为6)。
    • 协议地址长度:即IP地址的长度。
    • 操作类型:指定本次ARP报文的类型。1:ARP请求报文;0:ARP响应报文。
    • 源MAC地址:发送设备的MAC地址。
    • 源IP地址:发送设备的IP地址。
    • 目标MAC地址:接收设备的MAC地址。在ARP请求报文中,目标MAC地址未知,MAC字段的值为全0(即00-00-00-00-00-00)。
    • 目标IP地址:接收设备的IP地址。

    (2)ARP帧格式:

    ARP报文将被传输到链路层,加上以太网的帧头,形成ARP帧,再通过链路层发送出去。ARP帧的格式如下:

    • 目标MAC地址:接收设备的MAC地址。在ARP请求报文中,它的目标为网络上的所有主机,目标MAC字段的值为FF-FF-FF-FF-FF-FF(广播地址)。
    • 源MAC地址:发送设备的MAC地址。
    • 帧类型:标识帧封装的上层协议。此处封装的为ARP协议,它的值为0x0806。

    (3)帧格式的定义

     1 /*lwip2.1.2/src/include/lwip/port/ethernet.h*/
     2 #define ETH_HWADDR_LEN    6     //以太网地址长度
     3 
     4 struct eth_addr    //以太网地址结构体
     5 {    
     6     PACK_STRUCT_FLD_8(u8_t addr[ETH_HWADDR_LEN]); 
     7 } PACK_STRUCT_STRUCT;
     8 
     9 struct eth_hdr    //以太网首部  9 
    10 {
    11     PACK_STRUCT_FLD_S(struct eth_addr dest);  //以太网目标 MAC 地址
    12     PACK_STRUCT_FLD_S(struct eth_addr src);   //以太网源 MAC 地址 
    13     PACK_STRUCT_FIELD(u16_t type);            //帧类型 
    14 } PACK_STRUCT_STRUCT; 
    15 
    16 
    17 /*lwip2.1.2/src/include/lwip/port/etharp.h*/
    18 struct etharp_hdr               //ARP 报文
    19 {
    20     PACK_STRUCT_FIELD(u16_t hwtype);    //硬件类型 
    21     PACK_STRUCT_FIELD(u16_t proto);     //协议类型
    22     PACK_STRUCT_FLD_8(u8_t  hwlen);     //硬件地址长度 
    23     PACK_STRUCT_FLD_8(u8_t  protolen);  //协议地址长度 
    24     PACK_STRUCT_FIELD(u16_t opcode);    //op 字段 
    25     /* 以上是 ARP 报文首部 */ 
    26     
    27     PACK_STRUCT_FLD_S(struct eth_addr shwaddr);            //源 MAC 地址
    28     PACK_STRUCT_FLD_S(struct ip4_addr_wordaligned sipaddr);//源 ip 地址
    29     PACK_STRUCT_FLD_S(struct eth_addr dhwaddr);            //目标 MAC 地址 
    30     PACK_STRUCT_FLD_S(struct ip4_addr_wordaligned dipaddr);//目标 ip 地址 
    31 } PACK_STRUCT_STRUCT;  
    32 
    33 enum etharp_opcode    //op 字段操作 
    34 {
    35     ARP_REQUEST = 1,     //请求包 33     
    36     ARP_REPLY   = 2      //应答包 34 
    37 };
    ARP报文格式定义

    4. ARP协议工作流程

    (1)数据包接收流程说明:

    • 硬件网卡接收到数据之后,会调用ethernet_input()函数来处理接收到的数据包。ethernet_input()函数根据数据包中的以太网首部的帧类型进行分别处理;当帧类型为IP协议,则该数据包为IP数据包,调用ip4_input()函数进行处理;当帧类型为ARP协议,则该数据包为ARP数据包,调用 etharp_input()函数进行处理。
    • etharp_input()函数对ARP数据包进行处理。首先调用 etharp_update_arp_entry()更新ARP缓存表。然后判断ARP数据包类型。如果是ARP请求包,且是发送给本机的,则调用 etharp_raw()函数发送ARP应答包;如果不是发送给本机的ARP请求包,则丢弃。
    • etharp_update_arp_entry()对ARP缓存表进行更新。首先查找或创建ARP表项,设置新建表项的信息。然后检查改表项是否含有未发送的数据包,若存在,则调用ethernet_output()函数发送该表项上的数据。

    (2) 数据包接收流程说明:

    • 上层调用etharp_output()函数来发送IP数据包。对于广播、多播数据包,调用ethernet_output()函数直接发送数据包。对于单播数据包,若源主机与目标主机不在同一个子网,则修改IP地址为网关地址;然后遍历ARP缓存表,如果存在与目标IP地址对应的表项,且表项状态>=ETHARP_STATE_STABLE,则调用 etharp_output_to_arp_index()函数发送IP数据包;若不存在,则调用etharp_query()函数。
    •  etharp_output_to_arp_index()函数用来发送IP数据包。(此时表项状态必须>=ETHARP_STATE_STABLE)首先,更新该表项信息,确认目标主机是否在工作状态。当表项还有15s到期,调用(etharp_request()函数以广播方式发送ARP数据包;当表项还有30秒到期,调用etharp_request_dst()函数以单播方式发送ARP请求包。若表项有效期大于30s,则调用ethernet_output()函数发送IP数据包。
    • 当ARP表中没有与目标IP地址对应的表项,或表项的状态为ETHARP_STATE_PENDING,则etharp_query()函数被调用。etharp_query()函数首先调用 etharp_find_entry()函数查询或创建新的表项,当该表项为新建表项,或该表项的数据队列为空时,调用etharp_request()函数发送ARP请求。然后判断表项的状态,当表项状态>=ETHARP_STATE_STABLE,则调用ethernet_output函数发送数据包;当表项状态为ETHARP_STATE_PENDING,则将数据包插入该表项的数据包队列。

    5. 参考资料

    [1] 野火《LwIP应用开发实战指南》。

  • 相关阅读:
    18.12.30 【sssx】Trie图
    18.12.30 【sssx】线段树
    18.12.25 POJ 1039 Pipe
    18.12.25 POJ 3525 Most Distant Point from the Sea(半平面+二分)
    18.12.25 POJ 1228 Grandpa's Estate
    18.12.22 luogu P3047 [USACO12FEB]附近的牛Nearby Cows
    18.12.21 DSA 中缀表达式的值
    18.12.21 luogu P3650 [USACO1.3]滑雪课程设计Ski Course Design
    18.12.21 【USACO】Times17
    18.12.20 DSA Full Tank?(DP+BFS)
  • 原文地址:https://www.cnblogs.com/linfeng-learning/p/12346488.html
Copyright © 2011-2022 走看看