[CRIU] Re: [PATCH 1/2] sockets: Restore unbound inet sockets v3

Cyrill Gorcunov gorcunov at openvz.org
Thu Jun 28 13:48:19 EDT 2012


On Thu, Jun 28, 2012 at 09:40:53PM +0400, Pavel Emelyanov wrote:
> 
> > Which value would be appropriate here?
> 
> zero

Update is attached.

	Cyrill
-------------- next part --------------
>From 3ce606880b9cbf540c546b823ecb5da59da1b714 Mon Sep 17 00:00:00 2001
From: Cyrill Gorcunov <gorcunov at openvz.org>
Date: Fri, 25 May 2012 13:01:09 +0400
Subject: [PATCH] sockets: Restore unbound inet sockets v5

v2:
 - Use do_dump_opt in dump_socket to not call
   lookup_socket redundantly

v3:
 - use getsockopt to check that unconnected
   socket has no peername and it's not listening
 - do test only socket protocol since family and
   type will be called in dump_one_inet_fd.

v4:
 - Move proto tests to can_dump_inet_sk
 - Use SOL_TCP/TCP_INFO to gather info about tcp sockets

v5:
 - hash unconnected sockets to run BUG_ON(already-dumped) logic
 - no default value for sk->wqlen, use zero from xzalloc

Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
 include/sockets.h |    2 +
 sk-inet.c         |  111 ++++++++++++++++++++++++++++++++++++++++++++++++----
 sockets.c         |    2 +-
 3 files changed, 105 insertions(+), 10 deletions(-)

diff --git a/include/sockets.h b/include/sockets.h
index 798b413..267e7e2 100644
--- a/include/sockets.h
+++ b/include/sockets.h
@@ -53,4 +53,6 @@ extern int dump_one_unix(struct fd_parms *p, int lfd, const struct cr_fdset *set
 extern int inet_collect_one(struct nlmsghdr *h, int family, int type, int proto);
 extern int unix_receive_one(struct nlmsghdr *h);
 
+extern int do_dump_opt(int sk, int name, void *val, int len);
+
 #endif /* CR_SOCKETS_H__ */
diff --git a/sk-inet.c b/sk-inet.c
index cd3e443..6ddf417 100644
--- a/sk-inet.c
+++ b/sk-inet.c
@@ -1,3 +1,4 @@
+#include <sys/types.h>
 #include <sys/socket.h>
 #include <linux/netlink.h>
 #include <unistd.h>
@@ -81,25 +82,102 @@ static int can_dump_inet_sk(const struct inet_sk_desc *sk)
 			return 0;
 		}
 		break;
+	case TCP_CLOSE:
+		/* Trivial case, we just need to create a socket on restore */
+		break;
 	default:
 		pr_err("Unknown state %d\n", sk->state);
 		return 0;
 	}
 
+	/* Make sure it's a proto we support */
+	switch (sk->proto) {
+	case IPPROTO_IP:
+	case IPPROTO_TCP:
+	case IPPROTO_UDP:
+	case IPPROTO_UDPLITE:
+		break;
+	default:
+		pr_err("Unsupported socket proto %d\n", sk->proto);
+		return 0;
+	}
+
 	return 1;
 }
 
 #define tcp_connection(sk)	(((sk)->proto == IPPROTO_TCP) &&	\
 				 ((sk)->state == TCP_ESTABLISHED))
 
