[06/11] net: save network namespaces for sockets

Submitted by Andrei Vagin on Feb. 2, 2017, 12:04 a.m.

Details

Message ID 1485993871-3990-7-git-send-email-avagin@openvz.org
State New
Series "Dump and restore nested network namespaces"
Headers show

Commit Message

Andrei Vagin Feb. 2, 2017, 12:04 a.m.
From: Andrei Vagin <avagin@virtuozzo.com>

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

Here is an issue about unconnected and unbound sockets,
they are not reported via socket-diag and we can't to
get their network namespaces.

Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
---
 criu/include/namespaces.h |  2 ++
 criu/include/sockets.h    |  3 ++-
 criu/net.c                | 25 +++++++++++++++++++++++++
 criu/sk-inet.c            | 16 ++++++++++++++--
 criu/sk-netlink.c         | 14 +++++++++++++-
 criu/sk-packet.c          |  5 ++++-
 criu/sk-unix.c            |  4 +++-
 criu/sockets.c            |  3 ++-
 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 ++
 13 files changed, 71 insertions(+), 7 deletions(-)

Patch hide | download patch | download mbox

diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h
index c9f3e8a..18eafb2 100644
--- a/criu/include/namespaces.h
+++ b/criu/include/namespaces.h
@@ -184,4 +184,6 @@  extern int __userns_call(const char *func_name, uns_call_t call, int flags,
 
 extern int add_ns_shared_cb(int (*actor)(void *data), void *data);
 
+extern struct ns_id *get_socket_ns(int lfd);
+
 #endif /* __CR_NS_H__ */
diff --git a/criu/include/sockets.h b/criu/include/sockets.h
index 18e20d1..7685eeb 100644
--- a/criu/include/sockets.h
+++ b/criu/include/sockets.h
@@ -18,6 +18,7 @@  struct socket_desc {
 	unsigned int		family;
 	unsigned int		ino;
 	struct socket_desc	*next;
+	struct ns_id		*sk_ns;
 	int			already_dumped;
 };
 
@@ -30,7 +31,7 @@  extern void preload_socket_modules(void);
 
 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);
diff --git a/criu/net.c b/criu/net.c
index 0666fa9..7dadc8d 100644
--- a/criu/net.c
+++ b/criu/net.c
@@ -1915,6 +1915,7 @@  err_nl:
 	goto out;
 }
 
