[CRIU] [PATCH 05/10] net: save network namespaces for sockets

Andrei Vagin avagin at openvz.org
Wed Aug 31 15:55:28 PDT 2016


From: Andrew Vagin <avagin at virtuozzo.com>

Each socket has to be restored in a proper namespaces where
it has been created.

Signed-off-by: Andrei Vagin <avagin at virtuozzo.com>
---
 criu/include/sockets.h   | 10 ++++++++--
 criu/sk-inet.c           | 18 +++++++++++++++---
 criu/sk-netlink.c        | 15 ++++++++++++++-
 criu/sk-packet.c         |  6 +++++-
 criu/sk-unix.c           |  9 ++++++---
 criu/sockets.c           | 35 +++++++++++++++++++++++------------
 images/packet-sock.proto |  1 +
 images/sk-inet.proto     |  1 +
 images/sk-netlink.proto  |  1 +
 images/sk-packet.proto   |  1 +
 images/sk-unix.proto     |  2 ++
 11 files changed, 77 insertions(+), 22 deletions(-)

diff --git a/criu/include/sockets.h b/criu/include/sockets.h
index 40295bb..fc64ac2 100644
--- a/criu/include/sockets.h
+++ b/criu/include/sockets.h
@@ -21,9 +21,15 @@ struct socket_desc {
 	unsigned int		family;
 	unsigned int		ino;
 	struct socket_desc	*next;
+	struct ns_id		*ns;
 	int			already_dumped;
 };
 
+struct sock_req_args {
+	struct ns_id *ns;
+	void *req;
+};
+
 extern int dump_socket(struct fd_parms *p, int lfd, struct cr_img *);
 extern int dump_socket_opts(int sk, SkOptsEntry *soe);
 extern int restore_socket_opts(int sk, SkOptsEntry *soe);
@@ -33,7 +39,7 @@ extern void preload_socket_modules();
 
 extern bool socket_test_collect_bit(unsigned int family, unsigned int proto);
 
-extern int sk_collect_one(unsigned ino, int family, struct socket_desc *d);
+extern int sk_collect_one(unsigned ino, int family, struct socket_desc *d, struct ns_id *ns);
 struct ns_id;
 extern int collect_sockets(struct ns_id *);
 extern int collect_inet_sockets(void);
@@ -50,7 +56,7 @@ extern const struct fdtype_ops inet6_dump_ops;
 extern const struct fdtype_ops netlink_dump_ops;
 extern const struct fdtype_ops packet_dump_ops;
 
-extern int inet_collect_one(struct nlmsghdr *h, int family, int type);
+extern int inet_collect_one(struct nlmsghdr *h, int family, int type, struct ns_id *ns);
 extern int unix_receive_one(struct nlmsghdr *h, void *);
 extern int netlink_receive_one(struct nlmsghdr *hdr, void *arg);
 
diff --git a/criu/sk-inet.c b/criu/sk-inet.c
index f4bc519..8083c05 100644
--- a/criu/sk-inet.c
+++ b/criu/sk-inet.c
@@ -22,6 +22,7 @@
 #include "rst-malloc.h"
 #include "sockets.h"
 #include "sk-inet.h"
+#include "namespaces.h"
 
 #define PB_ALEN_INET	1
 #define PB_ALEN_INET6	4
