From ad25c439839bfc74435402a861b5eea1af1ef2f3 Mon Sep 17 00:00:00 2001 From: Alexander Lunev Date: Sat, 22 Jan 2022 01:00:27 +0300 Subject: [PATCH] net/tcp/sendfile: fast retransmit on duplicate acknowledgments (RFC 5681). (the same as it was implemented in tcp_send_unbuffered.c) --- net/tcp/tcp_send_unbuffered.c | 1 + net/tcp/tcp_sendfile.c | 52 ++++++++++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/net/tcp/tcp_send_unbuffered.c b/net/tcp/tcp_send_unbuffered.c index d327007454..d8cd4110a9 100644 --- a/net/tcp/tcp_send_unbuffered.c +++ b/net/tcp/tcp_send_unbuffered.c @@ -293,6 +293,7 @@ static uint16_t tcpsend_eventhandler(FAR struct net_driver_s *dev, CONFIG_NET_TCP_FAST_RETRANSMIT_WATERMARK) { flags |= TCP_REXMIT; + pstate->snd_dup_acks = 0; } } else diff --git a/net/tcp/tcp_sendfile.c b/net/tcp/tcp_sendfile.c index e60aa88eb9..c533e7fc6d 100644 --- a/net/tcp/tcp_sendfile.c +++ b/net/tcp/tcp_sendfile.c @@ -84,6 +84,15 @@ struct sendfile_s ssize_t snd_sent; /* The number of bytes sent */ uint32_t snd_isn; /* Initial sequence number */ uint32_t snd_acked; /* The number of bytes acked */ + uint32_t snd_prev_ack; /* The previous ACKed seq number */ +#ifdef CONFIG_NET_TCP_WINDOW_SCALE + uint32_t snd_prev_wnd; /* The advertised window in the last + * incoming acknowledgment + */ +#else + uint16_t snd_prev_wnd; +#endif + int snd_dup_acks; /* Duplicate ACK counter */ }; /**************************************************************************** @@ -218,6 +227,7 @@ static uint16_t sendfile_eventhandler(FAR struct net_driver_s *dev, if ((flags & TCP_ACKDATA) != 0) { + uint32_t ackno; FAR struct tcp_hdr_s *tcp; /* Get the offset address of the TCP header */ @@ -242,14 +252,14 @@ static uint16_t sendfile_eventhandler(FAR struct net_driver_s *dev, } #endif /* CONFIG_NET_IPv4 */ - /* The current acknowledgement number number is the (relative) offset + /* The current acknowledgement number is the (relative) offset * of the of the next byte needed by the receiver. The snd_isn is the * offset of the first byte to send to the receiver. The difference * is the number of bytes to be acknowledged. */ - pstate->snd_acked = TCP_SEQ_SUB(tcp_getsequence(tcp->ackno), - pstate->snd_isn); + ackno = tcp_getsequence(tcp->ackno); + pstate->snd_acked = TCP_SEQ_SUB(ackno, pstate->snd_isn); ninfo("ACK: acked=%" PRId32 " sent=%zd flen=%zu\n", pstate->snd_acked, pstate->snd_sent, pstate->snd_flen); @@ -264,15 +274,43 @@ static uint16_t sendfile_eventhandler(FAR struct net_driver_s *dev, goto end_wait; } - /* No. Fall through to send more data if necessary */ + /* Fast Retransmit (RFC 5681): an acknowledgment is considered a + * "duplicate" when (a) the receiver of the ACK has outstanding data, + * (b) the incoming acknowledgment carries no data, (c) the SYN and + * FIN bits are both off, (d) the acknowledgment number is equal to + * the greatest acknowledgment received on the given connection + * and (e) the advertised window in the incoming acknowledgment equals + * the advertised window in the last incoming acknowledgment. + */ + + if (pstate->snd_acked < pstate->snd_sent && + (flags & TCP_NEWDATA) == 0 && + (tcp->flags & (TCP_SYN | TCP_FIN)) == 0 && + ackno == pstate->snd_prev_ack && + conn->snd_wnd == pstate->snd_prev_wnd) + { + if (++pstate->snd_dup_acks >= + CONFIG_NET_TCP_FAST_RETRANSMIT_WATERMARK) + { + flags |= TCP_REXMIT; + pstate->snd_dup_acks = 0; + } + } + else + { + pstate->snd_dup_acks = 0; + } + + pstate->snd_prev_ack = ackno; + pstate->snd_prev_wnd = conn->snd_wnd; } /* Check if we are being asked to retransmit data. - * This condition is located here after TCP_ACKDATA for performance reasons - * (TCP_REXMIT is less frequent than TCP_ACKDATA). + * This condition is located here (after TCP_ACKDATA and before + * TCP_DISCONN_EVENTS) for performance reasons. */ - else if ((flags & TCP_REXMIT) != 0) + if ((flags & TCP_REXMIT) != 0) { uint32_t sndlen;