前言
从前面的文章,我们知道,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表项,就无法进行通信。
来源:CSDN
作者:芋圆-钰源
链接:https://blog.csdn.net/weixin_37571125/article/details/104813311