diff --git a/net/ipforward/Kconfig b/net/ipforward/Kconfig index 3be48eac75998..8f6484d389cd1 100644 --- a/net/ipforward/Kconfig +++ b/net/ipforward/Kconfig @@ -19,7 +19,7 @@ config NET_IPFORWARD_BROADCAST If selected, broadcast packets received on one network device will be forwarded though other network devices. -config NET_IPFORWARD_NSTRUCT +config NET_IPFORWARD_PREALLOC_STRUCT int "Number of pre-allocated forwarding structures" default 4 depends on NET_IPFORWARD @@ -40,3 +40,21 @@ config NET_IPFORWARD_NSTRUCT WARNING: DO NOT set this setting to a value greater than or equal to CONFIG_IOB_NBUFFERS, otherwise it may consume all the IOB and let netdev fail to work. + +config NET_IPFORWARD_ALLOC_STRUCT + int "Dynamic forwarding structures allocation" + default 0 + ---help--- + When set to 0 all dynamic allocations are disabled + + When set to 1 a new forwarding structure will be allocated every + time, and it will be free'd when no longer needed. + + Setting this to 2 or more will allocate the forwarding structures + in batches (with batch size equal to this config). When a I/O buffer + chain head is no longer needed, it will be returned to the free + forwarding structures pool, and it will never be deallocated! + + Note: maximum number of allocated forwarding structures is limited + to CONFIG_IOB_NBUFFERS - CONFIG_IOB_THROTTLE to avoid consuming all + the IOBs. diff --git a/net/ipforward/ipfwd_alloc.c b/net/ipforward/ipfwd_alloc.c index b0b5536dea8a5..d8612aacdcfa7 100644 --- a/net/ipforward/ipfwd_alloc.c +++ b/net/ipforward/ipfwd_alloc.c @@ -37,6 +37,7 @@ #include #include "ipforward/ipforward.h" +#include "utils/utils.h" #ifdef CONFIG_NET_IPFORWARD @@ -66,13 +67,12 @@ * Private Data ****************************************************************************/ -/* This is an array of pre-allocating forwarding structures */ +/* This is the state of the global forwarding structures */ -static struct forward_s g_fwdpool[CONFIG_NET_IPFORWARD_NSTRUCT]; - -/* This is a list of free forwarding structures */ - -static FAR struct forward_s *g_fwdfree; +NET_BUFPOOL_DECLARE(g_fwdpool, sizeof(struct forward_s), + CONFIG_NET_IPFORWARD_PREALLOC_STRUCT, + CONFIG_NET_IPFORWARD_ALLOC_STRUCT, + CONFIG_IOB_NBUFFERS - CONFIG_IOB_THROTTLE); /**************************************************************************** * Public Functions @@ -91,25 +91,13 @@ static FAR struct forward_s *g_fwdfree; void ipfwd_initialize(void) { - FAR struct forward_s *fwd; - int i; - /* The IOB size must be such that the maximum L2 and L3 headers fit into * the contiguous memory of the first IOB in the IOB chain. */ DEBUGASSERT(MAX_HDRLEN <= CONFIG_IOB_BUFSIZE); - /* Add all pre-allocated forwarding structures to the free list */ - - g_fwdfree = NULL; - - for (i = 0; i < CONFIG_NET_IPFORWARD_NSTRUCT; i++) - { - fwd = &g_fwdpool[i]; - fwd->f_flink = g_fwdfree; - g_fwdfree = fwd; - } + NET_BUFPOOL_INIT(g_fwdpool); } /**************************************************************************** @@ -127,16 +115,7 @@ void ipfwd_initialize(void) FAR struct forward_s *ipfwd_alloc(void) { - FAR struct forward_s *fwd; - - fwd = g_fwdfree; - if (fwd != NULL) - { - g_fwdfree = fwd->f_flink; - memset (fwd, 0, sizeof(struct forward_s)); - } - - return fwd; + return NET_BUFPOOL_TRYALLOC(g_fwdpool); } /**************************************************************************** @@ -153,8 +132,7 @@ FAR struct forward_s *ipfwd_alloc(void) void ipfwd_free(FAR struct forward_s *fwd) { - fwd->f_flink = g_fwdfree; - g_fwdfree = fwd; + NET_BUFPOOL_FREE(g_fwdpool, fwd); } #endif /* CONFIG_NET_IPFORWARD */ diff --git a/net/tcp/Kconfig b/net/tcp/Kconfig index fd2bcec121177..58630822f8a92 100644 --- a/net/tcp/Kconfig +++ b/net/tcp/Kconfig @@ -249,7 +249,7 @@ config NET_TCP_WRITE_BUFFERS if NET_TCP_WRITE_BUFFERS -config NET_TCP_NWRBCHAINS +config NET_TCP_PREALLOC_WRBCHAINS int "Number of pre-allocated I/O buffer chain heads" default 8 ---help--- @@ -259,6 +259,20 @@ config NET_TCP_NWRBCHAINS choice for this value would be the same as the maximum number of TCP connections. +config NET_TCP_ALLOC_WRBCHAINS + int "Dynamic I/O buffer chain heads allocation" + default 0 + ---help--- + When set to 0 all dynamic allocations are disabled + + When set to 1 a new I/O buffer chain head will be allocated every + time, and it will be free'd when no longer needed. + + Setting this to 2 or more will allocate the I/O buffer chain heads + in batches (with batch size equal to this config). When a I/O buffer + chain head is no longer needed, it will be returned to the free + I/O buffer chain heads pool, and it will never be deallocated! + config NET_TCP_WRBUFFER_DEBUG bool "Force write buffer debug" default n diff --git a/net/tcp/tcp_wrbuffer.c b/net/tcp/tcp_wrbuffer.c index 4e426736092f3..271a2ad57be92 100644 --- a/net/tcp/tcp_wrbuffer.c +++ b/net/tcp/tcp_wrbuffer.c @@ -48,34 +48,15 @@ #if defined(CONFIG_NET_TCP) && defined(CONFIG_NET_TCP_WRITE_BUFFERS) -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* Package all globals used by this logic into a structure */ - -struct wrbuffer_s -{ - /* The semaphore to protect the buffers */ - - sem_t sem; - - /* This is the list of available write buffers */ - - sq_queue_t freebuffers; - - /* These are the pre-allocated write buffers */ - - struct tcp_wrbuffer_s buffers[CONFIG_NET_TCP_NWRBCHAINS]; -}; - /**************************************************************************** * Private Data ****************************************************************************/ /* This is the state of the global write buffer resource */ -static struct wrbuffer_s g_wrbuffer; +NET_BUFPOOL_DECLARE(g_wrbuffer, sizeof(struct tcp_wrbuffer_s), + CONFIG_NET_TCP_PREALLOC_WRBCHAINS, + CONFIG_NET_TCP_ALLOC_WRBCHAINS, 0); /**************************************************************************** * Public Functions @@ -94,16 +75,7 @@ static struct wrbuffer_s g_wrbuffer; void tcp_wrbuffer_initialize(void) { - int i; - - sq_init(&g_wrbuffer.freebuffers); - - nxsem_init(&g_wrbuffer.sem, 0, CONFIG_NET_TCP_NWRBCHAINS); - - for (i = 0; i < CONFIG_NET_TCP_NWRBCHAINS; i++) - { - sq_addfirst(&g_wrbuffer.buffers[i].wb_node, &g_wrbuffer.freebuffers); - } + NET_BUFPOOL_INIT(g_wrbuffer); } /**************************************************************************** @@ -127,7 +99,6 @@ void tcp_wrbuffer_initialize(void) FAR struct tcp_wrbuffer_s *tcp_wrbuffer_timedalloc(unsigned int timeout) { FAR struct tcp_wrbuffer_s *wrb; - int ret; /* We need to allocate two things: (1) A write buffer structure and (2) * at least one I/O buffer to start the chain. @@ -137,20 +108,12 @@ FAR struct tcp_wrbuffer_s *tcp_wrbuffer_timedalloc(unsigned int timeout) * buffer */ - ret = net_sem_timedwait_uninterruptible(&g_wrbuffer.sem, timeout); - if (ret != OK) + wrb = NET_BUFPOOL_TIMEDALLOC(g_wrbuffer, timeout); + if (wrb == NULL) { return NULL; } - /* Now, we are guaranteed to have a write buffer structure reserved - * for us in the free list. - */ - - wrb = (FAR struct tcp_wrbuffer_s *)sq_remfirst(&g_wrbuffer.freebuffers); - DEBUGASSERT(wrb); - memset(wrb, 0, sizeof(struct tcp_wrbuffer_s)); - /* Now get the first I/O buffer for the write buffer structure */ wrb->wb_iob = net_iobtimedalloc(true, timeout); @@ -247,8 +210,7 @@ void tcp_wrbuffer_release(FAR struct tcp_wrbuffer_s *wrb) /* Then free the write buffer structure */ - sq_addlast(&wrb->wb_node, &g_wrbuffer.freebuffers); - nxsem_post(&g_wrbuffer.sem); + NET_BUFPOOL_FREE(g_wrbuffer, wrb); } /**************************************************************************** @@ -304,16 +266,7 @@ uint32_t tcp_wrbuffer_inqueue_size(FAR struct tcp_conn_s *conn) int tcp_wrbuffer_test(void) { - int val = 0; - int ret; - - ret = nxsem_get_value(&g_wrbuffer.sem, &val); - if (ret >= 0) - { - ret = val > 0 ? OK : -ENOSPC; - } - - return ret; + return NET_BUFPOOL_TEST(g_wrbuffer); } #endif /* CONFIG_NET_TCP && CONFIG_NET_TCP_WRITE_BUFFERS */ diff --git a/net/udp/Kconfig b/net/udp/Kconfig index e147b7a608a90..390d0156fe30f 100644 --- a/net/udp/Kconfig +++ b/net/udp/Kconfig @@ -93,7 +93,7 @@ config NET_UDP_WRITE_BUFFERS if NET_UDP_WRITE_BUFFERS -config NET_UDP_NWRBCHAINS +config NET_UDP_PREALLOC_WRBCHAINS int "Number of pre-allocated I/O buffer chain heads" default 8 ---help--- @@ -103,6 +103,20 @@ config NET_UDP_NWRBCHAINS choice for this value would be the same as the maximum number of UDP connections. +config NET_UDP_ALLOC_WRBCHAINS + int "Dynamic I/O buffer chain heads allocation" + default 0 + ---help--- + When set to 0 all dynamic allocations are disabled. + + When set to 1 a new I/O buffer chain head will be allocated every + time, and it will be free'd when no longer needed. + + Setting this to 2 or more will allocate the I/O buffer chain heads + in batches (with batch size equal to this config). When a I/O buffer + chain head is no longer needed, it will be returned to the free + I/O buffer chain heads pool, and it will never be deallocated! + config NET_UDP_WRBUFFER_DEBUG bool "Force write buffer debug" default n diff --git a/net/udp/udp_wrbuffer.c b/net/udp/udp_wrbuffer.c index 0b9846c77f66e..9486465f0fe4e 100644 --- a/net/udp/udp_wrbuffer.c +++ b/net/udp/udp_wrbuffer.c @@ -47,34 +47,15 @@ #include "utils/utils.h" #include "udp/udp.h" -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* Package all globals used by this logic into a structure */ - -struct wrbuffer_s -{ - /* The semaphore to protect the buffers */ - - sem_t sem; - - /* This is the list of available write buffers */ - - sq_queue_t freebuffers; - - /* These are the pre-allocated write buffers */ - - struct udp_wrbuffer_s buffers[CONFIG_NET_UDP_NWRBCHAINS]; -}; - /**************************************************************************** * Private Data ****************************************************************************/ /* This is the state of the global write buffer resource */ -static struct wrbuffer_s g_wrbuffer; +NET_BUFPOOL_DECLARE(g_wrbuffer, sizeof(struct udp_wrbuffer_s), + CONFIG_NET_UDP_PREALLOC_WRBCHAINS, + CONFIG_NET_UDP_ALLOC_WRBCHAINS, 0); /**************************************************************************** * Public Functions @@ -93,16 +74,7 @@ static struct wrbuffer_s g_wrbuffer; void udp_wrbuffer_initialize(void) { - int i; - - sq_init(&g_wrbuffer.freebuffers); - - nxsem_init(&g_wrbuffer.sem, 0, CONFIG_NET_UDP_NWRBCHAINS); - - for (i = 0; i < CONFIG_NET_UDP_NWRBCHAINS; i++) - { - sq_addfirst(&g_wrbuffer.buffers[i].wb_node, &g_wrbuffer.freebuffers); - } + NET_BUFPOOL_INIT(g_wrbuffer); } /**************************************************************************** @@ -133,15 +105,8 @@ FAR struct udp_wrbuffer_s *udp_wrbuffer_alloc(void) * buffer */ - net_sem_wait_uninterruptible(&g_wrbuffer.sem); - - /* Now, we are guaranteed to have a write buffer structure reserved - * for us in the free list. - */ - - wrb = (FAR struct udp_wrbuffer_s *)sq_remfirst(&g_wrbuffer.freebuffers); + wrb = NET_BUFPOOL_ALLOC(g_wrbuffer); DEBUGASSERT(wrb); - memset(wrb, 0, sizeof(struct udp_wrbuffer_s)); /* Now get the first I/O buffer for the write buffer structure */ @@ -177,7 +142,6 @@ FAR struct udp_wrbuffer_s *udp_wrbuffer_alloc(void) FAR struct udp_wrbuffer_s *udp_wrbuffer_timedalloc(unsigned int timeout) { FAR struct udp_wrbuffer_s *wrb; - int ret; /* We need to allocate two things: (1) A write buffer structure and (2) * at least one I/O buffer to start the chain. @@ -187,20 +151,12 @@ FAR struct udp_wrbuffer_s *udp_wrbuffer_timedalloc(unsigned int timeout) * buffer */ - ret = net_sem_timedwait_uninterruptible(&g_wrbuffer.sem, timeout); - if (ret != OK) + wrb = NET_BUFPOOL_TIMEDALLOC(g_wrbuffer, timeout); + if (wrb == NULL) { return NULL; } - /* Now, we are guaranteed to have a write buffer structure reserved - * for us in the free list. - */ - - wrb = (FAR struct udp_wrbuffer_s *)sq_remfirst(&g_wrbuffer.freebuffers); - DEBUGASSERT(wrb); - memset(wrb, 0, sizeof(struct udp_wrbuffer_s)); - /* Now get the first I/O buffer for the write buffer structure */ wrb->wb_iob = net_iobtimedalloc(true, timeout); @@ -253,19 +209,12 @@ FAR struct udp_wrbuffer_s *udp_wrbuffer_tryalloc(void) * buffer */ - if (nxsem_trywait(&g_wrbuffer.sem) != OK) + wrb = NET_BUFPOOL_TRYALLOC(g_wrbuffer); + if (wrb == NULL) { return NULL; } - /* Now, we are guaranteed to have a write buffer structure reserved - * for us in the free list. - */ - - wrb = (FAR struct udp_wrbuffer_s *)sq_remfirst(&g_wrbuffer.freebuffers); - DEBUGASSERT(wrb); - memset(wrb, 0, sizeof(struct udp_wrbuffer_s)); - /* Now get the first I/O buffer for the write buffer structure */ wrb->wb_iob = @@ -312,8 +261,7 @@ void udp_wrbuffer_release(FAR struct udp_wrbuffer_s *wrb) /* Then free the write buffer structure */ - sq_addlast(&wrb->wb_node, &g_wrbuffer.freebuffers); - nxsem_post(&g_wrbuffer.sem); + NET_BUFPOOL_FREE(g_wrbuffer, wrb); } /**************************************************************************** @@ -363,9 +311,7 @@ uint32_t udp_wrbuffer_inqueue_size(FAR struct udp_conn_s *conn) int udp_wrbuffer_test(void) { - int val = 0; - nxsem_get_value(&g_wrbuffer.sem, &val); - return val > 0 ? OK : -ENOSPC; + return NET_BUFPOOL_TEST(g_wrbuffer); } #endif /* CONFIG_NET && CONFIG_NET_UDP && CONFIG_NET_UDP_WRITE_BUFFERS */ diff --git a/net/utils/net_bufpool.c b/net/utils/net_bufpool.c index 283f2748da6a1..8e65ced82ddae 100644 --- a/net/utils/net_bufpool.c +++ b/net/utils/net_bufpool.c @@ -170,3 +170,28 @@ void net_bufpool_free(FAR struct net_bufpool_s *pool, FAR void *node) nxsem_post(&pool->u.sem); } + +/**************************************************************************** + * Name: net_bufpool_test + * + * Description: + * Check if there is room in the buffer pool. Does not reserve any space. + * + * Assumptions: + * None. + * + ****************************************************************************/ + +int net_bufpool_test(FAR struct net_bufpool_s *pool) +{ + int val = 0; + int ret; + + ret = nxsem_get_value(&pool->u.sem, &val); + if (ret >= 0) + { + ret = val > 0 ? OK : -ENOSPC; + } + + return ret; +} diff --git a/net/utils/utils.h b/net/utils/utils.h index 4bd59159c800f..fa05c2690cb61 100644 --- a/net/utils/utils.h +++ b/net/utils/utils.h @@ -102,6 +102,7 @@ #define NET_BUFPOOL_TRYALLOC(p) net_bufpool_timedalloc(&p, 0) #define NET_BUFPOOL_ALLOC(p) net_bufpool_timedalloc(&p, UINT_MAX) #define NET_BUFPOOL_FREE(p,n) net_bufpool_free(&p, n) +#define NET_BUFPOOL_TEST(p) net_bufpool_test(&p) /**************************************************************************** * Public Types @@ -416,6 +417,19 @@ FAR void *net_bufpool_timedalloc(FAR struct net_bufpool_s *pool, void net_bufpool_free(FAR struct net_bufpool_s *pool, FAR void *node); +/**************************************************************************** + * Name: net_bufpool_test + * + * Description: + * Check if there is room in the buffer pool. Does not reserve any space. + * + * Assumptions: + * None. + * + ****************************************************************************/ + +int net_bufpool_test(FAR struct net_bufpool_s *pool); + /**************************************************************************** * Name: net_chksum_adjust *