[CRIU] [PATCH 02/11] criu: check whether tcp_repair can be enabled for half-closed sockets
Andrei Vagin
avagin at openvz.org
Thu Nov 10 23:10:02 PST 2016
From: Andrei Vagin <avagin at virtuozzo.com>
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 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();
--
2.7.4
More information about the CRIU
mailing list