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

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


The following commit(s) were added to refs/heads/master by this push:
     new f61dc72892  net/tcp:Add NewReno congestion control.
f61dc72892 is described below

commit f61dc728927b1c61ccbb277cee08fdbb3a8df8b7
Author: liqinhui <liqin...@xiaomi.com>
AuthorDate: Thu Apr 20 11:08:02 2023 +0800

     net/tcp:Add NewReno congestion control.
    
    - NewReno congestion control algorithm is used to solve the problem
      of network congestion breakdown. NewReno congestion control includes
      slow start, collision avoidance, fast retransmission, and fast
      recovery. The implementation refers to RFC6582 and RFC5681.
    
    - In addition, we optimize the congestion algorithm. In the conflict
      avoidance stage, the maximum congestion window max_cwnd is used to
      limit the excessive growth of cwnd and prevent network jitter
      caused by congestion. Maximum congestion window max_cwnd is updated
      with the current congestion window cwnd and the update weight is
      0.875 when an RTO timeout occurs.
    
    Signed-off-by: liqinhui <liqin...@xiaomi.com>
---
 Documentation/reference/os/newreno.rst | 172 +++++++++++++++++++
 net/tcp/Kconfig                        |   9 +
 net/tcp/Make.defs                      |   6 +
 net/tcp/tcp.h                          |  85 +++++++++-
 net/tcp/tcp_cc.c                       | 301 +++++++++++++++++++++++++++++++++
 net/tcp/tcp_conn.c                     |  12 ++
 net/tcp/tcp_input.c                    |  11 ++
 net/tcp/tcp_send_buffered.c            |  40 ++++-
 net/tcp/tcp_timer.c                    |  19 +++
 net/tcp/tcp_wrbuffer.c                 |   2 +-
 10 files changed, 652 insertions(+), 5 deletions(-)

