mirror of
https://github.com/apache/nuttx.git
synced 2026-09-09 02:16:35 +00:00
net/tcp: add configurable delayed ACK threshold
Some checks are pending
Build Documentation / build-html (push) Waiting to run
MemBrowse Memory Report / changes-filter (push) Waiting to run
MemBrowse Memory Report / load-targets (push) Waiting to run
MemBrowse Memory Report / identical (push) Blocked by required conditions
MemBrowse Memory Report / analyze (push) Blocked by required conditions
Some checks are pending
Build Documentation / build-html (push) Waiting to run
MemBrowse Memory Report / changes-filter (push) Waiting to run
MemBrowse Memory Report / load-targets (push) Waiting to run
MemBrowse Memory Report / identical (push) Blocked by required conditions
MemBrowse Memory Report / analyze (push) Blocked by required conditions
The delayed ACK logic previously sent an ACK for at least every second received segment (hard-coded threshold of 2 per RFC 1122). Add the NET_TCP_ACK_FREQUENCY Kconfig option (range 1-255, default 2) to make this threshold configurable at build time. The delayed ACK timer still forces an ACK after at most 0.5 seconds, so RFC 1122 timing compliance is preserved regardless of the configured threshold. The default value of 2 keeps the exact current behavior: the new condition rx_unackseg >= FREQ - 1 is equivalent to the previous rx_unackseg > 0, and the counter increment degenerates to the previous rx_unackseg = 1 assignment. Signed-off-by: zhekunren <zhekunren@qq.com> Assisted-by: GLM-5.2 <noreply@z.ai>
This commit is contained in:
parent
af2a8c6412
commit
078782846e
3 changed files with 66 additions and 21 deletions
|
|
@ -131,9 +131,30 @@ ACKing behavior and you have MSS sizes that are larger that
|
|||
the average size of the user buffers, then your throughput
|
||||
can probably be greatly improved by enabling ``CONFIG_NET_TCP_SPLIT=y``
|
||||
|
||||
NOTE: NuttX is `not` an RFC 1122 recipient; NuttX will ACK
|
||||
NOTE: NuttX is `not` an RFC 1122 recipient; NuttX will ACK
|
||||
every TCP/IP packet that it receives.
|
||||
|
||||
The Delayed ACK Threshold Configuration
|
||||
=======================================
|
||||
|
||||
The delayed ACK logic is enabled with ``CONFIG_NET_TCP_DELAYED_ACK``.
|
||||
When enabled, the number of received data segments that trigger one
|
||||
ACK can be configured with ``CONFIG_NET_TCP_ACK_FREQUENCY``:
|
||||
|
||||
* Value 1 degenerates to an immediate ACK per received segment
|
||||
(delayed ACK effectively disabled).
|
||||
* Value 2 (default) is the RFC 1122 compliant behavior: an ACK for
|
||||
at least every second segment in a stream of full-sized segments.
|
||||
* Values above 2 reduce ACK traffic and can improve throughput when
|
||||
bulk data is received, at the cost of a coarser ACK clock and
|
||||
slower peer congestion window growth.
|
||||
|
||||
NOTE: RFC 1122 Section 4.2.3.2 states that in a stream of full-sized
|
||||
segments there SHOULD be an ACK for at least every second segment.
|
||||
Setting ``CONFIG_NET_TCP_ACK_FREQUENCY`` above 2 no longer meets
|
||||
that requirement. The delayed ACK timer still forces an ACK after
|
||||
at most 0.5 seconds as required by RFC 1122.
|
||||
|
||||
Write Buffering
|
||||
===============
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,28 @@ config NET_TCP_DELAYED_ACK
|
|||
0.5 seconds, and in a stream of full-sized segments there should
|
||||
be an ACK for at least every second segments.
|
||||
|
||||
config NET_TCP_ACK_FREQUENCY
|
||||
int "Segments received per ACK (delayed ACK threshold)"
|
||||
depends on NET_TCP_DELAYED_ACK
|
||||
range 1 255
|
||||
default 2
|
||||
---help---
|
||||
Number of received data segments that trigger one ACK (the
|
||||
delayed ACK threshold). The delayed ACK timer still forces
|
||||
an ACK after at most 0.5 seconds per RFC 1122.
|
||||
|
||||
Value 1 degenerates to an immediate ACK per received segment
|
||||
(delayed ACK effectively disabled). Value 2 (default) is the
|
||||
RFC 1122 compliant behavior (an ACK for at least every second
|
||||
segment). Values above 2 reduce the ACK traffic at the cost of
|
||||
a coarser ACK clock and slower peer congestion window growth.
|
||||
|
||||
NOTE: RFC 1122 Section 4.2.3.2 states that in a stream of
|
||||
full-sized segments there SHOULD be an ACK for at least every
|
||||
second segment. Setting this value above 2 no longer meets
|
||||
that requirement, but the delayed ACK timer still limits the
|
||||
ACK delay to 0.5 seconds as required by RFC 1122.
|
||||
|
||||
config NET_TCP_KEEPALIVE
|
||||
bool "TCP/IP Keep-alive support"
|
||||
default n
|
||||
|
|
|
|||
|
|
@ -118,19 +118,22 @@ void tcp_appsend(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
|
|||
* NOTES:
|
||||
* 1. If there is a data payload or other flags to be sent with the
|
||||
* outgoing packet, then we may as well include the ACK too.
|
||||
* 2. The RFC refers to full-size segments. It is not clear what
|
||||
* 2. The ACK threshold is CONFIG_NET_TCP_ACK_FREQUENCY segments.
|
||||
* The default value of 2 preserves the RFC 1122 behavior (an
|
||||
* ACK for at least every second segment).
|
||||
* 3. The RFC refers to full-size segments. It is not clear what
|
||||
* "full-size" means. Does that mean that the payload is the size
|
||||
* of the MSS? Payload size is not considered other there being
|
||||
* a payload or or not. Should there be some special action for
|
||||
* small payloads of size < MSS?
|
||||
* 3. Experimentation shows that Windows and Linux behave somewhat
|
||||
* 4. Experimentation shows that Windows and Linux behave somewhat
|
||||
* differently; they delay the ACKs for many more segments (6 or
|
||||
* more). Delaying for more segments would provide less network
|
||||
* traffic and better performance but seems non-compliant.
|
||||
*/
|
||||
|
||||
if (conn->rx_unackseg > 0 || dev->d_sndlen > 0 ||
|
||||
result != TCP_SNDACK)
|
||||
if (conn->rx_unackseg >= CONFIG_NET_TCP_ACK_FREQUENCY - 1 ||
|
||||
dev->d_sndlen > 0 || result != TCP_SNDACK)
|
||||
{
|
||||
/* Reset the delayed ACK state and send the ACK with this packet. */
|
||||
|
||||
|
|
@ -138,12 +141,11 @@ void tcp_appsend(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
|
|||
}
|
||||
else
|
||||
{
|
||||
/* This is only an ACK and there is no pending delayed ACK and
|
||||
* no TX data is being sent. Indicate that there is one un-ACKed
|
||||
* segment and don't send anything now.
|
||||
/* This is only an ACK and there is no TX data being sent.
|
||||
* Count one more un-ACKed segment and don't send anything now.
|
||||
*/
|
||||
|
||||
conn->rx_unackseg = 1;
|
||||
conn->rx_unackseg++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -224,21 +226,21 @@ void tcp_appsend(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
|
|||
{
|
||||
#endif
|
||||
|
||||
/* If d_sndlen > 0, the application has data to be sent. */
|
||||
/* If d_sndlen > 0, the application has data to be sent. */
|
||||
|
||||
if (dev->d_sndlen > 0)
|
||||
{
|
||||
/* Remember how much data we send out now so that we know
|
||||
* when everything has been acknowledged. Just increment the
|
||||
* amount of data sent. This will be needed in sequence number
|
||||
* calculations and we know that this is not a re-transmission.
|
||||
* Retransmissions do not go through this path.
|
||||
*/
|
||||
if (dev->d_sndlen > 0)
|
||||
{
|
||||
/* Remember how much data we send out now so that we know
|
||||
* when everything has been acknowledged. Just increment the
|
||||
* amount of data sent. This will be needed in sequence number
|
||||
* calculations and we know that this is not a re-transmission.
|
||||
* Retransmissions do not go through this path.
|
||||
*/
|
||||
|
||||
conn->tx_unacked += dev->d_sndlen;
|
||||
}
|
||||
conn->tx_unacked += dev->d_sndlen;
|
||||
}
|
||||
|
||||
conn->nrtx = 0;
|
||||
conn->nrtx = 0;
|
||||
|
||||
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue