LwIP中的ARP协议实现(1)

LwIP的ARP协议实现系列文章

LwIP中的ARP实现(1)之 ARP缓存表的数据结构
LwIP中的ARP实现(2)之 ARP缓存表的超时处理
LwIP中的ARP实现(3)之 发送ARP请求包
LwIP中的ARP实现(4)之 ARP数据包接收
LwIP中的ARP实现(5)之 ARP数据包发送

前言

从前面的文章,我们知道,ARP协议的核心是ARP缓存表,而ARP协议的实质就是对缓存表项(entry)的建立、更新、查询等操作。

那么,LwIP中是是怎么实现ARP协议的呢?

ARP缓存表的数据结构

LwIP使用一个arp_table数组描述ARP缓存表,数组的内容是表项的内容,每个表项都必须记录一对IP地址与MAC地址的映射关系,此外还有一些基本的信息,如表项的状态、生命周期(生存时间)以及对应网卡的基本信息,LwIP使用一个etharp_entry结构体对表项进行描述。
而且LwIP预先定义了缓存表的大小,ARP_TABLE_SIZE默认为10,也就是最大能存放10个表项,由于这个表很小,LwIP对表的操作直接采用遍历方式,遍历每个表项并且更改其中的内容。

static struct etharp_entry arp_table[ARP_TABLE_SIZE];

struct etharp_q_entry 
{
  struct etharp_q_entry *next;
  struct pbuf *p;
};

struct etharp_entry 
{
#if ARP_QUEUEING
  /** 指向此ARP表项上挂起的数据包队列的指针. */
  struct etharp_q_entry *q;
#else /* ARP_QUEUEING */
  /** 指向此ARP表项上的单个挂起数据包的指针. */
  struct pbuf *q;
#endif 
  ip4_addr_t ipaddr;	//记录目标IP地址
  struct netif *netif;	//对应网卡信息
  struct eth_addr ethaddr;	//记录与目标IP地址对应的MAC地址
  u16_t ctime;	//生存时间
  u8_t state;	//表项的状态
};

因为APR协议在没找到MAC地址的时候是不会发送数据的,因此这些数据会暂时存储在ARP表项中,因此LwIP实现了ARP表项挂载数据的结构,etharp_q_entry指向的是数据包缓存队列,etharp_q_entry是一个结构体,LwIP为了方便管理pbuf数据包,直接再一次封装这个结构体,让数据包能形成队列的形式,其实简单理解为数据包就行了。而q指向的就是一个pbuf数据包。

除此之外,ARP表项还有很重要的信息,那就是IP地址 MAC地址,状态、生存时间等信息。
而对于ARP表项的状态,LwIP还枚举了多种不同的状态:

/** ARP states */
enum etharp_state {
  ETHARP_STATE_EMPTY = 0,
  ETHARP_STATE_PENDING,
  ETHARP_STATE_STABLE,
  ETHARP_STATE_STABLE_REREQUESTING_1,
  ETHARP_STATE_STABLE_REREQUESTING_2
#if ETHARP_SUPPORT_STATIC_ENTRIES
  , ETHARP_STATE_STATIC
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
};

ARP缓存表在初始化的时候,所有的表项都会被初始化为ETHARP_STATE_EMPTY,也就是空状态,表示这些表项能被使用,在需要添加表项的时候,LwIP内核就会遍历ARP缓存表,找到合适的表项,进行添加。如果ARP表项处于ETHARP_STATE_PENDING状态,表示ARP已经发出了一个ARP请求包,但是还未收到目标IP地址主机的应答,处于这个状态的缓存表项是有等待时间的,它通过宏定义ARP_MAXPENDING指定,默认为5秒钟,如果从发出ARP请求包后的5秒内还没收到应答,那么该表项又会被删除;而如果收到应答后,ARP就会更新缓存表的信息,记录目标IP地址与目标MAC地址的映射关系并且开始记录表项的生存时间,同时该表项的状态会变成ETHARP_STATE_STABLE状态。当要发送数据包的时候,而此时表项为ETHARP_STATE_PENDING状态,那么这些数据包就会暂时被挂载到表项的数据包缓冲队列上,直到表项的状态为ETHARP_STATE_STABLE,才进行发送数据包。对于状态为ETHARP_STATE_STABLE的表项,这些表项代表着ARP记录了IP地址与MAC地址的映射关系,能随意通过IP地址进行数据的发送,但是这些表项是具有生存时间的,通过宏定义ARP_MAXAGE指定,默认为5分钟,在这些时间,LwIP会不断维护这些缓存表以保持缓存表的有效。当表项是ETHARP_STATE_STABLE的时候又发送一个ARP请求包,那么表项状态会暂时被设置为ETHARP_STATE_STABLE_REREQUESTING_1,然后被设置为ETHARP_STATE_STABLE_REREQUESTING_2状态,这些是一个过渡状态,当收到ARP应答后,表项又会被设置为ETHARP_STATE_STABLE,这样子能保持表项的有效。

所以ARP缓存表是一个动态更新的过程,为什么要动态更新呢?因为以太网的物理性质并不能保证数据传输的是可靠的。以太网发送数据并不会知道对方是否已经介绍成功,而两台主机的物理线路不可能一直保持有效畅通,那么如果不是动态更新的话,主机就不会知道另一台主机是否在工作中,这样子发出去的数据是没有意义的。

比如两台主机A和B,一开始两台主机都是处于连接状态,能正常进行通信,但是某个时刻主机B断开了,但是主机A不会知道主机B是否正常运行,因为以太网不会提示主机B已经断开,那么主机A会一直按照MAC地址发送数据,而此时在物理链路层就已经是不通的,那么这些数据是没有意义的,而如果ARP动态更新的话,主机A就会发出ARP请求包,如果得不到主机B的回应,则说明无法与主机B进行通信,那么就会删除ARP表项,就无法进行通信。

欢迎关注杰杰个人公众号,更多干货等着你!

你可能感兴趣的:(LwIP,杰杰开源社区)