diff --git a/criu/net.c b/criu/net.c index 97c53f84f..ee46f1c49 100644 --- a/criu/net.c +++ b/criu/net.c @@ -2128,6 +2128,79 @@ nft_ctx_free_out: } #endif +static const char *ipv4_sysctl_entries[] = { + "ping_group_range", +}; + +#define IPV4_SYSCTL_BASE "net/ipv4" +#define IPV4_SYSCTL_FMT IPV4_SYSCTL_BASE"/%s" +#define MAX_IPV4_SYSCTL_OPT 32 +#define MAX_IPV4_SYSCTL_PATH (sizeof(IPV4_SYSCTL_FMT) + MAX_IPV4_SYSCTL_OPT - 2) +#define MAX_STR_IPV4_SYSCTL_LEN 200 + +static int ipv4_sysctls_op(SysctlEntry ***rsysctl, size_t *pn, int op) +{ + int i, ret = -1, flags = 0; + char path[ARRAY_SIZE(ipv4_sysctl_entries)][MAX_IPV4_SYSCTL_PATH] = {}; + struct sysctl_req req[ARRAY_SIZE(ipv4_sysctl_entries)] = {}; + SysctlEntry **sysctl = *rsysctl; + size_t n = *pn; + + if (n != ARRAY_SIZE(ipv4_sysctl_entries)) { + pr_err("unix: Unexpected entries in sysctlig (%zu %zu)\n", n, ARRAY_SIZE(ipv4_sysctl_entries)); + return -EINVAL; + } + + if (opts.weak_sysctls || op == CTL_READ) + flags = CTL_FLAGS_OPTIONAL; + + for (i = 0; i < n; i++) { + snprintf(path[i], MAX_IPV4_SYSCTL_PATH, IPV4_SYSCTL_FMT, ipv4_sysctl_entries[i]); + req[i].name = path[i]; + req[i].flags = flags; + + switch (sysctl[i]->type) { + case SYSCTL_TYPE__CTL_STR: + req[i].type = CTL_STR(MAX_STR_IPV4_SYSCTL_LEN); + + /* skip write if have no value */ + if (op == CTL_WRITE && !sysctl[i]->sarg) + continue; + + req[i].arg = sysctl[i]->sarg; + break; + default: + pr_err("ipv4: Unknown sysctl type %d\n", sysctl[i]->type); + return -1; + } + } + + ret = sysctl_op(req, n, op, CLONE_NEWNET); + if (ret < 0) { + pr_err("unix: Failed to %s %s/\n", (op == CTL_READ) ? "read" : "write", IPV4_SYSCTL_BASE); + return -1; + } + + if (op == CTL_READ) { + bool has_entries = false; + + for (i = 0; i < n; i++) { + if (req[i].flags & CTL_FLAGS_HAS) { + sysctl[i]->has_iarg = true; + if (!has_entries) + has_entries = true; + } + } + + if (!has_entries) { + *pn = 0; + *rsysctl = NULL; + } + } + + return 0; +} + static int dump_netns_conf(struct ns_id *ns, struct cr_imgset *fds) { void *buf, *o_buf; @@ -2142,6 +2215,9 @@ static int dump_netns_conf(struct ns_id *ns, struct cr_imgset *fds) int size6 = ARRAY_SIZE(devconfs6); char def_stable_secret[MAX_STR_CONF_LEN + 1] = {}; char all_stable_secret[MAX_STR_CONF_LEN + 1] = {}; + SysctlEntry *ipv4_sysctls = NULL; + size_t ipv4_sysctl_size = ARRAY_SIZE(ipv4_sysctl_entries); + char ping_group_range[MAX_STR_IPV4_SYSCTL_LEN + 1] = {}; NetnsId *ids; struct netns_id *p; @@ -2157,7 +2233,7 @@ static int dump_netns_conf(struct ns_id *ns, struct cr_imgset *fds) * arrays and then finally save them into images. */ o_buf = buf = xmalloc(i * (sizeof(NetnsId *) + sizeof(NetnsId)) + - (size4 * 2 + size6 * 2 + sizex) * + (2 * size4 + 2 * size6 + sizex + ipv4_sysctl_size) * (sizeof(SysctlEntry *) + sizeof(SysctlEntry))); if (!buf) goto out; @@ -2223,6 +2299,21 @@ static int dump_netns_conf(struct ns_id *ns, struct cr_imgset *fds) netns.unix_conf[i]->type = SYSCTL_TYPE__CTL_32; } + netns.n_ipv4_sysctl = ipv4_sysctl_size; + netns.ipv4_sysctl = xptr_pull_s(&buf, ipv4_sysctl_size * sizeof(SysctlEntry *)); + ipv4_sysctls = xptr_pull_s(&buf, ipv4_sysctl_size * sizeof(SysctlEntry)); + for (i = 0; i < ipv4_sysctl_size; i++) { + sysctl_entry__init(&ipv4_sysctls[i]); + netns.ipv4_sysctl[i] = &ipv4_sysctls[i]; + if (!strcmp(ipv4_sysctl_entries[i], "ping_group_range")) { + netns.ipv4_sysctl[i]->type = SYSCTL_TYPE__CTL_STR; + netns.ipv4_sysctl[i]->sarg = ping_group_range; + } else { + /* Need to handle this case when we have more sysctls */ + BUG(); + } + } + ret = ipv4_conf_op("default", netns.def_conf4, size4, CTL_READ, NULL); if (ret < 0) goto err_free; @@ -2241,6 +2332,10 @@ static int dump_netns_conf(struct ns_id *ns, struct cr_imgset *fds) if (ret < 0) goto err_free; + ret = ipv4_sysctls_op(&netns.ipv4_sysctl, &netns.n_ipv4_sysctl, CTL_READ); + if (ret < 0) + goto err_free; + ret = pb_write_one(img_from_set(fds, CR_FD_NETNS), &netns, PB_NETNS); err_free: xfree(o_buf); @@ -2593,6 +2688,12 @@ static int restore_netns_conf(struct ns_id *ns) goto out; } + if ((netns)->ipv4_sysctl) { + ret = ipv4_sysctls_op(&(netns)->ipv4_sysctl, &(netns)->n_ipv4_sysctl, CTL_WRITE); + if (ret) + goto out; + } + ns->net.netns = netns; out: return ret; diff --git a/images/netdev.proto b/images/netdev.proto index 748fd0200..42e2bc7d7 100644 --- a/images/netdev.proto +++ b/images/netdev.proto @@ -74,4 +74,5 @@ message netns_entry { repeated netns_id nsids = 7; optional string ext_key = 8; repeated sysctl_entry unix_conf = 9; + repeated sysctl_entry ipv4_sysctl = 10; }