mirror of
https://github.com/apache/nuttx.git
synced 2026-05-30 21:36: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
|
The maximum age of ARP table entries measured in deciseconds. The
|
||||||
default value of 120 corresponds to 20 minutes (BSD default).
|
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
|
config NET_ARP_IPIN
|
||||||
bool "ARP address harvesting"
|
bool "ARP address harvesting"
|
||||||
default n
|
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);
|
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 destination address was not in our ARP table, so we overwrite
|
||||||
* the IP packet with an ARP request.
|
* 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;
|
FAR struct net_driver_s *dev;
|
||||||
struct arp_notify_s notify;
|
struct arp_notify_s notify;
|
||||||
struct arp_send_s state;
|
struct arp_send_s state;
|
||||||
|
bool sending = false;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* First check if destination is a local broadcast. */
|
/* First check if destination is a local broadcast. */
|
||||||
@@ -306,12 +307,12 @@ int arp_send(in_addr_t ipaddr)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
netdev_lock(dev);
|
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);
|
netdev_unlock(dev);
|
||||||
ret = OK;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,6 +320,15 @@ int arp_send(in_addr_t ipaddr)
|
|||||||
|
|
||||||
arp_wait_setup(ipaddr, ¬ify);
|
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
|
/* Allocate resources to receive a callback. This and the following
|
||||||
* initialization is performed with the network lock because we don't
|
* initialization is performed with the network lock because we don't
|
||||||
* want anything to happen until we are ready.
|
* want anything to happen until we are ready.
|
||||||
@@ -351,6 +361,16 @@ int arp_send(in_addr_t ipaddr)
|
|||||||
|
|
||||||
netdev_txnotify_dev(dev);
|
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.
|
/* Wait for the send to complete or an error to occur.
|
||||||
* net_sem_wait will also terminate if a signal is received.
|
* 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. */
|
/* Now wait for response to the ARP response to be received. */
|
||||||
|
|
||||||
|
wait:
|
||||||
ret = arp_wait(¬ify, CONFIG_ARP_SEND_DELAYMSEC);
|
ret = arp_wait(¬ify, CONFIG_ARP_SEND_DELAYMSEC);
|
||||||
|
|
||||||
/* arp_wait will return OK if and only if the matching ARP response
|
/* arp_wait will return OK if and only if the matching ARP response
|
||||||
@@ -406,7 +427,6 @@ timeout:
|
|||||||
|
|
||||||
nxsem_destroy(&state.snd_sem);
|
nxsem_destroy(&state.snd_sem);
|
||||||
arp_callback_free(dev, state.snd_cb);
|
arp_callback_free(dev, state.snd_cb);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+39
-2
@@ -72,6 +72,8 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#define ARP_MAXAGE_TICK SEC2TICK(10 * CONFIG_NET_ARP_MAXAGE)
|
#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
|
* Private Types
|
||||||
@@ -91,6 +93,13 @@ struct arp_table_info_s
|
|||||||
|
|
||||||
static struct arp_entry_s g_arptable[CONFIG_NET_ARPTAB_SIZE];
|
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
|
* 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 */
|
/* When overwrite old entry, notify old entry RTM_DELNEIGH */
|
||||||
|
|
||||||
#ifdef CONFIG_NETLINK_ROUTE
|
#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);
|
tabptr = arp_lookup(ipaddr, dev, check_expiry);
|
||||||
if (tabptr != NULL)
|
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
|
/* Yes.. return the Ethernet MAC address if the caller has provided a
|
||||||
* non-NULL address in 'ethaddr'.
|
* 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);
|
memcpy(ethaddr, &tabptr->at_ethaddr, ETHER_ADDR_LEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return success in any case meaning that a valid Ethernet MAC
|
/* Return success meaning that a valid Ethernet MAC address mapping
|
||||||
* address mapping is available for the IP address.
|
* is available for the IP address.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
|
|||||||
Reference in New Issue
Block a user