diff --git a/Documentation/reference/os/newreno.rst 
b/Documentation/reference/os/newreno.rst
new file mode 100644
index 0000000000..7f238e5a60
--- /dev/null
+++ b/Documentation/reference/os/newreno.rst
@@ -0,0 +1,172 @@
+==========================
+Congestion Control NewReno
+==========================
+
+NewReno congestion control algorithm is used to solve the problem of network 
congestion breakdown, which includes:
+ - Slow Start
+ - Congestion Avoidance
+ - Fast Retransmission
+ - Fast Recovery.
+
+ The implementation refers to RFC6582 and RFC5681. In addition, we optimize 
the congestion algorithm. In the congestion avoidance state, the maximum 
congestion window (max_cwnd) is used to limit the excessive growth of cwnd and 
prevent network jitter caused by congestion. Maximum congestion window 
(max_cwnd) is updated with the current congestion window (cwnd) and the update 
weight is 0.875 when an RTO timeout occurs.
+
+Workflow
+========
+
+
+The NewReno on the tcp sender adjusts the cwnd and ssthresh based on received 
ack and Retransmitted Timeout (RTO) events.
+
+Using the cwnd, together with snd_wnd, controls the number of bytes sent to 
the network. Here's how newreno works, as following:
+
+- Initialize the ssthresh and cwnd, on establishing the tcp connection.
+- When the ack is received, check whether the ack is repeated.
+
+ + If yes, increase the dupack counts. If the dupack exceeds the Fast 
Retransmission Threshold 3, after retransmitting the lost segments (Fast 
Retransmission), enter to  the Fast Recovery state.
+ + If no, receive the new ack.
+
+   * If the current ackno is bigger than fr_ack which is the snd_seq when Fast 
Retransmission ocurrs, exit the Fast Recovery state and enter to congestion 
avoidance.
+   * If the cwnd is less than ssthresh, increase the cwnd on slow start state.
+   * If the cwnd is greater than or equal to ssthresh, the increased cwnd can 
not exceed max_cwnd.
+
+- when RTO times out, reset the values of cwnd and ssthresh, update the 
max_cwnd, and enter to Slow Start state.
+- When sending a segment, the minimum value of cwnd and snd_wnd is used to 
calculate the number of bytes that can be sent.
+
+The simple state transition diagram of the NewReno is shown below.
+
+::
+
+                                    |           ^
+                                    | ------------------------
+                                    | initialize cwnd ssthresh
+                                    V
+                              +------------+
+             .--------------->| Slow Start |-----------------.
+             |                +------------+                 |
+             |                     |  |                      |
+             |    timeout          |  |  recv dup ack        | recv new ack
+             |------------------   |  |  ---------------     | ----------------
+             |reset cwnd ssthresh  |  |  dupack >= 3         | cwnd >= ssthresh
+             |update max_cwnd      |  |  fr_ack = snd_seq    |
+             |<--------------------'  |<------------------.  |
+             |                        |                   |  |
+             |                        v                   |  V
+             |                    +--------+     +--------------------+
+             |                    |   FT   |     |Congestion Avoidance|
+             |                    +--------+     +--------------------+
+             |                        |                   ^  |
+             |              retransmit|lost segment       |  |
+             |                        |                   |  |
+             |                        |      recv new ack |  |
+             |                        v      ------------ |  |
+             |                    +--------+ ack > fr_ack |  |
+             |                    |   FR   |--------------'  |
+             |                    +--------+                 |
+             |                        |                      |
+             |                        v                      v
+             '-----------------------------------------------'
+
+Configuration Options
+=====================
+``NET_TCP_CC_NEWRENO``
+  Enable or disable NewRenofunction.
+
+  Depends on ``NET_TCP_FAST_RETRANSMIT``.
+
+Test
+====
+
+
+Test topology
+-------------
+
+::
+
+                         IP:10.0.1.1
+
+                         +--------+
+                 --------| nuttx0 |--------
+                 |       +--------+       |
+                 |          /|\           |
+                 |           |            |
+                 |       +-------+        |
+                 |       | ifb0  |        |
+                 |       +-------+        |
+                \|/         /|\          \|/
+             +-------+       |        +-------+
+             | tap0  |------/ \-------| tap1  |
+             +-------+                +-------+
+                /|\                      /|\
+                 |                        |
+                \|/                      \|/
+             +-------+                +-------+
+        sim1 | eth0  |                | eth0  | sim2
+             +-------+                +-------+
+
+             IP:10.0.1.3              IP:10.0.1.4
+
+Test steps
+----------
+
+Test the function on the Ubuntu 22.04 x86_64 with NuttX SIM by following steps:
+
+:1.Configure the test environment:
+
+- Set the nuttx0 inbound speed to 10Mbps.
+
+ ..  code-block:: bash
+
+    # Load fib module, and start ifb0 interface
+    modprobe ifb
+    ip link set dev ifb0 up
+
+    # Import the nuttx0 ingress packets into ifb0
+    tc qdisc add dev nuttx0 handle ffff: ingress
+    tc filter add dev nuttx0 parent ffff: u32 match u32 0 0 action mirred 
egress redirect dev ifb0
+
+    # Limit nuttx0 ingress 10Mbps
+    tc qdisc add dev ifb0 root tbf rate 10Mbit latency 50ms burst 1540
+
+- configure the sim simulator.
+
+ + Start iperf3 server on ubuntu.
+
+ ..  code-block:: bash
+
+     iperf3 -s -i1 -p10003  #for sim1
+     iperf3 -s -i1 -p10004  #for sim2
+
+
+ + start the emulators sim1 and sim2 and configure ip addresses.
+
+ ..  code-block:: bash
+
+  # start and configure sim1
+  start gdb nuttx
+  ifconfig eth0 10.0.1.3
+
+  # start and configure sim2
+  start gdb nuttx
+  ifconfig eth0 10.0.1.4 # sim2
+
+
+:2.Stream Testing:
+
+
+- Use iperf3 to perform the stream testing.
+
+ ..  code-block:: bash
+
+  iperf3 -c 10.0.1.1 -i1 -t60 -p10003 # sim1
+
+  iperf3 -c 10.0.1.1 -i1 -t60 -p10004 # sim2
+
+
+:3.Comparison Testing:
+
+ Compares the test results of enabling and disabling NewReno.
+
+
+Test results
+------------
+
+ The test results should indicate that the total network throughput was 
significantly increased when NewReno congestion control was enabled, which was 
close to the actual total network bandwidth, and the rates of both sim devices 
were stable.
diff --git a/net/tcp/Kconfig b/net/tcp/Kconfig
index 996f98ffad..d287271911 100644
--- a/net/tcp/Kconfig
+++ b/net/tcp/Kconfig
@@ -149,6 +149,15 @@ config NET_TCP_FAST_RETRANSMIT
                        missing segment, without waiting for a retransmission 