+static int netns_nr;
 static int collect_net_ns(struct ns_id *ns, void *oarg)
 {
 	bool for_dump = (oarg == (void *)1);
@@ -1925,6 +1926,8 @@  static int collect_net_ns(struct ns_id *ns, void *oarg)
 	if (ret)
 		return ret;
 
+	netns_nr++;
+
 	if (!for_dump)
 		return 0;
 
@@ -1939,6 +1942,28 @@  int collect_net_namespaces(bool for_dump)
 
 struct ns_desc net_ns_desc = NS_DESC_ENTRY(CLONE_NEWNET, "net");
 
+static struct ns_id *get_root_netns()
+{
+	static struct ns_id *root_netns = NULL;
+
+	if (root_item->ids == NULL)
+		return NULL;
+
+	if (root_netns == NULL)
+		root_netns = lookup_ns_by_id(root_item->ids->net_ns_id, &net_ns_desc);
+
+	return root_netns;
+}
+
+struct ns_id *get_socket_ns(int lfd)
+{
+	if (netns_nr == 1)
+		return get_root_netns();
+
+	pr_perror("Unable to get a socket net namespace");
+	return NULL;
+}
+
 static int move_to_bridge(struct external *ext, void *arg)
 {
 	int s = *(int *)arg;
diff --git a/criu/sk-inet.c b/criu/sk-inet.c
index b8bd9e2..bb898d5 100644
--- a/criu/sk-inet.c
+++ b/criu/sk-inet.c
@@ -25,6 +25,7 @@ 
 #include "sk-inet.h"
 #include "protobuf.h"
 #include "util.h"
+#include "namespaces.h"
 
 #define PB_ALEN_INET	1
 #define PB_ALEN_INET6	4
@@ -210,9 +211,16 @@  static struct inet_sk_desc *gen_uncon_sk(int lfd, const struct fd_parms *p, int
 {
 	struct inet_sk_desc *sk;
 	union libsoccr_addr address;
+	struct ns_id *ns = NULL;
 	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;
@@ -272,7 +280,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:
@@ -341,6 +349,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.sk_ns) {
+		ie.ns_id	= sk->sd.sk_ns->id;
+		ie.has_ns_id	= true;
+	}
 	ie.family	= family;
 	ie.proto	= proto;
 	ie.type		= sk->type;
@@ -477,7 +489,7 @@  int inet_collect_one(struct nlmsghdr *h, int family, int type, struct ns_id *ns)
 	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 0fb873c..4ef934a 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;
@@ -61,7 +62,7 @@  int netlink_receive_one(struct nlmsghdr *hdr, struct ns_id *ns, 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, ns);
 }
 
 static bool can_dump_netlink_sk(int lfd)
@@ -94,6 +95,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.sk_ns->id;
+		ne.has_ns_id = true;
 		ne.protocol = sk->protocol;
 		ne.portid = sk->portid;
 		ne.groups = sk->groups;
@@ -120,9 +123,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 cdd0595..f1cf117 100644
--- a/criu/sk-packet.c
+++ b/criu/sk-packet.c
@@ -20,6 +20,7 @@ 
 #include "xmalloc.h"
 #include "images/packet-sock.pb-c.h"
 #include "images/fdinfo.pb-c.h"
+#include "namespaces.h"
 
 struct packet_sock_info {
 	PacketSockEntry *pse;
@@ -162,6 +163,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.sk_ns->id;
+	psk.has_ns_id = true;
 	psk.type = sd->type;
 	psk.flags = p->flags;
 	psk.fown = (FownEntry *)&p->fown;
@@ -296,7 +299,7 @@  int packet_receive_one(struct nlmsghdr *hdr, struct ns_id *ns, 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, ns);
 err:
 	xfree(sd->tx);
 	xfree(sd->rx);
diff --git a/criu/sk-unix.c b/criu/sk-unix.c
index f0048ea..35c4d32 100644
--- a/criu/sk-unix.c
+++ b/criu/sk-unix.c
@@ -297,6 +297,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.sk_ns->id;
+	ue->has_ns_id	= true;
 	ue->type	= sk->type;
 	ue->state	= sk->state;
 	ue->flags	= p->flags;
@@ -660,7 +662,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);
 
diff --git a/criu/sockets.c b/criu/sockets.c
index fa551eb..86a6b21 100644
--- a/criu/sockets.c
+++ b/criu/sockets.c
@@ -353,13 +353,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->sk_ns	= ns;
 
 	chain = &sockets[ino % SK_HASH_SIZE];
 	d->next = *chain;
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;
 }

Comments

Pavel Emelianov Feb. 8, 2017, 9:48 a.m.
On 02/02/2017 03:04 AM, Andrei Vagin wrote:
> From: Andrei Vagin <avagin@virtuozzo.com>
> 
> Each socket has to be restored in a proper namespaces where
> it has been created.
> 
> Here is an issue about unconnected and unbound sockets,
> they are not reported via socket-diag and we can't to
> get their network namespaces.
> 
> Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
> ---
>  criu/include/namespaces.h |  2 ++
>  criu/include/sockets.h    |  3 ++-
>  criu/net.c                | 25 +++++++++++++++++++++++++
>  criu/sk-inet.c            | 16 ++++++++++++++--
>  criu/sk-netlink.c         | 14 +++++++++++++-
>  criu/sk-packet.c          |  5 ++++-
>  criu/sk-unix.c            |  4 +++-
>  criu/sockets.c            |  3 ++-
>  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 ++
>  13 files changed, 71 insertions(+), 7 deletions(-)
> 
> diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h
> index c9f3e8a..18eafb2 100644
> --- a/criu/include/namespaces.h
> +++ b/criu/include/namespaces.h
> @@ -184,4 +184,6 @@ extern int __userns_call(const char *func_name, uns_call_t call, int flags,
>  
>  extern int add_ns_shared_cb(int (*actor)(void *data), void *data);
>  
> +extern struct ns_id *get_socket_ns(int lfd);
> +
>  #endif /* __CR_NS_H__ */
> diff --git a/criu/include/sockets.h b/criu/include/sockets.h
> index 18e20d1..7685eeb 100644
> --- a/criu/include/sockets.h
> +++ b/criu/include/sockets.h
> @@ -18,6 +18,7 @@ struct socket_desc {
>  	unsigned int		family;
>  	unsigned int		ino;
>  	struct socket_desc	*next;
> +	struct ns_id		*sk_ns;
>  	int			already_dumped;
>  };
>  
> @@ -30,7 +31,7 @@ extern void preload_socket_modules(void);
>  
>  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);
> diff --git a/criu/net.c b/criu/net.c
> index 0666fa9..7dadc8d 100644
> --- a/criu/net.c
> +++ b/criu/net.c
> @@ -1915,6 +1915,7 @@ err_nl:
>  	goto out;
>  }
>  
> +static int netns_nr;
>  static int collect_net_ns(struct ns_id *ns, void *oarg)
>  {
>  	bool for_dump = (oarg == (void *)1);
> @@ -1925,6 +1926,8 @@ static int collect_net_ns(struct ns_id *ns, void *oarg)
>  	if (ret)
>  		return ret;
>  
> +	netns_nr++;
> +
>  	if (!for_dump)
>  		return 0;
>  
> @@ -1939,6 +1942,28 @@ int collect_net_namespaces(bool for_dump)
>  
>  struct ns_desc net_ns_desc = NS_DESC_ENTRY(CLONE_NEWNET, "net");
>  
> +static struct ns_id *get_root_netns()
> +{
> +	static struct ns_id *root_netns = NULL;
> +
> +	if (root_item->ids == NULL)
> +		return NULL;

Shouldn't we check this under if (root_netns == NULL) check?

> +
> +	if (root_netns == NULL)
> +		root_netns = lookup_ns_by_id(root_item->ids->net_ns_id, &net_ns_desc);
> +
> +	return root_netns;
> +}
> +
> +struct ns_id *get_socket_ns(int lfd)

Please, rename to get_uncollected_socket_ns() and add a comment
describing what the problem is.

> +{
> +	if (netns_nr == 1)

This is called under root_ns_mask & CLONE_NEWNET, so we want to
check whether there are NS_OTHER net namespaces or not. Right?

> +		return get_root_netns();
> +
> +	pr_perror("Unable to get a socket net namespace");
> +	return NULL;
> +}
> +
>  static int move_to_bridge(struct external *ext, void *arg)
>  {
>  	int s = *(int *)arg;
> diff --git a/criu/sk-inet.c b/criu/sk-inet.c
> index b8bd9e2..bb898d5 100644
> --- a/criu/sk-inet.c
> +++ b/criu/sk-inet.c
> @@ -25,6 +25,7 @@
>  #include "sk-inet.h"
>  #include "protobuf.h"
>  #include "util.h"
> +#include "namespaces.h"
>  
>  #define PB_ALEN_INET	1
>  #define PB_ALEN_INET6	4
> @@ -210,9 +211,16 @@ static struct inet_sk_desc *gen_uncon_sk(int lfd, const struct fd_parms *p, int
>  {
>  	struct inet_sk_desc *sk;
>  	union libsoccr_addr address;
> +	struct ns_id *ns = NULL;
>  	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;
> @@ -272,7 +280,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:
> @@ -341,6 +349,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.sk_ns) {
> +		ie.ns_id	= sk->sd.sk_ns->id;
> +		ie.has_ns_id	= true;
> +	}
>  	ie.family	= family;
>  	ie.proto	= proto;
>  	ie.type		= sk->type;
> @@ -477,7 +489,7 @@ int inet_collect_one(struct nlmsghdr *h, int family, int type, struct ns_id *ns)
>  	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 0fb873c..4ef934a 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;
> @@ -61,7 +62,7 @@ int netlink_receive_one(struct nlmsghdr *hdr, struct ns_id *ns, 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, ns);
>  }
>  
>  static bool can_dump_netlink_sk(int lfd)
> @@ -94,6 +95,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.sk_ns->id;
> +		ne.has_ns_id = true;
>  		ne.protocol = sk->protocol;
>  		ne.portid = sk->portid;
>  		ne.groups = sk->groups;
> @@ -120,9 +123,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 cdd0595..f1cf117 100644
> --- a/criu/sk-packet.c
> +++ b/criu/sk-packet.c
> @@ -20,6 +20,7 @@
>  #include "xmalloc.h"
>  #include "images/packet-sock.pb-c.h"
>  #include "images/fdinfo.pb-c.h"
> +#include "namespaces.h"
>  
>  struct packet_sock_info {
>  	PacketSockEntry *pse;
> @@ -162,6 +163,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.sk_ns->id;
> +	psk.has_ns_id = true;
>  	psk.type = sd->type;
>  	psk.flags = p->flags;
>  	psk.fown = (FownEntry *)&p->fown;
> @@ -296,7 +299,7 @@ int packet_receive_one(struct nlmsghdr *hdr, struct ns_id *ns, 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, ns);
>  err:
>  	xfree(sd->tx);
>  	xfree(sd->rx);
> diff --git a/criu/sk-unix.c b/criu/sk-unix.c
> index f0048ea..35c4d32 100644
> --- a/criu/sk-unix.c
> +++ b/criu/sk-unix.c
> @@ -297,6 +297,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.sk_ns->id;
> +	ue->has_ns_id	= true;
>  	ue->type	= sk->type;
>  	ue->state	= sk->state;
>  	ue->flags	= p->flags;
> @@ -660,7 +662,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);
>  
> diff --git a/criu/sockets.c b/criu/sockets.c
> index fa551eb..86a6b21 100644
> --- a/criu/sockets.c
> +++ b/criu/sockets.c
> @@ -353,13 +353,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->sk_ns	= ns;
>  
>  	chain = &sockets[ino % SK_HASH_SIZE];
>  	d->next = *chain;
> 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;

Why is ns_id needed here? The id_for is unique across namespaces, isn't it?

>  }
> 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;
>  }
>
Andrey Vagin Feb. 9, 2017, 12:53 a.m.
On Wed, Feb 08, 2017 at 12:48:00PM +0300, Pavel Emelyanov wrote:
> On 02/02/2017 03:04 AM, Andrei Vagin wrote:
> > From: Andrei Vagin <avagin@virtuozzo.com>
> > 
> > Each socket has to be restored in a proper namespaces where
> > it has been created.
> > 
> > Here is an issue about unconnected and unbound sockets,
> > they are not reported via socket-diag and we can't to
> > get their network namespaces.
> > 
> > Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
> > ---
> >  criu/include/namespaces.h |  2 ++
> >  criu/include/sockets.h    |  3 ++-
> >  criu/net.c                | 25 +++++++++++++++++++++++++
> >  criu/sk-inet.c            | 16 ++++++++++++++--
> >  criu/sk-netlink.c         | 14 +++++++++++++-
> >  criu/sk-packet.c          |  5 ++++-
> >  criu/sk-unix.c            |  4 +++-
> >  criu/sockets.c            |  3 ++-
> >  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 ++
> >  13 files changed, 71 insertions(+), 7 deletions(-)
> > 
> > diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h
> > index c9f3e8a..18eafb2 100644
> > --- a/criu/include/namespaces.h
> > +++ b/criu/include/namespaces.h
> > @@ -184,4 +184,6 @@ extern int __userns_call(const char *func_name, uns_call_t call, int flags,
> >  
> >  extern int add_ns_shared_cb(int (*actor)(void *data), void *data);
> >  
> > +extern struct ns_id *get_socket_ns(int lfd);
> > +
> >  #endif /* __CR_NS_H__ */
> > diff --git a/criu/include/sockets.h b/criu/include/sockets.h
> > index 18e20d1..7685eeb 100644
> > --- a/criu/include/sockets.h
> > +++ b/criu/include/sockets.h
> > @@ -18,6 +18,7 @@ struct socket_desc {
> >  	unsigned int		family;
> >  	unsigned int		ino;
> >  	struct socket_desc	*next;
> > +	struct ns_id		*sk_ns;
> >  	int			already_dumped;
> >  };
> >  
> > @@ -30,7 +31,7 @@ extern void preload_socket_modules(void);
> >  
> >  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);
> > diff --git a/criu/net.c b/criu/net.c
> > index 0666fa9..7dadc8d 100644
> > --- a/criu/net.c
> > +++ b/criu/net.c
> > @@ -1915,6 +1915,7 @@ err_nl:
> >  	goto out;
> >  }
> >  
> > +static int netns_nr;
> >  static int collect_net_ns(struct ns_id *ns, void *oarg)
> >  {
> >  	bool for_dump = (oarg == (void *)1);
> > @@ -1925,6 +1926,8 @@ static int collect_net_ns(struct ns_id *ns, void *oarg)
> >  	if (ret)
> >  		return ret;
> >  
> > +	netns_nr++;
> > +
> >  	if (!for_dump)
> >  		return 0;
> >  
> > @@ -1939,6 +1942,28 @@ int collect_net_namespaces(bool for_dump)
> >  
> >  struct ns_desc net_ns_desc = NS_DESC_ENTRY(CLONE_NEWNET, "net");
> >  
> > +static struct ns_id *get_root_netns()
> > +{
> > +	static struct ns_id *root_netns = NULL;
> > +
> > +	if (root_item->ids == NULL)
> > +		return NULL;
> 
> Shouldn't we check this under if (root_netns == NULL) check?

Yes, we should
> 
> > +
> > +	if (root_netns == NULL)
> > +		root_netns = lookup_ns_by_id(root_item->ids->net_ns_id, &net_ns_desc);
> > +
> > +	return root_netns;
> > +}
> > +
> > +struct ns_id *get_socket_ns(int lfd)
> 
> Please, rename to get_uncollected_socket_ns() and add a comment
> describing what the problem is.

hmmmm, this function works for all sockets. Let's add a comment and save
the function name. If you still think that we have to rename this
function, could you just rename it before appling this patch.
> 
> > +{
> > +	if (netns_nr == 1)
> 
> This is called under root_ns_mask & CLONE_NEWNET, so we want to
> check whether there are NS_OTHER net namespaces or not. Right?

yes, if netns_nr is 1, it means that there is only NS_ROOT.

> 
> > +		return get_root_netns();
> > +
> > +	pr_perror("Unable to get a socket net namespace");
> > +	return NULL;
> > +}
> > +
> >  static int move_to_bridge(struct external *ext, void *arg)
> >  {
> >  	int s = *(int *)arg;
> > diff --git a/criu/sk-inet.c b/criu/sk-inet.c
> > index b8bd9e2..bb898d5 100644
> > --- a/criu/sk-inet.c
> > +++ b/criu/sk-inet.c
> > @@ -25,6 +25,7 @@
> >  #include "sk-inet.h"
> >  #include "protobuf.h"
> >  #include "util.h"
> > +#include "namespaces.h"
> >  
> >  #define PB_ALEN_INET	1
> >  #define PB_ALEN_INET6	4
> > @@ -210,9 +211,16 @@ static struct inet_sk_desc *gen_uncon_sk(int lfd, const struct fd_parms *p, int
> >  {
> >  	struct inet_sk_desc *sk;
> >  	union libsoccr_addr address;
> > +	struct ns_id *ns = NULL;
> >  	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;
> > @@ -272,7 +280,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:
> > @@ -341,6 +349,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.sk_ns) {
> > +		ie.ns_id	= sk->sd.sk_ns->id;
> > +		ie.has_ns_id	= true;
> > +	}
> >  	ie.family	= family;
> >  	ie.proto	= proto;
> >  	ie.type		= sk->type;
> > @@ -477,7 +489,7 @@ int inet_collect_one(struct nlmsghdr *h, int family, int type, struct ns_id *ns)
> >  	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 0fb873c..4ef934a 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;
> > @@ -61,7 +62,7 @@ int netlink_receive_one(struct nlmsghdr *hdr, struct ns_id *ns, 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, ns);
> >  }
> >  
> >  static bool can_dump_netlink_sk(int lfd)
> > @@ -94,6 +95,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.sk_ns->id;
> > +		ne.has_ns_id = true;
> >  		ne.protocol = sk->protocol;
> >  		ne.portid = sk->portid;
> >  		ne.groups = sk->groups;
> > @@ -120,9 +123,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 cdd0595..f1cf117 100644
> > --- a/criu/sk-packet.c
> > +++ b/criu/sk-packet.c
> > @@ -20,6 +20,7 @@
> >  #include "xmalloc.h"
> >  #include "images/packet-sock.pb-c.h"
> >  #include "images/fdinfo.pb-c.h"
> > +#include "namespaces.h"
> >  
> >  struct packet_sock_info {
> >  	PacketSockEntry *pse;
> > @@ -162,6 +163,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.sk_ns->id;
> > +	psk.has_ns_id = true;
> >  	psk.type = sd->type;
> >  	psk.flags = p->flags;
> >  	psk.fown = (FownEntry *)&p->fown;
> > @@ -296,7 +299,7 @@ int packet_receive_one(struct nlmsghdr *hdr, struct ns_id *ns, 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, ns);
> >  err:
> >  	xfree(sd->tx);
> >  	xfree(sd->rx);
> > diff --git a/criu/sk-unix.c b/criu/sk-unix.c
> > index f0048ea..35c4d32 100644
> > --- a/criu/sk-unix.c
> > +++ b/criu/sk-unix.c
> > @@ -297,6 +297,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.sk_ns->id;
> > +	ue->has_ns_id	= true;
> >  	ue->type	= sk->type;
> >  	ue->state	= sk->state;
> >  	ue->flags	= p->flags;
> > @@ -660,7 +662,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);
> >  
> > diff --git a/criu/sockets.c b/criu/sockets.c
> > index fa551eb..86a6b21 100644
> > --- a/criu/sockets.c
> > +++ b/criu/sockets.c
> > @@ -353,13 +353,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->sk_ns	= ns;
> >  
> >  	chain = &sockets[ino % SK_HASH_SIZE];
> >  	d->next = *chain;
> > 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;
> 
> Why is ns_id needed here? The id_for is unique across namespaces, isn't it?

Ooops. It is my fault, it should not be here. Thanks!
I just added ns_id to all [SK_TYPE]_sk_entry and added this ns_id by mistake.

Why do we have two images for packet sockets?

[root@fc24 criu]# ls -l images/*sock*.proto
-rw-r--r-- 1 root root 1171 Feb  9 02:55 images/packet-sock.proto
[root@fc24 criu]# ls -l images/sk-*.proto
-rw-r--r-- 1 root root 1247 Feb  9 02:55 images/sk-inet.proto
-rw-r--r-- 1 root root  537 Feb  9 02:55 images/sk-netlink.proto
-rw-r--r-- 1 root root  678 Nov 22 11:07 images/sk-opts.proto
-rw-r--r-- 1 root root  110 Feb  9 03:02 images/sk-packet.proto
-rw-r--r-- 1 root root 1306 Feb  9 03:04 images/sk-unix.proto

> 
> >  }
> > 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;
> >  }
> > 
>
Andrey Vagin Feb. 9, 2017, 3:15 a.m.
On Wed, Feb 08, 2017 at 04:53:25PM -0800, Andrei Vagin wrote:
> On Wed, Feb 08, 2017 at 12:48:00PM +0300, Pavel Emelyanov wrote:
> > On 02/02/2017 03:04 AM, Andrei Vagin wrote:
> > > From: Andrei Vagin <avagin@virtuozzo.com>
> > > 
> > > Each socket has to be restored in a proper namespaces where
> > > it has been created.
> > > 
> > > Here is an issue about unconnected and unbound sockets,
> > > they are not reported via socket-diag and we can't to
> > > get their network namespaces.
> > > 
> > > Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
> > > ---
> > >  criu/include/namespaces.h |  2 ++
> > >  criu/include/sockets.h    |  3 ++-
> > >  criu/net.c                | 25 +++++++++++++++++++++++++
> > >  criu/sk-inet.c            | 16 ++++++++++++++--
> > >  criu/sk-netlink.c         | 14 +++++++++++++-
> > >  criu/sk-packet.c          |  5 ++++-
> > >  criu/sk-unix.c            |  4 +++-
> > >  criu/sockets.c            |  3 ++-
> > >  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 ++
> > >  13 files changed, 71 insertions(+), 7 deletions(-)
> > > 
> > > diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h
> > > index c9f3e8a..18eafb2 100644
> > > --- a/criu/include/namespaces.h
> > > +++ b/criu/include/namespaces.h
> > > @@ -184,4 +184,6 @@ extern int __userns_call(const char *func_name, uns_call_t call, int flags,
> > >  
> > >  extern int add_ns_shared_cb(int (*actor)(void *data), void *data);
> > >  
> > > +extern struct ns_id *get_socket_ns(int lfd);
> > > +
> > >  #endif /* __CR_NS_H__ */
> > > diff --git a/criu/include/sockets.h b/criu/include/sockets.h
> > > index 18e20d1..7685eeb 100644
> > > --- a/criu/include/sockets.h
> > > +++ b/criu/include/sockets.h
> > > @@ -18,6 +18,7 @@ struct socket_desc {
> > >  	unsigned int		family;
> > >  	unsigned int		ino;
> > >  	struct socket_desc	*next;
> > > +	struct ns_id		*sk_ns;
> > >  	int			already_dumped;
> > >  };
> > >  
> > > @@ -30,7 +31,7 @@ extern void preload_socket_modules(void);
> > >  
> > >  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);
> > > diff --git a/criu/net.c b/criu/net.c
> > > index 0666fa9..7dadc8d 100644
> > > --- a/criu/net.c
> > > +++ b/criu/net.c
> > > @@ -1915,6 +1915,7 @@ err_nl:
> > >  	goto out;
> > >  }
> > >  
> > > +static int netns_nr;
> > >  static int collect_net_ns(struct ns_id *ns, void *oarg)
> > >  {
> > >  	bool for_dump = (oarg == (void *)1);
> > > @@ -1925,6 +1926,8 @@ static int collect_net_ns(struct ns_id *ns, void *oarg)
> > >  	if (ret)
> > >  		return ret;
> > >  
> > > +	netns_nr++;
> > > +
> > >  	if (!for_dump)
> > >  		return 0;
> > >  
> > > @@ -1939,6 +1942,28 @@ int collect_net_namespaces(bool for_dump)
> > >  
> > >  struct ns_desc net_ns_desc = NS_DESC_ENTRY(CLONE_NEWNET, "net");
> > >  
> > > +static struct ns_id *get_root_netns()
> > > +{
> > > +	static struct ns_id *root_netns = NULL;
> > > +
> > > +	if (root_item->ids == NULL)
> > > +		return NULL;
> > 
> > Shouldn't we check this under if (root_netns == NULL) check?
> 
> Yes, we should
> > 
> > > +
> > > +	if (root_netns == NULL)
> > > +		root_netns = lookup_ns_by_id(root_item->ids->net_ns_id, &net_ns_desc);
> > > +
> > > +	return root_netns;
> > > +}
> > > +
> > > +struct ns_id *get_socket_ns(int lfd)
> > 
> > Please, rename to get_uncollected_socket_ns() and add a comment
> > describing what the problem is.
> 
> hmmmm, this function works for all sockets. Let's add a comment and save
> the function name. If you still think that we have to rename this
> function, could you just rename it before appling this patch.
> > 
> > > +{
> > > +	if (netns_nr == 1)
> > 
> > This is called under root_ns_mask & CLONE_NEWNET, so we want to
> > check whether there are NS_OTHER net namespaces or not. Right?
> 
> yes, if netns_nr is 1, it means that there is only NS_ROOT.
> 
> > 
> > > +		return get_root_netns();
> > > +
> > > +	pr_perror("Unable to get a socket net namespace");
> > > +	return NULL;
> > > +}
> > > +
> > >  static int move_to_bridge(struct external *ext, void *arg)
> > >  {
> > >  	int s = *(int *)arg;
> > > diff --git a/criu/sk-inet.c b/criu/sk-inet.c
> > > index b8bd9e2..bb898d5 100644
> > > --- a/criu/sk-inet.c
> > > +++ b/criu/sk-inet.c
> > > @@ -25,6 +25,7 @@
> > >  #include "sk-inet.h"
> > >  #include "protobuf.h"
> > >  #include "util.h"
> > > +#include "namespaces.h"
> > >  
> > >  #define PB_ALEN_INET	1
> > >  #define PB_ALEN_INET6	4
> > > @@ -210,9 +211,16 @@ static struct inet_sk_desc *gen_uncon_sk(int lfd, const struct fd_parms *p, int
> > >  {
> > >  	struct inet_sk_desc *sk;
> > >  	union libsoccr_addr address;
> > > +	struct ns_id *ns = NULL;
> > >  	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;
> > > @@ -272,7 +280,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:
> > > @@ -341,6 +349,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.sk_ns) {
> > > +		ie.ns_id	= sk->sd.sk_ns->id;
> > > +		ie.has_ns_id	= true;
> > > +	}
> > >  	ie.family	= family;
> > >  	ie.proto	= proto;
> > >  	ie.type		= sk->type;
> > > @@ -477,7 +489,7 @@ int inet_collect_one(struct nlmsghdr *h, int family, int type, struct ns_id *ns)
> > >  	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 0fb873c..4ef934a 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;
> > > @@ -61,7 +62,7 @@ int netlink_receive_one(struct nlmsghdr *hdr, struct ns_id *ns, 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, ns);
> > >  }
> > >  
> > >  static bool can_dump_netlink_sk(int lfd)
> > > @@ -94,6 +95,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.sk_ns->id;
> > > +		ne.has_ns_id = true;
> > >  		ne.protocol = sk->protocol;
> > >  		ne.portid = sk->portid;
> > >  		ne.groups = sk->groups;
> > > @@ -120,9 +123,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 cdd0595..f1cf117 100644
> > > --- a/criu/sk-packet.c
> > > +++ b/criu/sk-packet.c
> > > @@ -20,6 +20,7 @@
> > >  #include "xmalloc.h"
> > >  #include "images/packet-sock.pb-c.h"
> > >  #include "images/fdinfo.pb-c.h"
> > > +#include "namespaces.h"
> > >  
> > >  struct packet_sock_info {
> > >  	PacketSockEntry *pse;
> > > @@ -162,6 +163,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.sk_ns->id;
> > > +	psk.has_ns_id = true;
> > >  	psk.type = sd->type;
> > >  	psk.flags = p->flags;
> > >  	psk.fown = (FownEntry *)&p->fown;
> > > @@ -296,7 +299,7 @@ int packet_receive_one(struct nlmsghdr *hdr, struct ns_id *ns, 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, ns);
> > >  err:
> > >  	xfree(sd->tx);
> > >  	xfree(sd->rx);
> > > diff --git a/criu/sk-unix.c b/criu/sk-unix.c
> > > index f0048ea..35c4d32 100644
> > > --- a/criu/sk-unix.c
> > > +++ b/criu/sk-unix.c
> > > @@ -297,6 +297,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.sk_ns->id;
> > > +	ue->has_ns_id	= true;
> > >  	ue->type	= sk->type;
> > >  	ue->state	= sk->state;
> > >  	ue->flags	= p->flags;
> > > @@ -660,7 +662,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);
> > >  
> > > diff --git a/criu/sockets.c b/criu/sockets.c
> > > index fa551eb..86a6b21 100644
> > > --- a/criu/sockets.c
> > > +++ b/criu/sockets.c
> > > @@ -353,13 +353,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->sk_ns	= ns;
> > >  
> > >  	chain = &sockets[ino % SK_HASH_SIZE];
> > >  	d->next = *chain;
> > > 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;
> > 
> > Why is ns_id needed here? The id_for is unique across namespaces, isn't it?
> 
> Ooops. It is my fault, it should not be here. Thanks!
> I just added ns_id to all [SK_TYPE]_sk_entry and added this ns_id by mistake.
> 
> Why do we have two images for packet sockets?

sk-packet isn't about packet sockets...

> 
> [root@fc24 criu]# ls -l images/*sock*.proto
> -rw-r--r-- 1 root root 1171 Feb  9 02:55 images/packet-sock.proto
> [root@fc24 criu]# ls -l images/sk-*.proto
> -rw-r--r-- 1 root root 1247 Feb  9 02:55 images/sk-inet.proto
> -rw-r--r-- 1 root root  537 Feb  9 02:55 images/sk-netlink.proto
> -rw-r--r-- 1 root root  678 Nov 22 11:07 images/sk-opts.proto
> -rw-r--r-- 1 root root  110 Feb  9 03:02 images/sk-packet.proto
> -rw-r--r-- 1 root root 1306 Feb  9 03:04 images/sk-unix.proto
> 
> > 
> > >  }
> > > 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;
> > >  }
> > > 
> >