[CRIU] [PATCHv3] Allow the veth-pair option to specify a bridge

Saied Kazemi saied at google.com
Mon Jan 5 10:13:21 PST 2015


When restoring a pair of veth devices that had one end inside a namespace
or container and the other end outside, CRIU creates a new veth pair,
puts one end in the namespace/container, and names the other end from
what's specified in the --veth-pair IN=OUT command line option.

This patch allows for appending a bridge name to the OUT string in the
form of OUT@<BRIDGE-NAME> in order for CRIU to move the outside veth to
the named bridge.  For example, --veth-pair eth0=veth1 at br0 tells CRIU
to name the peer of eth0 veth1 and move it to bridge br0.

This is a simple and handy extension of the --veth-pair option that
obviates the need for an action script although one can still do the same
(and possibly more) if they prefer to use action scripts.

Signed-off-by: Saied Kazemi <saied at google.com>
---
 cr-restore.c  |  4 +++
 crtools.c     |  2 ++
 include/net.h |  2 ++
 net.c         | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 95 insertions(+), 1 deletion(-)

diff --git a/cr-restore.c b/cr-restore.c
index dc855f7..b4fd8f7 100644
--- a/cr-restore.c
+++ b/cr-restore.c
@@ -1777,6 +1777,10 @@ static int restore_root_task(struct pstree_item *init)
 	if (ret < 0)
 		goto out_kill;
 
+	ret = move_veth_to_bridge();
+	if (ret < 0)
+		goto out_kill;
+
 	ret = run_scripts(ACT_POST_RESTORE);
 	if (ret != 0) {
 		pr_err("Aborting restore due to script ret code %d\n", ret);
diff --git a/crtools.c b/crtools.c
index d23f302..3cc4954 100644
--- a/crtools.c
+++ b/crtools.c
@@ -608,6 +608,8 @@ usage:
 "  --evasive-devices     use any path to a device file if the original one\n"
 "                        is inaccessible\n"
 "  --veth-pair IN=OUT    map inside veth device name to outside one\n"
+"                        can optionally append @<bridge-name> to OUT for moving\n"
+"                        the outside veth to the named bridge\n"
 "  --link-remap          allow to link unlinked files back when possible\n"
 "  --action-script FILE  add an external action script\n"
 "  -j|--" OPT_SHELL_JOB "        allow to dump and restore shell jobs\n"
diff --git a/include/net.h b/include/net.h
index df9e67d..c03105c 100644
--- a/include/net.h
+++ b/include/net.h
@@ -12,6 +12,7 @@ struct veth_pair {
 	struct list_head node;
 	char *inside;
 	char *outside;
+	char *bridge;
 };
 
 extern int collect_net_namespaces(bool for_dump);
@@ -27,5 +28,6 @@ extern int read_ns_sys_file(char *path, char *buf, int len);
 extern int restore_link_parms(NetDeviceEntry *nde, int nlsk);
 
 extern int veth_pair_add(char *in, char *out);
+extern int move_veth_to_bridge(void);
 
 #endif /* __CR_NET_H__ */
diff --git a/net.c b/net.c
index d8abb36..23ef597 100644
--- a/net.c
+++ b/net.c
@@ -7,6 +7,8 @@
 #include <sys/wait.h>
 #include <sched.h>
 #include <sys/mount.h>
+#include <net/if.h>
+#include <linux/sockios.h>
 
 #include "imgset.h"
 #include "syscall-types.h"
@@ -617,6 +619,7 @@ void network_unlock(void)
 
 int veth_pair_add(char *in, char *out)
 {
+	char *aux;
 	struct veth_pair *n;
 
 	n = xmalloc(sizeof(*n));
@@ -625,8 +628,23 @@ int veth_pair_add(char *in, char *out)
 
 	n->inside = in;
 	n->outside = out;
+	/*
+	 * Does the out string specify a bridge for
+	 * moving the outside end of the veth pair to?
+	 */
+	aux = strrchr(out, '@');
+	if (aux) {
+		*aux++ = '\0';
+		n->bridge = aux;
+	} else {
+		n->bridge = NULL;
+	}
+
 	list_add(&n->node, &opts.veth_pairs);
-	pr_debug("Added %s:%s veth map\n", in, out);
+	if (n->bridge)
+		pr_debug("Added %s:%s@%s veth map\n", in, out, aux);
+	else
+		pr_debug("Added %s:%s veth map\n", in, out);
 	return 0;
 }
 
@@ -707,3 +725,71 @@ int collect_net_namespaces(bool for_dump)
 }
 
 struct ns_desc net_ns_desc = NS_DESC_ENTRY(CLONE_NEWNET, "net");
+
+int move_veth_to_bridge(void)
+{
+	int s;
+	int ret;
+	struct veth_pair *n;
+	struct ifreq ifr;
+
+	s = -1;
+	ret = 0;
+	list_for_each_entry(n, &opts.veth_pairs, node) {
+		if (n->bridge == NULL)
+			continue;
+
+		pr_debug("\tMoving dev %s to bridge %s\n", n->outside, n->bridge);
+
+		if (s == -1) {
+			s = socket(AF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0);
+			if (s < 0) {
+				pr_perror("Can't create control socket");
+				return -1;
+			}
+		}
+
+		/*
+		 * Add the device to the bridge. This is equivalent to:
+		 * $ brctl addif <bridge> <device>
+		 */
+		ifr.ifr_ifindex = if_nametoindex(n->outside);
+		if (ifr.ifr_ifindex == 0) {
+			pr_perror("Can't get index of %s", n->outside);
+			ret = -1;
+			break;
+		}
+		strncpy(ifr.ifr_name, n->bridge, IFNAMSIZ);
+		ret = ioctl(s, SIOCBRADDIF, &ifr);
+		if (ret < 0) {
+			pr_perror("Can't add interface %s to bridge %s",
+				n->outside, n->bridge);
+			break;
+		}
+
+		/*
+		 * Make sure the device is up.  This is equivalent to:
+		 * $ ip link set dev <device> up
+		 */
+		ifr.ifr_ifindex = 0;
+		strncpy(ifr.ifr_name, n->outside, IFNAMSIZ);
+		ret = ioctl(s, SIOCGIFFLAGS, &ifr);
+		if (ret < 0) {
+			pr_perror("Can't get flags of interface %s", n->outside);
+			break;
+		}
+		if (ifr.ifr_flags & IFF_UP)
+			continue;
+		ifr.ifr_flags |= IFF_UP;
+		ret = ioctl(s, SIOCSIFFLAGS, &ifr);
+		if (ret < 0) {
+			pr_perror("Can't set flags of interface %s to 0x%x",
+				n->outside, ifr.ifr_flags);
+			break;
+		}
+	}
+
+	if (s >= 0)
+		close(s);
+	return ret;
+}
-- 
2.2.0.rc0.207.ga3a616c



More information about the CRIU mailing list