[CRIU] [PATCH 2/2] tcp: dump and restore window parameters

Andrey Vagin avagin at openvz.org
Tue Jul 12 19:16:57 PDT 2016


From: Andrew Vagin <avagin at virtuozzo.com>

We found that sometimes a restored tcp socket doesn't work.

A reason of this bug is incorrect window parameters and in this case
tcp_acceptable_seq() returns tcp_wnd_end(tp) instead of tp->snd_nxt. The
other side drops packets with this seq, because seq is less than
tp->rcv_nxt ( tcp_sequence() ).

We need to restore window parameters to avoid such side effects.

https://github.com/xemul/criu/issues/168
Signed-off-by: Andrew Vagin <avagin at virtuozzo.com>
---
 criu/sk-tcp.c           | 57 +++++++++++++++++++++++++++++++++++++++++++++++++
 images/tcp-stream.proto |  6 ++++++
 2 files changed, 63 insertions(+)

diff --git a/criu/sk-tcp.c b/criu/sk-tcp.c
index eaf4da5..d215545 100644
--- a/criu/sk-tcp.c
+++ b/criu/sk-tcp.c
@@ -319,6 +319,34 @@ err_sopt:
 	return -1;
 }
 
+static int tcp_get_window(int sk, TcpStreamEntry *tse)
+{
+	struct tcp_repair_window opt;
+	socklen_t optlen = sizeof(opt);
+
+	if (!kdat.has_tcp_window)
+		return 0;
+
+	if (getsockopt(sk, SOL_TCP,
+			TCP_REPAIR_WINDOW, &opt, &optlen)) {
+		pr_perror("Unable to get window properties");
+		return -1;
+	}
+
+	tse->has_snd_wl1	= true;
+	tse->has_snd_wnd	= true;
+	tse->has_max_window	= true;
+	tse->has_rcv_wnd	= true;
+	tse->has_rcv_wup	= true;
+	tse->snd_wl1		= opt.snd_wl1;
+	tse->snd_wnd		= opt.snd_wnd;
+	tse->max_window		= opt.max_window;
+	tse->rcv_wnd		= opt.rcv_wnd;
+	tse->rcv_wup		= opt.rcv_wup;
+
+	return 0;
+}
+
 static int dump_tcp_conn_state(struct inet_sk_desc *sk)
 {
 	int ret, aux;
@@ -364,6 +392,9 @@ static int dump_tcp_conn_state(struct inet_sk_desc *sk)
 	if (ret < 0)
 		goto err_opt;
 
+	if (tcp_get_window(sk->rfd, &tse))
+		goto err_opt;
+
 	/*
 	 * TCP socket options
 	 */
@@ -624,6 +655,29 @@ static int restore_tcp_opts(int sk, TcpStreamEntry *tse)
 	return 0;
 }
 
+static int restore_tcp_window(int sk, TcpStreamEntry *tse)
+{
+	struct tcp_repair_window opt = {
+		.snd_wl1 = tse->snd_wl1,
+		.snd_wnd = tse->snd_wnd,
+		.max_window = tse->max_window,
+		.rcv_wnd = tse->rcv_wnd,
+		.rcv_wup = tse->rcv_wup,
+	};
+
+	if (!kdat.has_tcp_window || !tse->has_snd_wnd) {
+		pr_warn_once("Window parameters are not restored\n");
+		return 0;
+	}
+
+	if (setsockopt(sk, SOL_TCP, TCP_REPAIR_WINDOW, &opt, sizeof(opt))) {
+		pr_perror("Unable to set window parameters");
+		return -1;
+	}
+
+	return 0;
+}
+
 static int restore_tcp_conn_state(int sk, struct inet_sk_info *ii)
 {
 	int aux;
@@ -657,6 +711,9 @@ static int restore_tcp_conn_state(int sk, struct inet_sk_info *ii)
 	if (restore_tcp_queues(sk, tse, img))
 		goto err_c;
 
+	if (restore_tcp_window(sk, tse))
+		goto err_c;
+
 	if (tse->has_nodelay && tse->nodelay) {
 		aux = 1;
 		if (restore_opt(sk, SOL_TCP, TCP_NODELAY, &aux))
diff --git a/images/tcp-stream.proto b/images/tcp-stream.proto
index 60ba123..1740783 100644
--- a/images/tcp-stream.proto
+++ b/images/tcp-stream.proto
@@ -18,4 +18,10 @@ message tcp_stream_entry {
 	optional bool		nodelay		= 11;
 
 	optional uint32		unsq_len	= 12; /* unsent data in the send queue */
+
+	optional uint32		snd_wl1		= 13;
+	optional uint32		snd_wnd		= 14;
+	optional uint32		max_window	= 15;
+	optional uint32		rcv_wnd		= 16;
+	optional uint32		rcv_wup		= 17;
 }
-- 
2.7.4



More information about the CRIU mailing list