@@ -182,10 +183,17 @@ static int can_dump_inet_sk(const struct inet_sk_desc *sk)
 static struct inet_sk_desc *gen_uncon_sk(int lfd, const struct fd_parms *p, int proto)
 {
 	struct inet_sk_desc *sk;
+	struct ns_id *ns = NULL;
 	char address;
 	socklen_t aux;
 	int ret;
 
+	if (root_ns_mask & CLONE_NEWNET) {
+		ns = get_socket_ns(lfd);
+		if (ns == NULL)
+			return NULL;
+	}
+
 	sk = xzalloc(sizeof(*sk));
 	if (!sk)
 		goto err;
@@ -231,7 +239,7 @@ static struct inet_sk_desc *gen_uncon_sk(int lfd, const struct fd_parms *p, int
 
 	sk->state = TCP_CLOSE;
 
-	sk_collect_one(sk->sd.ino, sk->sd.family, &sk->sd);
+	sk_collect_one(sk->sd.ino, sk->sd.family, &sk->sd, ns);
 
 	return sk;
 err:
@@ -300,6 +308,10 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa
 
 	ie.id		= id;
 	ie.ino		= sk->sd.ino;
+	if (sk->sd.ns) {
+		ie.ns_id	= sk->sd.ns->id;
+		ie.has_ns_id	= true;
+	}
 	ie.family	= family;
 	ie.proto	= proto;
 	ie.type		= sk->type;
@@ -408,7 +420,7 @@ const struct fdtype_ops inet6_dump_ops = {
 	.dump		= dump_one_inet6_fd,
 };
 
-int inet_collect_one(struct nlmsghdr *h, int family, int type)
+int inet_collect_one(struct nlmsghdr *h, int family, int type, struct ns_id *ns)
 {
 	struct inet_sk_desc *d;
 	struct inet_diag_msg *m = NLMSG_DATA(h);
@@ -435,7 +447,7 @@ int inet_collect_one(struct nlmsghdr *h, int family, int type)
 	else
 		pr_err_once("Can't check shutdown state of inet socket\n");
 
-	ret = sk_collect_one(m->idiag_inode, family, &d->sd);
+	ret = sk_collect_one(m->idiag_inode, family, &d->sd, ns);
 
 	show_one_inet("Collected", d);
 
diff --git a/criu/sk-netlink.c b/criu/sk-netlink.c
index dc5c4a1..252a484 100644
--- a/criu/sk-netlink.c
+++ b/criu/sk-netlink.c
@@ -12,6 +12,7 @@
 #include "images/sk-netlink.pb-c.h"
 #include "netlink_diag.h"
 #include "libnetlink.h"
+#include "namespaces.h"
 
 struct netlink_sk_desc {
 	struct socket_desc	sd;
@@ -30,6 +31,7 @@ int netlink_receive_one(struct nlmsghdr *hdr, void *arg)
 	struct netlink_diag_msg *m;
 	struct netlink_sk_desc *sd;
 	unsigned long *groups;
+	struct sock_req_args *req_args = arg;
 
 	m = NLMSG_DATA(hdr);
 	pr_debug("Collect netlink sock 0x%x\n", m->ndiag_ino);
@@ -61,7 +63,7 @@ int netlink_receive_one(struct nlmsghdr *hdr, void *arg)
 		sd->gsize = 0;
 	}
 
-	return sk_collect_one(m->ndiag_ino, PF_NETLINK, &sd->sd);
+	return sk_collect_one(m->ndiag_ino, PF_NETLINK, &sd->sd, req_args->ns);
 }
 
 static bool can_dump_netlink_sk(int lfd)
@@ -94,6 +96,8 @@ static int dump_one_netlink_fd(int lfd, u32 id, const struct fd_parms *p)
 	if (sk) {
 		BUG_ON(sk->sd.already_dumped);
 
+		ne.ns_id = sk->sd.ns->id;
+		ne.has_ns_id = true;
 		ne.protocol = sk->protocol;
 		ne.portid = sk->portid;
 		ne.groups = sk->groups;
@@ -120,9 +124,18 @@ static int dump_one_netlink_fd(int lfd, u32 id, const struct fd_parms *p)
 		ne.dst_portid = sk->dst_portid;
 		ne.dst_group = sk->dst_group;
 	} else { /* unconnected and unbound socket */
+		struct ns_id *nsid;
 		int val;
 		socklen_t aux = sizeof(val);
 
+		if (root_ns_mask & CLONE_NEWNET) {
+			nsid = get_socket_ns(lfd);
+			if (nsid == NULL)
+				return -1;
+			ne.ns_id = nsid->id;
+			ne.has_ns_id = true;
+		}
+
 		if (getsockopt(lfd, SOL_SOCKET, SO_PROTOCOL, &val, &aux) < 0) {
 			pr_perror("Unable to get protocol for netlink socket");
 			goto err;
diff --git a/criu/sk-packet.c b/criu/sk-packet.c
index d82268e..d064f36 100644
--- a/criu/sk-packet.c
+++ b/criu/sk-packet.c
@@ -18,6 +18,7 @@
 #include "protobuf.h"
 #include "images/packet-sock.pb-c.h"
 #include "images/fdinfo.pb-c.h"
+#include "namespaces.h"
 
 struct packet_sock_info {
 	PacketSockEntry *pse;
@@ -160,6 +161,8 @@ static int dump_one_packet_fd(int lfd, u32 id, const struct fd_parms *p)
 	sd->sd.already_dumped = 1;
 
 	psk.id = sd->file_id = id;
+	psk.ns_id = sd->sd.ns->id;
+	psk.has_ns_id = true;
 	psk.type = sd->type;
 	psk.flags = p->flags;
 	psk.fown = (FownEntry *)&p->fown;
@@ -245,6 +248,7 @@ int packet_receive_one(struct nlmsghdr *hdr, void *arg)
 	struct packet_diag_msg *m;
 	struct nlattr *tb[PACKET_DIAG_MAX + 1];
 	struct packet_sock_desc *sd;
+	struct sock_req_args *req_args = arg;
 
 	m = NLMSG_DATA(hdr);
 	nlmsg_parse(hdr, sizeof(struct packet_diag_msg),
@@ -294,7 +298,7 @@ int packet_receive_one(struct nlmsghdr *hdr, void *arg)
 		memcpy(sd->tx, RTA_DATA(tb[PACKET_DIAG_TX_RING]), sizeof(*sd->tx));
 	}
 
-	return sk_collect_one(m->pdiag_ino, PF_PACKET, &sd->sd);
+	return sk_collect_one(m->pdiag_ino, PF_PACKET, &sd->sd, req_args->ns);
 err:
 	xfree(sd->tx);
 	xfree(sd->rx);
diff --git a/criu/sk-unix.c b/criu/sk-unix.c
index 99f0b08..1b5d2aa 100644
--- a/criu/sk-unix.c
+++ b/criu/sk-unix.c
@@ -305,6 +305,8 @@ static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p)
 
 	ue->id		= id;
 	ue->ino		= sk->sd.ino;
+	ue->ns_id	= sk->sd.ns->id;
+	ue->has_ns_id	= true;
 	ue->type	= sk->type;
 	ue->state	= sk->state;
 	ue->flags	= p->flags;
@@ -591,7 +593,7 @@ skip:
 }
 
 static int unix_collect_one(const struct unix_diag_msg *m,
-			    struct nlattr **tb)
+			    struct nlattr **tb, struct ns_id *ns)
 {
 	struct unix_sk_desc *d;
 	int ret = 0;
@@ -668,7 +670,7 @@ static int unix_collect_one(const struct unix_diag_msg *m,
 		d->wqlen = rq->udiag_wqueue;
 	}
 
-	sk_collect_one(m->udiag_ino, AF_UNIX, &d->sd);
+	sk_collect_one(m->udiag_ino, AF_UNIX, &d->sd, ns);
 	list_add_tail(&d->list, &unix_sockets);
 	show_one_unix("Collected", d);
 
@@ -686,10 +688,11 @@ int unix_receive_one(struct nlmsghdr *h, void *arg)
 {
 	struct unix_diag_msg *m = NLMSG_DATA(h);
 	struct nlattr *tb[UNIX_DIAG_MAX+1];
+	struct sock_req_args *req_args = arg;
 
 	nlmsg_parse(h, sizeof(struct unix_diag_msg), tb, UNIX_DIAG_MAX, NULL);
 
-	return unix_collect_one(m, tb);
+	return unix_collect_one(m, tb, req_args->ns);
 }
 
 static int dump_external_sockets(struct unix_sk_desc *peer)
diff --git a/criu/sockets.c b/criu/sockets.c
index ffc4f39..edd459f 100644
--- a/criu/sockets.c
+++ b/criu/sockets.c
@@ -350,13 +350,14 @@ struct socket_desc *lookup_socket(unsigned ino, int family, int proto)
 	return NULL;
 }
 
-int sk_collect_one(unsigned ino, int family, struct socket_desc *d)
+int sk_collect_one(unsigned ino, int family, struct socket_desc *d, struct ns_id *ns)
 {
 	struct socket_desc **chain;
 
 	d->ino		= ino;
 	d->family	= family;
 	d->already_dumped = 0;
+	d->ns		= ns;
 
 	chain = &sockets[ino % SK_HASH_SIZE];
 	d->next = *chain;
@@ -583,7 +584,8 @@ int dump_socket(struct fd_parms *p, int lfd, struct cr_img *img)
 
 static int inet_receive_one(struct nlmsghdr *h, void *arg)
 {
-	struct inet_diag_req_v2 *i = arg;
+	struct sock_req_args *req_args = arg;
+	struct inet_diag_req_v2 *i = req_args->req;
 	int type;
 
 	switch (i->sdiag_protocol) {
@@ -599,7 +601,7 @@ static int inet_receive_one(struct nlmsghdr *h, void *arg)
 		return -1;
 	}
 
-	return inet_collect_one(h, i->sdiag_family, type);
+	return inet_collect_one(h, i->sdiag_family, type, req_args->ns);
 }
 
 static int do_collect_req(int nl, struct sock_diag_req *req, int size,
@@ -620,6 +622,7 @@ int collect_sockets(struct ns_id *ns)
 	int err = 0, tmp;
 	int nl = ns->net.nlsk;
 	struct sock_diag_req req;
+	struct sock_req_args args = { .ns = ns };
 
 	memset(&req, 0, sizeof(req));
 	req.hdr.nlmsg_len	= sizeof(req);
@@ -633,7 +636,7 @@ int collect_sockets(struct ns_id *ns)
 	req.r.u.udiag_show	= UDIAG_SHOW_NAME | UDIAG_SHOW_VFS |
 				  UDIAG_SHOW_PEER | UDIAG_SHOW_ICONS |
 				  UDIAG_SHOW_RQLEN;
-	tmp = do_collect_req(nl, &req, sizeof(req), unix_receive_one, NULL);
+	tmp = do_collect_req(nl, &req, sizeof(req), unix_receive_one, &args);
 	if (tmp)
 		err = tmp;
 
@@ -643,7 +646,8 @@ int collect_sockets(struct ns_id *ns)
 	req.r.i.idiag_ext	= 0;
 	/* Only listening and established sockets supported yet */
 	req.r.i.idiag_states	= (1 << TCP_LISTEN) | (1 << TCP_ESTABLISHED);
-	tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i);
+	args.req = &req.r.i;
+	tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &args);
 	if (tmp)
 		err = tmp;
 
@@ -652,7 +656,8 @@ int collect_sockets(struct ns_id *ns)
 	req.r.i.sdiag_protocol	= IPPROTO_UDP;
 	req.r.i.idiag_ext	= 0;
 	req.r.i.idiag_states	= -1; /* All */
-	tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i);
+	args.req = &req.r.i;
+	tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &args);
 	if (tmp)
 		err = tmp;
 
