diff --git a/net/route/Kconfig b/net/route/Kconfig index c927561ba5f..21026f61ce9 100644 --- a/net/route/Kconfig +++ b/net/route/Kconfig @@ -65,6 +65,24 @@ config ROUTE_MAX_IPv4_RAMROUTES eliminates dynamica memory allocations, but limits the maximum size of the in-memory routing table to this number. +config ROUTE_IPv4_CACHEROUTE + bool "In-memory IPv4 cache" + default n + depends on ROUTE_IPv4_FILEROUTE + ---help--- + Accessing a routing table on a file system before each packet is sent + can harm performance. This option will cache a few of the most + frequently used routing table entries in memory to reduce performance + issues. + +config ROUTE_MAX_IPv4_CACHEROUTES + int "IPv4 cache size" + default 4 + depends on ROUTE_IPv4_CACHEROUTE + ---help--- + This determines the maxium number of routes that can be cached in + memory. + choice prompt "IPv6 routing table" default ROUTE_IPv6_RAMROUTE @@ -125,5 +143,23 @@ config ROUTE_FILEDIR table will be accessed. This is a string and should not include any traling '/'. +config ROUTE_IPv6_CACHEROUTE + bool "In-memory IPv6 cache" + default n + depends on ROUTE_IPv6_FILEROUTE + ---help--- + Accessing a routing table on a file system before each packet is sent + can harm performance. This option will cache a few of the most + frequently used routing table entries in memory to reduce performance + issues. + +config ROUTE_MAX_IPv6_CACHEROUTES + int "IPv6 cache size" + default 4 + depends on ROUTE_IPv6_CACHEROUTE + ---help--- + This determines the maxium number of routes that can be cached in + memory. + endif # NET_ROUTE endmenu # ARP Configuration diff --git a/net/route/Make.defs b/net/route/Make.defs index 5785be6a9c0..ccad438dac4 100644 --- a/net/route/Make.defs +++ b/net/route/Make.defs @@ -67,6 +67,14 @@ SOCK_CSRCS += net_fileroute.c net_add_fileroute.c net_del_fileroute.c SOCK_CSRCS += net_foreach_fileroute.c endif +# In-memory cache for file-based routing tables + +ifeq ($(CONFIG_ROUTE_IPv4_CACHEROUTE),y) +SOCK_CSRCS += net_cacheroute.c +else ifeq ($(CONFIG_ROUTE_IPv6_CACHEROUTE),y) +SOCK_CSRCS += net_cacheroute.c +endif + ifeq ($(CONFIG_DEBUG_NET_INFO),y) SOCK_CSRCS += net_dumproute.c endif diff --git a/net/route/cacheroute.h b/net/route/cacheroute.h new file mode 100644 index 00000000000..f4ed8c7577d --- /dev/null +++ b/net/route/cacheroute.h @@ -0,0 +1,143 @@ +/**************************************************************************** + * net/route/cacheroute.h + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __NET_ROUTE_CACHEROUTE_H +#define __NET_ROUTE_CACHEROUTE_H 1 + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "route/route.h" + +#if defined(CONFIG_ROUTE_IPv4_CACHEROUTE) || defined(CONFIG_ROUTE_IPv6_CACHEROUTE) + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: net_init_cacheroute + * + * Description: + * Initialize the in-memory, routing table cache + * + * Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions: + * Called early in initialization so that no special protection is needed. + * + ****************************************************************************/ + +void net_init_cacheroute(void); + +/**************************************************************************** + * Name: net_addcache_ipv4 and net_addcache_ipv6 + * + * Description: + * Add one route to the routing table cache + * + * Parameters: + * None + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_ROUTE_IPv4_CACHEROUTE +int net_addcache_ipv4(FAR struct net_route_ipv4_s *route); +#endif + +#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE +int net_addcache_ipv6(FAR struct net_route_ipv6_s *route); +#endif + +/**************************************************************************** + * Name: net_foreachcache_ipv4/net_foreachcache_ipv6 + * + * Description: + * Traverse the routing table cahce + * + * Parameters: + * handler - Will be called for each route in the routing table cache. + * arg - An arbitrary value that will be passed tot he handler. + * + * Returned Value: + * Zero (OK) returned if the entire table was searched. A negated errno + * value will be returned in the event of a failure. Handlers may also + * terminate the search early with any non-zero value. + * + ****************************************************************************/ + +#ifdef CONFIG_ROUTE_IPv4_CACHEROUTE +int net_foreachcache_ipv4(route_handler_ipv4_t handler, FAR void *arg); +#endif + +#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE +int net_foreachcache_ipv6(route_handler_ipv6_t handler, FAR void *arg); +#endif + +/**************************************************************************** + * Name: net_flushcache_ipv4 and net_flushcache_ipv6 + * + * Description: + * Flush the content of the routing table cache + * + * Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_ROUTE_IPv4_CACHEROUTE +void net_flushcache_ipv4(void); +#endif + +#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE +void net_flushcache_ipv6(void); +#endif + +#endif /* CONFIG_ROUTE_IPv4_CACHEROUTE || CONFIG_ROUTE_IPv6_CACHEROUTE */ +#endif /* __NET_ROUTE_CACHEROUTE_H */ diff --git a/net/route/net_alloc_ramroute.c b/net/route/net_alloc_ramroute.c index 5883a97484b..a5e88768830 100644 --- a/net/route/net_alloc_ramroute.c +++ b/net/route/net_alloc_ramroute.c @@ -124,7 +124,7 @@ void net_init_ramroute(void) ramroute_init(&g_ipv4_routes); ramroute_init(&g_free_ipv4routes); - /* All all of the pre-allocated routing table entries to a free list */ + /* Add all of the pre-allocated routing table entries to a free list */ for (i = 0; i < CONFIG_ROUTE_MAX_IPv4_RAMROUTES; i++) { @@ -136,7 +136,7 @@ void net_init_ramroute(void) ramroute_init(&g_ipv6_routes); ramroute_init(&g_free_ipv6routes); - /* All all of the pre-allocated routing table entries to a free list */ + /* Add all of the pre-allocated routing table entries to a free list */ for (i = 0; i < CONFIG_ROUTE_MAX_IPv6_RAMROUTES; i++) { diff --git a/net/route/net_cacheroute.c b/net/route/net_cacheroute.c new file mode 100644 index 00000000000..7bff9487729 --- /dev/null +++ b/net/route/net_cacheroute.c @@ -0,0 +1,758 @@ +/**************************************************************************** + * net/route/net_cacheroute.c + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include "route/cacheroute.h" +#include "route/route.h" + +#if defined(CONFIG_ROUTE_IPv4_CACHEROUTE) || defined(CONFIG_ROUTE_IPv6_CACHEROUTE) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#ifndef CONFIG_ROUTE_MAX_IPv4_CACHEROUTES +# define CONFIG_ROUTE_MAX_IPv4_CACHEROUTES 4 +#endif + +#ifndef CONFIG_ROUTE_MAX_IPv6_CACHEROUTES +# define CONFIG_ROUTE_MAX_IPv6_CACHEROUTES 4 +#endif + +/* Routing table initializer */ + +#define cacheroute_init(rr) \ + do \ + { \ + (rr)->head = NULL; \ + (rr)->tail = NULL; \ + } \ + while (0) \ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifdef CONFIG_ROUTE_IPv4_CACHEROUTE +/* This structure describes one entry in the routing table cache */ + +struct net_cache_ipv4_entry_s +{ + struct net_route_ipv4_s entry; + FAR struct net_cache_ipv4_entry_s *flink; +}; + +/* This structure describes the head of a routing table cache list */ + +struct net_cache_ipv4_queue_s +{ + FAR struct net_cache_ipv4_entry_s *head; + FAR struct net_cache_ipv4_entry_s *tail; +}; +#endif + +#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE +/* This structure describes one entry in the routing table cache */ + +struct net_cache_ipv6_entry_s +{ + struct net_route_ipv6_s entry; + FAR struct net_cache_ipv6_entry_s *flink; +}; + +/* This structure describes the head of a routing table cache list */ + +struct net_cache_ipv6_queue_s +{ + FAR struct net_cache_ipv6_entry_s *head; + FAR struct net_cache_ipv6_entry_s *tail; +}; +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* These are the routing tables */ + +#if defined(CONFIG_ROUTE_IPv4_CACHEROUTE) +/* The in-memory cache as a singly linked list. */ + +static struct net_cache_ipv4_queue_s g_ipv4_cache; + +/* List of free routing table cache entries */ + +static struct net_cache_ipv4_queue_s g_free_ipv4cache; + +/* Pre-allocated routing table cache entries */ + +static struct net_cache_ipv4_entry_s + g_prealloc_ipv4cache[CONFIG_ROUTE_MAX_IPv4_CACHEROUTES]; + +/* Serializes access to the routing table cache */ + +static sem_t g_ipv4_cachelock; +#endif + +#if defined(CONFIG_ROUTE_IPv6_CACHEROUTE) +/* The in-memory routing tables are represented as singly linked lists. */ + +static struct net_cache_ipv6_queue_s g_ipv6_cache; + +/* List of free routing table cache entries */ + +static struct net_cache_ipv6_queue_s g_free_ipv6cache; + +/* Pre-allocated routing table cache entries */ + +static struct net_cache_ipv6_entry_s + g_prealloc_ipv6cache[CONFIG_ROUTE_MAX_IPv6_CACHEROUTES]; + +/* Serializes access to the routing table cache */ + +static sem_t g_ipv6_cachelock; +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: net_lock_ipv4_cache and net_lock_ipv6_cache + * + * Description: + * Lock the routing table cache list. + * + * Parameters: + * None + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_ROUTE_IPv4_CACHEROUTE +static int net_lock_ipv4_cache(void) +{ + int ret = sem_wait(&g_ipv4_cachelock); + if (ret < 0) + { + ret = -get_errno(); + } + + return ret; +} +#endif + +#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE +static int net_lock_ipv6_cache(void) +{ + int ret = sem_wait(&g_ipv6_cachelock); + if (ret < 0) + { + ret = -get_errno(); + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: net_unlock_ipv4_cache and net_unlock_ipv6_cache + * + * Description: + * Unlock the routing table cache list. + * + * Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#define net_unlock_ipv4_cache() (void)sem_post(&g_ipv4_cachelock) +#define net_unlock_ipv6_cache() (void)sem_post(&g_ipv6_cachelock) + +/**************************************************************************** + * Name: net_add_newest_ipv4 and net_add_newest_ipv6 + * + * Description: + * Add a new entry to the routing table cache list. The list is ordered + * by "new-ness" so this would be the entry at the head of the list. + * + * Parameters: + * cache - The cache entry to add to the head of the routing table cache + * list. + * + * Returned Value: + * None + * + * Assumptions: + * Caller has the routing table cache locked. + * + ****************************************************************************/ + +#ifdef CONFIG_ROUTE_IPv4_CACHEROUTE +static void net_add_newest_ipv4(FAR struct net_cache_ipv4_entry_s *cache) +{ + cache->flink = g_ipv4_cache.head; + if (!g_ipv4_cache.head) + { + g_ipv4_cache.tail = cache; + } + + g_ipv4_cache.head = cache; +} +#endif + +#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE +static void net_add_newest_ipv6(FAR struct net_cache_ipv6_entry_s *cache) +{ + cache->flink = g_ipv6_cache.head; + if (!g_ipv6_cache.head) + { + g_ipv6_cache.tail = cache; + } + + g_ipv6_cache.head = cache; +} +#endif + +/**************************************************************************** + * Name: net_remove_oldest_ipv4 and net_remove_oldest_ipv6 + * + * Description: + * Remove the oldest entry from the routing table cache list. The list is + * ordered + * + * Parameters: + * None + * + * Returned Value: + * On success, a pointer to the oldest routing table cache entry is + * returned. NULL would be returned if the routing table cache is empty. + * + * Assumptions: + * Caller has the routing table cache locked. + * + ****************************************************************************/ + +#ifdef CONFIG_ROUTE_IPv4_CACHEROUTE +FAR struct net_cache_ipv4_entry_s *net_remove_oldest_ipv4(void) +{ + FAR struct net_cache_ipv4_entry_s *cache; + FAR struct net_cache_ipv4_entry_s *prev; + + cache = g_ipv4_cache.tail; + if (cache != NULL) + { + if (g_ipv4_cache.head == g_ipv4_cache.tail) + { + g_ipv4_cache.head = NULL; + g_ipv4_cache.tail = NULL; + } + else + { + for (prev = g_ipv4_cache.head; + prev != NULL && prev->flink != cache; + prev = prev->flink); + + if (prev != NULL) + { + prev->flink = NULL; + g_ipv4_cache.tail = prev; + } + } + + cache->flink = NULL; + } + + return cache; +} +#endif + +#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE +FAR struct net_cache_ipv6_entry_s *net_remove_oldest_ipv6(void) +{ + FAR struct net_cache_ipv6_entry_s *cache; + FAR struct net_cache_ipv6_entry_s *prev; + + cache = g_ipv6_cache.tail; + if (cache != NULL) + { + if (g_ipv6_cache.head == g_ipv6_cache.tail) + { + g_ipv6_cache.head = NULL; + g_ipv6_cache.tail = NULL; + } + else + { + for (prev = g_ipv6_cache.head; + prev != NULL && prev->flink != cache; + prev = prev->flink); + + if (prev != NULL) + { + prev->flink = NULL; + g_ipv6_cache.tail = prev; + } + } + + cache->flink = NULL; + } + + return cache; +} +#endif + +/**************************************************************************** + * Name: net_alloccache_ipv4 and net_alloccache_ipv6 + * + * Description: + * Allocate one routing table cache entry by removing it from the free + * list. If the free list is empty, then remove the entry at the tail + * of the current routing table cache. + * + * Parameters: + * None + * + * Returned Value: + * On success, a pointer to the newly allocated routing table cache entry + * is returned. Should never fail + * + * Assumptions: + * Caller has the routing table cache locked. + * + ****************************************************************************/ + +#ifdef CONFIG_ROUTE_IPv4_CACHEROUTE +FAR struct net_cache_ipv4_entry_s *net_alloccache_ipv4(void) +{ + FAR struct net_cache_ipv4_entry_s *cache; + + /* Remove the first entry from the free list */ + + cache = g_free_ipv4cache.head; + if (cache != NULL) + { + g_free_ipv4cache.head = cache->flink; + if (g_free_ipv4cache.head == NULL) + { + g_free_ipv4cache.tail = NULL; + } + + cache->flink = NULL; + } + + /* If the free list is empty, then remove the oldest entry at the tail of + * the routing table cache. + */ + + else + { + /* If the free list is empty, then the cache list cannot be empty */ + + cache = net_remove_oldest_ipv4(); + DEBUGASSERT(cache != NULL); + } + + return cache; +} +#endif + +#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE +FAR struct net_cache_ipv6_entry_s *net_alloccache_ipv6(void) +{ + FAR struct net_cache_ipv6_entry_s *cache; + + /* Remove the first entry from the free list */ + + cache = g_free_ipv6cache.head; + if (cache != NULL) + { + g_free_ipv6cache.head = cache->flink; + if (g_free_ipv6cache.head == NULL) + { + g_free_ipv6cache.tail = NULL; + } + + cache->flink = NULL; + } + + /* If the free list is empty, then remove the oldest entry at the tail of + * the routing table cache. + */ + + else + { + /* If the free list is empty, then the cache list cannot be empty */ + + cache = net_remove_oldest_ipv6(); + DEBUGASSERT(cache != NULL); + } + + return cache; +} +#endif + +/**************************************************************************** + * Name: net_reset_ipv4_cache and net_reset_ipv6_cache + * + * Description: + * Clear the routing table cache and return the entries to the free list. + * + * Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_ROUTE_IPv4_CACHEROUTE +static void net_reset_ipv4_cache(void) +{ + int i; + + cacheroute_init(&g_ipv4_cache); + cacheroute_init(&g_free_ipv4cache); + + /* Add all of the pre-allocated routing table cache entries to a free list */ + + for (i = 0; i < CONFIG_ROUTE_MAX_IPv4_CACHEROUTES; i++) + { + net_add_newest_ipv4(&g_prealloc_ipv4cache[i]); + } +} +#endif + +#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE +static void net_reset_ipv6_cache(void) +{ + int i; + + cacheroute_init(&g_ipv6_cache); + cacheroute_init(&g_free_ipv6cache); + + /* Add all of the pre-allocated routing table entries to a free list */ + + for (i = 0; i < CONFIG_ROUTE_MAX_IPv6_CACHEROUTES; i++) + { + net_add_newest_ipv6(&g_prealloc_ipv6cache[i]); + } + +} +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: net_init_cacheroute + * + * Description: + * Initialize the in-memory, routing table cache + * + * Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions: + * Called early in initialization so that no special protection is needed. + * + ****************************************************************************/ + +void net_init_cacheroute(void) +{ + /* Initialize the routing table cash and the free list */ + +#ifdef CONFIG_ROUTE_IPv4_CACHEROUTE + sem_init(&g_ipv4_cachelock, 0, 1); + net_reset_ipv4_cache(); +#endif + +#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE + sem_init(&g_ipv6_cachelock, 0, 1); + net_reset_ipv6_cache(); +#endif +} + +/**************************************************************************** + * Name: net_addcache_ipv4 and net_addcache_ipv6 + * + * Description: + * Add one route to the routing table cache + * + * Parameters: + * None + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_ROUTE_IPv4_CACHEROUTE +int net_addcache_ipv4(FAR struct net_route_ipv4_s *route) +{ + FAR struct net_cache_ipv4_entry_s *cache; + int ret; + + DEBUGASSERT(route != NULL); + + /* Get exclusive access to the cache */ + + ret = net_lock_ipv4_cache(); + if (ret < 0) + { + return ret; + } + + /* Allocate a new cache entry (should never fail) */ + + cache = net_alloccache_ipv4(); + DEBUGASSERT(cache != NULL); + + /* Copy the routing table entry into the allocated cache entry */ + + memcpy(&cache->entry, route, sizeof(struct net_route_ipv4_s)); + + /* Then add the new cache entry as the newest entry in the table */ + + net_add_newest_ipv4(cache); + net_unlock_ipv4_cache(); + return OK; +} +#endif + +#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE +int net_addcache_ipv6(FAR struct net_route_ipv6_s *route) +{ + FAR struct net_cache_ipv6_entry_s *cache; + int ret; + + DEBUGASSERT(route != NULL); + + /* Get exclusive access to the cache */ + + ret = net_lock_ipv6_cache(); + if (ret < 0) + { + return ret; + } + + /* Allocate a new cache entry (should never fail) */ + + cache = net_alloccache_ipv6(); + DEBUGASSERT(cache != NULL); + + /* Copy the routing table entry into the allocated cache entry */ + + memcpy(&cache->entry, route, sizeof(struct net_route_ipv6_s)); + + /* Then add the new cache entry as the newest entry in the table */ + + net_add_newest_ipv6(cache); + net_unlock_ipv6_cache(); + return OK; +} +#endif + +/**************************************************************************** + * Name: net_foreachcache_ipv4/net_foreachcache_ipv6 + * + * Description: + * Traverse the routing table cahce + * + * Parameters: + * handler - Will be called for each route in the routing table cache. + * arg - An arbitrary value that will be passed tot he handler. + * + * Returned Value: + * Zero (OK) returned if the entire table was searched. A negated errno + * value will be returned in the event of a failure. Handlers may also + * terminate the search early with any non-zero value. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv4 +int net_foreachcache_ipv4(route_handler_ipv4_t handler, FAR void *arg) +{ + FAR struct net_cache_ipv4_entry_s *cache; + FAR struct net_cache_ipv4_entry_s *next; + int ret = 0; + + /* Get exclusive access to the cache */ + + ret = net_lock_ipv4_cache(); + if (ret < 0) + { + return ret; + } + + /* Visit each entry in the routing table */ + + for (cache = g_ipv4_cache.head; ret == 0 && cache != NULL; cache = next) + { + /* Get the next entry in the to visit. We do this BEFORE calling the + * handler because the hanlder may delete this entry. + */ + + next = cache->flink; + ret = handler(&cache->entry, arg); + } + + /* Unlock the cache */ + + net_unlock_ipv4_cache(); + return ret; +} +#endif + +#ifdef CONFIG_NET_IPv6 +int net_foreachcache_ipv6(route_handler_ipv6_t handler, FAR void *arg) +{ + FAR struct net_cache_ipv6_entry_s *cache; + FAR struct net_cache_ipv6_entry_s *next; + int ret = 0; + + /* Get exclusive access to the cache */ + + ret = net_lock_ipv6_cache(); + if (ret < 0) + { + return ret; + } + + /* Visit each entry in the routing table */ + + for (cache = g_ipv6_cache.head; ret == 0 && cache != NULL; cache = next) + { + /* Get the next entry in the to visit. We do this BEFORE calling the + * handler because the hanlder may delete this entry. + */ + + next = cache->flink; + ret = handler(&cache->entry, arg); + } + + /* Unlock the cache */ + + net_unlock_ipv6_cache(); + return ret; +} +#endif + +/**************************************************************************** + * Name: net_flushcache_ipv4 and net_flushcache_ipv6 + * + * Description: + * Flush the content of the routing table cache + * + * Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_ROUTE_IPv4_CACHEROUTE +void net_flushcache_ipv4(void) +{ + int ret; + + /* Get exclusive access to the cache */ + + do + { + ret = net_lock_ipv4_cache(); + } + while (ret == -EINTR); + DEBUGASSERT(ret == OK); + + /* Reset the cache */ + + net_reset_ipv4_cache(); + + /* Unlock the cache */ + + net_unlock_ipv4_cache(); +} +#endif + +#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE +void net_flushcache_ipv6(void) +{ + int ret; + + /* Get exclusive access to the cache */ + + do + { + ret = net_lock_ipv6_cache(); + } + while (ret == -EINTR); + DEBUGASSERT(ret == OK); + + /* Reset the cache */ + + net_reset_ipv6_cache(); + + /* Unlock the cache */ + + net_unlock_ipv6_cache(); +} +#endif + +#endif /* CONFIG_ROUTE_IPv4_CACHEROUTE || CONFIG_ROUTE_IPv6_CACHEROUTE */ diff --git a/net/route/net_del_fileroute.c b/net/route/net_del_fileroute.c index 056506d41e9..6f57033762a 100644 --- a/net/route/net_del_fileroute.c +++ b/net/route/net_del_fileroute.c @@ -51,6 +51,7 @@ #include #include "route/fileroute.h" +#include "route/cacheroute.h" #include "route/route.h" #if defined(CONFIG_ROUTE_IPv4_FILEROUTE) || defined(CONFIG_ROUTE_IPv6_FILEROUTE) @@ -276,6 +277,14 @@ int net_delroute_ipv4(in_addr_t target, in_addr_t netmask) goto errout_with_lock; } +#ifdef CONFIG_ROUTE_IPv4_CACHEROUTE + /* We are committed to modifying the routing table. Flush the in-memory + * routing table cache. + */ + + net_flushcache_ipv4(); +#endif + /* Loop, copying each entry, to the previous entry thus removing the entry * to be deleted. */ @@ -420,6 +429,14 @@ int net_delroute_ipv6(net_ipv6addr_t target, net_ipv6addr_t netmask) goto errout_with_lock; } +#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE + /* We are committed to modifying the routing table. Flush the in-memory + * routing table cache. + */ + + net_flushcache_ipv6(); +#endif + /* Loop, copying each entry, to the previous entry thus removing the entry * to be deleted. */ diff --git a/net/route/net_foreach_fileroute.c b/net/route/net_foreach_fileroute.c index ecacff2097e..678720f105d 100644 --- a/net/route/net_foreach_fileroute.c +++ b/net/route/net_foreach_fileroute.c @@ -73,7 +73,7 @@ ****************************************************************************/ #ifdef CONFIG_ROUTE_IPv4_FILEROUTE -int net_foreachroute_ipv4(route_handler_t handler, FAR void *arg) +int net_foreachroute_ipv4(route_handler_ipv4_t handler, FAR void *arg) { struct net_route_ipv4_s route; struct file fshandle; diff --git a/net/route/net_foreach_ramroute.c b/net/route/net_foreach_ramroute.c index 9d34481d63c..f236cfc7d7f 100644 --- a/net/route/net_foreach_ramroute.c +++ b/net/route/net_foreach_ramroute.c @@ -73,7 +73,7 @@ ****************************************************************************/ #ifdef CONFIG_ROUTE_IPv4_RAMROUTE -int net_foreachroute_ipv4(route_handler_t handler, FAR void *arg) +int net_foreachroute_ipv4(route_handler_ipv4_t handler, FAR void *arg) { FAR struct net_route_ipv4_entry_s *route; FAR struct net_route_ipv4_entry_s *next; diff --git a/net/route/net_foreach_romroute.c b/net/route/net_foreach_romroute.c index 7f8001aaa43..b022d17f704 100644 --- a/net/route/net_foreach_romroute.c +++ b/net/route/net_foreach_romroute.c @@ -68,7 +68,7 @@ ****************************************************************************/ #ifdef CONFIG_ROUTE_IPv4_ROMROUTE -int net_foreachroute_ipv4(route_handler_t handler, FAR void *arg) +int net_foreachroute_ipv4(route_handler_ipv4_t handler, FAR void *arg) { int ret = 0; int i; diff --git a/net/route/net_initroute.c b/net/route/net_initroute.c index 8fa1d7d43ca..83eeba4f062 100644 --- a/net/route/net_initroute.c +++ b/net/route/net_initroute.c @@ -41,6 +41,7 @@ #include "route/ramroute.h" #include "route/fileroute.h" +#include "route/cacheroute.h" #include "route/route.h" #ifdef CONFIG_NET_ROUTE @@ -72,6 +73,10 @@ void net_init_route(void) #if defined(CONFIG_ROUTE_IPv4_FILEROUTE) || defined(CONFIG_ROUTE_IPv6_FILEROUTE) net_init_fileroute(); #endif + +#if defined(CONFIG_ROUTE_IPv4_CACHEROUTE) || defined(CONFIG_ROUTE_IPv6_CACHEROUTE) + net_init_cacheroute(); +#endif } #endif /* CONFIG_NET_ROUTE */ diff --git a/net/route/net_router.c b/net/route/net_router.c index ef48bcffd1e..20451da6a2f 100644 --- a/net/route/net_router.c +++ b/net/route/net_router.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/route/net_router.c * - * Copyright (C) 2013-2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2013-2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -48,10 +48,27 @@ #include #include "devif/devif.h" +#include "route/cacheroute.h" #include "route/route.h" #if defined(CONFIG_NET) && defined(CONFIG_NET_ROUTE) +/**************************************************************************** + * Pre-processor defintions + ****************************************************************************/ + +#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE +# define IPv4_ROUTER entry.router +#else +# define IPv4_ROUTER router +#endif + +#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE +# define IPv6_ROUTER entry.router +#else +# define IPv6_ROUTER router +#endif + /**************************************************************************** * Public Types ****************************************************************************/ @@ -59,16 +76,24 @@ #ifdef CONFIG_NET_IPv4 struct route_ipv4_match_s { - in_addr_t target; /* Target IPv4 address on an external network to match */ - in_addr_t router; /* IPv4 address of the router on one of our networks */ + in_addr_t target; /* Target IPv4 address on remote network */ +#ifdef CONFIG_ROUTE_IPv4_CACHEROUTE + struct net_route_ipv4_s entry; /* Full entry from the IPv4 routing table */ +#else + in_addr_t router; /* IPv4 address of router a local networks */ +#endif }; #endif #ifdef CONFIG_NET_IPv6 struct route_ipv6_match_s { - net_ipv6addr_t target; /* Target IPv6 address on an external network to match */ - net_ipv6addr_t router; /* IPv6 address of the router on one of our networks */ + net_ipv6addr_t target; /* Target IPv6 address on remote network */ +#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE + struct net_route_ipv6_s entry; /* Full entry from the IPv6 routing table */ +#else + net_ipv6addr_t router; /* IPv6 address of router a local networks */ +#endif }; #endif @@ -103,9 +128,15 @@ static int net_ipv4_match(FAR struct net_route_ipv4_s *route, FAR void *arg) if (net_ipv4addr_maskcmp(route->target, match->target, route->netmask)) { +#ifdef CONFIG_ROUTE_IPv4_CACHEROUTE + /* They match.. Copy the entire routing table entry */ + + memcpy(&match->entry, route, sizeof(struct net_route_ipv4_s)); +#else /* They match.. Copy the router address */ net_ipv4addr_copy(match->router, route->router); +#endif return 1; } @@ -140,9 +171,15 @@ static int net_ipv6_match(FAR struct net_route_ipv6_s *route, FAR void *arg) if (net_ipv6addr_maskcmp(route->target, match->target, route->netmask)) { +#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE + /* They match.. Copy the entire routing table entry */ + + memcpy(&match->entry, route, sizeof(struct net_route_ipv6_s)); +#else /* They match.. Copy the router address */ net_ipv6addr_copy(match->router, route->router); +#endif return 1; } @@ -189,23 +226,45 @@ int net_ipv4_router(in_addr_t target, FAR in_addr_t *router) memset(&match, 0, sizeof(struct route_ipv4_match_s)); net_ipv4addr_copy(match.target, target); - /* Find an router entry with the routing table that can forward to this - * address - */ +#ifdef CONFIG_ROUTE_IPv4_CACHEROUTE + /* First see if we can find a router entry in the cache */ - ret = net_foreachroute_ipv4(net_ipv4_match, &match); + ret = net_foreachcache_ipv4(net_ipv4_match, &match); if (ret > 0) { /* We found a route. Return the router address. */ - net_ipv4addr_copy(*router, match.router); + net_ipv4addr_copy(*router, match.IPv4_ROUTER); ret = OK; } else +#endif { - /* There is no route for this address */ + /* Find a router entry with the routing table that can forward to this + * address + */ - ret = -ENOENT; + ret = net_foreachroute_ipv4(net_ipv4_match, &match); + if (ret > 0) + { + /* We found a route. */ + +#ifdef CONFIG_ROUTE_IPv4_CACHEROUTE + /* Add the route to the cache */ + + ret = net_addcache_ipv4(&match.entry); +#endif + /* Return the router address. */ + + net_ipv4addr_copy(*router, match.IPv4_ROUTER); + ret = OK; + } + else + { + /* There is no route for this address */ + + ret = -ENOENT; + } } return ret; @@ -247,23 +306,45 @@ int net_ipv6_router(const net_ipv6addr_t target, net_ipv6addr_t router) memset(&match, 0, sizeof(struct route_ipv6_match_s)); net_ipv6addr_copy(match.target, target); - /* Find an router entry with the routing table that can forward to this - * address - */ +#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE + /* First see if we can find a router entry in the cache */ - ret = net_foreachroute_ipv6(net_ipv6_match, &match); + ret = net_foreachcache_ipv6(net_ipv6_match, &match); if (ret > 0) { /* We found a route. Return the router address. */ - net_ipv6addr_copy(router, match.router); + net_ipv6addr_copy(router, match.IPv6_ROUTER); ret = OK; } else +#endif { - /* There is no route for this address */ + /* Find n router entry with the routing table that can forward to this + * address + */ - ret = -ENOENT; + ret = net_foreachroute_ipv6(net_ipv6_match, &match); + if (ret > 0) + { + /* We found a route */ + +#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE + /* Add the route to the cache */ + + ret = net_addcache_ipv6(&match.entry); +#endif + /* Return the router address. */ + + net_ipv6addr_copy(router, match.IPv6_ROUTER); + ret = OK; + } + else + { + /* There is no route for this address */ + + ret = -ENOENT; + } } return ret; diff --git a/net/route/netdev_router.c b/net/route/netdev_router.c index decdc00bac7..b86c89bd91f 100644 --- a/net/route/netdev_router.c +++ b/net/route/netdev_router.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/route/netdev_router.c * - * Copyright (C) 2013-2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2013-2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -47,10 +47,27 @@ #include #include "netdev/netdev.h" +#include "route/cacheroute.h" #include "route/route.h" #if defined(CONFIG_NET) && defined(CONFIG_NET_ROUTE) +/**************************************************************************** + * Pre-processor defintions + ****************************************************************************/ + +#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE +# define IPv4_ROUTER entry.router +#else +# define IPv4_ROUTER router +#endif + +#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE +# define IPv6_ROUTER entry.router +#else +# define IPv6_ROUTER router +#endif + /**************************************************************************** * Public Types ****************************************************************************/ @@ -58,18 +75,26 @@ #ifdef CONFIG_NET_IPv4 struct route_ipv4_devmatch_s { - FAR struct net_driver_s *dev; /* The route must use this device */ - in_addr_t target; /* Target IPv4 address on an external network to match */ - in_addr_t router; /* IPv6 address of the router on one of our networks */ + FAR struct net_driver_s *dev; /* The route must use this device */ + in_addr_t target; /* Target IPv4 address on remote network */ +#ifdef CONFIG_ROUTE_IPv4_CACHEROUTE + struct net_route_ipv4_s entry; /* Full entry from the IPv4 routing table */ +#else + in_addr_t router; /* IPv4 address of router a local networks */ +#endif }; #endif #ifdef CONFIG_NET_IPv6 struct route_ipv6_devmatch_s { - FAR struct net_driver_s *dev; /* The route must use this device */ - net_ipv6addr_t target; /* Target IPv4 address on an external network to match */ - net_ipv6addr_t router; /* IPv6 address of the router on one of our networks */ + FAR struct net_driver_s *dev; /* The route must use this device */ + net_ipv6addr_t target; /* Target IPv4 address on remote network */ +#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE + struct net_route_ipv6_s entry; /* Full entry from the IPv6 routing table */ +#else + net_ipv6addr_t router; /* IPv6 address of router a local networks */ +#endif }; #endif @@ -110,9 +135,15 @@ static int net_ipv4_devmatch(FAR struct net_route_ipv4_s *route, if (net_ipv4addr_maskcmp(route->target, match->target, route->netmask) && net_ipv4addr_maskcmp(route->router, dev->d_ipaddr, dev->d_netmask)) { +#ifdef CONFIG_ROUTE_IPv4_CACHEROUTE + /* They match.. Copy the entire routing table entry */ + + memcpy(&match->entry, route, sizeof(struct net_route_ipv4_s)); +#else /* They match.. Copy the router address */ net_ipv4addr_copy(match->router, route->router); +#endif return 1; } @@ -154,9 +185,15 @@ static int net_ipv6_devmatch(FAR struct net_route_ipv6_s *route, net_ipv6addr_maskcmp(route->router, dev->d_ipv6addr, dev->d_ipv6netmask)) { +#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE + /* They match.. Copy the entire routing table entry */ + + memcpy(&match->entry, route, sizeof(struct net_route_ipv6_s)); +#else /* They match.. Copy the router address */ net_ipv6addr_copy(match->router, route->router); +#endif return 1; } @@ -202,24 +239,46 @@ void netdev_ipv4_router(FAR struct net_driver_s *dev, in_addr_t target, match.dev = dev; net_ipv4addr_copy(match.target, target); - /* Find an router entry with the routing table that can forward to this - * address using this device. - */ +#ifdef CONFIG_ROUTE_IPv4_CACHEROUTE + /* First see if we can find a router entry in the cache */ - ret = net_foreachroute_ipv4(net_ipv4_devmatch, &match); + ret = net_foreachcache_ipv4(net_ipv4_devmatch, &match); if (ret > 0) { /* We found a route. Return the router address. */ - net_ipv4addr_copy(*router, match.router); + net_ipv4addr_copy(*router, match.IPv4_ROUTER); } else +#endif { - /* There isn't a matching route.. fallback and use the default router - * of the device. + /* Find a router entry with the routing table that can forward to this + * address using this device. */ - net_ipv4addr_copy(*router, dev->d_draddr); + ret = net_foreachroute_ipv4(net_ipv4_devmatch, &match); + if (ret > 0) + { + /* We found a route */ + +#ifdef CONFIG_ROUTE_IPv4_CACHEROUTE + /* Add the route to the cache */ + + ret = net_addcache_ipv4(&match.entry); +#endif + /* We Return the router address. */ + + net_ipv4addr_copy(*router, match.IPv4_ROUTER); + } + else + { + /* There isn't a matching route.. fallback and use the default + * router + * of the device. + */ + + net_ipv4addr_copy(*router, dev->d_draddr); + } } } #endif @@ -259,24 +318,45 @@ void netdev_ipv6_router(FAR struct net_driver_s *dev, match.dev = dev; net_ipv6addr_copy(match.target, target); - /* Find an router entry with the routing table that can forward to this - * address using this device. - */ +#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE + /* First see if we can find a router entry in the cache */ - ret = net_foreachroute_ipv6(net_ipv6_devmatch, &match); + ret = net_foreachcache_ipv6(net_ipv6_devmatch, &match); if (ret > 0) { /* We found a route. Return the router address. */ - net_ipv6addr_copy(router, match.router); + net_ipv6addr_copy(router, match.IPv6_ROUTER); } else +#endif { - /* There isn't a matching route.. fallback and use the default router - * of the device. + /* Find a router entry with the routing table that can forward to this + * address using this device. */ - net_ipv6addr_copy(router, dev->d_ipv6draddr); + ret = net_foreachroute_ipv6(net_ipv6_devmatch, &match); + if (ret > 0) + { + /* We found a route */ + +#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE + /* Add the route to the cache */ + + ret = net_addcache_ipv6(&match.entry); +#endif + /* Return the router address. */ + + net_ipv6addr_copy(router, match.IPv6_ROUTER); + } + else + { + /* There isn't a matching route.. fallback and use the default + * router of the device. + */ + + net_ipv6addr_copy(router, dev->d_ipv6draddr); + } } } #endif diff --git a/net/route/route.h b/net/route/route.h index 619898055b3..e65c8515674 100644 --- a/net/route/route.h +++ b/net/route/route.h @@ -64,7 +64,7 @@ struct net_route_ipv4_s /* Type of the call out function pointer provided to net_foreachroute_ipv4() */ -typedef int (*route_handler_t)(FAR struct net_route_ipv4_s *route, +typedef int (*route_handler_ipv4_t)(FAR struct net_route_ipv4_s *route, FAR void *arg); #endif /* CONFIG_NET_IPv4 */ @@ -260,7 +260,7 @@ void netdev_ipv6_router(FAR struct net_driver_s *dev, #endif /**************************************************************************** - * Name: net_foreachroute_ipv4 + * Name: net_foreachroute_ipv4/net_foreachroute_ipv6 * * Description: * Traverse the routing table @@ -270,14 +270,14 @@ void netdev_ipv6_router(FAR struct net_driver_s *dev, * arg - An arbitrary value that will be passed tot he handler. * * Returned Value: - * Zero (OK) returned if the entire table was search. A negated errno + * Zero (OK) returned if the entire table was searched. A negated errno * value will be returned in the event of a failure. Handlers may also - * terminate the search early with any non-zero, non-negative value. + * terminate the search early with any non-zero value. * ****************************************************************************/ #ifdef CONFIG_NET_IPv4 -int net_foreachroute_ipv4(route_handler_t handler, FAR void *arg); +int net_foreachroute_ipv4(route_handler_ipv4_t handler, FAR void *arg); #endif #ifdef CONFIG_NET_IPv6