forked from nuttx/nuttx-update
net/tcp: implement the fast retransmit
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>
This commit is contained in:
parent
19941b14b0
commit
c2b0006dcd
4 changed files with 59 additions and 0 deletions
|
@ -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
|
||||
|
|
|
@ -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) \
|
||||
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
/* Reset the duplicate ack counter */
|
||||
|
||||
TCP_WBNACK(wrb) = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* A special case is the head of the write_q which may be partially
|
||||
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue