Commit 8a95be06 authored by Tycho Andersen's avatar Tycho Andersen Committed by Pavel Emelyanov

net: allow c/r of empty bridges in the container

Implementing c/r of bridges with slaves shouldn't be too hard (viz. the
comment), but this is all I need to for right now.

v2: remove extra debug statement
v3: * remember to close fd in dump_bridge
    * use "known" buffer length and snprintf for spath in dump_bridge
    * change brace style
Signed-off-by: 's avatarTycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent b67bde83
...@@ -183,6 +183,8 @@ static inline bool dir_dots(struct dirent *de) ...@@ -183,6 +183,8 @@ static inline bool dir_dots(struct dirent *de)
return !strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."); return !strcmp(de->d_name, ".") || !strcmp(de->d_name, "..");
} }
extern int is_empty_dir(int dirfd);
/* /*
* Size of buffer to carry the worst case or /proc/self/fd/N * Size of buffer to carry the worst case or /proc/self/fd/N
* path. Since fd is an integer, we can easily estimate one :) * path. Since fd is an integer, we can easily estimate one :)
......
...@@ -1357,31 +1357,19 @@ out: ...@@ -1357,31 +1357,19 @@ out:
static int dump_empty_fs(struct mount_info *pm) static int dump_empty_fs(struct mount_info *pm)
{ {
int fd, ret = -1; int fd, ret = -1;
struct dirent *de;
DIR *fdir = NULL;
fd = open_mountpoint(pm); fd = open_mountpoint(pm);
if (fd < 0) if (fd < 0)
return -1; return -1;
fdir = fdopendir(fd); ret = is_empty_dir(fd);
if (fdir == NULL) {
close(fd); close(fd);
if (ret < 0) {
pr_err("%s isn't empty\n", pm->fstype->name);
return -1; return -1;
} }
while ((de = readdir(fdir))) { return ret ? 0 : -1;
if (dir_dots(de))
continue;
pr_err("%s isn't empty: %s\n", pm->fstype->name, de->d_name);
goto out;
}
ret = 0;
out:
closedir(fdir);
return ret;
} }
/* /*
......
...@@ -225,6 +225,41 @@ static int dump_unknown_device(struct ifinfomsg *ifi, char *kind, ...@@ -225,6 +225,41 @@ static int dump_unknown_device(struct ifinfomsg *ifi, char *kind,
return -1; return -1;
} }
static int dump_bridge(NetDeviceEntry *nde, struct cr_imgset *imgset)
{
char spath[IFNAMSIZ + 16]; /* len("class/net//brif") + 1 for null */
int ret, fd;
ret = snprintf(spath, sizeof(spath), "class/net/%s/brif", nde->name);
if (ret < 0 || ret >= sizeof(spath))
return -1;
/* Let's only allow dumping empty bridges for now. To do a full bridge
* restore, we need to make sure the bridge and slaves are restored in
* the right order and attached correctly. It looks like the veth code
* supports this, but we need some way to do ordering.
*/
fd = openat(ns_sysfs_fd, spath, O_DIRECTORY, 0);
if (fd < 0) {
pr_perror("opening %s failed", spath);
return -1;
}
ret = is_empty_dir(fd);
close(fd);
if (ret < 0) {
pr_perror("problem testing %s for emptiness", spath);
return -1;
}
if (!ret) {
pr_err("dumping bridges with attached slaves not supported currently\n");
return -1;
}
return write_netdev_img(nde, imgset);
}
static int dump_one_ethernet(struct ifinfomsg *ifi, char *kind, static int dump_one_ethernet(struct ifinfomsg *ifi, char *kind,
struct rtattr **tb, struct cr_imgset *fds) struct rtattr **tb, struct cr_imgset *fds)
{ {
...@@ -240,6 +275,8 @@ static int dump_one_ethernet(struct ifinfomsg *ifi, char *kind, ...@@ -240,6 +275,8 @@ static int dump_one_ethernet(struct ifinfomsg *ifi, char *kind,
return dump_one_netdev(ND_TYPE__VETH, ifi, tb, fds, NULL); return dump_one_netdev(ND_TYPE__VETH, ifi, tb, fds, NULL);
if (!strcmp(kind, "tun")) if (!strcmp(kind, "tun"))
return dump_one_netdev(ND_TYPE__TUN, ifi, tb, fds, dump_tun_link); return dump_one_netdev(ND_TYPE__TUN, ifi, tb, fds, dump_tun_link);
if (!strcmp(kind, "bridge"))
return dump_one_netdev(ND_TYPE__BRIDGE, ifi, tb, fds, dump_bridge);
return dump_unknown_device(ifi, kind, tb, fds); return dump_unknown_device(ifi, kind, tb, fds);
} }
...@@ -465,6 +502,17 @@ static int venet_link_info(NetDeviceEntry *nde, struct newlink_req *req) ...@@ -465,6 +502,17 @@ static int venet_link_info(NetDeviceEntry *nde, struct newlink_req *req)
return 0; return 0;
} }
static int bridge_link_info(NetDeviceEntry *nde, struct newlink_req *req)
{
struct rtattr *bridge_data;
bridge_data = NLMSG_TAIL(&req->h);
addattr_l(&req->h, sizeof(*req), IFLA_INFO_KIND, "bridge", sizeof("bridge"));
bridge_data->rta_len = (void *)NLMSG_TAIL(&req->h) - (void *)bridge_data;
return 0;
}
static int restore_link(NetDeviceEntry *nde, int nlsk) static int restore_link(NetDeviceEntry *nde, int nlsk)
{ {
pr_info("Restoring link %s type %d\n", nde->name, nde->type); pr_info("Restoring link %s type %d\n", nde->name, nde->type);
...@@ -479,6 +527,9 @@ static int restore_link(NetDeviceEntry *nde, int nlsk) ...@@ -479,6 +527,9 @@ static int restore_link(NetDeviceEntry *nde, int nlsk)
return restore_one_link(nde, nlsk, veth_link_info); return restore_one_link(nde, nlsk, veth_link_info);
case ND_TYPE__TUN: case ND_TYPE__TUN:
return restore_one_tun(nde, nlsk); return restore_one_tun(nde, nlsk);
case ND_TYPE__BRIDGE:
return restore_one_link(nde, nlsk, bridge_link_info);
default: default:
pr_err("Unsupported link type %d\n", nde->type); pr_err("Unsupported link type %d\n", nde->type);
break; break;
......
...@@ -16,6 +16,7 @@ enum nd_type { ...@@ -16,6 +16,7 @@ enum nd_type {
* Virtuozzo specific device. * Virtuozzo specific device.
*/ */
VENET = 5; VENET = 5;
BRIDGE = 6;
} }
message net_device_entry { message net_device_entry {
......
...@@ -665,6 +665,29 @@ int is_root_user() ...@@ -665,6 +665,29 @@ int is_root_user()
return 1; return 1;
} }
int is_empty_dir(int dirfd)
{
int ret = 0;
DIR *fdir = NULL;
struct dirent *de;
fdir = fdopendir(dirfd);
if (!fdir)
return -1;
while ((de = readdir(fdir))) {
if (dir_dots(de))
continue;
goto out;
}
ret = 1;
out:
closedir(fdir);
return ret;
}
int vaddr_to_pfn(unsigned long vaddr, u64 *pfn) int vaddr_to_pfn(unsigned long vaddr, u64 *pfn)
{ {
int fd, ret = -1; int fd, ret = -1;
......
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