[CRIU] [PATCHv2] Allow the veth-pair option to specify a bridge
Saied Kazemi
saied at google.com
Fri Jan 2 14:06:56 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>
---
This version uses the kernel directly instead of using ip and brctl tools.
cr-restore.c | 4 +++
crtools.c | 1 +
include/net.h | 2 ++
net.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 93 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..4322e69 100644
--- a/crtools.c
+++ b/crtools.c
@@ -608,6 +608,7 @@ 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 move the outside veth to\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..ee6b770 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,22 @@ 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 +724,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