Improvements in ICMPv6 connections allocation.

This commit is contained in:
Fotis Panagiotopoulos 2023-02-11 15:09:01 +02:00 committed by Xiang Xiao
parent 1c07a3a696
commit 90a93a7474
2 changed files with 70 additions and 11 deletions

View File

@ -200,9 +200,46 @@ endif # NET_ICMPv6_ROUTER
if NET_ICMPv6_SOCKET
config NET_ICMPv6_NCONNS
int "Max ICMPv6 packet sockets"
config NET_ICMPv6_PREALLOC_CONNS
int "Preallocated ICMPv6 packet sockets"
default 4
---help---
Number of ICMPv6 connections (all tasks).
This number of connections will be pre-allocated during system boot.
If dynamic connections allocation is enabled, more connections may
be allocated at a later time, as the system needs them. Else this
will be the maximum number of connections available to the system
at all times.
Set to 0 to disable (and rely only on dynamic allocations).
config NET_ICMPv6_ALLOC_CONNS
int "Dynamic ICMPv6 connections allocation"
default 0
---help---
Dynamic memory allocations for ICMPv6.
When set to 0 all dynamic allocations are disabled.
When set to 1 a new connection will be allocated every time,
and it will be free'd when no longer needed.
Setting this to 2 or more will allocate the connections in
batches (with batch size equal to this config). When a
connection is no longer needed, it will be returned to the
free connections pool, and it will never be deallocated!
config NET_ICMPv6_MAX_CONNS
int "Maximum number of ICMPv6 connections"
default 0
depends on NET_ICMPv6_ALLOC_CONNS > 0
---help---
If dynamic connections allocation is selected (NET_ICMPv6_ALLOC_CONNS > 0)
this will limit the number of connections that can be allocated.
This is useful in case the system is under very heavy load (or
under attack), ensuring that the heap will not be exhausted.
config NET_ICMPv6_NPOLLWAITERS
int "Number of ICMPv6 poll waiters"

View File

@ -48,8 +48,9 @@
/* The array containing all IPPROTO_ICMP socket connections */
#ifndef CONFIG_NET_ALLOC_CONNS
static struct icmpv6_conn_s g_icmpv6_connections[CONFIG_NET_ICMPv6_NCONNS];
#if CONFIG_NET_ICMPv6_PREALLOC_CONNS > 0
static struct icmpv6_conn_s
g_icmpv6_connections[CONFIG_NET_ICMPv6_PREALLOC_CONNS];
#endif
/* A list of all free IPPROTO_ICMP socket connections */
@ -76,10 +77,10 @@ static dq_queue_t g_active_icmpv6_connections;
void icmpv6_sock_initialize(void)
{
#ifndef CONFIG_NET_ALLOC_CONNS
#if CONFIG_NET_ICMPv6_PREALLOC_CONNS > 0
int i;
for (i = 0; i < CONFIG_NET_ICMPv6_NCONNS; i++)
for (i = 0; i < CONFIG_NET_ICMPv6_PREALLOC_CONNS; i++)
{
/* Move the connection structure to the free list */
@ -109,13 +110,22 @@ FAR struct icmpv6_conn_s *icmpv6_alloc(void)
ret = nxmutex_lock(&g_free_lock);
if (ret >= 0)
{
#ifdef CONFIG_NET_ALLOC_CONNS
#if CONFIG_NET_ICMPv6_ALLOC_CONNS > 0
if (dq_peek(&g_active_icmpv6_connections) == NULL)
{
conn = kmm_zalloc(sizeof(*conn) * CONFIG_NET_ICMPv6_NCONNS);
#if CONFIG_NET_ICMPv6_MAX_CONNS > 0
if (dq_count(&g_active_icmpv6_connections) +
CONFIG_NET_ICMPv6_ALLOC_CONNS >= CONFIG_NET_ICMPv6_MAX_CONNS)
{
nxmutex_unlock(&g_free_lock);
return NULL;
}
#endif
conn = kmm_zalloc(sizeof(*conn) * CONFIG_NET_ICMPv6_ALLOC_CONNS);
if (conn != NULL)
{
for (ret = 0; ret < CONFIG_NET_ICMPv6_NCONNS; ret++)
for (ret = 0; ret < CONFIG_NET_ICMPv6_ALLOC_CONNS; ret++)
{
dq_addlast(&conn[ret].sconn.node,
&g_free_icmpv6_connections);
@ -166,9 +176,21 @@ void icmpv6_free(FAR struct icmpv6_conn_s *conn)
memset(conn, 0, sizeof(*conn));
/* Free the connection */
/* If this is a preallocated or a batch allocated connection store it in
* the free connections list. Else free it.
*/
#if CONFIG_NET_ICMPv6_ALLOC_CONNS == 1
if (conn < g_icmpv6_connections || conn >= (g_icmpv6_connections +
CONFIG_NET_ICMPv6_PREALLOC_CONNS))
{
kmm_free(conn);
}
else
#endif
{
dq_addlast(&conn->sconn.node, &g_free_icmpv6_connections);
}
dq_addlast(&conn->sconn.node, &g_free_icmpv6_connections);
nxmutex_unlock(&g_free_lock);
}