[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