[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