[lxc-devel] [PATCH 1/2] c/r: refactor the way we pass data to criu/scripts

Tycho Andersen tycho.andersen at canonical.com
Thu Oct 16 13:13:59 UTC 2014


We previously wrote a bunch of files (eth*, veth*, and bridge*) as hard coded
files which we used as the names of interfaces to restore via criu's
--veth-pair. This meant that if people, e.g. gave a different bridge on their
new host, we would use our saved bridge in bridge* and try to restore to the
wrong bridge. Instead, we can just generate a new veth id (if the user hasn't
provided one), and use whatever the user configured values for the interface
name and bridge are.

This allows people to switch the bridge that they restore onto simply by
migrating the rootfs and config, and then changing the bridge name in the
container's configuration before running lxc-checkpoint.

Signed-off-by: Tycho Andersen <tycho.andersen at canonical.com>
---
 src/lxc/lxc-restore-net |  16 +++---
 src/lxc/lxccontainer.c  | 126 +++++++++++++++++++++++-------------------------
 2 files changed, 68 insertions(+), 74 deletions(-)

diff --git a/src/lxc/lxc-restore-net b/src/lxc/lxc-restore-net
index 7d45583..1725dc3 100755
--- a/src/lxc/lxc-restore-net
+++ b/src/lxc/lxc-restore-net
@@ -1,15 +1,15 @@
 #!/bin/sh
 
-[ -z "$CRTOOLS_IMAGE_DIR" ] && exit 1
-
 set -e
 
-dir="$CRTOOLS_IMAGE_DIR"
-
 i=0
-while [ -f "$dir/eth$i" ] && [ -f "$dir/veth$i" ] && [ -f "$dir/bridge$i" ]; do
-	veth=$(cat "$dir/veth$i")
-	bridge=$(cat "$dir/bridge$i")
+while true; do
+	eval "bridge=\$LXC_CRIU_BRIDGE$i"
+	eval "veth=\$LXC_CRIU_VETH$i"
+
+	if [ -z "$bridge" ] || [ -z "$veth" ]; then
+		exit 0
+	fi
 
 	if [ "$CRTOOLS_SCRIPT_ACTION" = "network-lock" ]; then
 		brctl delif $bridge $veth
@@ -22,3 +22,5 @@ while [ -f "$dir/eth$i" ] && [ -f "$dir/veth$i" ] && [ -f "$dir/bridge$i" ]; do
 
 	i=$((i+1))
 done
+
+exit 1
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index 703042a..61d06ea 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -54,6 +54,7 @@
 #include "attach.h"
 #include "monitor.h"
 #include "namespace.h"
+#include "network.h"
 #include "lxclock.h"
 #include "sync.h"
 
@@ -3488,37 +3489,12 @@ struct criu_opts {
 	const char *cgroup_path;
 };
 
-/*
- * @out must be 128 bytes long
- */
-static int read_criu_file(const char *directory, const char *file, int netnr, char *out)
-{
-	char path[PATH_MAX];
-	int ret;
-	FILE *f;
-
-	ret = snprintf(path, PATH_MAX,  "%s/%s%d", directory, file, netnr);
-	if (ret < 0 || ret >= PATH_MAX) {
-		ERROR("%s: path too long", __func__);
-		return -1;
-	}
-
-	f = fopen(path, "r");
-	if (!f)
-		return -1;
-
-	ret = fscanf(f, "%127s", out);
-	fclose(f);
-	if (ret <= 0)
-		return -1;
-
-	return 0;
-}
-
 static void exec_criu(struct criu_opts *opts)
 {
-	char **argv, log[PATH_MAX];
+	char **argv, log[PATH_MAX], buf[257];
 	int static_args = 14, argc = 0, i, ret;
+	int netnr = 0;
+	struct lxc_list *it;
 
 	/* The command line always looks like:
 	 * criu $(action) --tcp-established --file-locks --link-remap --force-irmap \
@@ -3600,9 +3576,6 @@ static void exec_criu(struct criu_opts *opts)
 		if (!opts->stop)
 			DECLARE_ARG("--leave-running");
 	} else if (strcmp(opts->action, "restore") == 0) {
-		int netnr = 0;
-		struct lxc_list *it;
-
 		DECLARE_ARG("--root");
 		DECLARE_ARG(opts->c->lxc_conf->rootfs.mount);
 		DECLARE_ARG("--restore-detached");
@@ -3613,18 +3586,24 @@ static void exec_criu(struct criu_opts *opts)
 		DECLARE_ARG(opts->cgroup_path);
 
 		lxc_list_for_each(it, &opts->c->lxc_conf->network) {
-			char eth[128], veth[128], buf[257];
+			char eth[128], *veth;
 			void *m;
+			struct lxc_netdev *n = it->elem;
+
+			if (n->name) {
+				if (strlen(n->name) >= 128)
+					goto err;
+				strncpy(eth, n->name, 128);
+			} else
+				sprintf(eth, "eth%d", netnr);
+
+			veth = n->priv.veth_attr.pair;
 
-			if (read_criu_file(opts->directory, "veth", netnr, veth))
-				goto err;
-			if (read_criu_file(opts->directory, "eth", netnr, eth))
-				goto err;
 			ret = snprintf(buf, 257, "%s=%s", eth, veth);
 			if (ret < 0 || ret >= 257)
 				goto err;
 
-			/* final NULL and --veth-pair eth0:vethASDF */
+			/* final NULL and --veth-pair eth0=vethASDF */
 			m = realloc(argv, (argc + 1 + 2) * sizeof(*argv));
 			if (!m)
 				goto err;
@@ -3634,12 +3613,43 @@ static void exec_criu(struct criu_opts *opts)
 			DECLARE_ARG(buf);
 			argv[argc] = NULL;
 
-			netnr++;
 		}
 	}
 
