net/arp: limit arp request when arp is in progress to prevent ARP flooding

Wait a fixed number of milliseconds before sending a retry ARP request for the same destination if the IP address mapping is not exist to prevent ARP flooding

Signed-off-by: wenquan1 <wenquan1@xiaomi.com>
This commit is contained in:
wenquan1
2025-07-16 15:28:18 +08:00
committed by Xiang Xiao
parent 6b30226c0e
commit 4ae08155f9
4 changed files with 88 additions and 6 deletions
+8
View File
@@ -28,6 +28,14 @@ config NET_ARP_MAXAGE
The maximum age of ARP table entries measured in deciseconds. The
default value of 120 corresponds to 20 minutes (BSD default).
config NET_ARP_MAXAGE_UNREACHABLE
int "Max unreachable ARP entry age"
default 1
---help---
The maximum age of unreachable ARP table entries measured in
deciseconds. During unreachable period not send a retry ARP
request for the same destination.
config NET_ARP_IPIN
bool "ARP address harvesting"
default n
+17
View File
@@ -262,6 +262,23 @@ void arp_out(FAR struct net_driver_s *dev)
ninfo("ARP request for IP %08lx\n", (unsigned long)ipaddr);
if (ret == -EINPROGRESS)
{
/* The destination address was not in our ARP table, and
* the last arp request is in progress, directly drop the packet
* to prevent arp flood.
*/
dev->d_len = 0;
return;
}
/* MAC address marked with all zeros to limit concurrent task
* send ARP request for same destination.
*/
arp_update(dev, ipaddr, NULL);
/* The destination address was not in our ARP table, so we overwrite
* the IP packet with an ARP request.
*/
+24 -4
View File
@@ -180,6 +180,7 @@ int arp_send(in_addr_t ipaddr)
FAR struct net_driver_s *dev;
struct arp_notify_s notify;
struct arp_send_s state;
bool sending = false;
int ret;
/* First check if destination is a local broadcast. */
@@ -306,12 +307,12 @@ int arp_send(in_addr_t ipaddr)
*/
netdev_lock(dev);
if (arp_find(ipaddr, NULL, dev, true) >= 0)
ret = arp_find(ipaddr, NULL, dev, true);
if (ret >= 0 || ret == -ENETUNREACH)
{
/* We have it! Break out with success */
/* We have it! Break out with ret value */
netdev_unlock(dev);
ret = OK;
break;
}
@@ -319,6 +320,15 @@ int arp_send(in_addr_t ipaddr)
arp_wait_setup(ipaddr, &notify);
if (ret == -EINPROGRESS && !sending)
{
/* ARP request for the same destination is in progress, directly
* wait arp response notify.
*/
goto wait;
}
/* Allocate resources to receive a callback. This and the following
* initialization is performed with the network lock because we don't
* want anything to happen until we are ready.
@@ -351,6 +361,16 @@ int arp_send(in_addr_t ipaddr)
netdev_txnotify_dev(dev);
/* MAC address marked with all zeros to limit concurrent task
* send ARP request for same destination.
*/
if (state.snd_retries == 0)
{
arp_update(dev, ipaddr, NULL);
sending = true;
}
/* Wait for the send to complete or an error to occur.
* net_sem_wait will also terminate if a signal is received.
*/
@@ -381,6 +401,7 @@ int arp_send(in_addr_t ipaddr)
/* Now wait for response to the ARP response to be received. */
wait:
ret = arp_wait(&notify, CONFIG_ARP_SEND_DELAYMSEC);
/* arp_wait will return OK if and only if the matching ARP response
@@ -406,7 +427,6 @@ timeout:
nxsem_destroy(&state.snd_sem);
arp_callback_free(dev, state.snd_cb);
return ret;
}
+39 -2
View File
@@ -72,6 +72,8 @@
****************************************************************************/
#define ARP_MAXAGE_TICK SEC2TICK(10 * CONFIG_NET_ARP_MAXAGE)
#define ARP_MAXAGE_UNREACHABLE_TICK SEC2TICK(10 * CONFIG_NET_ARP_MAXAGE_UNREACHABLE)
#define ARP_INPROGRESS_TICK MSEC2TICK(CONFIG_ARP_SEND_MAXTRIES * CONFIG_ARP_SEND_DELAYMSEC)
/****************************************************************************
* Private Types
@@ -91,6 +93,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
****************************************************************************/
@@ -322,6 +331,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 overwrite old entry, notify old entry RTM_DELNEIGH */
#ifdef CONFIG_NETLINK_ROUTE
@@ -422,6 +436,29 @@ int arp_find(in_addr_t ipaddr, FAR uint8_t *ethaddr,
tabptr = arp_lookup(ipaddr, dev, check_expiry);
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)
{
clock_t elapsed;
elapsed = clock_systime_ticks() - tabptr->at_time;
if (elapsed <= ARP_INPROGRESS_TICK)
{
return -EINPROGRESS;
}
else if (elapsed <= ARP_MAXAGE_UNREACHABLE_TICK)
{
return -ENETUNREACH;
}
else
{
return -ENOENT;
}
}
/* Yes.. return the Ethernet MAC address if the caller has provided a
* non-NULL address in 'ethaddr'.
*/
@@ -431,8 +468,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;