net/arp: Improve arp_find() commit 9774d35010 to reduce the amount and frequency of data copies.

This commit is contained in:
Gregory Nutt 2018-08-25 06:47:10 -06:00
parent aa409f46ab
commit 3bf96c8e7e
11 changed files with 94 additions and 55 deletions

View file

@ -2,7 +2,8 @@
* include/nuttx/net/arp.h
* Macros and definitions for the ARP module.
*
* Copyright (C) 2007, 2009-2012, 2015-2016 Gregory Nutt. All rights reserved.
* Copyright (C) 2007, 2009-2012, 2015-2016, 2018 Gregory Nutt. All rights
* reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Derived from uIP with has a similar BSD-style license:
@ -78,7 +79,7 @@
/* One entry in the ARP table (volatile!) */
struct arp_entry
struct arp_entry_s
{
in_addr_t at_ipaddr; /* IP address */
struct ether_addr at_ethaddr; /* Hardware address */

View file

@ -1,7 +1,7 @@
/****************************************************************************
* net/arp/arp.h
*
* Copyright (C) 2014-2016 Gregory Nutt. All rights reserved.
* Copyright (C) 2014-2016, 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -384,7 +384,7 @@ void arp_notify(in_addr_t ipaddr);
*
****************************************************************************/
FAR struct arp_entry *arp_lookup(in_addr_t ipaddr);
FAR struct arp_entry_s *arp_lookup(in_addr_t ipaddr);
/****************************************************************************
* Name: arp_find
@ -394,15 +394,19 @@ FAR struct arp_entry *arp_lookup(in_addr_t ipaddr);
* not be in the ARP table (it may, instead, be a local network device).
*
* Input Parameters:
* ipaddr - Refers to an IP address in network order
* entry - location to return a copy of the ARP table entry.
* ipaddr - Refers to an IP address in network order
* ethaddr - Location to return the corresponding Ethernet MAN address.
* This address may be NULL. In that case, this function may be
* used simply to determine if the Ethernet MAC address is
* available.
*
* Assumptions
* The network is locked to assure exclusive access to the ARP table.
*
****************************************************************************/
int arp_find(in_addr_t ipaddr, FAR struct arp_entry *entry);
struct ether_addr; /* Forward reference */
int arp_find(in_addr_t ipaddr, FAR struct ether_addr *ethaddr);
/****************************************************************************
* Name: arp_delete

View file

@ -1,7 +1,8 @@
/****************************************************************************
* net/arp/arp_out.c
*
* Copyright (C) 2007-2011, 2014-2015, 2017 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2011, 2014-2015, 2017-2018 Gregory Nutt. All rights
* reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Based on uIP which also has a BSD style license:
@ -136,7 +137,7 @@ static const uint8_t g_multicast_ethaddr[3] =
void arp_out(FAR struct net_driver_s *dev)
{
struct arp_entry entry;
struct ether_addr ethaddr;
FAR struct eth_hdr_s *peth = ETHBUF;
FAR struct arp_iphdr_s *pip = IPBUF;
in_addr_t ipaddr;
@ -250,7 +251,7 @@ void arp_out(FAR struct net_driver_s *dev)
/* Check if we already have this destination address in the ARP table */
ret = arp_find(ipaddr, &entry);
ret = arp_find(ipaddr, &ethaddr);
if (ret >= 0)
{
ninfo("ARP request for IP %08lx\n", (unsigned long)ipaddr);
@ -266,7 +267,7 @@ void arp_out(FAR struct net_driver_s *dev)
/* Build an Ethernet header. */
memcpy(peth->dest, entry.at_ethaddr.ether_addr_octet, ETHER_ADDR_LEN);
memcpy(peth->dest, ethaddr.ether_addr_octet, ETHER_ADDR_LEN);
/* Finish populating the Ethernet header */

View file

@ -315,8 +315,6 @@ int arp_send(in_addr_t ipaddr)
while (state.snd_retries < CONFIG_ARP_SEND_MAXTRIES)
{
struct arp_entry entry;
/* Check if the address mapping is present in the ARP table. This
* is only really meaningful on the first time through the loop.
*
@ -324,7 +322,7 @@ int arp_send(in_addr_t ipaddr)
* issue.
*/
if (arp_find(ipaddr, &entry) >= 0)
if (arp_find(ipaddr, NULL) >= 0)
{
/* We have it! Break out with success */

View file

@ -49,7 +49,6 @@
#include <sys/ioctl.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <debug.h>
#include <netinet/in.h>
@ -66,13 +65,23 @@
#ifdef CONFIG_NET_ARP
/****************************************************************************
* Private Types
****************************************************************************/
struct arp_table_info_s
{
in_addr_t ai_ipaddr; /* IP address for lookup */
FAR struct ether_addr *ai_ethaddr; /* Location to return the MAC address */
};
/****************************************************************************
* Private Data
****************************************************************************/
/* The table of known address mappings */
static struct arp_entry g_arptable[CONFIG_NET_ARPTAB_SIZE];
static struct arp_entry_s g_arptable[CONFIG_NET_ARPTAB_SIZE];
static uint8_t g_arptime;
/****************************************************************************
@ -90,19 +99,38 @@ static uint8_t g_arptime;
static int arp_match(FAR struct net_driver_s *dev, FAR void *arg)
{
FAR struct arp_entry *entry = arg;
FAR struct arp_table_info_s *info = arg;
if (dev->d_lltype != NET_LL_ETHERNET)
/* Make sure that this is an Ethernet device (or an IEEE 802.11 device
* which is also Ethernet)
*/
if (dev->d_lltype != NET_LL_ETHERNET &&
dev->d_lltype != NET_LL_IEEE80211)
{
return 0;
}
if (!net_ipv4addr_cmp(dev->d_ipaddr, entry->at_ipaddr))
/* Check if the network device has been assigned the IP address of the
* lookup.
*/
if (!net_ipv4addr_cmp(dev->d_ipaddr, info->ai_ipaddr))
{
return 0;
}
memcpy(&entry->at_ethaddr, &dev->d_mac.ether, ETHER_ADDR_LEN);
/* Yes.. Return the matching Ethernet MAC address if the caller of
* arp_find() provided a non-NULL location.
*/
if (info->ai_ethaddr != NULL)
{
memcpy(info->ai_ethaddr, &dev->d_mac.ether, ETHER_ADDR_LEN);
}
/* Return success in any event */
return 1;
}
@ -141,7 +169,7 @@ void arp_reset(void)
void arp_timer(void)
{
FAR struct arp_entry *tabptr;
FAR struct arp_entry_s *tabptr;
int i;
++g_arptime;
@ -179,7 +207,7 @@ void arp_timer(void)
int arp_update(in_addr_t ipaddr, FAR uint8_t *ethaddr)
{
struct arp_entry *tabptr = NULL;
struct arp_entry_s *tabptr = NULL;
int i;
/* Walk through the ARP mapping table and try to find an entry to
@ -299,9 +327,9 @@ void arp_hdr_update(FAR uint16_t *pipaddr, FAR uint8_t *ethaddr)
*
****************************************************************************/
FAR struct arp_entry *arp_lookup(in_addr_t ipaddr)
FAR struct arp_entry_s *arp_lookup(in_addr_t ipaddr)
{
FAR struct arp_entry *tabptr;
FAR struct arp_entry_s *tabptr;
int i;
/* Check if the IPv4 address is already in the ARP table. */
@ -328,25 +356,40 @@ FAR struct arp_entry *arp_lookup(in_addr_t ipaddr)
* not be in the ARP table (it may, instead, be a local network device).
*
* Input Parameters:
* ipaddr - Refers to an IP address in network order
* ipaddr - Refers to an IP address in network order
* ethaddr - Location to return the corresponding Ethernet MAN address.
* This address may be NULL. In that case, this function may be
* used simply to determine if the Ethernet MAC address is
* available.
*
* Assumptions:
* Assumptions
* The network is locked to assure exclusive access to the ARP table.
*
****************************************************************************/
int arp_find(in_addr_t ipaddr, FAR struct arp_entry *entry)
int arp_find(in_addr_t ipaddr, FAR struct ether_addr *ethaddr)
{
FAR struct arp_entry *tabptr;
DEBUGASSERT(entry);
FAR struct arp_entry_s *tabptr;
struct arp_table_info_s info;
/* Check if the IPv4 address is already in the ARP table. */
tabptr = arp_lookup(ipaddr);
if (tabptr != NULL)
{
memcpy(entry, tabptr, sizeof(struct arp_entry));
/* Yes.. return the Ethernet MAC address if the caller has provided a
* non-NULL address in 'ethaddr'.
*/
if (ethaddr != NULL)
{
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 OK;
}
@ -355,8 +398,10 @@ int arp_find(in_addr_t ipaddr, FAR struct arp_entry *entry)
* to the Ethernet MAC address assigned to the network device.
*/
entry->at_ipaddr = ipaddr;
if (netdev_foreach(arp_match, entry) != 0)
info.ai_ipaddr = ipaddr;
info.ai_ethaddr = ethaddr;
if (netdev_foreach(arp_match, &info) != 0)
{
return OK;
}
@ -382,7 +427,7 @@ int arp_find(in_addr_t ipaddr, FAR struct arp_entry *entry)
void arp_delete(in_addr_t ipaddr)
{
FAR struct arp_entry *tabptr;
FAR struct arp_entry_s *tabptr;
/* Check if the IPv4 address is in the ARP table. */

View file

@ -159,10 +159,9 @@ static inline bool ipfwd_addrchk(FAR struct forward_s *fwd)
{
#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND)
FAR struct ipv4_hdr_s *ipv4 = (FAR struct ipv4_hdr_s *)fwd->f_iob->io_data;
struct arp_entry entry;
int ret;
ret = arp_find(*(in_addr_t *)ipv4->destipaddr, &entry);
ret = arp_find(*(in_addr_t *)ipv4->destipaddr, NULL);
return (ret >= 0);
#else
return true;

View file

@ -1259,7 +1259,7 @@ static int netdev_arp_ioctl(FAR struct socket *psock, int cmd,
/* Find the existing ARP table entry for this protocol address. */
FAR struct arp_entry *entry = arp_lookup(addr->sin_addr.s_addr);
FAR struct arp_entry_s *entry = arp_lookup(addr->sin_addr.s_addr);
if (entry != NULL)
{
/* The ARP table is fixed size; an entry is deleted
@ -1287,19 +1287,18 @@ static int netdev_arp_ioctl(FAR struct socket *psock, int cmd,
{
FAR struct sockaddr_in *addr =
(FAR struct sockaddr_in *)&req->arp_pa;
struct arp_entry entry;
/* Find the existing ARP table entry for this protocol address. */
/* Get the hardware address from an existing ARP table entry
* matching this protocol address.
*/
ret = arp_find(addr->sin_addr.s_addr, &entry);
ret = arp_find(addr->sin_addr.s_addr,
(FAR struct ether_addr *)req->arp_ha.sa_data);
if (ret >= 0)
{
/* Return the mapped hardware address. */
req->arp_ha.sa_family = ARPHRD_ETHER;
memcpy(req->arp_ha.sa_data,
entry.at_ethaddr.ether_addr_octet,
ETHER_ADDR_LEN);
ret = OK;
}
}

View file

@ -309,9 +309,7 @@ static inline bool psock_send_addrchck(FAR struct tcp_conn_s *conn)
#endif
#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND)
struct arp_entry entry;
if (arp_find(conn->u.ipv4.raddr, &entry) >= 0)
if (arp_find(conn->u.ipv4.raddr, NULL) >= 0)
{
/* Return true if the address was found in the ARP table */

View file

@ -258,9 +258,7 @@ static inline bool psock_send_addrchck(FAR struct tcp_conn_s *conn)
in_addr_t router;
#endif
#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND)
struct arp_entry entry;
if (arp_find(conn->u.ipv4.raddr, &entry) >= 0)
if (arp_find(conn->u.ipv4.raddr, NULL) >= 0)
{
/* Return true if the address was found in the ARP table */

View file

@ -296,9 +296,7 @@ static inline bool sendfile_addrcheck(FAR struct tcp_conn_s *conn)
#endif
{
#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND)
struct arp_entry entry;
return (arp_find(conn->u.ipv4.raddr, &entry) >= 0);
return (arp_find(conn->u.ipv4.raddr, NULL) >= 0);
#else
return true;
#endif

View file

@ -281,9 +281,7 @@ static inline bool sendto_addrcheck(FAR struct udp_conn_s *conn,
#endif
{
#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND)
struct arp_entry entry;
return (arp_find(conn->u.ipv4.raddr, entry) >= 0);
return (arp_find(conn->u.ipv4.raddr, NULL) >= 0);
#else
return true;
#endif