You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2022/01/02 15:25:22 UTC

[incubator-nuttx] branch master updated: net/tcp(unbuffered): fast retransmit on duplicate acknowledgments

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 0afb1d8  net/tcp(unbuffered): fast retransmit on duplicate acknowledgments
0afb1d8 is described below

commit 0afb1d8dbb14c30660a64761fd3b0aaa8e5101a5
Author: Alexander Lunev <al...@mail.ru>
AuthorDate: Sun Jan 2 07:15:57 2022 +0300

    net/tcp(unbuffered): fast retransmit on duplicate acknowledgments
---
 net/tcp/tcp_send_unbuffered.c | 60 +++++++++++++++++++++++++++++++++++--------
 1 file changed, 49 insertions(+), 11 deletions(-)

diff --git a/net/tcp/tcp_send_unbuffered.c b/net/tcp/tcp_send_unbuffered.c
index d2e0aa1..01f5055 100644
--- a/net/tcp/tcp_send_unbuffered.c
+++ b/net/tcp/tcp_send_unbuffered.c
@@ -80,14 +80,23 @@
 
 struct send_s
 {
-  FAR struct socket      *snd_sock;    /* Points to the parent socket structure */
-  FAR struct devif_callback_s *snd_cb; /* Reference to callback instance */
-  sem_t                   snd_sem;     /* Used to wake up the waiting thread */
-  FAR const uint8_t      *snd_buffer;  /* Points to the buffer of data to send */
-  size_t                  snd_buflen;  /* Number of bytes in the buffer to send */
-  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 */
+  FAR struct socket      *snd_sock;     /* Points to the parent socket structure */
+  FAR struct devif_callback_s *snd_cb;  /* Reference to callback instance */
+  sem_t                   snd_sem;      /* Used to wake up the waiting thread */
+  FAR const uint8_t      *snd_buffer;   /* Points to the buffer of data to send */
+  size_t                  snd_buflen;   /* Number of bytes in the buffer to send */
+  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 */
 };
 
 /****************************************************************************
@@ -183,6 +192,7 @@ static uint16_t tcpsend_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 */
@@ -213,7 +223,8 @@ static uint16_t tcpsend_eventhandler(FAR struct net_driver_s *dev,
        * of bytes to be acknowledged.
        */
 
-      pstate->snd_acked = TCP_SEQ_SUB(tcp_getsequence(tcp->ackno),
+      ackno = tcp_getsequence(tcp->ackno);
+      pstate->snd_acked = TCP_SEQ_SUB(ackno,
                                       pstate->snd_isn);
       ninfo("ACK: acked=%" PRId32 " sent=%zd buflen=%zd\n",
             pstate->snd_acked, pstate->snd_sent, pstate->snd_buflen);
@@ -229,12 +240,39 @@ static uint16_t tcpsend_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;
+            }
+        }
+      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 */
 
-  else if ((flags & TCP_REXMIT) != 0)
+  if ((flags & TCP_REXMIT) != 0)
     {
       /* According to RFC 6298 (5.4), retransmit the earliest segment
        * that has not been acknowledged by the TCP receiver.