[CRIU] [PATCH 02/21] criu: check whether tcp_repair can be enabled for half-closed sockets

Andrei Vagin avagin at openvz.org
Mon Nov 28 11:27:37 PST 2016


From: Andrei Vagin <avagin at virtuozzo.com>

Originally the repair mode could be enable only for sockets
in closed and established states. Starting with the 4.10 kernel,
it is possible to enable the repair mode for all connected sockets
and now we can dump syn-sent and half closed sockets.

Signed-off-by: Andrei Vagin <avagin at virtuozzo.com>
---
 criu/cr-check.c        | 18 +++++++++++++
 criu/include/kerndat.h |  2 ++
 criu/kerndat.c         | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 90 insertions(+)

diff --git a/criu/cr-check.c b/criu/cr-check.c
index e85b105..fa5c2eb 100644
--- a/criu/cr-check.c
+++ b/criu/cr-check.c
@@ -921,6 +921,22 @@ static int check_cgroupns(void)
 	return 0;
 }
 
+static int check_tcp_halt_closed(void)
+{
+	int ret;
+
+	ret = kerndat_tcp_repair();
+	if (ret < 0)
+		return -1;
+
+	if (!kdat.has_tcp_half_closed) {
+		pr_err("TCP_REPAIR can't be enabled for half-closed sockets\n");
+		return -1;
+	}
+
+	return 0;
+}
+
 static int check_tcp_window(void)
 {
 	int ret;
@@ -1037,6 +1053,7 @@ int cr_check(void)
 		ret |= check_clone_parent_vs_pid();
 		ret |= check_cgroupns();
 		ret |= check_tcp_window();
+		ret |= check_tcp_halt_closed();
 	}
 
 	/*
@@ -1116,6 +1133,7 @@ static struct feature_list feature_list[] = {
 	{ "loginuid", check_loginuid },
 	{ "cgroupns", check_cgroupns },
 	{ "autofs", check_autofs },
+	{ "tcp_half_closed", check_tcp_halt_closed },
 	{ NULL, NULL },
 };
 
diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h
index e0e8bc8..7021c18 100644
--- a/criu/include/kerndat.h
+++ b/criu/include/kerndat.h
@@ -38,6 +38,7 @@ struct kerndat_s {
 	bool has_compat_sigreturn;
 	enum pagemap_func pmap;
 	unsigned int has_xtlocks;
+	bool has_tcp_half_closed;
 };
 
 extern struct kerndat_s kdat;
@@ -59,5 +60,6 @@ enum {
 extern int kerndat_fs_virtualized(unsigned int which, u32 kdev);
 
 extern int kerndat_tcp_repair_window();
+extern int kerndat_tcp_repair();
 
 #endif /* __CR_KERNDAT_H__ */
diff --git a/criu/kerndat.c b/criu/kerndat.c
index a6499a1..c30e18e 100644
--- a/criu/kerndat.c
+++ b/criu/kerndat.c
@@ -7,6 +7,8 @@
 #include <sys/mman.h>
 #include <errno.h>
 #include <sys/syscall.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>  /* for sockaddr_in and inet_ntoa() */
 
 #include "int.h"
 #include "log.h"
@@ -21,6 +23,7 @@
 #include "lsm.h"
 #include "proc_parse.h"
 #include "config.h"
+#include "sk-inet.h"
 #include <compel/plugins/std/syscall-codes.h>
 #include <compel/compel.h>
 
@@ -456,6 +459,69 @@ static int kerndat_iptables_has_xtlocks(void)
 	return 0;
 }
 
+int kerndat_tcp_repair(void)
+{
+	int sock, clnt = -1, yes = 1, exit_code = -1;
+	struct sockaddr_in addr;
+	socklen_t aux;
+
+	memset(&addr,0,sizeof(addr));
+	addr.sin_family = AF_INET;
+	inet_pton(AF_INET, "127.0.0.1", &(addr.sin_addr));
+	addr.sin_port = 0;
+	sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+	if (sock < 0) {
+		pr_perror("Unable to create a socket");
+		return -1;
+	}
+
+	if (bind(sock, (struct sockaddr *) &addr, sizeof(addr))) {
+		pr_perror("Unable to bind a socket");
+		goto err;
+	}
+
+	aux = sizeof(addr);
+	if (getsockname(sock, (struct sockaddr *) &addr, &aux)) {
+		pr_perror("Unable to get a socket name");
+		goto err;
+	}
+
+	if (listen(sock, 1)) {
+		pr_perror("Unable to listen a socket");
+		goto err;
+	}
+
+	clnt = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+	if (clnt < 0) {
+		pr_perror("Unable to create a socket");
+		goto err;
+	}
+
+	if (connect(clnt, (struct sockaddr *) &addr, sizeof(addr))) {
+		pr_perror("Unable to connect a socket");
+		goto err;
+	}
+
+	if (shutdown(clnt, SHUT_WR)) {
+		pr_perror("Unable to shutdown a socket");
+		goto err;
+	}
+
+	if (setsockopt(clnt, SOL_TCP, TCP_REPAIR, &yes, sizeof(yes))) {
+		if (errno != EPERM)
+			goto err;
+		kdat.has_tcp_half_closed = false;
+	} else
+		kdat.has_tcp_half_closed = true;
+
+	exit_code = 0;
+err:
+	close_safe(&clnt);
+	close(sock);
+
+	return exit_code;
+}
+
 static int kerndat_compat_restore(void)
 {
 	int ret = kdat_compat_sigreturn_test();
@@ -493,6 +559,8 @@ int kerndat_init(void)
 		ret = kerndat_tcp_repair_window();
 	if (!ret)
 		ret = kerndat_compat_restore();
+	if (!ret)
+		ret = kerndat_tcp_repair();
 
 	kerndat_lsm();
 
@@ -526,6 +594,8 @@ int kerndat_init_rst(void)
 		ret = kerndat_tcp_repair_window();
 	if (!ret)
 		ret = kerndat_compat_restore();
+	if (!ret)
+		ret = kerndat_tcp_repair();
 
 	kerndat_lsm();
 
-- 
2.7.4



More information about the CRIU mailing list