net/arp: modify some flow of arp return failure.

If arp search fails once, subsequent searches for the ip will directly
return failure, and sends an asynchronous arp request to try to update
arp table in the future. In this way, the psock_sendmsg interface will
not block for a long time each time because arp cannot be obtained.

This scenario is triggered when a udp socket frequently attempts to
access an ip address that does not exist on the LAN.

Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
This commit is contained in:
zhanghongyu 2024-09-25 20:12:20 +08:00 committed by Xiang Xiao
parent 85591fc360
commit 8bb1e30884
2 changed files with 51 additions and 10 deletions

View File

@ -148,6 +148,10 @@ static uint16_t arp_send_eventhandler(FAR struct net_driver_s *dev,
return flags;
}
static void arp_send_async_finish(FAR struct net_driver_s *dev, int result)
{
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -301,9 +305,7 @@ int arp_send(in_addr_t ipaddr)
* sending the ARP request if it is not.
*/
ret = -ETIMEDOUT; /* Assume a timeout failure */
while (state.snd_retries < CONFIG_ARP_SEND_MAXTRIES)
do
{
/* Check if the address mapping is present in the ARP table. This
* is only really meaningful on the first time through the loop.
@ -312,12 +314,21 @@ int arp_send(in_addr_t ipaddr)
* issue.
*/
if (arp_find(ipaddr, NULL, dev) >= 0)
ret = arp_find(ipaddr, NULL, dev);
if (ret >= 0)
{
/* We have it! Break out with success */
ret = OK;
break;
goto out;
}
else if (ret == -ENETUNREACH)
{
/* We have failed before, simply send an asynchronous ARP request
* to try to update the ARP table.
*/
arp_send_async(ipaddr, NULL);
goto out;
}
/* Set up the ARP response wait BEFORE we send the ARP request */
@ -377,7 +388,7 @@ int arp_send(in_addr_t ipaddr)
{
/* Break out if arp_wait() fails */
break;
goto out;
}
timeout:
@ -389,7 +400,15 @@ timeout:
ip4_addr1(ipaddr), ip4_addr2(ipaddr),
ip4_addr3(ipaddr), ip4_addr4(ipaddr));
}
while (state.snd_retries < CONFIG_ARP_SEND_MAXTRIES);
/* MAC address marked with all zeros, therefore, we can quickly execute
* asynchronous ARP request next time.
*/
arp_update(dev, ipaddr, NULL);
out:
nxsem_destroy(&state.snd_sem);
arp_callback_free(dev, state.snd_cb);
errout_with_lock:
@ -464,7 +483,7 @@ int arp_send_async(in_addr_t ipaddr, arp_send_finish_cb_t cb)
state->snd_cb->flags = (ARP_POLL | NETDEV_DOWN);
state->snd_cb->priv = (FAR void *)state;
state->snd_cb->event = arp_send_eventhandler;
state->finish_cb = cb;
state->finish_cb = cb ? cb : arp_send_async_finish;
/* Notify the device driver that new TX data is available. */

View File

@ -91,6 +91,13 @@ struct arp_table_info_s
static struct arp_entry_s g_arptable[CONFIG_NET_ARPTAB_SIZE];
static const struct ether_addr g_zero_ethaddr =
{
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
}
};
/****************************************************************************
* Private Functions
****************************************************************************/
@ -308,6 +315,11 @@ int arp_update(FAR struct net_driver_s *dev, in_addr_t ipaddr,
}
}
if (ethaddr == NULL)
{
ethaddr = g_zero_ethaddr.ether_addr_octet;
}
/* When overwite old entry, notify old entry RTM_DELNEIGH */
#ifdef CONFIG_NETLINK_ROUTE
@ -407,6 +419,16 @@ int arp_find(in_addr_t ipaddr, FAR uint8_t *ethaddr,
tabptr = arp_lookup(ipaddr, dev);
if (tabptr != NULL)
{
/* Addresses that have failed to be searched will return a special
* error code so that the upper layer can return faster.
*/
if (memcmp(&tabptr->at_ethaddr, &g_zero_ethaddr,
sizeof(tabptr->at_ethaddr)) == 0)
{
return -ENETUNREACH;
}
/* Yes.. return the Ethernet MAC address if the caller has provided a
* non-NULL address in 'ethaddr'.
*/
@ -416,8 +438,8 @@ int arp_find(in_addr_t ipaddr, FAR uint8_t *ethaddr,
memcpy(ethaddr, &tabptr->at_ethaddr, ETHER_ADDR_LEN);
}
/* Return success in any case meaning that a valid Ethernet MAC
* address mapping is available for the IP address.
/* Return success meaning that a valid Ethernet MAC address mapping
* is available for the IP address.
*/
return OK;