timer to
                        expire.
 
+config NET_TCP_CC_NEWRENO
+       bool "Enable the NewReno Congestion Control algorithm"
+       default n
+       select NET_TCP_FAST_RETRANSMIT
+       ---help---
+               RFC5681:
+                       The TCP Congestion Control defines four congestion 
control algorithms,
+                       slow start, congestion avoidance, fast retransmit, and 
fast recovery.
+
 config NET_TCP_WINDOW_SCALE
        bool "Enable TCP/IP Window Scale Option"
        default n
diff --git a/net/tcp/Make.defs b/net/tcp/Make.defs
index faa03db524..2adbc976fe 100644
--- a/net/tcp/Make.defs
+++ b/net/tcp/Make.defs
@@ -61,6 +61,12 @@ ifeq ($(CONFIG_NET_TCP_WRITE_BUFFERS),y)
 NET_CSRCS += tcp_wrbuffer.c
 endif
 
+# TCP congestion control
+
+ifeq ($(CONFIG_NET_TCP_CC_NEWRENO),y)
+NET_CSRCS += tcp_cc.c
+endif
+
 # TCP debug
 
 ifeq ($(CONFIG_DEBUG_FEATURES),y)
diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h
index 0d0acd7356..255dbe4c96 100644
--- a/net/tcp/tcp.h
+++ b/net/tcp/tcp.h
@@ -71,7 +71,7 @@
 #  define TCP_WBPKTLEN(wrb)          ((wrb)->wb_iob->io_pktlen)
 #  define TCP_WBSENT(wrb)            ((wrb)->wb_sent)
 #  define TCP_WBNRTX(wrb)            ((wrb)->wb_nrtx)
-#ifdef CONFIG_NET_TCP_FAST_RETRANSMIT
+#if defined(CONFIG_NET_TCP_FAST_RETRANSMIT) && 
!defined(CONFIG_NET_TCP_CC_NEWRENO)
 #  define TCP_WBNACK(wrb)            ((wrb)->wb_nack)
 #endif
 #  define TCP_WBIOB(wrb)             ((wrb)->wb_iob)
@@ -107,6 +107,14 @@
 #define TCP_WSCALE            0x01U /* Window Scale option enabled */
 #define TCP_SACK              0x02U /* Selective ACKs enabled */
 
+#ifdef CONFIG_NET_TCP_CC_NEWRENO
+/* The TCP flags for congestion control */
+
+#define TCP_INFR              0x04U /* The flag in Fast Recovery */
+#define TCP_INFT              0x08U /* The flag in Fast Transmitted */
+
+#endif
+
 /* The Max Range count of TCP Selective ACKs */
 
 #define TCP_SACK_RANGES_MAX   4
@@ -234,6 +242,15 @@ struct tcp_conn_s
                            * connection */
 #endif
   uint32_t rcv_adv;       /* The right edge of the recv window advertized */
+#ifdef CONFIG_NET_TCP_CC_NEWRENO
+  uint32_t last_ackno;    /* The ack number at the last receive ack */
+  uint32_t dupacks;       /* The number of duplicate ack */
+  uint32_t fr_recover;    /* The snd_seq at the retransmissions */
+
+  uint32_t cwnd;          /* The Congestion window */
+  uint32_t max_cwnd;      /* The Congestion window maximum value */
+  uint32_t ssthresh;      /* The Slow start threshold */
+#endif
 #ifdef CONFIG_NET_TCP_WINDOW_SCALE
   uint32_t snd_wnd;       /* Sequence and acknowledgement numbers of last
                            * window update */
