[CRIU] [PATCH CRIU 04/14] dump/net/ipv4: add unused bitmask to allow negative sysctl values

Pavel Tikhomirov ptikhomirov at virtuozzo.com
Wed Mar 30 03:42:22 PDT 2016


Some sysctls can be set with value < 0: ipv4/conf//accept_source_route,
ipv4/conf//medium_id, ipv4/conf//tag, ipv6/conf//accept_source_route,
ipv6/conf//keep_addr_on_down. So we can not use -1 as unused value.

So 1) make sysctl_op set CTL_FLAGS_UNUSED flags for sysctl files which
are CTL_FLAGS_OPTIONAL and does not exist, 2) write info about unused
files into bitmask on image.

Leave DEVCONFS_UNUSED for forward/backward compatibility.

https://jira.sw.ru/browse/PSBM-30942
Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
---
 criu/include/sysctl.h |  1 +
 criu/net.c            | 53 ++++++++++++++++++++++++++++++++++++++-------------
 criu/sysctl.c         |  5 ++++-
 images/netdev.proto   |  2 ++
 4 files changed, 47 insertions(+), 14 deletions(-)

diff --git a/criu/include/sysctl.h b/criu/include/sysctl.h
index b949a40..79a2711 100644
--- a/criu/include/sysctl.h
+++ b/criu/include/sysctl.h
@@ -35,5 +35,6 @@ enum {
  * Some entries might be missing mark them as optional.
  */
 #define CTL_FLAGS_OPTIONAL	1
+#define CTL_FLAGS_UNUSED	2
 
 #endif /* __CR_SYSCTL_H__ */
diff --git a/criu/net.c b/criu/net.c
index 096cd25..4a5ae17 100644
--- a/criu/net.c
+++ b/criu/net.c
@@ -95,9 +95,8 @@ static char *devconfs4[] = {
 };
 
 /*
- * I case if some entry is missing in
- * the kernel, simply write DEVCONFS_UNUSED
- * into the image so we would skip it.
+ * Leave for compatibility if have no mask_unused
+ * use it to determine missing entries.
  */
 #define DEVCONFS_UNUSED        (-1u)
 
@@ -106,7 +105,7 @@ static char *devconfs4[] = {
 
 static int net_conf_op(char *tgt, int *conf, int n, int op, char *proto,
 		struct sysctl_req *req, char (*path)[MAX_CONF_OPT_PATH], int size,
-		char **devconfs, int32_t *def_conf)
+		char **devconfs, int *mask_unused, int32_t *def_conf)
 {
 	int i, ri;
 	int ret, flags = op == CTL_READ ? CTL_FLAGS_OPTIONAL : 0;
@@ -127,9 +126,13 @@ static int net_conf_op(char *tgt, int *conf, int n, int op, char *proto,
 			continue;
 		}
 
-		if (op == CTL_WRITE && conf[i] == DEVCONFS_UNUSED)
+		if (op == CTL_WRITE && (mask_unused
+		                        ? mask_unused[i / WORD_BIT] & (1 << (i % WORD_BIT))
+		                        /* Forward compatibility */
+		                        : conf[i] == DEVCONFS_UNUSED))
 			continue;
 		else if (op == CTL_READ)
+			/* Backward compatibility */
 			conf[i] = DEVCONFS_UNUSED;
 
 		snprintf(path[i], MAX_CONF_OPT_PATH, CONF_OPT_PATH, proto, tgt, devconfs[i]);
@@ -145,17 +148,27 @@ static int net_conf_op(char *tgt, int *conf, int n, int op, char *proto,
 		pr_err("Failed to %s %s/<confs>\n", (op == CTL_READ)?"read":"write", tgt);
 		return -1;
 	}
+
+	if (op == CTL_READ)
+		for (i = 0; i < ri; i++) {
+			if (req[i].flags & CTL_FLAGS_UNUSED) {
+				int unused = (int *)req[i].arg - conf;
+				mask_unused[unused / WORD_BIT] |= 1 << (unused % WORD_BIT);
+			}
+		}
+
 	return 0;
 }
 
-static int ipv4_conf_op(char *tgt, int *conf, int n, int op, NetnsEntry **netns)
+static int ipv4_conf_op(char *tgt, int *conf, int n,
+		int op, int *mask_unused, NetnsEntry **netns)
 {
 	struct sysctl_req req[ARRAY_SIZE(devconfs4)];
 	char path[ARRAY_SIZE(devconfs4)][MAX_CONF_OPT_PATH];
 
 	return net_conf_op(tgt, conf, n, op, "ipv4",
 			req, path, ARRAY_SIZE(devconfs4),
-			devconfs4, netns ? (*netns)->def_conf4 : NULL);
+			devconfs4, mask_unused, netns ? (*netns)->def_conf4 : NULL);
 }
 
 int write_netdev_img(NetDeviceEntry *nde, struct cr_imgset *fds)
@@ -163,11 +176,14 @@ int write_netdev_img(NetDeviceEntry *nde, struct cr_imgset *fds)
 	return pb_write_one(img_from_set(fds, CR_FD_NETDEV), nde, PB_NETDEV);
 }
 