+static struct inet_sk_desc *gen_uncon_sk(int lfd, const struct fd_parms *p)
+{
+	struct inet_sk_desc *sk;
+	char address[128];
+	socklen_t aux;
+	int ret;
+
+	sk = xzalloc(sizeof(*sk));
+	if (!sk)
+		goto err;
+
+	/* It should has no peer name */
+	aux = sizeof(address);
+	ret = getsockopt(lfd, SOL_SOCKET, SO_PEERNAME, address, &aux);
+	if (ret != -1 || errno != ENOTCONN) {
+		pr_err("Errno %d returned from unconnected socket\n", errno);
+		goto err;
+	}
+
+	sk->sd.ino = p->stat.st_ino;
+
+	ret  = do_dump_opt(lfd, SO_DOMAIN, &sk->sd.family, sizeof(sk->sd.family));
+	ret |= do_dump_opt(lfd, SO_TYPE, &sk->type, sizeof(sk->type));
+	ret |= do_dump_opt(lfd, SO_PROTOCOL, &sk->proto, sizeof(sk->proto));
+	if (ret)
+		goto err;
+
+	if (sk->proto == IPPROTO_TCP) {
+		struct tcp_info info;
+
+		aux = sizeof(info);
+		ret = getsockopt(lfd, SOL_TCP, TCP_INFO, &info, &aux);
+		if (ret) {
+			pr_perror("Failt to obtain TCP_INFO");
+			goto err;
+		}
+
+		if (info.tcpi_state != TCP_CLOSE) {
+			pr_err("Socket state %d obtained but expected %d\n",
+			       info.tcpi_state, TCP_CLOSE);
+			goto err;
+		}
+
+		sk->wqlen = info.tcpi_backoff;
+	}
+
+	sk->state = TCP_CLOSE;
+
+	sk_collect_one(sk->sd.ino, sk->sd.family, &sk->sd);
+
+	return sk;
+err:
+	xfree(sk);
+	return NULL;
+}
+
 static int dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p)
 {
+	bool should_free_sk = false;
 	struct inet_sk_desc *sk;
 	struct inet_sk_entry ie;
+	int ret = -1;
 
 	sk = (struct inet_sk_desc *)lookup_socket(p->stat.st_ino);
-	if (!sk)
-		goto err;
+	if (!sk) {
+		sk = gen_uncon_sk(lfd, p);
+		if (!sk)
+			goto err;
+		should_free_sk = true;
+	}
 
 	if (!can_dump_inet_sk(sk))
 		goto err;
@@ -134,12 +212,13 @@ static int dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p)
 	sk->sd.already_dumped = 1;
 
 	if (tcp_connection(sk))
-		return dump_one_tcp(lfd, sk);
-
-	return 0;
-
+		ret = dump_one_tcp(lfd, sk);
+	else
+		ret = 0;
 err:
-	return -1;
+	if (should_free_sk)
+		xfree(sk);
+	return ret;
 }
 
 static const struct fdtype_ops inet_dump_ops = {
@@ -184,6 +263,18 @@ int inet_collect_one(struct nlmsghdr *h, int family, int type, int proto)
 	return ret;
 }
 
+static u32 zero_addr[4];
+
+static bool is_bound(struct inet_sk_info *ii)
+{
+	BUILD_BUG_ON(sizeof(zero_addr) <
+		     max(sizeof(ii->ie.dst_addr), sizeof(ii->ie.src_addr)));
+
+	return memcmp(zero_addr, ii->ie.src_addr, sizeof(ii->ie.src_addr)) ||
+	       memcmp(zero_addr, ii->ie.dst_addr, sizeof(ii->ie.dst_addr));
+}
+
+
 static int open_inet_sk(struct file_desc *d);
 
 static struct file_desc_ops inet_desc_ops = {
@@ -265,8 +356,10 @@ static int open_inet_sk(struct file_desc *d)
 	 * bind() and listen(), and that's all.
 	 */
 
-	if (inet_bind(sk, ii))
-		goto err;
+	if (is_bound(ii)) {
+		if (inet_bind(sk, ii))
+			goto err;
+	}
 
 	if (ii->ie.state == TCP_LISTEN) {
 		if (ii->ie.proto != IPPROTO_TCP) {
diff --git a/sockets.c b/sockets.c
index 4e2c22e..d802759 100644
--- a/sockets.c
+++ b/sockets.c
@@ -75,7 +75,7 @@ int restore_socket_opts(int sk, struct sk_opts_entry *soe)
 	return ret;
 }
 
-static int do_dump_opt(int sk, int name, void *val, int len)
+int do_dump_opt(int sk, int name, void *val, int len)
 {
 	socklen_t aux = len;
 
-- 
1.7.7.6



More information about the CRIU mailing list