@@ -661,7 +666,8 @@ int collect_sockets(struct ns_id *ns)
 	req.r.i.sdiag_protocol	= IPPROTO_UDPLITE;
 	req.r.i.idiag_ext	= 0;
 	req.r.i.idiag_states	= -1; /* All */
-	tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i);
+	args.req = &req.r.i;
+	tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &args);
 	if (tmp)
 		err = tmp;
 
@@ -671,7 +677,8 @@ int collect_sockets(struct ns_id *ns)
 	req.r.i.idiag_ext	= 0;
 	/* Only listening sockets supported yet */
 	req.r.i.idiag_states	= (1 << TCP_LISTEN) | (1 << TCP_ESTABLISHED);
-	tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i);
+	args.req = &req.r.i;
+	tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &args);
 	if (tmp)
 		err = tmp;
 
@@ -680,7 +687,8 @@ int collect_sockets(struct ns_id *ns)
 	req.r.i.sdiag_protocol	= IPPROTO_UDP;
 	req.r.i.idiag_ext	= 0;
 	req.r.i.idiag_states	= -1; /* All */
-	tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i);
+	args.req = &req.r.i;
+	tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &args);
 	if (tmp)
 		err = tmp;
 
@@ -689,7 +697,8 @@ int collect_sockets(struct ns_id *ns)
 	req.r.i.sdiag_protocol	= IPPROTO_UDPLITE;
 	req.r.i.idiag_ext	= 0;
 	req.r.i.idiag_states	= -1; /* All */
