Skip to content

Conversation

@fjpanag
Copy link
Contributor

@fjpanag fjpanag commented Nov 4, 2022

Summary

This is an attempt to fix the issues reported in #6960:

  • Only a single connection is allocated, the one actually needed.
  • In tcp_free() the connection is actually deallocated, instead of leaving it existing forever in the list.

This is only the first step, possibly with more to come (list of pre-allocated connections, maximum connections limit etc).

For the moment, this PR handles only TCP, till we determine all the details.
Then the fix will be copied to all other connections that use similar logic.

Impact

Improved memory utilization in TCP.

Testing

Only minimal testing for the moment.
More testing is expected on actual hardware soon, I will report back.

@fjpanag
Copy link
Contributor Author

fjpanag commented Nov 4, 2022

Previously, when CONFIG_NET_SOLINGER was enabled, there was some functionality to drop an old connection and reuse it.

I believe this has no meaning now, as we cannot really run out of connections (as easily before at least), and since there is no free connections lists, the connection is nowhere to be returned.

Also, as there will never be any free connections, this will trigger this code every time, causing old connections to be dropped constantly, instead of only when actually needed.

@anchao
Copy link
Contributor

anchao commented Nov 7, 2022

@fjpanag

Only a single connection is allocated, the one actually needed.

On some platforms this behavior can cause the memory fragmentation, and also if you think the memory fragmentation is acceptable, please configure the numb er of connections to 1, which will consistent with your expectations.

In tcp_free() the connection is actually deallocated, instead of leaving it existing forever in the list.

as mentioned in #6960, please release the connections instance if the number of connections is configured to 1, otherwise keep the current behavior, in some cases memory fragmentation is unacceptable.

@fjpanag
Copy link
Contributor Author

fjpanag commented Nov 8, 2022

@fjpanag

Only a single connection is allocated, the one actually needed.

On some platforms this behavior can cause the memory fragmentation, and also if you think the memory fragmentation is acceptable, please configure the numb er of connections to 1, which will consistent with your expectations.

In tcp_free() the connection is actually deallocated, instead of leaving it existing forever in the list.

as mentioned in #6960, please release the connections instance if the number of connections is configured to 1, otherwise keep the current behavior, in some cases memory fragmentation is unacceptable.

As I mentioned, my intention is to add a pool of preallocated connections, to avoid heap fragmentation. So new connections will be allocated only when the pool is exhausted.

I will include this change in this PR.

@fjpanag fjpanag marked this pull request as draft November 8, 2022 11:19
@fjpanag fjpanag force-pushed the conn_alloc branch 2 times, most recently from dbd4d5d to 6e8b289 Compare November 25, 2022 12:10
@fjpanag
Copy link
Contributor Author

fjpanag commented Nov 25, 2022

This is my second take on improving dynamically allocated connections.

Now a pool of preallocated connections is created during start.
These connections are preferred, reducing the danger of heap fragmentation.

If nevertheless the connections are exhausted, a new one will be allocated, allowing normal operation of the system even during temporal high load.

When these "extra" connections are no longer needed, they are properly deallocated.


This is not fully tested yet, I am working on this and I will comment back. In the meantime please review the proposed solution.

I am planning on also adding a maximum connections limit. This way a misbehaving system, or possibly a network attack, will not exhaust the heap (which will possibly have disastrous consequences).

@fjpanag
Copy link
Contributor Author

fjpanag commented Nov 25, 2022

Also added the maximum connections limit.

@fjpanag fjpanag force-pushed the conn_alloc branch 2 times, most recently from aaec433 to 46cb9c4 Compare November 26, 2022 13:44
@fjpanag
Copy link
Contributor Author

fjpanag commented Nov 26, 2022

Everything seems fine now.

Tested on a custom server with a few dozens of connections. It seems stable, and no memory leaks were observed.

@fjpanag fjpanag marked this pull request as ready for review November 26, 2022 14:04
@xiaoxiang781216 xiaoxiang781216 linked an issue Nov 27, 2022 that may be closed by this pull request
@fjpanag
Copy link
Contributor Author

fjpanag commented Dec 3, 2022

I removed the extra Kconfig and all connections are allocated in a single batch.

Also I changed init a bit, so it is simpler now, and there is no code duplication.

@fjpanag fjpanag force-pushed the conn_alloc branch 2 times, most recently from 0be2fb8 to 7398953 Compare December 4, 2022 14:44
@fjpanag
Copy link
Contributor Author

