fixed bug #34617: Stable etharp entries that are about to expire are now refreshed using unicast to prevent unnecessary broadcast.

Only if no answer is received after 15 seconds, broadcast is used.
This commit is contained in:
sg 2015-03-23 21:38:19 +01:00
parent 33d5e646e5
commit 440c99100b
2 changed files with 49 additions and 12 deletions

View File

@ -6,6 +6,11 @@ HISTORY
++ New features:
2015-03-23: Simon Goldschmidt
* etharp.c: Stable etharp entries that are about to expire are now refreshed
using unicast to prevent unnecessary broadcast. Only if no answer is received
after 15 seconds, broadcast is used.
2015-03-06: Philip Gladstone
* netif.h/.c: patch #8359 (Provide utility function to add an IPv6 address to
an interface)

View File

@ -80,7 +80,8 @@ const struct eth_addr ethzero = {{0,0,0,0,0,0}};
#define ARP_MAXAGE 1200
/** Re-request a used ARP entry 1 minute before it would expire to prevent
* breaking a steadily used connection because the ARP entry timed out. */
#define ARP_AGE_REREQUEST_USED (ARP_MAXAGE - 60)
#define ARP_AGE_REREQUEST_USED_UNICAST (ARP_MAXAGE - 30)
#define ARP_AGE_REREQUEST_USED_BROADCAST (ARP_MAXAGE - 15)
/** the time an ARP entry stays pending after first request,
* for ARP_TMR_INTERVAL = 1000, this is
@ -97,7 +98,8 @@ enum etharp_state {
ETHARP_STATE_EMPTY = 0,
ETHARP_STATE_PENDING,
ETHARP_STATE_STABLE,
ETHARP_STATE_STABLE_REREQUESTING
ETHARP_STATE_STABLE_REREQUESTING_1,
ETHARP_STATE_STABLE_REREQUESTING_2
#if ETHARP_SUPPORT_STATIC_ENTRIES
,ETHARP_STATE_STATIC
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
@ -146,6 +148,9 @@ static u8_t etharp_cached_entry;
#endif
static err_t etharp_request_dst(struct netif *netif, const ip_addr_t *ipaddr, const struct eth_addr* hw_dst_addr);
#if ARP_QUEUEING
/**
* Free a complete queue of etharp entries
@ -200,7 +205,7 @@ etharp_free_entry(int i)
/**
* Clears expired entries in the ARP table.
*
* This function should be called every ETHARP_TMR_INTERVAL milliseconds (5 seconds),
* This function should be called every ARP_TMR_INTERVAL milliseconds (1 second),
* in order to expire entries in the ARP table.
*/
void
@ -226,8 +231,10 @@ etharp_tmr(void)
arp_table[i].state >= ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i));
/* clean up entries that have just been expired */
etharp_free_entry(i);
}
else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING) {
} else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING_1) {
/* Don't send more than one request every 2 seconds. */
arp_table[i].state = ETHARP_STATE_STABLE_REREQUESTING_2;
} else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING_2) {
/* Reset state to stable, so that the next transmitted packet will
re-send an ARP request. */
arp_table[i].state = ETHARP_STATE_STABLE;
@ -863,10 +870,17 @@ etharp_output_to_arp_index(struct netif *netif, struct pbuf *q, u8_t arp_idx)
/* if arp table entry is about to expire: re-request it,
but only if its state is ETHARP_STATE_STABLE to prevent flooding the
network with ARP requests if this address is used frequently. */
if ((arp_table[arp_idx].state == ETHARP_STATE_STABLE) &&
(arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED)) {
if (etharp_request(netif, &arp_table[arp_idx].ipaddr) == ERR_OK) {
arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING;
if (arp_table[arp_idx].state == ETHARP_STATE_STABLE) {
if (arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED_BROADCAST) {
/* issue a standard request using broadcast */
if (etharp_request(netif, &arp_table[arp_idx].ipaddr) == ERR_OK) {
arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING_1;
}
} else if (arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED_UNICAST) {
/* issue a unicast request (for 15 seconds) to prevent unnecessary broadcast */
if (etharp_request_dst(netif, &arp_table[arp_idx].ipaddr, &arp_table[arp_idx].ethaddr) == ERR_OK) {
arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING_1;
}
}
}
@ -1316,6 +1330,26 @@ etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
return result;
}
/**
* Send an ARP request packet asking for ipaddr to a specific eth address.
* Used to send unicast request to refresh the ARP table just before an entry
* times out
*
* @param netif the lwip network interface on which to send the request
* @param ipaddr the IP address for which to ask
* @param hw_dst_addr the ethernet address to send this packet to
* @return ERR_OK if the request has been sent
* ERR_MEM if the ARP packet couldn't be allocated
* any other err_t on failure
*/
static err_t
etharp_request_dst(struct netif *netif, const ip_addr_t *ipaddr, const struct eth_addr* hw_dst_addr)
{
return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, hw_dst_addr,
(struct eth_addr *)netif->hwaddr, &netif->ip_addr, &ethzero,
ipaddr, ARP_REQUEST);
}
/**
* Send an ARP request packet asking for ipaddr.
*
@ -1329,9 +1363,7 @@ err_t
etharp_request(struct netif *netif, const ip_addr_t *ipaddr)
{
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_request: sending ARP request.\n"));
return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &ethbroadcast,
(struct eth_addr *)netif->hwaddr, &netif->ip_addr, &ethzero,
ipaddr, ARP_REQUEST);
return etharp_request_dst(netif, ipaddr, &ethbroadcast);
}
#endif /* LWIP_ARP */