Commit 7d95face authored by Andrew Vagin's avatar Andrew Vagin Committed by Pavel Emelyanov

tcp: dump and restore window parameters

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/168Signed-off-by: 's avatarAndrew Vagin <avagin@virtuozzo.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
parent f3b730d0
...@@ -319,6 +319,34 @@ err_sopt: ...@@ -319,6 +319,34 @@ err_sopt:
return -1; 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) static int dump_tcp_conn_state(struct inet_sk_desc *sk)
{ {
int ret, aux; int ret, aux;
...@@ -364,6 +392,9 @@ static int dump_tcp_conn_state(struct inet_sk_desc *sk) ...@@ -364,6 +392,9 @@ static int dump_tcp_conn_state(struct inet_sk_desc *sk)
if (ret < 0) if (ret < 0)
goto err_opt; goto err_opt;
if (tcp_get_window(sk->rfd, &tse))
goto err_opt;
/* /*
* TCP socket options * TCP socket options
*/ */
...@@ -624,6 +655,29 @@ static int restore_tcp_opts(int sk, TcpStreamEntry *tse) ...@@ -624,6 +655,29 @@ static int restore_tcp_opts(int sk, TcpStreamEntry *tse)
return 0; 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) static int restore_tcp_conn_state(int sk, struct inet_sk_info *ii)
{ {
int aux; int aux;
...@@ -657,6 +711,9 @@ static int restore_tcp_conn_state(int sk, struct inet_sk_info *ii) ...@@ -657,6 +711,9 @@ static int restore_tcp_conn_state(int sk, struct inet_sk_info *ii)
if (restore_tcp_queues(sk, tse, img)) if (restore_tcp_queues(sk, tse, img))
goto err_c; goto err_c;
if (restore_tcp_window(sk, tse))
goto err_c;
if (tse->has_nodelay && tse->nodelay) { if (tse->has_nodelay && tse->nodelay) {
aux = 1; aux = 1;
if (restore_opt(sk, SOL_TCP, TCP_NODELAY, &aux)) if (restore_opt(sk, SOL_TCP, TCP_NODELAY, &aux))
......
...@@ -18,4 +18,10 @@ message tcp_stream_entry { ...@@ -18,4 +18,10 @@ message tcp_stream_entry {
optional bool nodelay = 11; optional bool nodelay = 11;
optional uint32 unsq_len = 12; /* unsent data in the send queue */ 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;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment