mirror of
https://github.com/apache/nuttx.git
synced 2026-05-26 10:46:28 +08:00
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:
@@ -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
|
||||
|
||||
@@ -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
@@ -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, ¬ify);
|
||||
|
||||
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(¬ify, 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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user