Commit 29612929 authored by Saied Kazemi's avatar Saied Kazemi Committed by Pavel Emelyanov

Allow the veth-pair option to specify a bridge

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@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: 's avatarSaied Kazemi <saied@google.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 70f28122
......@@ -1774,6 +1774,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);
......
......@@ -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"
......
......@@ -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__ */
......@@ -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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment