mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-17 16:47:50 +00:00
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/168 Signed-off-by: Andrew Vagin <avagin@virtuozzo.com> Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
This commit is contained in:
parent
f3b730d0e2
commit
7d95face06
2 changed files with 63 additions and 0 deletions
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue