[CRIU] [PATCH 1/3] net: allow c/r of empty bridges in the container

Tycho Andersen tycho.andersen at canonical.com
Wed Nov 11 11:10:01 PST 2015


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: Tycho Andersen <tycho.andersen at canonical.com>
---
 include/util.h        |  2 ++
 mount.c               | 22 +++++-----------------
 net.c                 | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 protobuf/netdev.proto |  1 +
 util.c                | 23 +++++++++++++++++++++++
 5 files changed, 82 insertions(+), 17 deletions(-)

diff --git a/include/util.h b/include/util.h
index e815117..9339c1b 100644
--- a/include/util.h
+++ b/include/util.h
@@ -180,6 +180,8 @@ static inline bool dir_dots(struct dirent *de)
 	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
  * path. Since fd is an integer, we can easily estimate one :)
diff --git a/mount.c b/mount.c
index 102d129..1016b97 100644
--- a/mount.c
+++ b/mount.c
@@ -1357,31 +1357,19 @@ out:
 static int dump_empty_fs(struct mount_info *pm)
 {
 	int fd, ret = -1;
-	struct dirent *de;
-	DIR *fdir = NULL;
 	fd = open_mountpoint(pm);
 
 	if (fd < 0)
 		return -1;
 
-	fdir = fdopendir(fd);
-	if (fdir == NULL) {
-		close(fd);
+	ret = is_empty_dir(fd);
+	close(fd);
+	if (ret < 0) {
+		pr_err("%s isn't empty\n", pm->fstype->name);
 		return -1;
 	}
 
-	while ((de = readdir(fdir))) {
-		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;
+	return ret ? 0 : -1;
 }
 
 /*
diff --git a/net.c b/net.c
index f68a2d8..148d6b2 100644
--- a/net.c
+++ b/net.c
@@ -225,6 +225,41 @@ static int dump_unknown_device(struct ifinfomsg *ifi, char *kind,
 	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,
 		struct rtattr **tb, struct cr_imgset *fds)
 {
@@ -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);
 	if (!strcmp(kind, "tun"))
 		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);
 }
@@ -465,6 +502,17 @@ static int venet_link_info(NetDeviceEntry *nde, struct newlink_req *req)
 	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)
 {
 	pr_info("Restoring link %s type %d\n", nde->name, nde->type);
@@ -479,6 +527,9 @@ static int restore_link(NetDeviceEntry *nde, int nlsk)
 		return restore_one_link(nde, nlsk, veth_link_info);
 	case ND_TYPE__TUN:
 		return restore_one_tun(nde, nlsk);
+	case ND_TYPE__BRIDGE:
+		return restore_one_link(nde, nlsk, bridge_link_info);
+
 	default:
 		pr_err("Unsupported link type %d\n", nde->type);
 		break;
diff --git a/protobuf/netdev.proto b/protobuf/netdev.proto
index c189ff6..dafa2bd 100644
--- a/protobuf/netdev.proto
+++ b/protobuf/netdev.proto
@@ -16,6 +16,7 @@ enum nd_type {
 	 * Virtuozzo specific device.
 	 */
 	VENET		= 5;
+	BRIDGE		= 6;
 }
 
 message net_device_entry {
diff --git a/util.c b/util.c
index 337b0ed..2c1271b 100644
--- a/util.c
+++ b/util.c
@@ -662,6 +662,29 @@ int is_root_user()
 	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 fd, ret = -1;
-- 
2.6.2



More information about the CRIU mailing list