[CRIU] [PATCH v2 05/15] net/ipv4: add net_conf_op to reuse for ipv6
Pavel Tikhomirov
ptikhomirov at virtuozzo.com
Wed Apr 20 07:42:46 PDT 2016
use new SysctlEntry, leave old ipv4_conf_op as ipv4_conf_op_old
for forward compatibility
https://jira.sw.ru/browse/PSBM-30942
Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
---
criu/net.c | 212 +++++++++++++++++++++++++++++++++++++++++++++-------------
criu/sysctl.c | 1 +
2 files changed, 168 insertions(+), 45 deletions(-)
diff --git a/criu/net.c b/criu/net.c
index 51e3e77..574391b 100644
--- a/criu/net.c
+++ b/criu/net.c
@@ -61,6 +61,21 @@ int read_ns_sys_file(char *path, char *buf, int len)
return rlen;
}
+static bool sysctl_entries_equal(SysctlEntry *a, SysctlEntry *b)
+{
+ if (a->type != b->type)
+ return false;
+
+ switch (a->type) {
+ case CTL_32:
+ return a->has_iarg && b->has_iarg && a->iarg == b->iarg;
+ case __CTL_STR:
+ return a->sarg && b->sarg && !strcmp(a->sarg, b->sarg);
+ }
+
+ return false;
+}
+
static char *devconfs4[] = {
"accept_local",
"accept_redirects",
@@ -94,6 +109,74 @@ static char *devconfs4[] = {
"drop_unicast_in_l2_multicast",
};
+#define CONF_OPT_PATH "net/%s/conf/%s/%s"
+#define MAX_CONF_OPT_PATH IFNAMSIZ+50
+
+static int net_conf_op(char *tgt, SysctlEntry **conf, int n, int op, char *proto,
+ struct sysctl_req *req, char (*path)[MAX_CONF_OPT_PATH], int size,
+ char **devconfs, SysctlEntry **def_conf)
+{
+ int i, ri;
+ int ret, flags = op == CTL_READ ? CTL_FLAGS_OPTIONAL : 0;
+
+ if (n > size)
+ pr_warn("The image contains unknown sysctl-s\n");
+
+ for (i = 0, ri = 0; i < size; i++) {
+ if (i >= n) {
+ pr_warn("Skip %s/%s\n", tgt, devconfs[i]);
+ continue;
+ }
+ /*
+ * If dev conf value is the same as default skip restoring it
+ */
+ if (def_conf && sysctl_entries_equal(conf[i], def_conf[i])) {
+ pr_debug("Skip %s/%s, coincides with default\n", tgt, devconfs[i]);
+ continue;
+ }
+
+ snprintf(path[i], MAX_CONF_OPT_PATH, CONF_OPT_PATH, proto, tgt, devconfs[i]);
+ req[ri].name = path[i];
+ req[ri].type = conf[i]->type;
+ switch (CTL_TYPE(conf[i]->type)) {
+ case CTL_32:
+ if (op == CTL_WRITE && !conf[i]->has_iarg)
+ continue;
+ req[ri].arg = &conf[i]->iarg;
+ req[ri].has = &conf[i]->has_iarg;
+ break;
+ case __CTL_STR:
+ if (op == CTL_WRITE && !conf[i]->sarg)
+ continue;
+ req[ri].arg = &conf[i]->sarg;
+ req[ri].has = NULL;
+ break;
+ default:
+ continue;
+ }
+ req[ri].flags = flags;
+ ri++;
+ }
+
+ ret = sysctl_op(req, ri, op, CLONE_NEWNET);
+ if (ret < 0) {
+ pr_err("Failed to %s %s/<confs>\n", (op == CTL_READ)?"read":"write", tgt);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int ipv4_conf_op(char *tgt, SysctlEntry **conf, int n, int op, SysctlEntry **def_conf)
+{
+ 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, def_conf);
+}
+
/*
* I case if some entry is missing in
* the kernel, simply write DEVCONFS_UNUSED
@@ -101,10 +184,7 @@ static char *devconfs4[] = {
*/
#define DEVCONFS_UNUSED (-1u)
-#define NET_CONF_PATH "net/ipv4/conf"
-#define MAX_CONF_OPT_PATH IFNAMSIZ+50
-
-static int ipv4_conf_op(char *tgt, int *conf, int n, int op, NetnsEntry **netns)
+static int ipv4_conf_op_old(char *tgt, int *conf, int n, int op, int *def_conf)
{
int i, ri;
int ret, flags = op == CTL_READ ? CTL_FLAGS_OPTIONAL : 0;
@@ -122,7 +202,7 @@ static int ipv4_conf_op(char *tgt, int *conf, int n, int op, NetnsEntry **netns)
/*
* If dev conf value is the same as default skip restoring it
*/
- if (netns && conf[i] == (*netns)->def_conf[i]) {
+ if (def_conf && conf[i] == def_conf[i]) {
pr_debug("DEBUG Skip %s/%s, val =%d\n", tgt, devconfs4[i], conf[i]);
continue;
}
@@ -132,9 +212,10 @@ static int ipv4_conf_op(char *tgt, int *conf, int n, int op, NetnsEntry **netns)
else if (op == CTL_READ)
conf[i] = DEVCONFS_UNUSED;
- snprintf(path[i], MAX_CONF_OPT_PATH, "%s/%s/%s", NET_CONF_PATH, tgt, devconfs4[i]);
+ snprintf(path[i], MAX_CONF_OPT_PATH, CONF_OPT_PATH, "ipv4", tgt, devconfs4[i]);
req[ri].name = path[i];
req[ri].arg = &conf[i];
+ req[ri].has = NULL;
req[ri].type = CTL_32;
req[ri].flags = flags;
ri++;
@@ -157,8 +238,11 @@ 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 ret = -1;
+ int i;
NetDeviceEntry netdev = NET_DEVICE_ENTRY__INIT;
+ SysctlEntry *confs4 = NULL;
+ int size4 = ARRAY_SIZE(devconfs4);
if (!tb[IFLA_IFNAME]) {
pr_err("No name for link %d\n", ifi->ifi_index);
@@ -180,12 +264,22 @@ static int dump_one_netdev(int type, struct ifinfomsg *ifi,
(int)netdev.address.len, netdev.name);
}
- netdev.n_conf = ARRAY_SIZE(devconfs4);
- netdev.conf = xmalloc(sizeof(int) * netdev.n_conf);
- if (!netdev.conf)
- return -1;
+ netdev.n_conf4 = size4;
+ netdev.conf4 = xmalloc(sizeof(SysctlEntry *) * size4);
+ if (!netdev.conf4)
+ goto err_free;
+
+ confs4 = xmalloc(sizeof(SysctlEntry) * size4);
+ if (!confs4)
+ goto err_free;
+
+ for (i = 0; i < size4; i++) {
+ sysctl_entry__init(&confs4[i]);
+ netdev.conf4[i] = &confs4[i];
+ netdev.conf4[i]->type = CTL_32;
+ }
- ret = ipv4_conf_op(netdev.name, netdev.conf, netdev.n_conf, CTL_READ, NULL);
+ ret = ipv4_conf_op(netdev.name, netdev.conf4, size4, CTL_READ, NULL);
if (ret < 0)
goto err_free;
@@ -194,7 +288,8 @@ static int dump_one_netdev(int type, struct ifinfomsg *ifi,
ret = dump(&netdev, fds);
err_free:
- xfree(netdev.conf);
+ xfree(confs4);
+ xfree(netdev.conf4);
return ret;
}
@@ -772,6 +867,8 @@ static int restore_links(int pid, NetnsEntry **netns)
}
while (1) {
+ NetnsEntry **def_netns = netns;
+
ret = pb_read_one_eof(img, &nde, PB_NETDEV);
if (ret <= 0)
break;
@@ -782,17 +879,18 @@ static int restore_links(int pid, NetnsEntry **netns)
goto exit;
}
- if (nde->conf) {
- NetnsEntry **def_netns = netns;
- /*
- * optimize restore of devices configuration except lo
- * lo is created with namespace and before default is set
- * so we cant optimize its restore
- */
- if (nde->type == ND_TYPE__LOOPBACK)
- def_netns = NULL;
- ret = ipv4_conf_op(nde->name, nde->conf, nde->n_conf, CTL_WRITE, def_netns);
- }
+ /*
+ * optimize restore of devices configuration except lo
+ * lo is created with namespace and before default is set
+ * so we cant optimize its restore
+ */
+ if (nde->type == ND_TYPE__LOOPBACK)
+ def_netns = NULL;
+
+ if (nde->conf4)
+ ret = ipv4_conf_op(nde->name, nde->conf4, nde->n_conf4, CTL_WRITE, def_netns ? (*def_netns)->def_conf4 : NULL);
+ else if (nde->conf)
+ ret = ipv4_conf_op_old(nde->name, nde->conf, nde->n_conf, CTL_WRITE, def_netns ? (*def_netns)->def_conf : NULL);
exit:
net_device_entry__free_unpacked(nde, NULL);
if (ret)
@@ -907,32 +1005,49 @@ static inline int dump_iptables(struct cr_imgset *fds)
static int dump_netns_conf(struct cr_imgset *fds)
{
- int ret, n;
+ int ret = -1;
+ int i;
NetnsEntry netns = NETNS_ENTRY__INIT;
+ SysctlEntry *def_confs4 = NULL, *all_confs4 = NULL;
+ int size4 = ARRAY_SIZE(devconfs4);
- netns.n_def_conf = ARRAY_SIZE(devconfs4);
- netns.n_all_conf = ARRAY_SIZE(devconfs4);
- netns.def_conf = xmalloc(sizeof(int) * netns.n_def_conf);
- if (!netns.def_conf)
- return -1;
- netns.all_conf = xmalloc(sizeof(int) * netns.n_all_conf);
- if (!netns.all_conf) {
- xfree(netns.def_conf);
- return -1;
+ netns.n_def_conf4 = size4;
+ netns.n_all_conf4 = size4;
+ netns.def_conf4 = xmalloc(sizeof(SysctlEntry *) * size4);
+ if (!netns.def_conf4)
+ goto err_free;
+ netns.all_conf4 = xmalloc(sizeof(SysctlEntry *) * size4);
+ if (!netns.all_conf4)
+ goto err_free;
+ def_confs4 = xmalloc(sizeof(SysctlEntry) * size4);
+ if (!def_confs4)
+ goto err_free;
+ all_confs4 = xmalloc(sizeof(SysctlEntry) * size4);
+ if (!all_confs4)
+ goto err_free;
+
+ for (i = 0; i < size4; i++) {
+ sysctl_entry__init(&def_confs4[i]);
+ sysctl_entry__init(&all_confs4[i]);
+ netns.def_conf4[i] = &def_confs4[i];
+ netns.all_conf4[i] = &all_confs4[i];
+ netns.def_conf4[i]->type = CTL_32;
+ netns.all_conf4[i]->type = CTL_32;
}
- n = netns.n_def_conf;
- ret = ipv4_conf_op("default", netns.def_conf, n, CTL_READ, NULL);
+ ret = ipv4_conf_op("default", netns.def_conf4, size4, CTL_READ, NULL);
if (ret < 0)
goto err_free;
- ret = ipv4_conf_op("all", netns.all_conf, n, CTL_READ, NULL);
+ ret = ipv4_conf_op("all", netns.all_conf4, size4, CTL_READ, NULL);
if (ret < 0)
goto err_free;
ret = pb_write_one(img_from_set(fds, CR_FD_NETNS), &netns, PB_NETNS);
err_free:
- xfree(netns.def_conf);
- xfree(netns.all_conf);
+ xfree(netns.def_conf4);
+ xfree(netns.all_conf4);
+ xfree(def_confs4);
+ xfree(all_confs4);
return ret;
}
@@ -1028,7 +1143,7 @@ static inline int restore_iptables(int pid)
static int restore_netns_conf(int pid, NetnsEntry **netns)
{
- int ret = 0, n;
+ int ret = 0;
struct cr_img *img;
img = open_image(CR_FD_NETNS, O_RSTR, pid);
@@ -1045,11 +1160,18 @@ static int restore_netns_conf(int pid, NetnsEntry **netns)
return -1;
}
- n = (*netns)->n_def_conf;
- ret = ipv4_conf_op("default", (*netns)->def_conf, n, CTL_WRITE, NULL);
- if (ret)
- goto out;
- ret = ipv4_conf_op("all", (*netns)->all_conf, n, CTL_WRITE, NULL);
+ if ((*netns)->def_conf4) {
+ ret = ipv4_conf_op("default", (*netns)->def_conf4, (*netns)->n_def_conf4, CTL_WRITE, NULL);
+ if (ret)
+ goto out;
+ ret = ipv4_conf_op("all", (*netns)->all_conf4, (*netns)->n_all_conf4, CTL_WRITE, NULL);
+ } else if ((*netns)->def_conf) {
+ /* Backward compatibility */
+ ret = ipv4_conf_op_old("default", (*netns)->def_conf, (*netns)->n_def_conf, CTL_WRITE, NULL);
+ if (ret)
+ goto out;
+ ret = ipv4_conf_op_old("all", (*netns)->all_conf, (*netns)->n_all_conf, CTL_WRITE, NULL);
+ }
out:
close_image(img);
return ret;
diff --git a/criu/sysctl.c b/criu/sysctl.c
index bd584bd..57e1b50 100644
--- a/criu/sysctl.c
+++ b/criu/sysctl.c
@@ -455,6 +455,7 @@ int sysctl_op(struct sysctl_req *req, size_t nr_req, int op, unsigned int ns)
/* copy over the non-pointer fields */
cur->type = req[i].type;
cur->flags = req[i].flags;
+ cur->has = req[i].has;
cur->name = (char *) &cur[1];
strcpy(cur->name, req[i].name);
--
1.9.3
More information about the CRIU
mailing list