summary refs log tree commit diff
diff options
context:
space:
mode:
authorCristian Ciocaltea <cristian.ciocaltea@collabora.com>2023-09-13 00:42:01 +0300
committerCristian Ciocaltea <cristian.ciocaltea@collabora.com>2023-09-13 00:42:01 +0300
commitf57671f6978c109b9f6727117f71967c3b5cdd96 (patch)
treecc435b04cf66de458a84d7d8c85ad671e87bc019
parent51ac122641823209b6249d9670e774466aa6c48b (diff)
parentef76035f50a1147a0d39b3d9c1b80b92a2961028 (diff)
downloadlinux-f57671f6978c109b9f6727117f71967c3b5cdd96.tar.gz
Merge branch 6.1/features/tcp-timewait
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
-rw-r--r--include/net/tcp.h29
-rw-r--r--net/ipv4/tcp_minisocks.c8
2 files changed, 33 insertions, 4 deletions
diff --git a/include/net/tcp.h b/include/net/tcp.h
index e9c8f88f4769..27039f55ef43 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -122,6 +122,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo);
 
 #define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to destroy TIME-WAIT
 				  * state, about 60 seconds	*/
+#define TCP_TIMEWAIT_LEN_MIN (1*HZ)
 #define TCP_FIN_TIMEOUT	TCP_TIMEWAIT_LEN
                                  /* BSD style FIN_WAIT2 deadlock breaker.
 				  * It used to be 3min, new value is 60sec,
@@ -1565,6 +1566,34 @@ static inline int tcp_fin_time(const struct sock *sk)
 	return fin_timeout;
 }
 
+static inline int tcp_timewait_len(const struct inet_timewait_sock *tw)
+{
+	bool loopback = false;
+
+	if (tw->tw_bound_dev_if == LOOPBACK_IFINDEX)
+		loopback = true;
+#if IS_ENABLED(CONFIG_IPV6)
+	else if (tw->tw_family == AF_INET6) {
+		if (ipv6_addr_loopback(&tw->tw_v6_daddr) ||
+			ipv6_addr_v4mapped_loopback(&tw->tw_v6_daddr) ||
+			ipv6_addr_loopback(&tw->tw_v6_rcv_saddr) ||
+			ipv6_addr_v4mapped_loopback(&tw->tw_v6_rcv_saddr))
+			loopback = true;
+	}
+#endif
+	else
+	{
+		if (ipv4_is_loopback(tw->tw_daddr) ||
+			ipv4_is_loopback(tw->tw_rcv_saddr))
+			loopback = true;
+	}
+
+	if (!loopback)
+		return TCP_TIMEWAIT_LEN;
+
+	return max(TCP_TIMEWAIT_LEN_MIN, sock_net((const struct sock*)tw)->ipv4.sysctl_tcp_fin_timeout);
+}
+
 static inline bool tcp_paws_check(const struct tcp_options_received *rx_opt,
 				  int paws_win)
 {
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 42844d20da02..607d4258416d 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -142,7 +142,7 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
 			tcptw->tw_ts_recent	  = tmp_opt.rcv_tsval;
 		}
 
-		inet_twsk_reschedule(tw, TCP_TIMEWAIT_LEN);
+		inet_twsk_reschedule(tw, tcp_timewait_len(tw));
 		return TCP_TW_ACK;
 	}
 
@@ -179,7 +179,7 @@ kill:
 				return TCP_TW_SUCCESS;
 			}
 		} else {
-			inet_twsk_reschedule(tw, TCP_TIMEWAIT_LEN);
+			inet_twsk_reschedule(tw, tcp_timewait_len(tw));
 		}
 
 		if (tmp_opt.saw_tstamp) {
@@ -230,7 +230,7 @@ kill:
 		 * Do not reschedule in the last case.
 		 */
 		if (paws_reject || th->ack)
-			inet_twsk_reschedule(tw, TCP_TIMEWAIT_LEN);
+			inet_twsk_reschedule(tw, tcp_timewait_len(tw));
 
 		return tcp_timewait_check_oow_rate_limit(
 			tw, skb, LINUX_MIB_TCPACKSKIPPEDTIMEWAIT);
@@ -308,7 +308,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
 			timeo = rto;
 
 		if (state == TCP_TIME_WAIT)
-			timeo = TCP_TIMEWAIT_LEN;
+			timeo = tcp_timewait_len(tw);
 
 		/* tw_timer is pinned, so we need to make sure BH are disabled
 		 * in following section, otherwise timer handler could run before