]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - net/ipv4/tcp_timer.c
UBUNTU: Ubuntu-4.15.0-96.97
[mirror_ubuntu-bionic-kernel.git] / net / ipv4 / tcp_timer.c
index 968fda1983762e6d7c078a28ccfcbd9066788daf..a78f782205af86728ae37c84155fc9c8e3e25cb7 100644 (file)
@@ -34,6 +34,7 @@ static void tcp_write_err(struct sock *sk)
        sk->sk_err = sk->sk_err_soft ? : ETIMEDOUT;
        sk->sk_error_report(sk);
 
+       tcp_write_queue_purge(sk);
        tcp_done(sk);
        __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONTIMEOUT);
 }
@@ -48,11 +49,19 @@ static void tcp_write_err(struct sock *sk)
  *  to prevent DoS attacks. It is called when a retransmission timeout
  *  or zero probe timeout occurs on orphaned socket.
  *
+ *  Also close if our net namespace is exiting; in that case there is no
+ *  hope of ever communicating again since all netns interfaces are already
+ *  down (or about to be down), and we need to release our dst references,
+ *  which have been moved to the netns loopback interface, so the namespace
+ *  can finish exiting.  This condition is only possible if we are a kernel
+ *  socket, as those do not hold references to the namespace.
+ *
  *  Criteria is still not confirmed experimentally and may change.
  *  We kill the socket, if:
  *  1. If number of orphaned sockets exceeds an administratively configured
  *     limit.
  *  2. If we have strong memory pressure.
+ *  3. If our net namespace is exiting.
  */
 static int tcp_out_of_resources(struct sock *sk, bool do_reset)
 {
@@ -81,6 +90,13 @@ static int tcp_out_of_resources(struct sock *sk, bool do_reset)
                __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONMEMORY);
                return 1;
        }
+
+       if (!check_net(sock_net(sk))) {
+               /* Not possible to send reset; just close */
+               tcp_done(sk);
+               return 1;
+       }
+
        return 0;
 }
 
@@ -121,6 +137,7 @@ static void tcp_mtu_probing(struct inet_connection_sock *icsk, struct sock *sk)
                mss = tcp_mtu_to_mss(sk, icsk->icsk_mtup.search_low) >> 1;
                mss = min(net->ipv4.sysctl_tcp_base_mss, mss);
                mss = max(mss, 68 - tcp_sk(sk)->tcp_header_len);
+               mss = max(mss, net->ipv4.sysctl_tcp_min_snd_mss);
                icsk->icsk_mtup.search_low = tcp_mss_to_mtu(sk, mss);
        }
        tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
@@ -344,7 +361,7 @@ static void tcp_probe_timer(struct sock *sk)
                        return;
        }
 
-       if (icsk->icsk_probes_out > max_probes) {
+       if (icsk->icsk_probes_out >= max_probes) {
 abort:         tcp_write_err(sk);
        } else {
                /* Only send another probe if we didn't close things up. */
@@ -409,10 +426,8 @@ void tcp_retransmit_timer(struct sock *sk)
                 */
                return;
        }
-       if (!tp->packets_out)
-               goto out;
-
-       WARN_ON(tcp_rtx_queue_empty(sk));
+       if (!tp->packets_out || WARN_ON_ONCE(tcp_rtx_queue_empty(sk)))
+               return;
 
        tp->tlp_high_seq = 0;
 
@@ -450,11 +465,12 @@ void tcp_retransmit_timer(struct sock *sk)
                goto out_reset_timer;
        }
 
+       __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPTIMEOUTS);
        if (tcp_write_timeout(sk))
                goto out;
 
        if (icsk->icsk_retransmits == 0) {
-               int mib_idx;
+               int mib_idx = 0;
 
                if (icsk->icsk_ca_state == TCP_CA_Recovery) {
                        if (tcp_is_sack(tp))
@@ -469,10 +485,9 @@ void tcp_retransmit_timer(struct sock *sk)
                                mib_idx = LINUX_MIB_TCPSACKFAILURES;
                        else
                                mib_idx = LINUX_MIB_TCPRENOFAILURES;
-               } else {
-                       mib_idx = LINUX_MIB_TCPTIMEOUTS;
                }
-               __NET_INC_STATS(sock_net(sk), mib_idx);
+               if (mib_idx)
+                       __NET_INC_STATS(sock_net(sk), mib_idx);
        }
 
        tcp_enter_loss(sk);