[CRIU] [PATCH 07/10] net: set a proper network namespace to create a socket
Andrei Vagin
avagin at openvz.org
Sun Feb 12 21:49:17 PST 2017
From: Andrei Vagin <avagin at 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.
v2: don't set the root netns for transport sockets
Signed-off-by: Andrei Vagin <avagin at virtuozzo.com>
---
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 +++++++++++++++++++++++++++++++++++++
6 files changed, 54 insertions(+), 1 deletion(-)
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 4d7a890..bf1a3b8 100644
--- a/criu/sk-unix.c
+++ b/criu/sk-unix.c
@@ -1095,6 +1095,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;
@@ -1170,6 +1173,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
@@ -1273,7 +1279,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;
+}
--
2.7.4
More information about the CRIU
mailing list