From 96e4ec4a15abe1ac7c07d361cce22ab566ba1273 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Mon, 2 Jul 2007 20:41:22 +0000 Subject: [PATCH] Added option LWIP_NETIF_HWADDRHINT (default=off) to cache ARP table indices with each pcb instead of single-entry cache for the complete stack. --- CHANGELOG | 8 +++++- src/core/ipv4/ip.c | 9 ++++--- src/core/netif.c | 3 +++ src/core/raw.c | 6 +++++ src/core/tcp_out.c | 39 +++++++++++++++++++++++++++++ src/core/udp.c | 12 +++++++++ src/include/ipv4/lwip/ip.h | 4 ++- src/include/ipv6/lwip/ip.h | 4 ++- src/include/lwip/netif.h | 3 +++ src/include/lwip/opt.h | 9 +++++++ src/include/netif/etharp.h | 5 ++++ src/netif/etharp.c | 51 ++++++++++++++++++++++++++++++++++++++ 12 files changed, 146 insertions(+), 7 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index df5c37db..9b71c25b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -241,7 +241,13 @@ HISTORY ++ Bug fixes: - 2007-06-28 Simon Goldschmidt + 2007-07-02 Simon Goldschmidt + * ipv4/ip.h, ipv6/ip.h, opt.h, netif.h, etharp.h, ipv4/ip.c, netif.c, raw.c, + tcp_out.c, udp.c, etharp.c: Added option LWIP_NETIF_HWADDRHINT (default=off) + to cache ARP table indices with each pcb instead of single-entry cache for + the complete stack. + + 2007-07-02 Simon Goldschmidt * tcp.h, tcp.c, tcp_in.c, tcp_out.c: Added some ASSERTS and casts to prevent warnings when assigning to smaller types. diff --git a/src/core/ipv4/ip.c b/src/core/ipv4/ip.c index a4b7cd81..3fc59a34 100644 --- a/src/core/ipv4/ip.c +++ b/src/core/ipv4/ip.c @@ -96,6 +96,11 @@ ip_route(struct ip_addr *dest) return netif; } } + if (netif_default == NULL) { + LWIP_DEBUGF(IP_DEBUG | 2, ("ip_route: No route to 0x%"X32_F"\n", dest->addr)); + IP_STATS_INC(ip.rterr); + snmp_inc_ipoutnoroutes(); + } /* no matching netif found, use default netif */ return netif_default; } @@ -515,10 +520,6 @@ ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, struct netif *netif; if ((netif = ip_route(dest)) == NULL) { - LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: No route to 0x%"X32_F"\n", dest->addr)); - - IP_STATS_INC(ip.rterr); - snmp_inc_ipoutnoroutes(); return ERR_RTE; } diff --git a/src/core/netif.c b/src/core/netif.c index 073e99f8..9f46642c 100644 --- a/src/core/netif.c +++ b/src/core/netif.c @@ -105,6 +105,9 @@ netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask, netif->state = state; netif->num = netifnum++; netif->input = input; +#if LWIP_NETIF_HWADDRHINT + netif->addr_hint = NULL; +#endif /* LWIP_NETIF_HWADDRHINT*/ netif_set_addr(netif, ipaddr, netmask, gw); diff --git a/src/core/raw.c b/src/core/raw.c index e754123b..c61bdb47 100644 --- a/src/core/raw.c +++ b/src/core/raw.c @@ -248,7 +248,13 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr) src_ip = &(pcb->local_ip); } +#if LWIP_NETIF_HWADDRHINT + netif->addr_hint = &(pcb->addr_hint); +#endif /* LWIP_NETIF_HWADDRHINT*/ err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif); +#if LWIP_NETIF_HWADDRHINT + netif->addr_hint = NULL; +#endif /* LWIP_NETIF_HWADDRHINT*/ /* did we chain a header earlier? */ if (q != p) { diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index 0b779ceb..f0df636a 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -456,8 +456,21 @@ tcp_output(struct tcp_pcb *pcb) tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip), IP_PROTO_TCP, p->tot_len); #endif +#if LWIP_NETIF_HWADDRHINT + { + struct netif *netif; + netif = ip_route(&pcb->remote_ip); + if(netif != NULL){ + netif->addr_hint = &(pcb->addr_hint); + ip_output_if(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, + pcb->tos, IP_PROTO_TCP, netif); + netif->addr_hint = NULL; + } + } +#else /* LWIP_NETIF_HWADDRHINT*/ ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, IP_PROTO_TCP); +#endif /* LWIP_NETIF_HWADDRHINT*/ pbuf_free(p); return ERR_OK; @@ -602,8 +615,21 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) #endif TCP_STATS_INC(tcp.xmit); +#if LWIP_NETIF_HWADDRHINT + { + struct netif *netif; + netif = ip_route(&pcb->remote_ip); + if(netif != NULL){ + netif->addr_hint = &(pcb->addr_hint); + ip_output_if(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, + pcb->tos, IP_PROTO_TCP, netif); + netif->addr_hint = NULL; + } + } +#else /* LWIP_NETIF_HWADDRHINT*/ ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, IP_PROTO_TCP); +#endif /* LWIP_NETIF_HWADDRHINT*/ } /** @@ -776,7 +802,20 @@ tcp_keepalive(struct tcp_pcb *pcb) TCP_STATS_INC(tcp.xmit); /* Send output to IP */ +#if LWIP_NETIF_HWADDRHINT + { + struct netif *netif; + netif = ip_route(&pcb->remote_ip); + if(netif != NULL){ + netif->addr_hint = &(pcb->addr_hint); + ip_output_if(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, + 0, IP_PROTO_TCP, netif); + netif->addr_hint = NULL; + } + } +#else /* LWIP_NETIF_HWADDRHINT*/ ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP); +#endif /* LWIP_NETIF_HWADDRHINT*/ pbuf_free(p); diff --git a/src/core/udp.c b/src/core/udp.c index b9b3a736..391df770 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -439,7 +439,13 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p) #endif /* CHECKSUM_CHECK_UDP */ /* output to IP */ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n")); +#if LWIP_NETIF_HWADDRHINT + netif->addr_hint = &(pcb->addr_hint); +#endif /* LWIP_NETIF_HWADDRHINT*/ err = ip_output_if(q, src_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif); +#if LWIP_NETIF_HWADDRHINT + netif->addr_hint = NULL; +#endif /* LWIP_NETIF_HWADDRHINT*/ } else #endif /* LWIP_UDPLITE */ { /* UDP */ @@ -456,7 +462,13 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p) LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum)); LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n")); /* output to IP */ +#if LWIP_NETIF_HWADDRHINT + netif->addr_hint = &(pcb->addr_hint); +#endif /* LWIP_NETIF_HWADDRHINT*/ err = ip_output_if(q, src_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif); +#if LWIP_NETIF_HWADDRHINT + netif->addr_hint = NULL; +#endif /* LWIP_NETIF_HWADDRHINT*/ } /* TODO: must this be increased even if error occured? */ snmp_inc_udpoutdatagrams(); diff --git a/src/include/ipv4/lwip/ip.h b/src/include/ipv4/lwip/ip.h index 866214d3..beb482a3 100644 --- a/src/include/ipv4/lwip/ip.h +++ b/src/include/ipv4/lwip/ip.h @@ -83,7 +83,9 @@ err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, /* Type Of Service */ \ u8_t tos; \ /* Time To Live */ \ - u8_t ttl + u8_t ttl; \ + /* link layer address resolution hint */ \ + u8_t addr_hint /* * Option flags per-socket. These are the same like SO_XXX. diff --git a/src/include/ipv6/lwip/ip.h b/src/include/ipv6/lwip/ip.h index 3849781f..71845fd2 100644 --- a/src/include/ipv6/lwip/ip.h +++ b/src/include/ipv6/lwip/ip.h @@ -69,7 +69,9 @@ extern "C" { /* Type Of Service */ \ u8_t tos; \ /* Time To Live */ \ - u8_t ttl + u8_t ttl; \ + /* link layer address resolution hint */ \ + u8_t addr_hint /* The IPv6 header. */ diff --git a/src/include/lwip/netif.h b/src/include/lwip/netif.h index f3717ae6..fefe7638 100644 --- a/src/include/lwip/netif.h +++ b/src/include/lwip/netif.h @@ -155,6 +155,9 @@ struct netif { /* This function could be called to add or delete a entry in the multicast filter table of the ethernet MAC.*/ err_t (*igmp_mac_filter)( struct netif *netif, struct ip_addr *group, u8_t action); #endif /* LWIP_IGMP */ +#if LWIP_NETIF_HWADDRHINT + u8_t *addr_hint; +#endif /* LWIP_NETIF_HWADDRHINT */ }; #if LWIP_SNMP diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index fe8bbabe..aeb42663 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -481,6 +481,15 @@ #define LWIP_NETIF_CALLBACK 0 #endif +/** Cache link-layer-address hints (e.g. table indices) in struct netif. + TCP and UDP can make use of this to prevent scanning the ARP table + for every sent packet. While this is faster for big ARP tables or many + concurrent connections, it might be contra-productive if having a tiny + ARP table only or there never are concurrent connections. */ +#ifndef LWIP_NETIF_HWADDRHINT +#define LWIP_NETIF_HWADDRHINT 0 +#endif + /* Support loop interface (127.0.0.1) */ #ifndef LWIP_HAVE_LOOPIF #define LWIP_HAVE_LOOPIF 0 diff --git a/src/include/netif/etharp.h b/src/include/netif/etharp.h index 481471a9..9fa422d7 100644 --- a/src/include/netif/etharp.h +++ b/src/include/netif/etharp.h @@ -157,6 +157,11 @@ err_t etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, #define eth_addr_cmp(addr1, addr2) (memcmp((addr1)->addr, (addr2)->addr, ETHARP_HWADDR_LEN) == 0) +/* finally, check some defines */ +#if ARP_TABLE_SIZE > 0x7f +#error ARP_TABLE_SIZE must fit in an s8_t +#endif + #ifdef __cplusplus } #endif diff --git a/src/netif/etharp.c b/src/netif/etharp.c index ed1351de..191a6caf 100644 --- a/src/netif/etharp.c +++ b/src/netif/etharp.c @@ -105,7 +105,9 @@ struct etharp_entry { static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; static const struct eth_addr ethzero = {{0,0,0,0,0,0}}; static struct etharp_entry arp_table[ARP_TABLE_SIZE]; +#if !LWIP_NETIF_HWADDRHINT static u8_t etharp_cached_entry = 0; +#endif /** * Try hard to create a new entry - we want the IP address to appear in @@ -113,7 +115,14 @@ static u8_t etharp_cached_entry = 0; #define ETHARP_TRY_HARD 1 #define ETHARP_FIND_ONLY 2 +#if LWIP_NETIF_HWADDRHINT +#define NETIF_SET_HINT(netif, hint) (((netif) != NULL) && ((netif)->addr_hint != NULL)) ? \ + *((netif)->addr_hint) = (hint) : LWIP_UNUSED_ARG(hint) ; +static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags, struct netif *netif); +#else /* LWIP_NETIF_HWADDRHINT */ static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags); +#endif /* LWIP_NETIF_HWADDRHINT */ + static err_t update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags); /** @@ -231,7 +240,11 @@ etharp_tmr(void) * entry is found or could be recycled. */ static s8_t +#if LWIP_NETIF_HWADDRHINT +find_entry(struct ip_addr *ipaddr, u8_t flags, struct netif *netif) +#else /* LWIP_NETIF_HWADDRHINT */ find_entry(struct ip_addr *ipaddr, u8_t flags) +#endif /* LWIP_NETIF_HWADDRHINT */ { s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE; s8_t empty = ARP_TABLE_SIZE; @@ -247,6 +260,19 @@ find_entry(struct ip_addr *ipaddr, u8_t flags) * same address. If so, we're really fast! */ if (ipaddr) { /* ipaddr to search for was given */ +#if LWIP_NETIF_HWADDRHINT + if ((netif != NULL) && (netif->addr_hint != NULL)) { + /* per-pcb cached entry was given */ + u8_t per_pcb_cache = *(netif->addr_hint); + if ((per_pcb_cache < ARP_TABLE_SIZE) && arp_table[per_pcb_cache].state == ETHARP_STATE_STABLE) { + /* the per-pcb-cached entry is stable */ + if (ip_addr_cmp(ipaddr, &arp_table[per_pcb_cache].ipaddr)) { + /* per-pcb cached entry was the right one! */ + return per_pcb_cache; + } + } + } +#else /* #if LWIP_NETIF_HWADDRHINT */ if (arp_table[etharp_cached_entry].state == ETHARP_STATE_STABLE) { /* the cached entry is stable */ if (ip_addr_cmp(ipaddr, &arp_table[etharp_cached_entry].ipaddr)) { @@ -254,6 +280,7 @@ find_entry(struct ip_addr *ipaddr, u8_t flags) return etharp_cached_entry; } } +#endif /* #if LWIP_NETIF_HWADDRHINT */ } /** @@ -284,7 +311,11 @@ find_entry(struct ip_addr *ipaddr, u8_t flags) if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching pending entry %"U16_F"\n", (u16_t)i)); /* found exact IP address match, simply bail out */ +#if LWIP_NETIF_HWADDRHINT + NETIF_SET_HINT(netif, i); +#else /* #if LWIP_NETIF_HWADDRHINT */ etharp_cached_entry = i; +#endif /* #if LWIP_NETIF_HWADDRHINT */ return i; #if ARP_QUEUEING /* pending with queued packets? */ @@ -308,7 +339,11 @@ find_entry(struct ip_addr *ipaddr, u8_t flags) if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching stable entry %"U16_F"\n", (u16_t)i)); /* found exact IP address match, simply bail out */ +#if LWIP_NETIF_HWADDRHINT + NETIF_SET_HINT(netif, i); +#else /* #if LWIP_NETIF_HWADDRHINT */ etharp_cached_entry = i; +#endif /* #if LWIP_NETIF_HWADDRHINT */ return i; /* remember entry with oldest stable entry in oldest, its age in maxtime */ } else if (arp_table[i].ctime >= age_stable) { @@ -384,7 +419,11 @@ find_entry(struct ip_addr *ipaddr, u8_t flags) ip_addr_set(&arp_table[i].ipaddr, ipaddr); } arp_table[i].ctime = 0; +#if LWIP_NETIF_HWADDRHINT + NETIF_SET_HINT(netif, i); +#else /* #if LWIP_NETIF_HWADDRHINT */ etharp_cached_entry = i; +#endif /* #if LWIP_NETIF_HWADDRHINT */ return (err_t)i; } @@ -456,7 +495,11 @@ update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *e return ERR_ARG; } /* find or create ARP entry */ +#if LWIP_NETIF_HWADDRHINT + i = find_entry(ipaddr, flags, netif); +#else /* LWIP_NETIF_HWADDRHINT */ i = find_entry(ipaddr, flags); +#endif /* LWIP_NETIF_HWADDRHINT */ /* bail out if no entry could be found */ if (i < 0) return (err_t)i; @@ -516,7 +559,11 @@ etharp_find_addr(struct netif *netif, struct ip_addr *ipaddr, { s8_t i; +#if LWIP_NETIF_HWADDRHINT + i = find_entry(ipaddr, ETHARP_FIND_ONLY, NULL); +#else /* LWIP_NETIF_HWADDRHINT */ i = find_entry(ipaddr, ETHARP_FIND_ONLY); +#endif /* LWIP_NETIF_HWADDRHINT */ if((i >= 0) && arp_table[i].state == ETHARP_STATE_STABLE) { *eth_ret = &arp_table[i].ethaddr; *ip_ret = &arp_table[i].ipaddr; @@ -833,7 +880,11 @@ etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q) } /* find entry in ARP cache, ask to create entry if queueing packet */ +#if LWIP_NETIF_HWADDRHINT + i = find_entry(ipaddr, ETHARP_TRY_HARD, netif); +#else /* LWIP_NETIF_HWADDRHINT */ i = find_entry(ipaddr, ETHARP_TRY_HARD); +#endif /* LWIP_NETIF_HWADDRHINT */ /* could not find or create entry? */ if (i < 0) {