Skip to content

Commit

Permalink
net/tcp: implement the fast retransmit
Browse files Browse the repository at this point in the history
RFC2001: TCP Slow Start, Congestion Avoidance, Fast Retransmit,
         and Fast Recovery Algorithms

...

3.  Fast Retransmit
  Modifications to the congestion avoidance algorithm were proposed in
  1990 [3].  Before describing the change, realize that TCP may
  generate an immediate acknowledgment (a duplicate ACK) when an out-
  of-order segment is received (Section 4.2.2.21 of [1], with a note
  that one reason for doing so was for the experimental fast-
  retransmit algorithm).  This duplicate ACK should not be delayed.
  The purpose of this duplicate ACK is to let the other end know that a
  segment was received out of order, and to tell it what sequence
  number is expected.

  Since TCP does not know whether a duplicate ACK is caused by a lost
  segment or just a reordering of segments, it waits for a small number
  of duplicate ACKs to be received.  It is assumed that if there is
  just a reordering of the segments, there will be only one or two
  duplicate ACKs before the reordered segment is processed, which will
  then generate a new ACK.  If three or more duplicate ACKs are
  received in a row, it is a strong indication that a segment has been
  lost.  TCP then performs a retransmission of what appears to be the
  missing segment, without waiting for a retransmission timer to
  expire.

Change-Id: Ie2cbcecab507c3d831f74390a6a85e0c5c8e0652
Signed-off-by: chao.an <anchao@xiaomi.com>
  • Loading branch information
anchao committed Nov 27, 2020
1 parent bcdee59 commit d049a89
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 0 deletions.
27 changes: 27 additions & 0 deletions net/tcp/Kconfig
Expand Up @@ -79,6 +79,33 @@ config NET_MAX_LISTENPORTS
---help---
Maximum number of listening TCP/IP ports (all tasks). Default: 20

config NET_TCP_FAST_RETRANSMIT_WATERMARK
int "WaterMark to trigger Fast Retransmission"
default 3
---help---
RFC2001:
3. Fast Retransmit
Modifications to the congestion avoidance algorithm were proposed in
1990 [3]. Before describing the change, realize that TCP may
generate an immediate acknowledgment (a duplicate ACK) when an out-
of-order segment is received (Section 4.2.2.21 of [1], with a note
that one reason for doing so was for the experimental fast-
retransmit algorithm). This duplicate ACK should not be delayed.
The purpose of this duplicate ACK is to let the other end know that a
segment was received out of order, and to tell it what sequence
number is expected.

Since TCP does not know whether a duplicate ACK is caused by a lost
segment or just a reordering of segments, it waits for a small number
of duplicate ACKs to be received. It is assumed that if there is
just a reordering of the segments, there will be only one or two
duplicate ACKs before the reordered segment is processed, which will
then generate a new ACK. If three or more duplicate ACKs are
received in a row, it is a strong indication that a segment has been
lost. TCP then performs a retransmission of what appears to be the
missing segment, without waiting for a retransmission timer to
expire.

config NET_TCP_NOTIFIER
bool "Support TCP notifications"
default n
Expand Down
2 changes: 2 additions & 0 deletions net/tcp/tcp.h
Expand Up @@ -79,6 +79,7 @@
# define TCP_WBPKTLEN(wrb) ((wrb)->wb_iob->io_pktlen)
# define TCP_WBSENT(wrb) ((wrb)->wb_sent)
# define TCP_WBNRTX(wrb) ((wrb)->wb_nrtx)
# define TCP_WBNACK(wrb) ((wrb)->wb_nack)
# define TCP_WBIOB(wrb) ((wrb)->wb_iob)
# define TCP_WBCOPYOUT(wrb,dest,n) (iob_copyout(dest,(wrb)->wb_iob,(n),0))
# define TCP_WBCOPYIN(wrb,src,n) \
Expand Down Expand Up @@ -299,6 +300,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 */
uint8_t wb_nack; /* The number of ack count */
struct iob_s *wb_iob; /* Head of the I/O buffer chain */
};
#endif
Expand Down
28 changes: 28 additions & 0 deletions net/tcp/tcp_send_buffered.c
Expand Up @@ -327,6 +327,7 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
{
FAR struct tcp_conn_s *conn = (FAR struct tcp_conn_s *)pvconn;
FAR struct socket *psock = (FAR struct socket *)pvpriv;
bool rexmit = false;

/* Check for a loss of connection */

Expand Down Expand Up @@ -484,6 +485,28 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
wrb, TCP_WBSEQNO(wrb), TCP_WBPKTLEN(wrb));
}
}
else if (ackno == TCP_WBSEQNO(wrb))
{
/* Duplicate ACK? Retransmit data if need */

TCP_WBNACK(wrb)++;

if (TCP_WBNACK(wrb) ==
CONFIG_NET_TCP_FAST_RETRANSMIT_WATERMARK)
{
/* Do fast retransmit */

rexmit = true;
}
else if ((TCP_WBNACK(wrb) >
CONFIG_NET_TCP_FAST_RETRANSMIT_WATERMARK) &&
TCP_WBNACK(wrb) == sq_count(&conn->unacked_q) - 1)
{
/* Reset the duplicate ack counter */

TCP_WBNACK(wrb) = 0;
}
}
}

/* A special case is the head of the write_q which may be partially
Expand Down Expand Up @@ -524,6 +547,11 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
/* Check if we are being asked to retransmit data */

else if ((flags & TCP_REXMIT) != 0)
{
rexmit = true;
}

if (rexmit)
{
FAR struct tcp_wrbuffer_s *wrb;
FAR sq_entry_t *entry;
Expand Down
4 changes: 4 additions & 0 deletions net/tcp/tcp_wrbuffer.c
Expand Up @@ -260,6 +260,10 @@ void tcp_wrbuffer_release(FAR struct tcp_wrbuffer_s *wrb)
iob_free_chain(wrb->wb_iob, IOBUSER_NET_TCP_WRITEBUFFER);
}

/* Reset the ack counter */

TCP_WBNACK(wrb) = 0;

/* Then free the write buffer structure */

sq_addlast(&wrb->wb_node, &g_wrbuffer.freebuffers);
Expand Down

0 comments on commit d049a89

Please sign in to comment.