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

Submitted by Andrei Vagin on Nov. 11, 2016, 7:10 a.m.

Details

Message ID 1478848211-23802-3-git-send-email-avagin@openvz.org
State Superseded
Series "tcp: add support of half closed tcp sockets"
Headers show

Commit Message

Andrei Vagin Nov. 11, 2016, 7:10 a.m.
From: Andrei Vagin <avagin@virtuozzo.com>

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

Patch hide | download patch | download mbox

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 f50deaf..a74e4fd 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 "log.h"
 #include "restorer.h"
@@ -21,6 +23,7 @@ 
 #include "proc_parse.h"
 #include "config.h"
 #include <compel/plugins/std/syscall-codes.h>
+#include "sk-inet.h"
 
 struct kerndat_s kdat = {
 };
@@ -454,6 +457,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();
@@ -491,6 +557,8 @@  int kerndat_init(void)
 		ret = kerndat_tcp_repair_window();
 	if (!ret)
 		ret = kerndat_compat_restore();
+	if (!ret)
+		ret = kerndat_tcp_repair();
 
 	kerndat_lsm();
 
@@ -524,6 +592,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();