[2/3] criu: add support for external net namespaces

Submitted by Andrey Vagin on July 23, 2018, 4:20 p.m.

Details

Message ID 20180723162053.12443-3-avagin@virtuozzo.com
State Accepted
Series "criu: add support for external net namespaces"
Headers show

Commit Message

Andrey Vagin July 23, 2018, 4:20 p.m.
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

Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
---
 criu/cr-restore.c         |  6 +++++-
 criu/include/namespaces.h |  1 +
 criu/include/net.h        |  2 ++
 criu/net.c                | 48 +++++++++++++++++++++++++++++++++++++++++++----
 images/netdev.proto       |  1 +
 5 files changed, 53 insertions(+), 5 deletions(-)

Patch hide | download patch | download mbox

diff --git a/criu/cr-restore.c b/criu/cr-restore.c
index 807a582d0..0e5b06456 100644
--- a/criu/cr-restore.c
+++ b/criu/cr-restore.c
@@ -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;
diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h
index c0ad0f419..5fe8038bf 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 38b33a727..9976f6eb0 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 e5b35fb54..cbd03dd0a 100644
--- a/criu/net.c
+++ b/criu/net.c
@@ -2199,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;
@@ -2209,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);
@@ -2253,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;
 
@@ -2306,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);
@@ -2322,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);
 
@@ -2370,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;
 	}
@@ -2717,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 b4b64d2cc..476a92ced 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;
 }