diff --git a/criu/Makefile.config b/criu/Makefile.config index e6f5efe24..0c819c4b3 100644 --- a/criu/Makefile.config +++ b/criu/Makefile.config @@ -13,7 +13,7 @@ ifeq ($(call pkg-config-check,libselinux),y) endif FEATURES_LIST := TCP_REPAIR STRLCPY STRLCAT PTRACE_PEEKSIGINFO \ - SETPROCTITLE_INIT MEMFD + SETPROCTITLE_INIT MEMFD TCP_REPAIR_WINDOW # $1 - config name define gen-feature-test diff --git a/criu/cr-check.c b/criu/cr-check.c index ca506a1c5..b639afb76 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -917,6 +917,22 @@ static int check_cgroupns(void) return 0; } +static int check_tcp_window(void) +{ + int ret; + + ret = kerndat_tcp_repair_window(); + if (ret < 0) + return -1; + + if (!kdat.has_tcp_window) { + pr_err("The TCP_REPAIR_WINDOW option isn't supported.\n"); + return -1; + } + + return 0; +} + static int (*chk_feature)(void); /* @@ -1014,6 +1030,7 @@ int cr_check(void) ret |= check_fdinfo_lock(); ret |= check_clone_parent_vs_pid(); ret |= check_cgroupns(); + ret |= check_tcp_window(); } /* diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index dc95be147..1353b9e6e 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -31,6 +31,7 @@ struct kerndat_s { bool has_dirty_track; bool has_memfd; bool has_fdinfo_lock; + bool has_tcp_window; unsigned long task_size; bool ipv6; bool has_loginuid; @@ -56,4 +57,6 @@ enum { */ extern int kerndat_fs_virtualized(unsigned int which, u32 kdev); +extern int kerndat_tcp_repair_window(); + #endif /* __CR_KERNDAT_H__ */ diff --git a/criu/kerndat.c b/criu/kerndat.c index b00ba615e..2f1b31dbe 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -472,6 +472,8 @@ int kerndat_init(void) ret = kerndat_loginuid(true); if (!ret) ret = kerndat_iptables_has_xtlocks(); + if (!ret) + ret = kerndat_tcp_repair_window(); kerndat_lsm(); @@ -501,6 +503,8 @@ int kerndat_init_rst(void) ret = kerndat_loginuid(false); if (!ret) ret = kerndat_iptables_has_xtlocks(); + if (!ret) + ret = kerndat_tcp_repair_window(); kerndat_lsm(); diff --git a/criu/sk-tcp.c b/criu/sk-tcp.c index 13d175ab7..37bf69c3a 100644 --- a/criu/sk-tcp.c +++ b/criu/sk-tcp.c @@ -33,6 +33,17 @@ #define SIOCOUTQNSD 0x894B #endif +#ifndef CONFIG_HAS_TCP_REPAIR_WINDOW +struct tcp_repair_window { + u32 snd_wl1; + u32 snd_wnd; + u32 max_window; + + u32 rcv_wnd; + u32 rcv_wup; +}; +#endif + #ifndef CONFIG_HAS_TCP_REPAIR /* * It's been reported that both tcp_repair_opt @@ -58,6 +69,10 @@ enum { #define TCP_TIMESTAMP 24 #endif +#ifndef TCP_REPAIR_WINDOW +#define TCP_REPAIR_WINDOW 29 +#endif + #ifndef TCPOPT_SACK_PERM #define TCPOPT_SACK_PERM TCPOPT_SACK_PERMITTED #endif @@ -751,3 +766,41 @@ out: return ret; } + +int kerndat_tcp_repair_window() +{ + struct tcp_repair_window opt; + socklen_t optlen = sizeof(opt); + int sk, val = 1; + + sk = socket(AF_INET, SOCK_STREAM, 0); + if (sk < 0) { + pr_perror("Unable to create a netlink socket"); + return -1; + } + + if (setsockopt(sk, SOL_TCP, TCP_REPAIR, &val, sizeof(val))) { + if (errno == EPERM) { + kdat.has_tcp_window = false; + pr_warn("TCP_REPAIR isn't available to unprivileged users\n"); + return 0; + } + pr_perror("Unable to set TCP_REPAIR"); + close(sk); + return -1; + } + + if (getsockopt(sk, SOL_TCP, TCP_REPAIR_WINDOW, &opt, &optlen)) { + if (errno != ENOPROTOOPT) { + pr_perror("Unable to set TCP_REPAIR_WINDOW"); + close(sk); + return -1; + } + kdat.has_tcp_window = false; + } else + kdat.has_tcp_window = true; + close(sk); + + return 0; +} + diff --git a/scripts/feature-tests.mak b/scripts/feature-tests.mak index e009370ad..09bbdc815 100644 --- a/scripts/feature-tests.mak +++ b/scripts/feature-tests.mak @@ -12,6 +12,20 @@ int main(void) } endef +define FEATURE_TEST_TCP_REPAIR_WINDOW + +#include + +int main(void) +{ + struct tcp_repair_window opts; + + opts.snd_wl1 = 0; + + return opts.snd_wl1; +} +endef + define FEATURE_TEST_LIBBSD_DEV #include