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/06/16 10:14:34 UTC

[incubator-nuttx] branch master updated: net/tcp(buffered): retransmit only one the earliest not acknowledged segment

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 669fb83706 net/tcp(buffered): retransmit only one the earliest not acknowledged segment
669fb83706 is described below

commit 669fb83706c5ee8c93b78e685dba794d28786211
Author: chao.an <an...@xiaomi.com>
AuthorDate: Thu Jun 16 14:55:36 2022 +0800

    net/tcp(buffered): retransmit only one the earliest not acknowledged segment
    
    Retransmit only one the earliest not acknowledged segment
    (according to RFC 6298 (5.4)). The issue is the same as it was
    in tcp_send_unbuffered.c and tcp_sendfile.c.
    
    Signed-off-by: chao.an <an...@xiaomi.com>
---
 net/tcp/tcp.h               |  3 --
 net/tcp/tcp_appsend.c       | 29 ++++++---------
 net/tcp/tcp_send_buffered.c | 86 ++++++++++++++++++++++++++++++++++++++-------
 3 files changed, 85 insertions(+), 33 deletions(-)

diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h
index c11550d742..78147ed352 100644
--- a/net/tcp/tcp.h
+++ b/net/tcp/tcp.h
@@ -175,10 +175,7 @@ struct tcp_conn_s
   uint8_t  rcvseq[4];     /* The sequence number that we expect to
                            * receive next */
   uint8_t  sndseq[4];     /* The sequence number that was last sent by us */
-#if !defined(CONFIG_NET_TCP_WRITE_BUFFERS) || \
-    defined(CONFIG_NET_SENDFILE)
   uint32_t rexmit_seq;    /* The sequence number to be retrasmitted */
-#endif
   uint8_t  crefs;         /* Reference counts on this instance */
 #if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
   uint8_t  domain;        /* IP domain: PF_INET or PF_INET6 */
diff --git a/net/tcp/tcp_appsend.c b/net/tcp/tcp_appsend.c
index 1e8e58dbc2..39b120f3d8 100644
--- a/net/tcp/tcp_appsend.c
+++ b/net/tcp/tcp_appsend.c
@@ -322,30 +322,23 @@ void tcp_rexmit(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
    * new data in it, we must send out a packet.
    */
 
-#if defined(CONFIG_NET_TCP_WRITE_BUFFERS) && defined(CONFIG_NET_SENDFILE)
-  if (conn->sendfile)
-#endif
+  if ((result & TCP_REXMIT) != 0 &&
+      dev->d_sndlen > 0 && conn->tx_unacked > 0)
     {
-#if !defined(CONFIG_NET_TCP_WRITE_BUFFERS) || defined(CONFIG_NET_SENDFILE)
-      if ((result & TCP_REXMIT) != 0 &&
-          dev->d_sndlen > 0 && conn->tx_unacked > 0)
-        {
-          uint32_t saveseq;
+      uint32_t saveseq;
 
-          /* According to RFC 6298 (5.4), retransmit the earliest segment
-           * that has not been acknowledged by the TCP receiver.
-           */
+      /* According to RFC 6298 (5.4), retransmit the earliest segment
+       * that has not been acknowledged by the TCP receiver.
+       */
 
-          saveseq = tcp_getsequence(conn->sndseq);
-          tcp_setsequence(conn->sndseq, conn->rexmit_seq);
+      saveseq = tcp_getsequence(conn->sndseq);
+      tcp_setsequence(conn->sndseq, conn->rexmit_seq);
 
-          tcp_send(dev, conn, TCP_ACK | TCP_PSH, dev->d_sndlen + hdrlen);
+      tcp_send(dev, conn, TCP_ACK | TCP_PSH, dev->d_sndlen + hdrlen);
 
-          tcp_setsequence(conn->sndseq, saveseq);
+      tcp_setsequence(conn->sndseq, saveseq);
 
-          return;
-        }
-#endif
+      return;
     }
 
 #if defined(CONFIG_NET_TCP_WRITE_BUFFERS)
diff --git a/net/tcp/tcp_send_buffered.c b/net/tcp/tcp_send_buffered.c
index c5aac33db8..d00962c8ae 100644
--- a/net/tcp/tcp_send_buffered.c
+++ b/net/tcp/tcp_send_buffered.c
@@ -323,7 +323,9 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
    */
 
   FAR struct tcp_conn_s *conn = pvpriv;
-  bool rexmit = false;
+#ifdef CONFIG_NET_TCP_FAST_RETRANSMIT
+  uint32_t rexmitno = 0;
+#endif
 
   /* Get the TCP connection pointer reliably from
    * the corresponding TCP socket.
@@ -501,12 +503,9 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
                 {
                   /* Do fast retransmit */
 
-                  rexmit = true;
-                }
-              else if ((TCP_WBNACK(wrb) > TCP_FAST_RETRANSMISSION_THRESH) &&
-                       TCP_WBNACK(wrb) == sq_count(&conn->unacked_q) - 1)
-                {
-                  /* Reset the duplicate ack counter */
+                  rexmitno = ackno;
+
+                  /* Reset counter */
 
                   TCP_WBNACK(wrb) = 0;
                 }