-#undef DECLARE_ARG
+	netnr = 0;
+	lxc_list_for_each(it, &opts->c->lxc_conf->network) {
+		struct lxc_netdev *n = it->elem;
+		char veth[128];
+
+		/*
+		 * Here, we set some parameters that lxc-restore-net
+		 * will examine to figure out the right network to
+		 * restore.
+		 */
+		snprintf(buf, sizeof(buf), "LXC_CRIU_BRIDGE%d", netnr);
+		if (setenv(buf, n->link, 1))
+			goto err;
+
+		if (strcmp("restore", opts->action) == 0)
+			strncpy(veth, n->priv.veth_attr.pair, sizeof(veth));
+		else {
+			char *tmp;
+			ret = snprintf(buf, sizeof(buf), "lxc.network.%d.veth.pair", netnr);
+			if (ret < 0 || ret >= sizeof(buf))
+				goto err;
+			tmp = lxcapi_get_running_config_item(opts->c, buf);
+			strncpy(veth, tmp, sizeof(veth));
+			free(tmp);
+		}
+
+		snprintf(buf, sizeof(buf), "LXC_CRIU_VETH%d", netnr);
+		if (setenv(buf, veth, 1))
+			goto err;
 
+		netnr++;
+	}
+
+#undef DECLARE_ARG
 	execv(argv[0], argv);
 err:
 	for (i = 0; argv[i]; i++)
@@ -3723,10 +3733,6 @@ static bool dump_net_info(struct lxc_container *c, char *directory)
 			break;
 		}
 
-		pret = snprintf(veth_path, PATH_MAX, "lxc.network.%d.link", netnr);
-		if (pret < 0 || pret >= PATH_MAX)
-			goto out;
-
 		bridge = lxcapi_get_running_config_item(c, veth_path);
 		if (!bridge)
 			goto out;
@@ -3735,10 +3741,6 @@ static bool dump_net_info(struct lxc_container *c, char *directory)
 		if (pret < 0 || pret >= PATH_MAX || print_to_file(veth_path, veth) < 0)
 			goto out;
 
-		pret = snprintf(veth_path, PATH_MAX, "%s/bridge%d", directory, netnr);
-		if (pret < 0 || pret >= PATH_MAX || print_to_file(veth_path, bridge) < 0)
-			goto out;
-
 		if (n->name) {
 			if (strlen(n->name) >= 128)
 				goto out;
@@ -3746,10 +3748,6 @@ static bool dump_net_info(struct lxc_container *c, char *directory)
 		} else
 			sprintf(eth, "eth%d", netnr);
 
-		pret = snprintf(veth_path, PATH_MAX, "%s/eth%d", directory, netnr);
-		if (pret < 0 || pret >= PATH_MAX || print_to_file(veth_path, eth) < 0)
-			goto out;
-
 		has_error = false;
 out:
 		if (veth)
@@ -3808,30 +3806,24 @@ static bool lxcapi_checkpoint(struct lxc_container *c, char *directory, bool sto
 	}
 }
 
-static bool restore_net_info(struct lxc_container *c, char *directory)
+static bool restore_net_info(struct lxc_container *c)
 {
 	struct lxc_list *it;
 	bool has_error = true;
-	int netnr = 0;
 
 	if (container_mem_lock(c))
 		return false;
 
 	lxc_list_for_each(it, &c->lxc_conf->network) {
-		char eth[128], veth[128];
 		struct lxc_netdev *netdev = it->elem;
+		char template[IFNAMSIZ];
+		snprintf(template, sizeof(template), "vethXXXXXX");
 
-		if (read_criu_file(directory, "veth", netnr, veth))
-			goto out_unlock;
-
-		if (read_criu_file(directory, "eth", netnr, eth))
-			goto out_unlock;
+		if (!netdev->priv.veth_attr.pair)
+			netdev->priv.veth_attr.pair = lxc_mkifname(template);
 
-		netdev->priv.veth_attr.pair = strdup(veth);
 		if (!netdev->priv.veth_attr.pair)
 			goto out_unlock;
-
-		netnr++;
 	}
 
 	has_error = false;
@@ -3874,6 +3866,11 @@ static bool lxcapi_restore(struct lxc_container *c, char *directory, bool verbos
 		goto out_fini_handler;
 	}
 
+	if (!restore_net_info(c)) {
+		ERROR("failed restoring network info");
+		goto out_fini_handler;
+	}
+
 	pid = fork();
 	if (pid < 0)
 		goto out_fini_handler;
@@ -3944,11 +3941,6 @@ static bool lxcapi_restore(struct lxc_container *c, char *directory, bool verbos
 					goto out_fini_handler;
 				}
 
-				if (!restore_net_info(c, directory)) {
-					ERROR("failed restoring network info");
-					goto out_fini_handler;
-				}
-
 				if (lxc_set_state(c->name, handler, RUNNING))
 					goto out_fini_handler;
 			}
-- 
1.9.1



More information about the lxc-devel mailing list