From 1bdd592fcaf87764472a2cd179661c8a9624b5a3 Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Mon, 30 May 2016 20:38:40 +0800 Subject: [PATCH] tcp: Don't prematurely drop receiving-only connections. If the connection was persistent and receiving-only, several (12) sporadic device insufficient buffers would cause the connection be dropped prematurely: Upon ENOBUFS in tcp_output() for an ACK, retransmission timer is started. No one will stop this retransmission timer for receiving- only connection, so the retransmission timer promises to expire and t_rxtshift is promised to be increased. And t_rxtshift will not be reset to 0, since no RTT measurement will be done for receiving-only connection. If this receiving-only connection lived long enough, and it suffered 12 sporadic device insufficient buffers, i.e. t_rxtshift >= 12, this receiving-only connection would be dropped prematurely by the retransmission timer. We now assert that for data segments, SYNs or FINs either rexmit or persist timer was wired upon ENOBUFS. And don't set rexmit timer for other cases, i.e. ENOBUFS upon ACKs. And we no longer penalize send window upon ENOBUFS. Obtained-from: FreeBSD r300981 --- sys/netinet/tcp_output.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c index 6b3b6491ad..52bcf0bb5c 100644 --- a/sys/netinet/tcp_output.c +++ b/sys/netinet/tcp_output.c @@ -1281,24 +1281,10 @@ after_th: out: if (error == ENOBUFS) { - /* - * If we can't send, make sure there is something - * to get us going again later. - * - * The persist timer isn't necessarily allowed in all - * states, use the rexmt timer. - */ - if (!tcp_callout_active(tp, tp->tt_rexmt) && - !tcp_callout_active(tp, tp->tt_persist)) { - tcp_callout_reset(tp, tp->tt_rexmt, - tp->t_rxtcur, - tcp_timer_rexmt); -#if 0 - tp->t_rxtshift = 0; - tcp_setpersist(tp); -#endif - } - tcp_quench(inp, 0); + KASSERT((len == 0 && (flags & (TH_SYN | TH_FIN)) == 0) || + tcp_callout_active(tp, tp->tt_rexmt) || + tcp_callout_active(tp, tp->tt_persist), + ("neither rexmt nor persist timer is set")); return (0); } if (error == EMSGSIZE) { -- 2.11.4.GIT