@@ -573,14 +572,77 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
       return flags;
     }
 
-  /* Check if we are being asked to retransmit data */
-
-  else if ((flags & TCP_REXMIT) != 0)
+#ifdef CONFIG_NET_TCP_FAST_RETRANSMIT
+  if (rexmitno != 0)
     {
-      rexmit = true;
+      FAR struct tcp_wrbuffer_s *wrb;
+      FAR sq_entry_t *entry;
+      FAR sq_entry_t *next;
+      size_t sndlen;
+
+      /* According to RFC 6298 (5.4), retransmit the earliest segment
+       * that has not been acknowledged by the TCP receiver.
+       */
+
+      for (entry = sq_peek(&conn->unacked_q); entry; entry = next)
+        {
+          wrb = (FAR struct tcp_wrbuffer_s *)entry;
+          next = sq_next(entry);
+
+          if (rexmitno != TCP_WBSEQNO(wrb))
+            {
+              continue;
+            }
+
+          conn->rexmit_seq = rexmitno;
+
+          /* Reconstruct the length of the earliest segment to be
+           * retransmitted.
+           */
+
+          sndlen = TCP_WBPKTLEN(wrb);
+
+          if (sndlen > conn->mss)
+            {
+              sndlen = conn->mss;
+            }
+
+          /* As we are retransmitting, the sequence number is expected
+           * already set for this write buffer.
+           */
+
+          DEBUGASSERT(TCP_WBSEQNO(wrb) != (unsigned)-1);
+          conn->rexmit_seq = TCP_WBSEQNO(wrb);
+
+#ifdef NEED_IPDOMAIN_SUPPORT
+          /* If both IPv4 and IPv6 support are enabled, then we will need to
+           * select which one to use when generating the outgoing packet.
+           * If only one domain is selected, then the setup is already in
+           * place and we need do nothing.
+           */
+
+          send_ipselect(dev, conn);
+#endif
+          /* Then set-up to send that amount of data. (this won't actually
+           * happen until the polling cycle completes).
+           */
+
+          devif_iob_send(dev, TCP_WBIOB(wrb), sndlen, 0);
+
+          /* Reset the retransmission timer. */
+
+          tcp_update_retrantimer(conn, conn->rto);
+
+          /* Continue waiting */
+
+          return flags;
+        }
     }
+#endif
+
+  /* Check if we are being asked to retransmit data */
 
-  if (rexmit)
+  if ((flags & TCP_REXMIT) != 0)
     {
       FAR struct tcp_wrbuffer_s *wrb;
       FAR sq_entry_t *entry;