[CRIU] [PATCH 1/2 v2] kerndat: check the TCP_REPAIR_WINDOW option

Andrey Vagin avagin at openvz.org
Wed Jul 13 14:11:23 PDT 2016


From: Andrew Vagin <avagin at virtuozzo.com>

It's a new option to get/set window parameters.

v2: don't do this check to unprivileged users, because TCP_REPAIR
    is protected by CAP_NET_ADMIN.

Signed-off-by: Andrew Vagin <avagin at virtuozzo.com>
---
 criu/Makefile.config      |  2 +-
 criu/cr-check.c           | 17 +++++++++++++++
 criu/include/kerndat.h    |  3 +++
 criu/kerndat.c            |  4 ++++
 criu/sk-tcp.c             | 53 +++++++++++++++++++++++++++++++++++++++++++++++
 scripts/feature-tests.mak | 14 +++++++++++++
 6 files changed, 92 insertions(+), 1 deletion(-)

diff --git a/criu/Makefile.config b/criu/Makefile.config
index 15af65f..a502dda 100644
--- a/criu/Makefile.config
+++ b/criu/Makefile.config
@@ -15,7 +15,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 ca506a1..b639afb 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 0a5cd4b..860e32d 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;
@@ -57,4 +58,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 04a355b..3cb0a13 100644
--- a/criu/kerndat.c
+++ b/criu/kerndat.c
@@ -485,6 +485,8 @@ int kerndat_init(void)
 		ret = kerndat_iptables_has_xtlocks();
 	if (!ret)
 		ret = kerndat_compat_restore();
+	if (!ret)
+		ret = kerndat_tcp_repair_window();
 
 	kerndat_lsm();
 
@@ -516,6 +518,8 @@ int kerndat_init_rst(void)
 		ret = kerndat_iptables_has_xtlocks();
 	if (!ret)
 		ret = kerndat_compat_restore();
+	if (!ret)
+		ret = kerndat_tcp_repair_window();
 
 	kerndat_lsm();
 
diff --git a/criu/sk-tcp.c b/criu/sk-tcp.c
index 13d175a..37bf69c 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 e009370..09bbdc8 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 <netinet/tcp.h>
+
+int main(void)
+{
+	struct tcp_repair_window opts;
+
+	opts.snd_wl1 = 0;
+
+	return opts.snd_wl1;
+}
+endef
+
 define FEATURE_TEST_LIBBSD_DEV
 #include <bsd/string.h>
 
-- 
2.7.4



More information about the CRIU mailing list