Commit 6b7393c4 authored by Andrei Vagin's avatar Andrei Vagin

net: allow to dump and restore more than one network namespace

Restore all network namespaces from the root task and then set
a proper namespace for each task after restoring sockets, because
we need to switch network namespaces to restore sockets.

Each socket has to be created in a proper network namespace.

v2: fix a typo bug
Acked-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: 's avatarAndrei Vagin <avagin@virtuozzo.com>
parent a54d3cf1
...@@ -865,6 +865,13 @@ static int restore_one_alive_task(int pid, CoreEntry *core) ...@@ -865,6 +865,13 @@ static int restore_one_alive_task(int pid, CoreEntry *core)
if (prepare_vmas(current, ta)) if (prepare_vmas(current, ta))
return -1; return -1;
/*
* Sockets have to be restored in their network namespaces,
* so a task namespace has to be restored after sockets.
*/
if (restore_task_net_ns(current))
return -1;
if (setup_uffd(pid, ta)) if (setup_uffd(pid, ta))
return -1; return -1;
...@@ -1551,14 +1558,6 @@ static int restore_task_with_children(void *_arg) ...@@ -1551,14 +1558,6 @@ static int restore_task_with_children(void *_arg)
if (ret < 0) if (ret < 0)
goto err; goto err;
if (ca->clone_flags & CLONE_NEWNET) {
ret = unshare(CLONE_NEWNET);
if (ret) {
pr_perror("Can't unshare net-namespace");
goto err;
}
}
if (!(ca->clone_flags & CLONE_FILES)) { if (!(ca->clone_flags & CLONE_FILES)) {
ret = close_old_fds(); ret = close_old_fds();
if (ret) if (ret)
...@@ -3089,6 +3088,11 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns ...@@ -3089,6 +3088,11 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns
if (rst_prep_creds(pid, core, &creds_pos)) if (rst_prep_creds(pid, core, &creds_pos))
goto err_nv; goto err_nv;
if (current->parent == NULL) {
/* Wait when all tasks restored all files */
restore_wait_other_tasks();
}
/* /*
* We're about to search for free VM area and inject the restorer blob * We're about to search for free VM area and inject the restorer blob
* into it. No irrelevant mmaps/mremaps beyond this point, otherwise * into it. No irrelevant mmaps/mremaps beyond this point, otherwise
......
...@@ -36,7 +36,8 @@ ...@@ -36,7 +36,8 @@
#define CLONE_ALLNS (CLONE_NEWPID | CLONE_NEWNET | CLONE_NEWIPC | CLONE_NEWUTS | CLONE_NEWNS | CLONE_NEWUSER | CLONE_NEWCGROUP) #define CLONE_ALLNS (CLONE_NEWPID | CLONE_NEWNET | CLONE_NEWIPC | CLONE_NEWUTS | CLONE_NEWNS | CLONE_NEWUSER | CLONE_NEWCGROUP)
/* Nested namespaces are supported only for these types */ /* Nested namespaces are supported only for these types */
#define CLONE_SUBNS (CLONE_NEWNS) #define CLONE_SUBNS (CLONE_NEWNS | CLONE_NEWNET)
#define EXTRA_SIZE 20 #define EXTRA_SIZE 20
struct ns_desc { struct ns_desc {
...@@ -95,6 +96,7 @@ struct ns_id { ...@@ -95,6 +96,7 @@ struct ns_id {
} mnt; } mnt;
struct { struct {
int nsfd_id; /* a namespace descriptor id in fdstore */
int nlsk; /* for sockets collection */ int nlsk; /* for sockets collection */
int seqsk; /* to talk to parasite daemons */ int seqsk; /* to talk to parasite daemons */
} net; } net;
......
...@@ -12,9 +12,13 @@ ...@@ -12,9 +12,13 @@
struct cr_imgset; struct cr_imgset;
extern int dump_net_ns(int ns_id); extern int dump_net_ns(int ns_id);
extern int prepare_net_ns(int pid); extern int prepare_net_namespaces(void);
extern void fini_net_namespaces(void);
extern int netns_keep_nsfd(void); extern int netns_keep_nsfd(void);
struct pstree_item;
extern int restore_task_net_ns(struct pstree_item *current);
struct veth_pair { struct veth_pair {
struct list_head node; struct list_head node;
char *inside; char *inside;
......
...@@ -1666,9 +1666,6 @@ int prepare_namespace(struct pstree_item *item, unsigned long clone_flags) ...@@ -1666,9 +1666,6 @@ int prepare_namespace(struct pstree_item *item, unsigned long clone_flags)
* tree (i.e. -- mnt_ns restoring) * tree (i.e. -- mnt_ns restoring)
*/ */
id = ns_per_id ? item->ids->net_ns_id : pid;
if ((clone_flags & CLONE_NEWNET) && prepare_net_ns(id))
return -1;
id = ns_per_id ? item->ids->uts_ns_id : pid; id = ns_per_id ? item->ids->uts_ns_id : pid;
if ((clone_flags & CLONE_NEWUTS) && prepare_utsns(id)) if ((clone_flags & CLONE_NEWUTS) && prepare_utsns(id))
return -1; return -1;
...@@ -1676,6 +1673,9 @@ int prepare_namespace(struct pstree_item *item, unsigned long clone_flags) ...@@ -1676,6 +1673,9 @@ int prepare_namespace(struct pstree_item *item, unsigned long clone_flags)
if ((clone_flags & CLONE_NEWIPC) && prepare_ipc_ns(id)) if ((clone_flags & CLONE_NEWIPC) && prepare_ipc_ns(id))
return -1; return -1;
if (prepare_net_namespaces())
return -1;
/* /*
* This one is special -- there can be several mount * This one is special -- there can be several mount
* namespaces and prepare_mnt_ns handles them itself. * namespaces and prepare_mnt_ns handles them itself.
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "kerndat.h" #include "kerndat.h"
#include "util.h" #include "util.h"
#include "external.h" #include "external.h"
#include "fdstore.h"
#include "protobuf.h" #include "protobuf.h"
#include "images/netdev.pb-c.h" #include "images/netdev.pb-c.h"
...@@ -1902,7 +1903,7 @@ int dump_net_ns(int ns_id) ...@@ -1902,7 +1903,7 @@ int dump_net_ns(int ns_id)
return ret; return ret;
} }
int prepare_net_ns(int nsid) static int prepare_net_ns(int nsid)
{ {
int ret = 0; int ret = 0;
NetnsEntry *netns = NULL; NetnsEntry *netns = NULL;
...@@ -1929,9 +1930,99 @@ int prepare_net_ns(int nsid) ...@@ -1929,9 +1930,99 @@ int prepare_net_ns(int nsid)
if (!ret) if (!ret)
ret = restore_nf_ct(nsid, CR_FD_NETNF_EXP); ret = restore_nf_ct(nsid, CR_FD_NETNF_EXP);
return ret;
}
static int open_net_ns(struct ns_id *nsid, struct rst_info *rst)
{
int fd, id;
/* Pin one with a file descriptor */
fd = open_proc(PROC_SELF, "ns/net");
if (fd < 0)
return -1;
id = fdstore_add(fd);
close(fd);
if (id < 0) {
return -1;
}
nsid->net.nsfd_id = id;
return 0;
}
int prepare_net_namespaces()
{
struct ns_id *nsid;
if (!(root_ns_mask & CLONE_NEWNET))
return 0;
for (nsid = ns_ids; nsid != NULL; nsid = nsid->next) {
if (nsid->nd != &net_ns_desc)
continue;
if (unshare(CLONE_NEWNET)) {
pr_perror("Unable to create a new netns");
goto err;
}
if (prepare_net_ns(nsid->id))
goto err;
if (open_net_ns(nsid, rsti(root_item)))
goto err;
}
close_service_fd(NS_FD_OFF); close_service_fd(NS_FD_OFF);
return ret; return 0;
err:
return -1;
}
static int do_restore_task_net_ns(struct ns_id *nsid, struct pstree_item *current)
{
int fd;
if (!(root_ns_mask & CLONE_NEWNET))
return 0;
fd = fdstore_get(nsid->net.nsfd_id);
if (fd < 0)
return -1;
if (setns(fd, CLONE_NEWNET)) {
pr_perror("Can't restore netns");
close(fd);
return -1;
}
close(fd);
return 0;
}
int restore_task_net_ns(struct pstree_item *current)
{
if (current->ids && current->ids->has_net_ns_id) {
unsigned int id = current->ids->net_ns_id;
struct ns_id *nsid;
nsid = lookup_ns_by_id(id, &net_ns_desc);
if (nsid == NULL) {
pr_err("Can't find mount namespace %d\n", id);
return -1;
}
BUG_ON(nsid->type == NS_CRIU);
if (do_restore_task_net_ns(nsid, current))
return -1;
}
return 0;
} }
int netns_keep_nsfd(void) int netns_keep_nsfd(void)
......
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
#include "mount.h" #include "mount.h"
#include "dump.h" #include "dump.h"
#include "util.h" #include "util.h"
#include "net.h"
#include "protobuf.h" #include "protobuf.h"
#include "images/pstree.pb-c.h" #include "images/pstree.pb-c.h"
#include "crtools.h" #include "crtools.h"
...@@ -475,6 +477,10 @@ static int read_pstree_ids(struct pstree_item *pi) ...@@ -475,6 +477,10 @@ static int read_pstree_ids(struct pstree_item *pi)
if (rst_add_ns_id(pi->ids->mnt_ns_id, pi, &mnt_ns_desc)) if (rst_add_ns_id(pi->ids->mnt_ns_id, pi, &mnt_ns_desc))
return -1; return -1;
} }
if (pi->ids->has_net_ns_id) {
if (rst_add_ns_id(pi->ids->net_ns_id, pi, &net_ns_desc))
return -1;
}
return 0; return 0;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment