From c2b21fbf4baa5b134e90d9daf863b770b7518c73 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 24 Jul 2018 06:14:02 +0300 Subject: [PATCH] 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 Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 6 ++++- criu/include/namespaces.h | 1 + criu/include/net.h | 2 ++ criu/net.c | 49 +++++++++++++++++++++++++++++++++++---- images/netdev.proto | 1 + 5 files changed, 54 insertions(+), 5 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index ad28bbceba..833b44e82f 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1673,7 +1673,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; diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h index c0ad0f419a..5fe8038bf5 100644 --- a/criu/include/namespaces.h +++ b/criu/include/namespaces.h @@ -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 diff --git a/criu/include/net.h b/criu/include/net.h index 38b33a7272..9976f6eb06 100644 --- a/criu/include/net.h +++ b/criu/include/net.h @@ -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__ */ diff --git a/criu/net.c b/criu/net.c index e0e537a7c0..cbd03dd0a0 100644 --- a/criu/net.c +++ b/criu/net.c @@ -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; diff --git a/images/netdev.proto b/images/netdev.proto index b4b64d2ccd..476a92cedb 100644 --- a/images/netdev.proto +++ b/images/netdev.proto @@ -70,4 +70,5 @@ message netns_entry { repeated sysctl_entry all_conf6 = 6; repeated netns_id nsids = 7; + optional string ext_key = 8; }