fjpanag commented Dec 4, 2022

Here is another take on this issue.
Not fully tested yet, may change a few things here and there.

@xiaoxiang781216

NET_TCP_PREALLOC_CONNS to indicate the preallocated conn from .bss/data or heap:
zero disable the prealloation

Done. For the moment BSS is used, I am not sure whether I will change this to use the heap.

NET_TCP_ALLOC_CONNS to indicate the dynamic conn from heap:
0 mean disable dynamical allocation at all
1 mean allocate/free from heap every time
2... mean allocate batch from heap, but not return to heap

Done. This way it satisfies everyone.

Add NET_TCP_MAX_CONNS to limit the concurrent opened connection, actually I think it's better to impose the limitation from psocket level instead individual protocol(e.g. TCP/UDP/ICMP).

I left this in TCP level. I believe it is much better to be able to tune each protocol independently. Especially because each protocol has a different connection structure size, and different usage. For example the heap may have enough space for 50 UDP connections, but not for 50 TCP connections.

Finally, remove NET_ALLOC_CONNS once all conn convert to this style since we can achieve the same functionality by setting NET_xxx_ALLOC_CONNS to zero or non zero.

Yes will do, in a future PR though.

@fjpanag
Copy link
Contributor Author

fjpanag commented Dec 10, 2022

I just had the time to complete my tests, and this seems to behave as expected.

@xiaoxiang781216 What do you think, can we merge this?

Does anyone understand what is the issue with the CI?
Shall we just restart it?

@xiaoxiang781216
Copy link
Contributor

I just had the time to complete my tests, and this seems to behave as expected.

@xiaoxiang781216 What do you think, can we merge this?

I will take a look in tomorrow

Does anyone understand what is the issue with the CI? Shall we just restart it?

I am trying fix ci break here: #7842

@xiaoxiang781216
Copy link
Contributor

@fjpanag please rebase to the last master, ci break has been fixed.

@xiaoxiang781216
Copy link
Contributor

@fjpanag it's better to apply the similar change to all socket conn, not only tcp.

@xiaoxiang781216
Copy link
Contributor

not all comments get addressed?

@fjpanag
Copy link
Contributor Author

fjpanag commented Feb 18, 2023

not all comments get addressed?

Working on it... I will ping you.

@xiaoxiang781216
Copy link
Contributor

@fjpanag CONFIG_NET_ALLOC_SOCKETS need be removed from sim/dynconns/defconfig:

====================================================================================
Configuration/Tool: sim/dynconns
------------------------------------------------------------------------------------
  Cleaning...
  Configuring...
  Building NuttX...
  Normalize sim/dynconns
49d48
< CONFIG_NET_ALLOC_SOCKETS=1
Saving the new configuration file

@xiaoxiang781216 xiaoxiang781216 merged commit b6eb3c8 into apache:master Feb 20, 2023
@fjpanag fjpanag deleted the conn_alloc branch February 20, 2023 11:05
@fjpanag
Copy link
Contributor Author

fjpanag commented Feb 21, 2023

Users defconfigs are needed to be updated after this PR.
Maybe this must be marked to be included in the next release notes?

@xiaoxiang781216 xiaoxiang781216 added the breaking change This change requires a mitigation entry in the release notes. label Feb 21, 2023
@xiaoxiang781216
Copy link
Contributor

Marked.

else
#endif
{
dq_addlast(&conn->sconn.node, &g_free_ieee802154_connections);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we need to move memset(conn, 0, sizeof(*conn)); here and do not spend extra cycles to memset memory that is going to be free-ed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes this is a good idea, I will provide a new PR for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


/* Reset structure */

memset(conn, 0, sizeof(*conn));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto


/* Make sure that the connection is marked as uninitialized */

memset(conn, 0, sizeof(*conn));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

else
#endif
{
dq_addlast(&conn->sconn.node, &g_free_tcp_connections);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need memset(conn, 0, sizeof(*conn)); before adding to the queue

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think not. It seems that tcp_free() sets the contents of conn to specific values, for example see this.

If someone knows for sure how this works, I can add a memset() and then set the flags, or whatever else is needed.


/* Clear the connection structure */

memset(conn, 0, sizeof(*conn));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

/* Reset structure */

nxsem_destroy(&conn->resp.sem);
memset(conn, 0, sizeof(*conn));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking change This change requires a mitigation entry in the release notes.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Behaviour of CONFIG_NET_ALLOC_CONNS

6 participants