Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion Documentation/components/net/delay_act_and_tcp_perf.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
===============

Expand Down
22 changes: 22 additions & 0 deletions net/tcp/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Comment thread
zhekunren marked this conversation as resolved.
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
Expand Down
42 changes: 22 additions & 20 deletions net/tcp/tcp_appsend.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,32 +118,34 @@ 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. */

conn->rx_unackseg = 0;
}
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;
}
}
Expand Down Expand Up @@ -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
}
Expand Down
Loading