Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net/tcp: implement the fast retransmit #2414

Merged
merged 1 commit into from Dec 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
26 changes: 26 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,26 @@ 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 */

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)
xiaoxiang781216 marked this conversation as resolved.
Show resolved Hide resolved
{
/* 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 +545,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