这里说一下find_entry这个函数,这个函数主要是查找ARP表和在ARP表中申请一个empty的表项
这里有必要先翻译一下开头的注释:
函数有两个参数,一个ip地址,一个flag
如果ip地址有效,就返回一个pending或者stable状态的表项索引。
如果找不到,就创建一个新的,并把这个ip地址设置上去,状态变为empty。状态有上层调用函数去改变。
如果ip地址是空的。也返回一个empty的表项索引
上面的都不符合并且flasg标志为ETHARP_TRY_HARD,那么就尝试从ARP表中删除一个最早的表项,并返回之索引。
删除会有一个优先级别。
在代码搜索了一遍ARP表的时候,已经记录了一下表项的状态和生存时间
1.返回第一个empty状态的表项,代码中用empty表示
2.返回生存时间最长的stable表项。代码中用old_stable表示
3.返回生存时间最长且没有数据缓冲项的索引,代码中用old_pending表示
4.返回生存时间最长而且有数据缓冲项的索引,代码中用old_queue表示
下面给代码,照例删除一下调试用的代码,减少篇幅
static s8_t find_entry ( struct ip_addr *ipaddr, u8_t flags )
{
s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE;
s8_t empty = ARP_TABLE_SIZE;
u8_t i = 0, age_pending = 0, age_stable = 0;
#if ARP_QUEUEING
/* oldest entry with packets on queue */
s8_t old_queue = ARP_TABLE_SIZE;
/* its age */
u8_t age_queue = 0;
#endif
/*上面注意empty ,old_queue ,old_pending ,old_stable 这几个变量*/
if ( ipaddr )
{
/*etharp_cached_entry保存了上次返回的索引*/
if ( arp_table[etharp_cached_entry].state == ETHARP_STATE_STABLE )
{
/*如果上次的还有效,并且是这个要找的ip,直接返回,这个技巧很快*/
/* the cached entry is stable */
if ( ip_addr_cmp ( ipaddr, &arp_table[etharp_cached_entry].ipaddr ) )
{
/* cached entry was the right one! */
ETHARP_STATS_INC ( etharp.cachehit );
return etharp_cached_entry;
}
}
}
/*下面的for做搜索,并记录一下表项的状态和生存时间*/
for ( i = 0; i < ARP_TABLE_SIZE; ++i )
{
/* no empty entry found yet and now we do find one? */
if ( ( empty == ARP_TABLE_SIZE ) && ( arp_table[i].state == ETHARP_STATE_EMPTY ) )
{
/*empty == ARP_TABLE_SIZE
这个第一次生效会生效,这里只进入一次,就是记录第一个出现empty表项的位置*/
/* remember first empty entry */
empty = i;
}
/* pending entry? */
else if ( arp_table[i].state == ETHARP_STATE_PENDING )
{
/**看ip是否匹配,匹配的话就直接返回索引更新etharp_cached_entry,*/
/* if given, does IP address match IP address in ARP entry? */
if ( ipaddr && ip_addr_cmp ( ipaddr, &arp_table[i].ipaddr ) )
{
/* found exact IP address match, simply bail out */
etharp_cached_entry = i;
return i;
#if ARP_QUEUEING
/* pending with queued packets? */
}
else if ( arp_table[i].q != NULL )
{
/*找生存时间最长的*/
if ( arp_table[i].ctime >= age_queue )
{
old_queue = i;
age_queue = arp_table[i].ctime;
}
#endif
/* pending without queued packets? */
}
else
{
/*找生存时间最长的*/
if ( arp_table[i].ctime >= age_pending )
{
old_pending = i;
age_pending = arp_table[i].ctime;
}
}
}
/* stable entry? */
else if ( arp_table[i].state == ETHARP_STATE_STABLE )
{
/* if given, does IP address match IP address in ARP entry? */
if ( ipaddr && ip_addr_cmp ( ipaddr, &arp_table[i].ipaddr ) )
{
/*找到匹配的就直接返回了,就是它了!!*/
etharp_cached_entry = i;
return i;
/* remember entry with oldest stable entry in oldest, its age in maxtime */
}
else if ( arp_table[i].ctime >= age_stable )
{/*没有就记录一下它活了多久,一会会有判断,如果活得太久了,就干掉它,返回一个empty的给上层*/
old_stable = i;
age_stable = arp_table[i].ctime;
}
}
}
/* { we have no match } => try to create a new entry */
/* no empty entry found and not allowed to recycle? */
if ( ( ( empty == ARP_TABLE_SIZE ) && ( ( flags & ETHARP_TRY_HARD ) == 0 ) )
/* or don't create new entry, only search? */
|| ( ( flags & ETHARP_FIND_ONLY ) != 0 ) )
{
{
/*etharp_cached_entry保存了上次返回的索引*/
if ( arp_table[etharp_cached_entry].state == ETHARP_STATE_STABLE )
{
/*如果上次的还有效,并且是这个要找的ip,直接返回,这个技巧很快*/
/* the cached entry is stable */
if ( ip_addr_cmp ( ipaddr, &arp_table[etharp_cached_entry].ipaddr ) )
{
/* cached entry was the right one! */
ETHARP_STATS_INC ( etharp.cachehit );
return etharp_cached_entry;
}
}
}
/*下面的for做搜索,并记录一下表项的状态和生存时间*/
for ( i = 0; i < ARP_TABLE_SIZE; ++i )
{
/* no empty entry found yet and now we do find one? */
if ( ( empty == ARP_TABLE_SIZE ) && ( arp_table[i].state == ETHARP_STATE_EMPTY ) )
{
/*empty == ARP_TABLE_SIZE
这个第一次生效会生效,这里只进入一次,就是记录第一个出现empty表项的位置*/
/* remember first empty entry */
empty = i;
}
/* pending entry? */
else if ( arp_table[i].state == ETHARP_STATE_PENDING )
{
/**看ip是否匹配,匹配的话就直接返回索引更新etharp_cached_entry,*/
/* if given, does IP address match IP address in ARP entry? */
if ( ipaddr && ip_addr_cmp ( ipaddr, &arp_table[i].ipaddr ) )
{
/* found exact IP address match, simply bail out */
etharp_cached_entry = i;
return i;
#if ARP_QUEUEING
/* pending with queued packets? */
}
else if ( arp_table[i].q != NULL )
{
/*找生存时间最长的*/
if ( arp_table[i].ctime >= age_queue )
{
old_queue = i;
age_queue = arp_table[i].ctime;
}
#endif
/* pending without queued packets? */
}
else
{
/*找生存时间最长的*/
if ( arp_table[i].ctime >= age_pending )
{
old_pending = i;
age_pending = arp_table[i].ctime;
}
}
}
/* stable entry? */
else if ( arp_table[i].state == ETHARP_STATE_STABLE )
{
/* if given, does IP address match IP address in ARP entry? */
if ( ipaddr && ip_addr_cmp ( ipaddr, &arp_table[i].ipaddr ) )
{
/*找到匹配的就直接返回了,就是它了!!*/
etharp_cached_entry = i;
return i;
/* remember entry with oldest stable entry in oldest, its age in maxtime */
}
else if ( arp_table[i].ctime >= age_stable )
{/*没有就记录一下它活了多久,一会会有判断,如果活得太久了,就干掉它,返回一个empty的给上层*/
old_stable = i;
age_stable = arp_table[i].ctime;
}
}
}
/* { we have no match } => try to create a new entry */
/* no empty entry found and not allowed to recycle? */
if ( ( ( empty == ARP_TABLE_SIZE ) && ( ( flags & ETHARP_TRY_HARD ) == 0 ) )
/* or don't create new entry, only search? */
|| ( ( flags & ETHARP_FIND_ONLY ) != 0 ) )
{
/*找不到空位了,又不给杀人,只能返回错误了*/
return ( s8_t ) ERR_MEM;
}
/* b) choose the least destructive entry to recycle:
* 1) empty entry
* 2) oldest stable entry
* 3) oldest pending entry without queued packets
* 4) oldest pending entry with queued packets
*
* { ETHARP_TRY_HARD is set at this point }
*/
下面找到最合适杀掉的那一个。上面是解释,就不翻译了
/* 1) empty entry available? */
if ( empty < ARP_TABLE_SIZE )
{
i = empty;
}
/* 2) found recyclable stable entry? */
else if ( old_stable < ARP_TABLE_SIZE )
{
/* recycle oldest stable*/
i = old_stable;
#if ARP_QUEUEING
/* no queued packets should exist on stable entries */
LWIP_ASSERT ( "arp_table[i].q == NULL", arp_table[i].q == NULL );
#endif
/* 3) found recyclable pending entry without queued packets? */
}
else if ( old_pending < ARP_TABLE_SIZE )
{
/* recycle oldest pending */
i = old_pending;
#if ARP_QUEUEING
/* 4) found recyclable pending entry with queued packets? */
}
else if ( old_queue < ARP_TABLE_SIZE )
{
/* recycle oldest pending */
i = old_queue;
free_etharp_q ( arp_table[i].q );
arp_table[i].q = NULL;
#endif
/* no empty or recyclable entries found */
}
else
{
return ( s8_t ) ERR_MEM;
}
/* { empty or recyclable entry found } */
LWIP_ASSERT ( "i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE );
/*杀人开始*/
return ( s8_t ) ERR_MEM;
}
/* b) choose the least destructive entry to recycle:
* 1) empty entry
* 2) oldest stable entry
* 3) oldest pending entry without queued packets
* 4) oldest pending entry with queued packets
*
* { ETHARP_TRY_HARD is set at this point }
*/
下面找到最合适杀掉的那一个。上面是解释,就不翻译了
/* 1) empty entry available? */
if ( empty < ARP_TABLE_SIZE )
{
i = empty;
}
/* 2) found recyclable stable entry? */
else if ( old_stable < ARP_TABLE_SIZE )
{
/* recycle oldest stable*/
i = old_stable;
#if ARP_QUEUEING
/* no queued packets should exist on stable entries */
LWIP_ASSERT ( "arp_table[i].q == NULL", arp_table[i].q == NULL );
#endif
/* 3) found recyclable pending entry without queued packets? */
}
else if ( old_pending < ARP_TABLE_SIZE )
{
/* recycle oldest pending */
i = old_pending;
#if ARP_QUEUEING
/* 4) found recyclable pending entry with queued packets? */
}
else if ( old_queue < ARP_TABLE_SIZE )
{
/* recycle oldest pending */
i = old_queue;
free_etharp_q ( arp_table[i].q );
arp_table[i].q = NULL;
#endif
/* no empty or recyclable entries found */
}
else
{
return ( s8_t ) ERR_MEM;
}
/* { empty or recyclable entry found } */
LWIP_ASSERT ( "i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE );
/*杀人开始*/
/*从索引中删除*/
if ( arp_table[i].state != ETHARP_STATE_EMPTY )
{
snmp_delete_arpidx_tree ( arp_table[i].netif, &arp_table[i].ipaddr );
}
/* recycle entry (no-op for an already empty entry) */
arp_table[i].state = ETHARP_STATE_EMPTY;
/* IP address given? */
if ( arp_table[i].state != ETHARP_STATE_EMPTY )
{
snmp_delete_arpidx_tree ( arp_table[i].netif, &arp_table[i].ipaddr );
}
/* recycle entry (no-op for an already empty entry) */
arp_table[i].state = ETHARP_STATE_EMPTY;
/* IP address given? */
/*如果上面传了个ip下来,就把这个ip写进去*/
if ( ipaddr != NULL )
{
/* set IP address */
ip_addr_set ( &arp_table[i].ipaddr, ipaddr );
}
arp_table[i].ctime = 0;/*出生时间0*/
etharp_cached_entry = i;
return ( err_t ) i;
}
if ( ipaddr != NULL )
{
/* set IP address */
ip_addr_set ( &arp_table[i].ipaddr, ipaddr );
}
arp_table[i].ctime = 0;/*出生时间0*/
etharp_cached_entry = i;
return ( err_t ) i;
}