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
@ -79,6 +79,33 @@ config NET_MAX_LISTENPORTS
|
|||||||
---help---
|
---help---
|
||||||
Maximum number of listening TCP/IP ports (all tasks). Default: 20
|
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
|
config NET_TCP_NOTIFIER
|
||||||
bool "Support TCP notifications"
|
bool "Support TCP notifications"
|
||||||
default n
|
default n
|
||||||
|
@ -79,6 +79,7 @@
|
|||||||
# define TCP_WBPKTLEN(wrb) ((wrb)->wb_iob->io_pktlen)
|
# define TCP_WBPKTLEN(wrb) ((wrb)->wb_iob->io_pktlen)
|
||||||
# define TCP_WBSENT(wrb) ((wrb)->wb_sent)
|
# define TCP_WBSENT(wrb) ((wrb)->wb_sent)
|
||||||
# define TCP_WBNRTX(wrb) ((wrb)->wb_nrtx)
|
# define TCP_WBNRTX(wrb) ((wrb)->wb_nrtx)
|
||||||
|
# define TCP_WBNACK(wrb) ((wrb)->wb_nack)
|
||||||
# define TCP_WBIOB(wrb) ((wrb)->wb_iob)
|
# define TCP_WBIOB(wrb) ((wrb)->wb_iob)
|
||||||
# define TCP_WBCOPYOUT(wrb,dest,n) (iob_copyout(dest,(wrb)->wb_iob,(n),0))
|
# define TCP_WBCOPYOUT(wrb,dest,n) (iob_copyout(dest,(wrb)->wb_iob,(n),0))
|
||||||
# define TCP_WBCOPYIN(wrb,src,n) \
|
# 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 */
|
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
|
uint8_t wb_nrtx; /* The number of retransmissions for the last
|
||||||
* segment sent */
|
* segment sent */
|
||||||
|
uint8_t wb_nack; /* The number of ack count */
|
||||||
struct iob_s *wb_iob; /* Head of the I/O buffer chain */
|
struct iob_s *wb_iob; /* Head of the I/O buffer chain */
|
||||||
};
|
};
|
||||||
#endif
|
#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 tcp_conn_s *conn = (FAR struct tcp_conn_s *)pvconn;
|
||||||
FAR struct socket *psock = (FAR struct socket *)pvpriv;
|
FAR struct socket *psock = (FAR struct socket *)pvpriv;
|
||||||
|
bool rexmit = false;
|
||||||
|
|
||||||
/* Check for a loss of connection */
|
/* 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));
|
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
|
/* 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 */
|
/* Check if we are being asked to retransmit data */
|
||||||
|
|
||||||
else if ((flags & TCP_REXMIT) != 0)
|
else if ((flags & TCP_REXMIT) != 0)
|
||||||
|
{
|
||||||
|
rexmit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rexmit)
|
||||||
{
|
{
|
||||||
FAR struct tcp_wrbuffer_s *wrb;
|
FAR struct tcp_wrbuffer_s *wrb;
|
||||||
FAR sq_entry_t *entry;
|
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);
|
iob_free_chain(wrb->wb_iob, IOBUSER_NET_TCP_WRITEBUFFER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Reset the ack counter */
|
||||||
|
|
||||||
|
TCP_WBNACK(wrb) = 0;
|
||||||
|
|
||||||
/* Then free the write buffer structure */
|
/* Then free the write buffer structure */
|
||||||
|
|
||||||
sq_addlast(&wrb->wb_node, &g_wrbuffer.freebuffers);
|
sq_addlast(&wrb->wb_node, &g_wrbuffer.freebuffers);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user