summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorandre <andre@FreeBSD.org>2013-10-29 21:00:54 +0000
committerandre <andre@FreeBSD.org>2013-10-29 21:00:54 +0000
commit82fad41b08ce33288400daf41003952c88585a31 (patch)
tree1ce406999bfacb47f54bb8c9d9343d61fd1f0a6a
parent0d7fc2d68776ba1b8c68702bf2ddc0b3dcc7404e (diff)
downloadFreeBSD-src-82fad41b08ce33288400daf41003952c88585a31.zip
FreeBSD-src-82fad41b08ce33288400daf41003952c88585a31.tar.gz
MFC r256920:
The TCP delayed ACK logic isn't aware of LRO passing up large aggregated segments thinking it received only one segment. This causes it to enable the delay the ACK for 100ms to wait for another segment which may never come because all the data was received already. Doing delayed ACK for LRO segments is bogus for two reasons: a) it pushes us further away from acking every other packet; b) it introduces additional delay in responding to the sender. The latter is especially bad because it is in the nature of LRO to aggregated all segments of a burst with no more coming until an ACK is sent back. Change the delayed ACK logic to detect LRO segments by being larger than the MSS for this connection and issuing an immediate ACK for them to keep the ACK clock ticking without interruption. Reported by: julian, cperciva Tested by: cperciva Reviewed by: lstewart Approved by: re (glebius)
-rw-r--r--sys/netinet/tcp_input.c11
1 files changed, 7 insertions, 4 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 9a2ce9e..c3eecef 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -508,10 +508,13 @@ do { \
* the ack that opens up a 0-sized window and
* - delayed acks are enabled or
* - this is a half-synchronized T/TCP connection.
+ * - the segment size is not larger than the MSS and LRO wasn't used
+ * for this segment.
*/
-#define DELAY_ACK(tp) \
+#define DELAY_ACK(tp, tlen) \
((!tcp_timer_active(tp, TT_DELACK) && \
(tp->t_flags & TF_RXWIN0SENT) == 0) && \
+ (tlen <= tp->t_maxopd) && \
(V_tcp_delack_enabled || (tp->t_flags & TF_NEEDSYN)))
/*
@@ -1863,7 +1866,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
}
/* NB: sorwakeup_locked() does an implicit unlock. */
sorwakeup_locked(so);
- if (DELAY_ACK(tp)) {
+ if (DELAY_ACK(tp, tlen)) {
tp->t_flags |= TF_DELACK;
} else {
tp->t_flags |= TF_ACKNOW;
@@ -1954,7 +1957,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
* If there's data, delay ACK; if there's also a FIN
* ACKNOW will be turned on later.
*/
- if (DELAY_ACK(tp) && tlen != 0)
+ if (DELAY_ACK(tp, tlen) && tlen != 0)
tcp_timer_activate(tp, TT_DELACK,
tcp_delacktime);
else
@@ -2926,7 +2929,7 @@ dodata: /* XXX */
if (th->th_seq == tp->rcv_nxt &&
LIST_EMPTY(&tp->t_segq) &&
TCPS_HAVEESTABLISHED(tp->t_state)) {
- if (DELAY_ACK(tp))
+ if (DELAY_ACK(tp, tlen))
tp->t_flags |= TF_DELACK;
else
tp->t_flags |= TF_ACKNOW;
OpenPOWER on IntegriCloud