[09/11] net: set a proper network namespace to create a socket

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

Details

Message ID 1485993871-3990-10-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 from a proper network namespaces
where it was created.

We set a specified network namespace before restoring a socket.
A task network namespace is set after restoring all files.

Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
---
 criu/files.c           |  3 +++
 criu/include/sockets.h |  2 ++
 criu/sk-inet.c         |  3 +++
 criu/sk-netlink.c      |  3 +++
 criu/sk-packet.c       |  3 +++
 criu/sk-unix.c         |  7 ++++++-
 criu/sockets.c         | 37 +++++++++++++++++++++++++++++++++++++
 7 files changed, 57 insertions(+), 1 deletion(-)

Patch hide | download patch | download mbox

diff --git a/criu/files.c b/criu/files.c
index 8e4ed1b..b394947 100644
--- a/criu/files.c
+++ b/criu/files.c
@@ -1686,6 +1686,9 @@  int open_transport_socket(void)
 	if (!task_alive(current) || (fdt && fdt->pid != pid))
 		return 0;
 
+	if (root_item->ids && set_netns(root_item->ids->net_ns_id))
+		return -1;
+
 	sock = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
 	if (sock < 0) {
 		pr_perror("Can't create socket");
diff --git a/criu/include/sockets.h b/criu/include/sockets.h
index 7685eeb..28bf91e 100644
--- a/criu/include/sockets.h
+++ b/criu/include/sockets.h
@@ -82,4 +82,6 @@  static inline int sk_decode_shutdown(int val)
 #define NETLINK_SOCK_DIAG NETLINK_INET_DIAG
 #endif
 
+extern int set_netns(uint32_t ns_id);
+
 #endif /* __CR_SOCKETS_H__ */
diff --git a/criu/sk-inet.c b/criu/sk-inet.c
index bb898d5..ee6ce60 100644
--- a/criu/sk-inet.c
+++ b/criu/sk-inet.c
@@ -643,6 +643,9 @@  static int open_inet_sk(struct file_desc *d, int *new_fd)
 	if (inet_validate_address(ie))
 		return -1;
 
+	if (set_netns(ie->ns_id))
+		return -1;
+
 	sk = socket(ie->family, ie->type, ie->proto);
 	if (sk < 0) {
 		pr_perror("Can't create inet socket");
diff --git a/criu/sk-netlink.c b/criu/sk-netlink.c
index 4ef934a..1101ee8 100644
--- a/criu/sk-netlink.c
+++ b/criu/sk-netlink.c
@@ -179,6 +179,9 @@  static int open_netlink_sk(struct file_desc *d, int *new_fd)
 
 	pr_info("Opening netlink socket id %#x\n", nse->id);
 
+	if (set_netns(nse->ns_id))
+		return -1;
+
 	sk = socket(PF_NETLINK, SOCK_RAW, nse->protocol);
 	if (sk < 0) {
 		pr_perror("Can't create netlink sock");
diff --git a/criu/sk-packet.c b/criu/sk-packet.c
index f1cf117..297877a 100644
--- a/criu/sk-packet.c
+++ b/criu/sk-packet.c
@@ -470,6 +470,9 @@  static int open_packet_sk(struct file_desc *d, int *new_fd)
 
 	pr_info("Opening packet socket id %#x\n", pse->id);
 
+	if (set_netns(pse->ns_id))
+		return -1;
+
 	if (pse->type == SOCK_PACKET)
 		return open_packet_sk_spkt(pse, new_fd);
 
diff --git a/criu/sk-unix.c b/criu/sk-unix.c
index 35c4d32..fe6ff1b 100644
--- a/criu/sk-unix.c
+++ b/criu/sk-unix.c
@@ -1092,6 +1092,9 @@  static int open_unixsk_pair_master(struct unix_sk_info *ui, int *new_fd)
 	pr_info("Opening pair master (id %#x ino %#x peer %#x)\n",
 			ui->ue->id, ui->ue->ino, ui->ue->peer);
 
+	if (set_netns(ui->ue->ns_id))
+		return -1;
+
 	if (socketpair(PF_UNIX, ui->ue->type, 0, sk) < 0) {
 		pr_perror("Can't make socketpair");
 		return -1;
@@ -1167,6 +1170,9 @@  static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd)
 	pr_info("Opening standalone socket (id %#x ino %#x peer %#x)\n",
 			ui->ue->id, ui->ue->ino, ui->ue->peer);
 
+	if (set_netns(ui->ue->ns_id))
+		return -1;
+
 	/*
 	 * Check if this socket was connected to criu service.
 	 * If so, put response, that dumping and restoring
@@ -1270,7 +1276,6 @@  static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd)
 			return -1;
 		}
 
-
 		sk = socket(PF_UNIX, ui->ue->type, 0);
 		if (sk < 0) {
 			pr_perror("Can't make unix socket");
diff --git a/criu/sockets.c b/criu/sockets.c
index 86a6b21..95da999 100644
--- a/criu/sockets.c
+++ b/criu/sockets.c
@@ -1,3 +1,4 @@ 
+#include <sched.h>
 #include <unistd.h>
 #include <sys/socket.h>
 #include <linux/netlink.h>
@@ -24,6 +25,8 @@ 
 #include "net.h"
 #include "xmalloc.h"
 #include "fs-magic.h"
+#include "pstree.h"
+#include "util.h"
 
 #ifndef SOCK_DIAG_BY_FAMILY
 #define SOCK_DIAG_BY_FAMILY 20
@@ -740,3 +743,37 @@  int collect_sockets(struct ns_id *ns)
 
 	return err;
 }
+
+static uint32_t last_ns_id = 0;
+
+int set_netns(uint32_t ns_id)
+{
+	struct ns_id *ns;
+	int nsfd;
+
+	if (!(root_ns_mask & CLONE_NEWNET))
+		return 0;
+
+	if (ns_id == last_ns_id)
+		return 0;
+
+	ns = lookup_ns_by_id(ns_id, &net_ns_desc);
+	if (ns == NULL) {
+		pr_err("Unable to find a network namespace");
+		return -1;
+	}
+	nsfd = open_proc(root_item->pid->ns[0].virt, "fd/%d", ns->net.ns_fd);
+	if (nsfd < 0)
+		return -1;
+	if (setns(nsfd, CLONE_NEWNET)) {
+		pr_perror("Unable to switch a network namespace");
+		close(nsfd);
+		return -1;
+	}
+	last_ns_id = ns_id;
+	close(nsfd);
+
+	close_pid_proc();
+
+	return 0;
+}

Comments

Pavel Emelianov Feb. 8, 2017, 9:58 a.m.
On 02/02/2017 03:04 AM, Andrei Vagin wrote:
> From: Andrei Vagin <avagin@virtuozzo.com>
> 
> Each socket has to be restored from a proper network namespaces
> where it was created.
> 
> We set a specified network namespace before restoring a socket.

Should we restore it back after the socket is created?

> A task network namespace is set after restoring all files.
> 
> Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
> ---
>  criu/files.c           |  3 +++
>  criu/include/sockets.h |  2 ++
>  criu/sk-inet.c         |  3 +++
>  criu/sk-netlink.c      |  3 +++
>  criu/sk-packet.c       |  3 +++
>  criu/sk-unix.c         |  7 ++++++-
>  criu/sockets.c         | 37 +++++++++++++++++++++++++++++++++++++
>  7 files changed, 57 insertions(+), 1 deletion(-)
> 
> diff --git a/criu/files.c b/criu/files.c
> index 8e4ed1b..b394947 100644
> --- a/criu/files.c
> +++ b/criu/files.c
> @@ -1686,6 +1686,9 @@ int open_transport_socket(void)
>  	if (!task_alive(current) || (fdt && fdt->pid != pid))
>  		return 0;
>  
> +	if (root_item->ids && set_netns(root_item->ids->net_ns_id))
> +		return -1;

Tasks all live in one netns, why do we need to change it here?

> +
>  	sock = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
>  	if (sock < 0) {
>  		pr_perror("Can't create socket");
> diff --git a/criu/include/sockets.h b/criu/include/sockets.h
> index 7685eeb..28bf91e 100644
> --- a/criu/include/sockets.h
> +++ b/criu/include/sockets.h
> @@ -82,4 +82,6 @@ static inline int sk_decode_shutdown(int val)
>  #define NETLINK_SOCK_DIAG NETLINK_INET_DIAG
>  #endif
>  
> +extern int set_netns(uint32_t ns_id);
> +
>  #endif /* __CR_SOCKETS_H__ */
> diff --git a/criu/sk-inet.c b/criu/sk-inet.c
> index bb898d5..ee6ce60 100644
> --- a/criu/sk-inet.c
> +++ b/criu/sk-inet.c
> @@ -643,6 +643,9 @@ static int open_inet_sk(struct file_desc *d, int *new_fd)
>  	if (inet_validate_address(ie))
>  		return -1;
>  
> +	if (set_netns(ie->ns_id))
> +		return -1;
> +
>  	sk = socket(ie->family, ie->type, ie->proto);
>  	if (sk < 0) {
>  		pr_perror("Can't create inet socket");
> diff --git a/criu/sk-netlink.c b/criu/sk-netlink.c
> index 4ef934a..1101ee8 100644
> --- a/criu/sk-netlink.c
> +++ b/criu/sk-netlink.c
> @@ -179,6 +179,9 @@ static int open_netlink_sk(struct file_desc *d, int *new_fd)
>  
>  	pr_info("Opening netlink socket id %#x\n", nse->id);
>  
> +	if (set_netns(nse->ns_id))
> +		return -1;
> +
>  	sk = socket(PF_NETLINK, SOCK_RAW, nse->protocol);
>  	if (sk < 0) {
>  		pr_perror("Can't create netlink sock");
> diff --git a/criu/sk-packet.c b/criu/sk-packet.c
> index f1cf117..297877a 100644
> --- a/criu/sk-packet.c
> +++ b/criu/sk-packet.c
> @@ -470,6 +470,9 @@ static int open_packet_sk(struct file_desc *d, int *new_fd)
>  
>  	pr_info("Opening packet socket id %#x\n", pse->id);
>  
> +	if (set_netns(pse->ns_id))
> +		return -1;
> +
>  	if (pse->type == SOCK_PACKET)
>  		return open_packet_sk_spkt(pse, new_fd);
>  
> diff --git a/criu/sk-unix.c b/criu/sk-unix.c
> index 35c4d32..fe6ff1b 100644
> --- a/criu/sk-unix.c
> +++ b/criu/sk-unix.c
> @@ -1092,6 +1092,9 @@ static int open_unixsk_pair_master(struct unix_sk_info *ui, int *new_fd)
>  	pr_info("Opening pair master (id %#x ino %#x peer %#x)\n",
>  			ui->ue->id, ui->ue->ino, ui->ue->peer);
>  
> +	if (set_netns(ui->ue->ns_id))
> +		return -1;
> +
>  	if (socketpair(PF_UNIX, ui->ue->type, 0, sk) < 0) {
>  		pr_perror("Can't make socketpair");
>  		return -1;
> @@ -1167,6 +1170,9 @@ static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd)
>  	pr_info("Opening standalone socket (id %#x ino %#x peer %#x)\n",
>  			ui->ue->id, ui->ue->ino, ui->ue->peer);
>  
> +	if (set_netns(ui->ue->ns_id))
> +		return -1;
> +
>  	/*
>  	 * Check if this socket was connected to criu service.
>  	 * If so, put response, that dumping and restoring
> @@ -1270,7 +1276,6 @@ static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd)
>  			return -1;
>  		}
>  
> -
>  		sk = socket(PF_UNIX, ui->ue->type, 0);
>  		if (sk < 0) {
>  			pr_perror("Can't make unix socket");
> diff --git a/criu/sockets.c b/criu/sockets.c
> index 86a6b21..95da999 100644
> --- a/criu/sockets.c
> +++ b/criu/sockets.c
> @@ -1,3 +1,4 @@
> +#include <sched.h>
>  #include <unistd.h>
>  #include <sys/socket.h>
>  #include <linux/netlink.h>
> @@ -24,6 +25,8 @@
>  #include "net.h"
>  #include "xmalloc.h"
>  #include "fs-magic.h"
> +#include "pstree.h"
> +#include "util.h"
>  
>  #ifndef SOCK_DIAG_BY_FAMILY
>  #define SOCK_DIAG_BY_FAMILY 20
> @@ -740,3 +743,37 @@ int collect_sockets(struct ns_id *ns)
>  
>  	return err;
>  }
> +
> +static uint32_t last_ns_id = 0;
> +
> +int set_netns(uint32_t ns_id)
> +{
> +	struct ns_id *ns;
> +	int nsfd;
> +
> +	if (!(root_ns_mask & CLONE_NEWNET))
> +		return 0;
> +
> +	if (ns_id == last_ns_id)
> +		return 0;
> +
> +	ns = lookup_ns_by_id(ns_id, &net_ns_desc);
> +	if (ns == NULL) {
> +		pr_err("Unable to find a network namespace");
> +		return -1;
> +	}
> +	nsfd = open_proc(root_item->pid->ns[0].virt, "fd/%d", ns->net.ns_fd);
> +	if (nsfd < 0)
> +		return -1;
> +	if (setns(nsfd, CLONE_NEWNET)) {
> +		pr_perror("Unable to switch a network namespace");
> +		close(nsfd);
> +		return -1;
> +	}
> +	last_ns_id = ns_id;
> +	close(nsfd);
> +
> +	close_pid_proc();

Why this?

> +
> +	return 0;
> +}
>
Andrey Vagin Feb. 9, 2017, 3:27 a.m.
On Wed, Feb 08, 2017 at 12:58:46PM +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 from a proper network namespaces
> > where it was created.
> > 
> > We set a specified network namespace before restoring a socket.
> 
> Should we restore it back after the socket is created?

No, we should not.
> 
> > A task network namespace is set after restoring all files.
> > 
> > Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
> > ---
> >  criu/files.c           |  3 +++
> >  criu/include/sockets.h |  2 ++
> >  criu/sk-inet.c         |  3 +++
> >  criu/sk-netlink.c      |  3 +++
> >  criu/sk-packet.c       |  3 +++
> >  criu/sk-unix.c         |  7 ++++++-
> >  criu/sockets.c         | 37 +++++++++++++++++++++++++++++++++++++
> >  7 files changed, 57 insertions(+), 1 deletion(-)
> > 
> > diff --git a/criu/files.c b/criu/files.c
> > index 8e4ed1b..b394947 100644
> > --- a/criu/files.c
> > +++ b/criu/files.c
> > @@ -1686,6 +1686,9 @@ int open_transport_socket(void)
> >  	if (!task_alive(current) || (fdt && fdt->pid != pid))
> >  		return 0;
> >  
> > +	if (root_item->ids && set_netns(root_item->ids->net_ns_id))
> > +		return -1;
> 
> Tasks all live in one netns, why do we need to change it here?

This series was created when we had more than transport socket
per-process... Will fix.

> 
> > +
> >  	sock = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
> >  	if (sock < 0) {
> >  		pr_perror("Can't create socket");
> > diff --git a/criu/include/sockets.h b/criu/include/sockets.h
> > index 7685eeb..28bf91e 100644
> > --- a/criu/include/sockets.h
> > +++ b/criu/include/sockets.h
> > @@ -82,4 +82,6 @@ static inline int sk_decode_shutdown(int val)
> >  #define NETLINK_SOCK_DIAG NETLINK_INET_DIAG
> >  #endif
> >  
> > +extern int set_netns(uint32_t ns_id);
> > +
> >  #endif /* __CR_SOCKETS_H__ */
> > diff --git a/criu/sk-inet.c b/criu/sk-inet.c
> > index bb898d5..ee6ce60 100644
> > --- a/criu/sk-inet.c
> > +++ b/criu/sk-inet.c
> > @@ -643,6 +643,9 @@ static int open_inet_sk(struct file_desc *d, int *new_fd)
> >  	if (inet_validate_address(ie))
> >  		return -1;
> >  
> > +	if (set_netns(ie->ns_id))
> > +		return -1;
> > +
> >  	sk = socket(ie->family, ie->type, ie->proto);
> >  	if (sk < 0) {
> >  		pr_perror("Can't create inet socket");
> > diff --git a/criu/sk-netlink.c b/criu/sk-netlink.c
> > index 4ef934a..1101ee8 100644
> > --- a/criu/sk-netlink.c
> > +++ b/criu/sk-netlink.c
> > @@ -179,6 +179,9 @@ static int open_netlink_sk(struct file_desc *d, int *new_fd)
> >  
> >  	pr_info("Opening netlink socket id %#x\n", nse->id);
> >  
> > +	if (set_netns(nse->ns_id))
> > +		return -1;
> > +
> >  	sk = socket(PF_NETLINK, SOCK_RAW, nse->protocol);
> >  	if (sk < 0) {
> >  		pr_perror("Can't create netlink sock");
> > diff --git a/criu/sk-packet.c b/criu/sk-packet.c
> > index f1cf117..297877a 100644
> > --- a/criu/sk-packet.c
> > +++ b/criu/sk-packet.c
> > @@ -470,6 +470,9 @@ static int open_packet_sk(struct file_desc *d, int *new_fd)
> >  
> >  	pr_info("Opening packet socket id %#x\n", pse->id);
> >  
> > +	if (set_netns(pse->ns_id))
> > +		return -1;
> > +
> >  	if (pse->type == SOCK_PACKET)
> >  		return open_packet_sk_spkt(pse, new_fd);
> >  
> > diff --git a/criu/sk-unix.c b/criu/sk-unix.c
> > index 35c4d32..fe6ff1b 100644
> > --- a/criu/sk-unix.c
> > +++ b/criu/sk-unix.c
> > @@ -1092,6 +1092,9 @@ static int open_unixsk_pair_master(struct unix_sk_info *ui, int *new_fd)
> >  	pr_info("Opening pair master (id %#x ino %#x peer %#x)\n",
> >  			ui->ue->id, ui->ue->ino, ui->ue->peer);
> >  
> > +	if (set_netns(ui->ue->ns_id))
> > +		return -1;
> > +
> >  	if (socketpair(PF_UNIX, ui->ue->type, 0, sk) < 0) {
> >  		pr_perror("Can't make socketpair");
> >  		return -1;
> > @@ -1167,6 +1170,9 @@ static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd)
> >  	pr_info("Opening standalone socket (id %#x ino %#x peer %#x)\n",
> >  			ui->ue->id, ui->ue->ino, ui->ue->peer);
> >  
> > +	if (set_netns(ui->ue->ns_id))
> > +		return -1;
> > +
> >  	/*
> >  	 * Check if this socket was connected to criu service.
> >  	 * If so, put response, that dumping and restoring
> > @@ -1270,7 +1276,6 @@ static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd)
> >  			return -1;
> >  		}
> >  
> > -
> >  		sk = socket(PF_UNIX, ui->ue->type, 0);
> >  		if (sk < 0) {
> >  			pr_perror("Can't make unix socket");
> > diff --git a/criu/sockets.c b/criu/sockets.c
> > index 86a6b21..95da999 100644
> > --- a/criu/sockets.c
> > +++ b/criu/sockets.c
> > @@ -1,3 +1,4 @@
> > +#include <sched.h>
> >  #include <unistd.h>
> >  #include <sys/socket.h>
> >  #include <linux/netlink.h>
> > @@ -24,6 +25,8 @@
> >  #include "net.h"
> >  #include "xmalloc.h"
> >  #include "fs-magic.h"
> > +#include "pstree.h"
> > +#include "util.h"
> >  
> >  #ifndef SOCK_DIAG_BY_FAMILY
> >  #define SOCK_DIAG_BY_FAMILY 20
> > @@ -740,3 +743,37 @@ int collect_sockets(struct ns_id *ns)
> >  
> >  	return err;
> >  }
> > +
> > +static uint32_t last_ns_id = 0;
> > +
> > +int set_netns(uint32_t ns_id)
> > +{
> > +	struct ns_id *ns;
> > +	int nsfd;
> > +
> > +	if (!(root_ns_mask & CLONE_NEWNET))
> > +		return 0;
> > +
> > +	if (ns_id == last_ns_id)
> > +		return 0;
> > +
> > +	ns = lookup_ns_by_id(ns_id, &net_ns_desc);
> > +	if (ns == NULL) {
> > +		pr_err("Unable to find a network namespace");
> > +		return -1;
> > +	}
> > +	nsfd = open_proc(root_item->pid->ns[0].virt, "fd/%d", ns->net.ns_fd);
> > +	if (nsfd < 0)
> > +		return -1;
> > +	if (setns(nsfd, CLONE_NEWNET)) {
> > +		pr_perror("Unable to switch a network namespace");
> > +		close(nsfd);
> > +		return -1;
> > +	}
> > +	last_ns_id = ns_id;
> > +	close(nsfd);
> > +
> > +	close_pid_proc();
> 
> Why this?

open_proc_self_fd isn't a service descriptor now, so
we need to close it to avoid conflicts with restored file descritors.

Actually open_proc_self_fd has to be a service descriptor. Will fix.
> 
> > +
> > +	return 0;
> > +}
> > 
>