ARP: add more memory efficient way of handling arp requests

This commit is contained in:
kamendov-maxim 2024-07-31 13:31:11 +03:00
parent 73fcf72792
commit ca7e9a8123
4 changed files with 102 additions and 2 deletions

View File

@ -626,6 +626,8 @@ etharp_get_entry(size_t i, ip4_addr_t **ipaddr, struct netif **netif, struct eth
}
}
#define Swap(X,Y) do{ __typeof__ (X) _T = X; X = Y; Y = _T; }while(0)
/**
* Responds to ARP requests to us. Upon ARP replies to us, add entry to cache
* send out queued IP packets. Updates cache with snooped address pairs.
@ -635,11 +637,17 @@ etharp_get_entry(size_t i, ip4_addr_t **ipaddr, struct netif **netif, struct eth
*
* @param p The ARP packet that arrived on netif. Is freed by this function.
* @param netif The lwIP network interface on which the ARP packet pbuf arrived.
* @param header_size_document pass ethernet header size to handle both arp and ethernet headers
* here for more effective memory usage (see LWIP_ARP_REUSE_MEMORY description in opts.h)
*
* @see pbuf_free()
*/
void
etharp_input(struct pbuf *p, struct netif *netif)
etharp_input(struct pbuf *p, struct netif *netif
#if LWIP_ARP_REUSE_MEMORY
, size_t header_size_decrement
#endif /* LWIP_ARP_REUSE_MEMORY */
)
{
struct etharp_hdr *hdr;
/* these are aligned properly, whereas the ARP header fields might not be */
@ -650,7 +658,11 @@ etharp_input(struct pbuf *p, struct netif *netif)
LWIP_ERROR("netif != NULL", (netif != NULL), return;);
#if LWIP_ARP_REUSE_MEMORY
hdr = (struct etharp_hdr *)((u8_t *)p->payload + header_size_decrement);
#else
hdr = (struct etharp_hdr *)p->payload;
#endif /* LWIP_ARP_REUSE_MEMORY */
/* RFC 826 "Packet Reception": */
if ((hdr->hwtype != PP_HTONS(LWIP_IANA_HWTYPE_ETHERNET)) ||
@ -714,11 +726,81 @@ etharp_input(struct pbuf *p, struct netif *netif)
/* ARP request for our address? */
if (for_us && !from_us) {
/* send ARP response */
#if !LWIP_ARP_REUSE_MEMORY
etharp_raw(netif,
(struct eth_addr *)netif->hwaddr, &hdr->shwaddr,
(struct eth_addr *)netif->hwaddr, netif_ip4_addr(netif),
&hdr->shwaddr, &sipaddr,
ARP_REPLY);
#else
struct eth_hdr *ethhdr;
u16_t eth_type_be;
hdr->opcode = lwip_htons(ARP_REPLY);
Swap(hdr->shwaddr, hdr->dhwaddr);
Swap(hdr->sipaddr, hdr->dipaddr);
SMEMCPY(&hdr->shwaddr, (struct eth_addr *)netif->hwaddr, ETH_HWADDR_LEN);
ethhdr = (struct eth_hdr *)p->payload;
eth_type_be = lwip_htons(ETHTYPE_ARP);
#if ETHARP_SUPPORT_VLAN && (defined(LWIP_HOOK_VLAN_SET) || LWIP_VLAN_PCP)
s32_t vlan_prio_vid;
#ifdef LWIP_HOOK_VLAN_SET
vlan_prio_vid = LWIP_HOOK_VLAN_SET(netif, p, ethhdr->src, ethhdr->dest, ETHTYPE_ARP);
#elif LWIP_VLAN_PCP
vlan_prio_vid = -1;
if (netif->hints && (netif->hints->tci >= 0)) {
vlan_prio_vid = (u16_t)netif->hints->tci;
}
#endif
if (vlan_prio_vid >= 0) {
struct eth_vlan_hdr *vlanhdr;
LWIP_ASSERT("prio_vid must be <= 0xFFFF", vlan_prio_vid <= 0xFFFF);
vlanhdr = (struct eth_vlan_hdr *)(((u8_t *)p->payload) + SIZEOF_ETH_HDR);
vlanhdr->tpid = eth_type_be;
vlanhdr->prio_vid = lwip_htons((u16_t)vlan_prio_vid);
eth_type_be = PP_HTONS(ETHTYPE_VLAN);
}
#endif /* ETHARP_SUPPORT_VLAN && (defined(LWIP_HOOK_VLAN_SET) || LWIP_VLAN_PCP) */
LWIP_ASSERT_CORE_LOCKED();
ethhdr = (struct eth_hdr *)p->payload;
ethhdr->type = eth_type_be;
Swap(ethhdr->dest, ethhdr->src);
#if LWIP_AUTOIP
/* If we are using Link-Local, all ARP packets that contain a Link-Local
* 'sender IP address' MUST be sent using link-layer broadcast instead of
* link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */
if (ip4_addr_islinklocal(netif_ip4_addr(netif))) {
SMEMCPY(&ethhdr->src, &ethbroadcast, ETH_HWADDR_LEN);
} else
#endif /* LWIP_AUTOIP */
{
SMEMCPY(&ethhdr->src, &hdr->shwaddr, ETH_HWADDR_LEN);
}
LWIP_ASSERT("netif->hwaddr_len must be 6 for ethernet_output!",
(netif->hwaddr_len == ETH_HWADDR_LEN));
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
("ethernet_output: sending packet %p\n", (void *)p));
netif->linkoutput(netif, p);
ETHARP_STATS_INC(etharp.xmit);
#endif /* !LWIP_ARP_REUSE_MEMORY */
/* we are not configured? */
} else if (ip4_addr_isany_val(*netif_ip4_addr(netif))) {
/* { for_us == 0 and netif->ip_addr.addr == 0 } */

View File

@ -98,7 +98,11 @@ err_t etharp_add_static_entry(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr
err_t etharp_remove_static_entry(const ip4_addr_t *ipaddr);
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
void etharp_input(struct pbuf *p, struct netif *netif);
void etharp_input(struct pbuf *p, struct netif *netif
#if LWIP_ARP_REUSE_MEMORY
, size_t header_size_decrement
#endif
);
#ifdef __cplusplus
}

View File

@ -731,6 +731,16 @@
#if !defined ETHARP_TABLE_MATCH_NETIF || defined __DOXYGEN__
#define ETHARP_TABLE_MATCH_NETIF !LWIP_SINGLE_NETIF
#endif
/** LWIP_ARP_REUSE_MEMORY==1: Reuse pbuf used for arp request to send an
* arp reply as described in RFC 826.
* If disabled, new pbuf will be allocated and all required data from request
* packet will be copied with SMEMCPY (better if you want to separate layers
* but worse in terms of memory usage)
*/
#if !defined LWIP_ARP_REUSE_MEMORY || defined __DOXYGEN__
#define LWIP_ARP_REUSE_MEMORY 1
#endif
/**
* @}
*/

View File

@ -192,6 +192,7 @@ ethernet_input(struct pbuf *p, struct netif *netif)
goto free_and_return;
}
/* skip Ethernet header (min. size checked above) */
#if !LWIP_ARP_REUSE_MEMORY
if (pbuf_remove_header(p, next_hdr_offset)) {
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
("ethernet_input: ARP response packet dropped, too short (%"U16_F"/%"U16_F")\n",
@ -204,6 +205,9 @@ ethernet_input(struct pbuf *p, struct netif *netif)
/* pass p to ARP module */
etharp_input(p, netif);
}
#else
etharp_input(p, netif, next_hdr_offset);
#endif /* !LWIP_ARP_REUSE_MEMORY */
break;
#endif /* LWIP_IPV4 && LWIP_ARP */
#if PPPOE_SUPPORT