[CRIU] [PATCH] tcp: add ability to restore closing states (v2)

Andrey Vagin avagin at openvz.org
Mon Apr 7 04:03:14 PDT 2014


Here are TCP_FIN_WAIT{1,2}, TCP_WAIT_STOP, TCP_CLOSING, TCP_LAST_ACK,
TCP_TIME_WAIT.

v2: We decide to not use control message for repairing a fin packets in
queues. Because it looks quite tricky. Alexey suggested to restore each
state separately and in this case setsockopt looks more logical.

Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 include/net/tcp.h        |  1 +
 include/uapi/linux/tcp.h |  1 +
 net/ipv4/tcp.c           | 59 ++++++++++++++++++++++++++++++++++++++++++++++++
 net/ipv4/tcp_input.c     |  2 +-
 4 files changed, 62 insertions(+), 1 deletion(-)

diff --git a/include/net/tcp.h b/include/net/tcp.h
index 743acce..016fdb4 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -562,6 +562,7 @@ void tcp_cwnd_application_limited(struct sock *sk);
 void tcp_resume_early_retransmit(struct sock *sk);
 void tcp_rearm_rto(struct sock *sk);
 void tcp_reset(struct sock *sk);
+void tcp_fin(struct sock *sk);
 
 /* tcp_timer.c */
 void tcp_init_xmit_timers(struct sock *);
diff --git a/include/uapi/linux/tcp.h b/include/uapi/linux/tcp.h
index 377f1e5..4f6b3de 100644
--- a/include/uapi/linux/tcp.h
+++ b/include/uapi/linux/tcp.h
@@ -112,6 +112,7 @@ enum {
 #define TCP_FASTOPEN		23	/* Enable FastOpen on listeners */
 #define TCP_TIMESTAMP		24
 #define TCP_NOTSENT_LOWAT	25	/* limit number of unsent bytes in write queue */
+#define TCP_REPAIR_STATE	26	/* Current state of this connection */
 
 struct tcp_repair_opt {
 	__u32	opt_code;
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 964e3f8..393d769 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2431,6 +2431,58 @@ static int tcp_repair_options_est(struct tcp_sock *tp,
 	return 0;
 }
 
+static int tcp_repair_state(struct sock *sk, int state)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+
+	if (sk->sk_state != TCP_ESTABLISHED)
+		return -EINVAL;
+
+	switch (state) {
+	case TCP_ESTABLISHED:
+		break;
+
+	case TCP_FIN_WAIT2:
+		if (tp->snd_una != tp->write_seq)
+			return -EINVAL;
+		tcp_set_state(sk, TCP_FIN_WAIT2);
+		break;
+
+	case TCP_TIME_WAIT:
+		if (tp->snd_una != tp->write_seq)
+			return -EINVAL;
+		tcp_time_wait(sk, TCP_TIME_WAIT, 0);
+		break;
+
+	case TCP_CLOSE_WAIT:
+		tcp_set_state(sk, TCP_CLOSE_WAIT);
+		break;
+
+	case TCP_LAST_ACK:
+	case TCP_FIN_WAIT1:
+	case TCP_CLOSING:
+		tcp_set_state(sk, state);
+		tcp_send_fin(sk);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if ((1 << sk->sk_state) & (TCPF_FIN_WAIT1 |
+				   TCPF_FIN_WAIT2 |
+				   TCPF_CLOSING	|
+				   TCPF_LAST_ACK))
+		sk->sk_shutdown |= SEND_SHUTDOWN;
+
+	if ((1 << sk->sk_state) & (TCPF_CLOSE_WAIT |
+				   TCPF_CLOSING |
+				   TCPF_LAST_ACK))
+		sk->sk_shutdown |= RCV_SHUTDOWN;
+
+	return 0;
+}
+
 /*
  *	Socket option code for TCP.
  */
@@ -2568,6 +2620,13 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
 			err = -EPERM;
 		break;
 
+	case TCP_REPAIR_STATE:
+		if (tp->repair)
+			err = tcp_repair_state(sk, val);
+		else
+			err = -EINVAL;
+		break;
+
 	case TCP_CORK:
 		/* When set indicates to always queue non-full frames.
 		 * Later the user clears this option and we transmit
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index eeaac39..352480c 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -3820,7 +3820,7 @@ void tcp_reset(struct sock *sk)
  *
  *	If we are in FINWAIT-2, a received FIN moves us to TIME-WAIT.
  */
-static void tcp_fin(struct sock *sk)
+void tcp_fin(struct sock *sk)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 	const struct dst_entry *dst;
-- 
1.8.5.3



More information about the CRIU mailing list