+#define CONF_MASK_SIZE 2
+
 static int dump_one_netdev(int type, struct ifinfomsg *ifi,
 		struct nlattr **tb, struct cr_imgset *fds,
 		int (*dump)(NetDeviceEntry *, struct cr_imgset *))
 {
 	int ret;
+	int mask_unused4[CONF_MASK_SIZE] = { 0 };
 	NetDeviceEntry netdev = NET_DEVICE_ENTRY__INIT;
 
 	if (!tb[IFLA_IFNAME]) {
@@ -190,12 +206,15 @@ static int dump_one_netdev(int type, struct ifinfomsg *ifi,
 				(int)netdev.address.len, netdev.name);
 	}
 
+	netdev.n_mask_unused4 = CONF_MASK_SIZE;
+	netdev.mask_unused4 = mask_unused4;
 	netdev.n_conf4 = ARRAY_SIZE(devconfs4);
 	netdev.conf4 = xmalloc(sizeof(int) * netdev.n_conf4);
 	if (!netdev.conf4)
 		return -1;
 
-	ret = ipv4_conf_op(netdev.name, netdev.conf4, netdev.n_conf4, CTL_READ, NULL);
+	ret = ipv4_conf_op(netdev.name, netdev.conf4, netdev.n_conf4,
+			CTL_READ, netdev.mask_unused4, NULL);
 	if (ret < 0)
 		goto err_free;
 
@@ -762,7 +781,8 @@ static int restore_links(int pid, NetnsEntry **netns)
 			 */
 			if (nde->type == ND_TYPE__LOOPBACK)
 				def_netns = NULL;
-			ret = ipv4_conf_op(nde->name, nde->conf4, nde->n_conf4, CTL_WRITE, def_netns);
+			ret = ipv4_conf_op(nde->name, nde->conf4, nde->n_conf4,
+					CTL_WRITE, nde->mask_unused4, def_netns);
 		}
 exit:
 		net_device_entry__free_unpacked(nde, NULL);
@@ -879,8 +899,11 @@ static inline int dump_iptables(struct cr_imgset *fds)
 static int dump_netns_conf(struct cr_imgset *fds)
 {
 	int ret, n;
+	int mask_unused4[CONF_MASK_SIZE] = { 0 };
 	NetnsEntry netns = NETNS_ENTRY__INIT;
 
+	netns.n_mask_unused4 = CONF_MASK_SIZE;
+	netns.mask_unused4 = mask_unused4;
 	netns.n_def_conf4 = ARRAY_SIZE(devconfs4);
 	netns.n_all_conf4 = ARRAY_SIZE(devconfs4);
 	netns.def_conf4 = xmalloc(sizeof(int) * netns.n_def_conf4);
@@ -893,10 +916,12 @@ static int dump_netns_conf(struct cr_imgset *fds)
 	}
 
 	n = netns.n_def_conf4;
-	ret = ipv4_conf_op("default", netns.def_conf4, n, CTL_READ, NULL);
+	ret = ipv4_conf_op("default", netns.def_conf4, n,
+			CTL_READ, netns.mask_unused4, NULL);
 	if (ret < 0)
 		goto err_free;
-	ret = ipv4_conf_op("all", netns.all_conf4, n, CTL_READ, NULL);
+	ret = ipv4_conf_op("all", netns.all_conf4, n,
+			CTL_READ, netns.mask_unused4, NULL);
 	if (ret < 0)
 		goto err_free;
 
@@ -1017,10 +1042,12 @@ static int restore_netns_conf(int pid, NetnsEntry **netns)
 	}
 
 	n = (*netns)->n_def_conf4;
-	ret = ipv4_conf_op("default", (*netns)->def_conf4, n, CTL_WRITE, NULL);
+	ret = ipv4_conf_op("default", (*netns)->def_conf4, n,
+			CTL_WRITE, (*netns)->mask_unused4, NULL);
 	if (ret)
 		goto out;
-	ret = ipv4_conf_op("all", (*netns)->all_conf4, n, CTL_WRITE, NULL);
+	ret = ipv4_conf_op("all", (*netns)->all_conf4, n,
+			CTL_WRITE, (*netns)->mask_unused4, NULL);
 out:
 	close_image(img);
 	return ret;
diff --git a/criu/sysctl.c b/criu/sysctl.c
index 21ae4ce..a0e414d 100644
--- a/criu/sysctl.c
+++ b/criu/sysctl.c
@@ -255,8 +255,10 @@ static int __userns_sysctl_op(void *arg, int proc_fd, pid_t pid)
 
 		fd = openat(dir, req->name, flags);
 		if (fd < 0) {
-			if (errno == ENOENT && (req->flags & CTL_FLAGS_OPTIONAL))
+			if (errno == ENOENT && (req->flags & CTL_FLAGS_OPTIONAL)) {
+				req->flags |= CTL_FLAGS_UNUSED;
 				continue;
+			}
 			pr_perror("Can't open sysctl %s", req->name);
 			goto out;
 		}
@@ -364,6 +366,7 @@ static int __nonuserns_sysctl_op(struct sysctl_req *req, size_t nr_req, int op)
 		fd = openat(dir, req->name, flags);
 		if (fd < 0) {
 			if (errno == ENOENT && (req->flags & CTL_FLAGS_OPTIONAL)) {
+				req->flags |= CTL_FLAGS_UNUSED;
 				req++;
 				continue;
 			}
diff --git a/images/netdev.proto b/images/netdev.proto
index 7d7bb26..a2840eb 100644
--- a/images/netdev.proto
+++ b/images/netdev.proto
@@ -31,9 +31,11 @@ message net_device_entry {
 	optional bytes address		= 7;
 
 	repeated int32 conf4		= 8;
+	repeated int32 mask_unused4	= 9;
 }
 
 message netns_entry {
 	repeated int32 def_conf4	= 1;
 	repeated int32 all_conf4	= 2;
+	repeated int32 mask_unused4	= 3;
 }
-- 
1.9.3



More information about the CRIU mailing list