Permalink
Browse files

criu: add support for external net namespaces

It works like other external resources.
A user specify which namespaces are external and have not to be dumped.
On restore, the user gives file descriptors to preconfigured namespaces.

How to use:
dump:
        --external net[INO]:KEY
restore:
        --inherit-fd fd[NSFD]:KEY

The test script contains more details how to use this:
test/others/netns_ext/run.sh

Acked-by: Adrian Reber <areber@redhat.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
  • Loading branch information...
avagin committed Jul 24, 2018
1 parent 8ea79eb commit a8a3eb902305f0af603afa4c95b1b632fe7bd149
Showing with 54 additions and 5 deletions.
  1. +5 −1 criu/cr-restore.c
  2. +1 −0 criu/include/namespaces.h
  3. +2 −0 criu/include/net.h
  4. +45 −4 criu/net.c
  5. +1 −0 images/netdev.proto
@@ -1674,7 +1674,11 @@ static int restore_task_with_children(void *_arg)
* ACT_SETUP_NS scripts, so the root netns has to be created here
*/
if (root_ns_mask & CLONE_NEWNET) {
ret = unshare(CLONE_NEWNET);
struct ns_id *ns = net_get_root_ns();
if (ns->ext_key)
ret = net_set_ext(ns);
else
ret = unshare(CLONE_NEWNET);
if (ret) {
pr_perror("Can't unshare net-namespace");
goto err;
@@ -91,6 +91,7 @@ struct ns_id {
struct ns_desc *nd;
struct ns_id *next;
enum ns_type type;
char *ext_key;

/*
* For mount namespaces on restore -- indicates that
@@ -50,6 +50,8 @@ extern int net_get_nsid(int rtsk, int fd, int *nsid);
extern struct ns_id *net_get_root_ns();
extern int kerndat_nsid(void);
extern void check_has_netns_ioc(int fd, bool *kdat_val, const char *name);
extern int net_set_ext(struct ns_id *ns);
extern struct ns_id *get_root_netns();
extern int read_net_ns_img();

#endif /* __CR_NET_H__ */
@@ -2075,6 +2075,7 @@ int read_net_ns_img(void)
pr_err("Can not read netns object\n");
return -1;
}
ns->ext_key = ns->net.netns->ext_key;
}

return 0;
@@ -2198,6 +2199,22 @@ static int dump_netns_ids(int rtsk, struct ns_id *ns)
(void *)&arg);
}

int net_set_ext(struct ns_id *ns)
{
int fd, ret;

fd = inherit_fd_lookup_id(ns->ext_key);
if (fd < 0) {
pr_err("Unable to find an external netns: %s\n", ns->ext_key);
return -1;
}

ret = switch_ns_by_fd(fd, &net_ns_desc, NULL);
close(fd);

return ret;
}

int dump_net_ns(struct ns_id *ns)
{
struct cr_imgset *fds;
@@ -2208,7 +2225,14 @@ int dump_net_ns(struct ns_id *ns)
return -1;

ret = mount_ns_sysfs();
if (!(opts.empty_ns & CLONE_NEWNET)) {
if (ns->ext_key) {
NetnsEntry netns = NETNS_ENTRY__INIT;

netns.ext_key = ns->ext_key;
ret = pb_write_one(img_from_set(fds, CR_FD_NETNS), &netns, PB_NETNS);
if (ret)
goto out;
} else if (!(opts.empty_ns & CLONE_NEWNET)) {
int sk;

sk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
@@ -2252,6 +2276,7 @@ int dump_net_ns(struct ns_id *ns)
if (!ret)
ret = dump_nf_ct(fds, CR_FD_NETNF_EXP);

out:
close(ns_sysfs_fd);
ns_sysfs_fd = -1;

@@ -2305,7 +2330,7 @@ static int prepare_net_ns_first_stage(struct ns_id *ns)
{
int ret = 0;

if (opts.empty_ns & CLONE_NEWNET)
if (ns->ext_key || (opts.empty_ns & CLONE_NEWNET))
return 0;

ret = restore_netns_conf(ns);
@@ -2321,7 +2346,7 @@ static int prepare_net_ns_second_stage(struct ns_id *ns)
{
int ret = 0, nsid = ns->id;

if (!(opts.empty_ns & CLONE_NEWNET)) {
if (!(opts.empty_ns & CLONE_NEWNET) && !ns->ext_key) {
if (ns->net.netns)
netns_entry__free_unpacked(ns->net.netns, NULL);

@@ -2369,7 +2394,14 @@ static int open_net_ns(struct ns_id *nsid)

static int do_create_net_ns(struct ns_id *ns)
{
if (unshare(CLONE_NEWNET)) {
int ret;

if (ns->ext_key)
ret = net_set_ext(ns);
else
ret = unshare(CLONE_NEWNET);

if (ret) {
pr_perror("Unable to create a new netns");
return -1;
}
@@ -2716,9 +2748,18 @@ static int netns_nr;
static int collect_net_ns(struct ns_id *ns, void *oarg)
{
bool for_dump = (oarg == (void *)1);
char id[64], *val;
int ret;

pr_info("Collecting netns %d/%d\n", ns->id, ns->ns_pid);

snprintf(id, sizeof(id), "net[%u]", ns->kid);
val = external_lookup_by_key(id);
if (!IS_ERR_OR_NULL(val)) {
pr_debug("The %s netns is external\n", id);
ns->ext_key = val;
}

ret = prep_ns_sockets(ns, for_dump);
if (ret)
return ret;
@@ -70,4 +70,5 @@ message netns_entry {
repeated sysctl_entry all_conf6 = 6;

repeated netns_id nsids = 7;
optional string ext_key = 8;
}

0 comments on commit a8a3eb9

Please sign in to comment.