@@ -389,7 +406,7 @@ struct tcp_wrbuffer_s
   uint16_t   wb_sent;      /* Number of bytes sent from the I/O buffer chain */
   uint8_t    wb_nrtx;      /* The number of retransmissions for the last
                             * segment sent */
-#ifdef CONFIG_NET_TCP_FAST_RETRANSMIT
+#if defined(CONFIG_NET_TCP_FAST_RETRANSMIT) && 
!defined(CONFIG_NET_TCP_CC_NEWRENO)
   uint8_t    wb_nack;      /* The number of ack count */
 #endif
   struct iob_s *wb_iob;    /* Head of the I/O buffer chain */
@@ -2234,6 +2251,70 @@ int tcp_ofoseg_bufsize(FAR struct tcp_conn_s *conn);
 
 bool tcp_reorder_ofosegs(int nofosegs, FAR struct tcp_ofoseg_s *ofosegs);
 
+/****************************************************************************
+ * Name: tcp_cc_init
+ *
+ * Description:
+ *   Initialize the congestion control variables, cwnd, ssthresh and dupacks.
+ *   The function is called on starting a new connection.
+ *
+ * Input Parameters:
+ *   conn   - The TCP connection of interest
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   The normal user level code is calling the connect/accept to start a new
+ *   connection.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_TCP_CC_NEWRENO
+void tcp_cc_init(FAR struct tcp_conn_s *conn);
+
+/****************************************************************************
+ * Name: tcp_cc_update
+ *
+ * Description:
+ *   Update the congestion control variables when recieve the SYNACK/ACK
+ *   packet from the peer in the connection phase.
+ *
+ * Input Parameters:
+ *   conn   - The TCP connection of interest
+ *   tcp    - The TCP header.
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+void tcp_cc_update(FAR struct tcp_conn_s *conn, FAR struct tcp_hdr_s *tcp);
+
+/****************************************************************************
+ * Name: tcp_cc_recv_ack
+ *
+ * Description:
+ *   Update congestion control variables
+ *
+ * Input Parameters:
+ *   conn   - The TCP connection of interest
+ *   tcp    - The TCP header.
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+void tcp_cc_recv_ack(FAR struct tcp_conn_s *conn, FAR struct tcp_hdr_s *tcp);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/net/tcp/tcp_cc.c b/net/tcp/tcp_cc.c
new file mode 100644
index 0000000000..b143acd732
--- /dev/null
+++ b/net/tcp/tcp_cc.c
@@ -0,0 +1,301 @@
+/****************************************************************************
+ * net/tcp/tcp_cc.c
+ * Handling TCP congestion control
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <debug.h>
+
+#include "tcp/tcp.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define TCP_IPV4_DEFAULT_MSS 536
+
+/* Initial Window threshold constants */
+
+#define IW_MAX 4380          /* Initial Window maximum */
+#define IW_MAX_HALF 2190
+#define IW_MAX_QUATER 1095
+
+/* Calculate the Initial Window, also used as Restart Window
+ * RFC5681 Section 3.1 specifies the default conservative values.
+ */
+
+#define CC_INIT_CWND(cwnd, mss) \
+ do { \
+  if ((mss) > IW_MAX_HALF) \
+    { \
+      (cwnd) = 2 * (mss); \
+    } \
+  else if ((mss) > IW_MAX_QUATER) \
+    { \
+      (cwnd) = 3 * (mss); \
+    } \
+  else \
+    { \
+      (cwnd) = 4 * (mss); \
+    } \
+ } while(0)
+
+/* Increments a size inc and holds at max value rather than rollover. */
+
+#define CC_CWND_INC(wnd, inc) \
+ do { \
+  if ((uint32_t)((wnd) + (inc)) >= (wnd)) \
+    { \
+      (wnd) = (uint32_t)((wnd) + (inc)); \
+    } \
+  else \
+    { \
+      (wnd) = (uint32_t)-1; \
+    } \
+ } while(0)
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: tcp_cc_init
+ *
+ * Description:
+ *   Initialize the congestion control variables, cwnd, ssthresh and dupacks.
+ *   The function is called on starting a new connection.
+ *
+ * Input Parameters:
+ *   conn   - The TCP connection of interest
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   The normal user level code is calling the connect/accept to start a new
+ *   connection.
+ *
+ ****************************************************************************/
+
+void tcp_cc_init(FAR struct tcp_conn_s *conn)
+{
+  CC_INIT_CWND(conn->cwnd, conn->mss);
+
+  /* RFC 5681 recommends setting ssthresh arbitrarily high and
+   * gives an example of using the largest advertised receive window.
+   * We've seen complications with receiving TCPs that use window
+   * scaling and/or window auto-tuning where the initial advertised
+   * window is very small and then grows rapidly once the connection
+   * is established. To avoid these complications, we set ssthresh to
+   * the largest effective cwnd (amount of in-flight data) that the
+   * sender can have.
+   */
+
+  conn->ssthresh = 2 * TCP_IPV4_DEFAULT_MSS;
+  conn->dupacks = 0;
+}
+
+/****************************************************************************
+ * Name: tcp_cc_update
+ *
+ * Description:
+ *   Update the congestion control variables when recieve the SYNACK/ACK
+ *   packet from the peer in the connection phase.
+ *
+ * Input Parameters:
+ *   conn   - The TCP connection of interest
+ *   tcp    - The TCP header.
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+void tcp_cc_update(FAR struct tcp_conn_s *conn, FAR struct tcp_hdr_s *tcp)
+{
+  /* After Fast retransmitted, set ssthresh to the maximum of
+   * the unacked and the 2*SMSS, and enter to Fast Recovery.
+   * ssthresh = max (FlightSize / 2, 2*SMSS) referring to rfc5681
+   * cwnd=ssthresh + 3*SMSS  referring to rfc5681
+   */
+
+  if (conn->flags & TCP_INFT)
+    {
+      conn->ssthresh = MAX(conn->tx_unacked / 2, 2 * conn->mss);
+      conn->cwnd = conn->ssthresh + 3 * conn->mss;
+
+      conn->flags &= ~TCP_INFT;
+      conn->flags |= TCP_INFR;
+    }
+
+  /* Update the cc parameters in the TCP_SYN_RCVD and TCP_SYN_SENT states
+   * when the tcp connection is established.
+   */
+
+  else
+    {
+      conn->last_ackno = tcp_getsequence(tcp->ackno);
+      CC_INIT_CWND(conn->cwnd, conn->mss);
+      conn->max_cwnd = conn->snd_wnd;
+      conn->ssthresh = MAX(conn->snd_wnd, conn->ssthresh);
+    }
+}
+
+/****************************************************************************
+ * Name: tcp_cc_recv_ack
+ *
+ * Description:
+ *   Update congestion control variables
+ *
+ * Input Parameters:
+ *   conn   - The TCP connection of interest
+ *   tcp    - The TCP header.
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+void tcp_cc_recv_ack(FAR struct tcp_conn_s *conn, FAR struct tcp_hdr_s *tcp)
+{
+  uint32_t ackno = tcp_getsequence(tcp->ackno);
+
+  /* Its only a duplicate ack if:
+   * 1) It doesn't ACK new data
+   * 2) There is outstanding unacknowledged data (retransmission
+   *    timer running)
+   * 3) The ACK is == biggest ACK sequence number so far (last_ackno)
+   *
+   * If it passes all conditions, should process as a dupack:
+   * a) dupacks < 3: do nothing
+   * b) dupacks == 3: fast retransmit
+   * c) dupacks > 3: increase cwnd
+   *
+   * If ackno is between last_ackno and snd_seq, should reset dupack counter.
+   */
+
+  /* Clause 1 */
+
+  if (TCP_SEQ_LTE(ackno, conn->last_ackno))
+    {
+      /* Clause 2 and Clause 3 */
+
+      if (conn->timer >= 0 &&
+          conn->last_ackno == ackno)
+        {
+          if (++conn->dupacks > TCP_FAST_RETRANSMISSION_THRESH)
+            {
+              /* Inflate the congestion window */
+
+              CC_CWND_INC(conn->cwnd, conn->mss);
+            }
+
+          if (conn->dupacks >= TCP_FAST_RETRANSMISSION_THRESH)
+            {
+              /* Do fast retransmit, but it is delayed in
+               * psock_send_eventhandler. Set the TCP_INFT flag.
+               */
+
+              conn->flags |= TCP_INFT;
+              conn->fr_recover = tcp_getsequence(conn->sndseq);
+            }
+        }
+    }
+  else if (TCP_SEQ_GT(ackno, conn->last_ackno) &&
+           TCP_SEQ_LTE(ackno, tcp_getsequence(conn->sndseq)))
+    {
+      /* We come here when the ACK acknowledges new data. */
+
+      uint32_t acked = TCP_SEQ_SUB(ackno, conn->last_ackno);
+
+      /* Reset dupacks and update last_ackno. */
+
+      conn->dupacks = 0;
+      conn->last_ackno = ackno;
+
+      /* When the ackno covers more than the fr_recover, exit the
+       * fast recovery. Then, reset the "IN Fast Recovery" flags.
+       * Also reset the congestion window to the slow start threshold.
+       * If not, cwnd should be increased by mss. RFC6582.
+       */
+
+      if (conn->flags & TCP_INFR)
+        {
+          if (ackno - 1 > conn->fr_recover)
+            {
+              /* Reset the fast retransmit variables. */
+
+              conn->flags &= ~TCP_INFR;
+              conn->cwnd = conn->ssthresh;
+            }
+          else
+            {
+              CC_CWND_INC(conn->cwnd, conn->mss);
+              return;
+            }
+        }
+
+      /* Update the congestion control variables (cwnd and ssthresh). */
+
+      if (conn->tcpstateflags >= TCP_ESTABLISHED)
+        {
+          uint32_t increase;
+
+          if (conn->cwnd < conn->ssthresh)
+            {
+              /* slow start (RFC 5681):
+               * Grow cwnd exponentially by maxseg(smss) per ACK.
+               */
+
+              increase = acked > 0 ? MIN(acked, conn->mss) : conn->mss;
+
+              CC_CWND_INC(conn->cwnd, increase);
+              ninfo("update slow start cwnd to %u\n", conn->cwnd);
+            }
+          else
+            {
+              /* cong avoid (RFC 5681):
+               * Grow cwnd linearly by approximately maxseg per RTT using
+               * maxseg^2 / cwnd per ACK as the increment.
+               * If cwnd > maxseg^2, fix the cwnd increment at 1 byte to
+               * avoid capping cwnd.
+               */
+
+              increase = MAX((conn->mss * conn->mss / conn->cwnd), 1);
+
+              CC_CWND_INC(conn->cwnd, increase);
+              conn->cwnd = MIN(conn->cwnd, conn->max_cwnd);
+              ninfo("update congestion avoidance cwnd to %u\n", conn->cwnd);
+            }
+        }
+    }
+}
diff --git a/net/tcp/tcp_conn.c b/net/tcp/tcp_conn.c
index ef6a0d184c..e95f2a4ab7 100644
--- a/net/tcp/tcp_conn.c
+++ b/net/tcp/tcp_conn.c
@@ -1149,6 +1149,12 @@ FAR struct tcp_conn_s *tcp_alloc_accept(FAR struct 
net_driver_s *dev,
       conn->sndseq_max       = 0;
 #endif
 
+#ifdef CONFIG_NET_TCP_CC_NEWRENO
+      /* Initialize the variables of congestion control */
+
+      tcp_cc_init(conn);
+#endif
+
       /* rcvseq should be the seqno from the incoming packet + 1. */
 
       memcpy(conn->rcvseq, tcp->seqno, 4);
@@ -1449,6 +1455,12 @@ int tcp_connect(FAR struct tcp_conn_s *conn, FAR const 
struct sockaddr *addr)
   conn->sndseq_max = 0;
 #endif
 
+#ifdef CONFIG_NET_TCP_CC_NEWRENO
+  /* Initialize the variables of congestion control. */
+
+  tcp_cc_init(conn);
+#endif
+
   /* Initialize the list of TCP read-ahead buffers */
 
   conn->readahead = NULL;
diff --git a/net/tcp/tcp_input.c b/net/tcp/tcp_input.c
index a4f0786eef..fd3a128239 100644
--- a/net/tcp/tcp_input.c
+++ b/net/tcp/tcp_input.c
@@ -1160,6 +1160,11 @@ found:
   if ((tcp->flags & TCP_ACK) != 0 &&
       (conn->tcpstateflags & TCP_STATE_MASK) != TCP_SYN_RCVD)
     {
+#ifdef CONFIG_NET_TCP_CC_NEWRENO
+      /* If the packet is ack, update the cc var. */
+
+      tcp_cc_recv_ack(conn, tcp);
+#endif
       if (tcp_snd_wnd_update(conn, tcp))
         {
           /* Window updated, set the acknowledged flag. */
@@ -1230,6 +1235,9 @@ found:
             tcp_snd_wnd_init(conn, tcp);
             tcp_snd_wnd_update(conn, tcp);
 
+#ifdef CONFIG_NET_TCP_CC_NEWRENO
+            tcp_cc_update(conn, tcp);
+#endif
             flags               = TCP_CONNECTED;
             ninfo("TCP state: TCP_ESTABLISHED\n");
 
@@ -1279,6 +1287,9 @@ found:
             tcp_snd_wnd_init(conn, tcp);
             tcp_snd_wnd_update(conn, tcp);
 
+#ifdef CONFIG_NET_TCP_CC_NEWRENO
+            tcp_cc_update(conn, tcp);
+#endif
             net_incr32(conn->rcvseq, 1); /* ack SYN */
             conn->tx_unacked    = 0;
 
diff --git a/net/tcp/tcp_send_buffered.c b/net/tcp/tcp_send_buffered.c
index 144484310d..f81b0895dc 100644
--- a/net/tcp/tcp_send_buffered.c
+++ b/net/tcp/tcp_send_buffered.c
@@ -584,6 +584,9 @@ static uint16_t psock_send_eventhandler(FAR struct 
net_driver_s *dev,
             }
           else if (ackno == TCP_WBSEQNO(wrb))
             {
+#ifdef CONFIG_NET_TCP_CC_NEWRENO
+              if (conn->dupacks >= TCP_FAST_RETRANSMISSION_THRESH)
+#else
               /* Reset the duplicate ack counter */
 
               if ((flags & TCP_NEWDATA) != 0)
@@ -594,6 +597,7 @@ static uint16_t psock_send_eventhandler(FAR struct 
net_driver_s *dev,
               /* Duplicate ACK? Retransmit data if need */
 
               if (++TCP_WBNACK(wrb) == TCP_FAST_RETRANSMISSION_THRESH)
+#endif
                 {
 #ifdef CONFIG_NET_TCP_SELECTIVE_ACK
                   if ((conn->flags & TCP_SACK) &&
@@ -614,11 +618,12 @@ static uint16_t psock_send_eventhandler(FAR struct 
net_driver_s *dev,
                       /* Do fast retransmit */
 
                       rexmitno = ackno;
-#endif
-
+#ifndef CONFIG_NET_TCP_CC_NEWRENO
                       /* Reset counter */
 
                       TCP_WBNACK(wrb) = 0;
+#endif
+#endif
                     }
                 }
             }
@@ -744,6 +749,19 @@ static uint16_t psock_send_eventhandler(FAR struct 
net_driver_s *dev,
               return flags;
             }
 
+#ifdef CONFIG_NET_TCP_CC_NEWRENO
+          /* After Fast retransmitted, set ssthresh to the maximum of
+           * the unacked and the 2*SMSS, and enter to Fast Recovery.
+           * ssthresh = max (FlightSize / 2, 2*SMSS) referring to rfc5681
+           * cwnd=ssthresh + 3*SMSS  referring to rfc5681
+           */
+
+          if (conn->flags & TCP_INFT)
+            {
+              tcp_cc_update(conn, NULL);
+            }
+#endif
+
           /* Reset the retransmission timer. */
 
           tcp_update_retrantimer(conn, conn->rto);
@@ -802,6 +820,19 @@ static uint16_t psock_send_eventhandler(FAR struct 
net_driver_s *dev,
               right = ofosegs[i].right;
             }
         }
+
+#ifdef CONFIG_NET_TCP_CC_NEWRENO
+          /* After Fast retransmitted, set ssthresh to the maximum of
+           * the unacked and the 2*SMSS, and enter to Fast Recovery.
+           * ssthresh = max (FlightSize / 2, 2*SMSS) referring to rfc5681
+           * cwnd=ssthresh + 3*SMSS  referring to rfc5681
+           */
+
+          if (conn->flags & TCP_INFT)
+            {
+              tcp_cc_update(conn, NULL);
+            }
+#endif
     }
   else
 #endif
@@ -965,7 +996,12 @@ static uint16_t psock_send_eventhandler(FAR struct 
net_driver_s *dev,
        */
 
       seq = TCP_WBSEQNO(wrb) + TCP_WBSENT(wrb);
+
+#ifdef CONFIG_NET_TCP_CC_NEWRENO
+      snd_wnd_edge = conn->snd_wl2 + MIN(conn->snd_wnd, conn->cwnd);
+#else
       snd_wnd_edge = conn->snd_wl2 + conn->snd_wnd;
+#endif
       if (TCP_SEQ_LT(seq, snd_wnd_edge))
         {
           uint32_t remaining_snd_wnd;
diff --git a/net/tcp/tcp_timer.c b/net/tcp/tcp_timer.c
index de3ed740a1..591c884e12 100644
--- a/net/tcp/tcp_timer.c
+++ b/net/tcp/tcp_timer.c
@@ -567,6 +567,25 @@ void tcp_timer(FAR struct net_driver_s *dev, FAR struct 
tcp_conn_s *conn)
 
                     result = tcp_callback(dev, conn, TCP_REXMIT);
                     tcp_rexmit(dev, conn, result);
+
+#ifdef CONFIG_NET_TCP_CC_NEWRENO
+                    /* If conn is TCP_INFR, it should enter to slow start */
+
+                    if (conn->flags & TCP_INFR)
+                      {
+                        conn->flags &= ~TCP_INFR;
+                      }
+
+                    /* update the max_cwnd */
+
+                    conn->max_cwnd = (conn->max_cwnd + 7 * conn->cwnd) >> 3;
+
+                    /* reset cwnd and ssthresh, refers to RFC5861. */
+
+                    conn->ssthresh =
+                                    MAX(conn->tx_unacked / 2, 2 * conn->mss);
+                    conn->cwnd = conn->mss;
+#endif
                     goto done;
 
                   case TCP_FIN_WAIT_1:
diff --git a/net/tcp/tcp_wrbuffer.c b/net/tcp/tcp_wrbuffer.c
index 7501e4b382..686f025503 100644
--- a/net/tcp/tcp_wrbuffer.c
+++ b/net/tcp/tcp_wrbuffer.c
@@ -236,7 +236,7 @@ void tcp_wrbuffer_release(FAR struct tcp_wrbuffer_s *wrb)
       iob_free_chain(wrb->wb_iob);
     }
 
-#ifdef CONFIG_NET_TCP_FAST_RETRANSMIT
+#if defined(CONFIG_NET_TCP_FAST_RETRANSMIT) && 
!defined(CONFIG_NET_TCP_CC_NEWRENO)
   /* Reset the ack counter */
 
   TCP_WBNACK(wrb) = 0;

Reply via email to