-	tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i);
+	args.req = &req.r.i;
+	tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &args);
 	if (tmp)
 		err = tmp;
 
@@ -697,7 +706,8 @@ int collect_sockets(struct ns_id *ns)
 	req.r.p.sdiag_protocol	= 0;
 	req.r.p.pdiag_show	= PACKET_SHOW_INFO | PACKET_SHOW_MCLIST |
 					PACKET_SHOW_FANOUT | PACKET_SHOW_RING_CFG;
-	tmp = do_collect_req(nl, &req, sizeof(req), packet_receive_one, NULL);
+	args.req = NULL;
+	tmp = do_collect_req(nl, &req, sizeof(req), packet_receive_one, &args);
 	if (tmp) {
 		pr_warn("The current kernel doesn't support packet_diag\n");
 		if (ns->ns_pid == 0 || tmp != -ENOENT) /* Fedora 19 */
@@ -707,7 +717,8 @@ int collect_sockets(struct ns_id *ns)
 	req.r.n.sdiag_family	= AF_NETLINK;
 	req.r.n.sdiag_protocol	= NDIAG_PROTO_ALL;
 	req.r.n.ndiag_show	= NDIAG_SHOW_GROUPS;
-	tmp = do_collect_req(nl, &req, sizeof(req), netlink_receive_one, NULL);
+	args.req = NULL;
+	tmp = do_collect_req(nl, &req, sizeof(req), netlink_receive_one, &args);
 	if (tmp) {
 		pr_warn("The current kernel doesn't support netlink_diag\n");
 		if (ns->ns_pid == 0 || tmp != -ENOENT) /* Fedora 19 */
diff --git a/images/packet-sock.proto b/images/packet-sock.proto
index f6198c1..25875b4 100644
--- a/images/packet-sock.proto
+++ b/images/packet-sock.proto
@@ -43,4 +43,5 @@ message packet_sock_entry {
 	optional uint32		fanout		= 17 [ default = 0xffffffff ];
 	optional packet_ring	rx_ring		= 18;
 	optional packet_ring	tx_ring		= 19;
+	optional uint32		ns_id		= 20;
 }
diff --git a/images/sk-inet.proto b/images/sk-inet.proto
index 01dda87..09c5a47 100644
--- a/images/sk-inet.proto
+++ b/images/sk-inet.proto
@@ -39,4 +39,5 @@ message inet_sk_entry {
 	/* for ipv6, we need to send the ifindex to bind(); we keep the ifname
 	 * here and convert it on restore */
 	optional string			ifname		= 17;
+	optional uint32			ns_id		= 18;
 }
diff --git a/images/sk-netlink.proto b/images/sk-netlink.proto
index ed24c50..402281d 100644
--- a/images/sk-netlink.proto
+++ b/images/sk-netlink.proto
@@ -16,4 +16,5 @@ message netlink_sk_entry {
 	required uint32			dst_group	=  10;
 	required fown_entry		fown		=  11;
 	required sk_opts_entry		opts		=  12;
+	optional uint32			ns_id		=  13;
 }
diff --git a/images/sk-packet.proto b/images/sk-packet.proto
index 5f61c73..33ace1d 100644
--- a/images/sk-packet.proto
+++ b/images/sk-packet.proto
@@ -3,4 +3,5 @@ syntax = "proto2";
 message sk_packet_entry {
 	required uint32		id_for		= 1;
 	required uint32		length		= 2;
+	optional uint32		ns_id		= 4;
 }
diff --git a/images/sk-unix.proto b/images/sk-unix.proto
index 3026214..d695070 100644
--- a/images/sk-unix.proto
+++ b/images/sk-unix.proto
@@ -48,4 +48,6 @@ message unix_sk_entry {
 	 */
 	optional string			name_dir	= 14;
 	optional bool			deleted		= 15;
+
+	optional uint32			ns_id		= 16;
 }
-- 
2.7.4



More information about the CRIU mailing list