Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

checkpoint/restore ping_group_range sysctl #2565

Open
wants to merge 3 commits into
base: criu-dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 110 additions & 3 deletions criu/net.c
Original file line number Diff line number Diff line change
Expand Up @@ -2128,6 +2128,79 @@
}
#endif

static const char *ipv4_sysctl_entries[] = {
"ping_group_range",
};

#define IPV4_SYSCTL_BASE "net/ipv4"

Check warning on line 2135 in criu/net.c

View workflow job for this annotation

GitHub Actions / build

#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;
}
github-advanced-security[bot] marked this conversation as resolved.
Dismissed
Show resolved Hide resolved
}

ret = sysctl_op(req, n, op, CLONE_NEWNET);
if (ret < 0) {
pr_err("unix: Failed to %s %s/<sysctls>\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;
Expand All @@ -2142,17 +2215,26 @@
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;

i = 0;
list_for_each_entry(p, &ns->net.ids, node)
i++;

/*
* Here we allocate one single big buffer for storing multiple arrays
* of protobuf entries and pointers to entries in it and we later use
* xptr_pull_s to claim a part of this buffer of proper size for each
* particular array. Next we read data from sysctl files to those
* arrays and then finally save them into images.
*/
o_buf = buf = xmalloc(i * (sizeof(NetnsId *) + sizeof(NetnsId)) +
size4 * (sizeof(SysctlEntry *) + sizeof(SysctlEntry)) * 2 +
size6 * (sizeof(SysctlEntry *) + sizeof(SysctlEntry)) * 2 +
sizex * (sizeof(SysctlEntry *) + sizeof(SysctlEntry)));
(2 * size4 + 2 * size6 + sizex + ipv4_sysctl_size) *
(sizeof(SysctlEntry *) + sizeof(SysctlEntry)));

Check warning on line 2237 in criu/net.c

View workflow job for this annotation

GitHub Actions / build

Snorch marked this conversation as resolved.
Show resolved Hide resolved
if (!buf)
goto out;

Expand Down Expand Up @@ -2217,6 +2299,21 @@
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;
github-advanced-security[bot] marked this conversation as resolved.
Dismissed
Show resolved Hide resolved
} 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;
Expand All @@ -2235,6 +2332,10 @@
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);
Expand Down Expand Up @@ -2587,6 +2688,12 @@
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;
Expand Down
1 change: 1 addition & 0 deletions images/netdev.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
43 changes: 43 additions & 0 deletions test/zdtm/lib/sysctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,49 @@
#include "zdtmtst.h"
#include "sysctl.h"

int sysctl_read_str(const char *name, char *data, size_t size)
{
int fd, ret;

fd = open(name, O_RDONLY);
if (fd < 0) {
pr_perror("Can't open %s", name);
return -1;
}

ret = read(fd, data, size - 1);
if (ret < 0) {
pr_perror("Can't read %s", name);
close(fd);
return -1;
}
data[ret] = '\0';
close(fd);

return 0;
}

int sysctl_write_str(const char *name, char *data)
{
int fd, ret;

fd = open(name, O_WRONLY);
if (fd < 0) {
pr_perror("Can't open %s", name);
return -1;
}

ret = write(fd, data, strlen(data));
if (ret < 0) {
pr_perror("Can't write %s into %s", data, name);
close(fd);
return -1;
}
close(fd);

return 0;
}

int sysctl_read_int(const char *name, int *data)
{
int fd;
Expand Down
2 changes: 2 additions & 0 deletions test/zdtm/lib/sysctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@

extern int sysctl_read_int(const char *name, int *data);
extern int sysctl_write_int(const char *name, int val);
extern int sysctl_read_str(const char *name, char *data, size_t size);
extern int sysctl_write_str(const char *name, char *data);

#endif
58 changes: 46 additions & 12 deletions test/zdtm/static/netns_sub_sysctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,33 @@
#include "zdtmtst.h"
#include "sysctl.h"

const char *test_doc = "Check dump and restore a net.unix.max_dgram_qlen sysctl parameter in subns";
const char *test_doc = "Check dump and restore of sysctls in subns";
const char *test_author = "Alexander Mikhalitsyn <alexander@mihalicyn.com>";

#define MAX_STR_SYSCTL_LEN 200

enum {
SYSCTL_INT,
SYSCTL_STR,
};

typedef struct {
const char *path;
int type;
int old;
int new;
char s_old[MAX_STR_SYSCTL_LEN];
char s_new[MAX_STR_SYSCTL_LEN];
} sysctl_opt_t;

#define CONF_UNIX_BASE "/proc/sys/net/unix"
#define IPV4_SYSCTL_BASE "/proc/sys/net/ipv4"

static sysctl_opt_t net_unix_params[] = { { CONF_UNIX_BASE "/max_dgram_qlen", 0, 0 }, { NULL, 0, 0 } };
static sysctl_opt_t net_unix_params[] = {
{CONF_UNIX_BASE "/max_dgram_qlen", SYSCTL_INT},

Check warning on line 29 in test/zdtm/static/netns_sub_sysctl.c

View workflow job for this annotation

GitHub Actions / build

{IPV4_SYSCTL_BASE "/ping_group_range", SYSCTL_STR, 0, 0, "40000\t50000\n"},
{NULL, 0, 0}
};

int main(int argc, char **argv)
{
Expand All @@ -23,24 +38,43 @@
test_init(argc, argv);

for (p = net_unix_params; p->path != NULL; p++) {
p->old = (((unsigned)lrand48()) % 1023) + 1;
if (sysctl_write_int(p->path, p->old)) {
pr_perror("Can't change %s", p->path);
return -1;
if (p->type == SYSCTL_INT) {
p->old = (((unsigned)lrand48()) % 1023) + 1;
if (sysctl_write_int(p->path, p->old)) {
pr_perror("Can't change %s", p->path);
return -1;
}
} else if (p->type == SYSCTL_STR) {
if (sysctl_write_str(p->path, p->s_old)) {
pr_perror("Can't change %s", p->path);
return -1;
}
}
}

test_daemon();
test_waitsig();

for (p = net_unix_params; p->path != NULL; p++) {
if (sysctl_read_int(p->path, &p->new))
ret = 1;
if (p->type == SYSCTL_INT) {
if (sysctl_read_int(p->path, &p->new))
ret = 1;

if (p->old != p->new) {
errno = EINVAL;
pr_perror("%s changed: %d ---> %d", p->path, p->old, p->new);
ret = 1;
if (p->old != p->new) {
errno = EINVAL;
pr_perror("%s changed: %d ---> %d", p->path, p->old, p->new);
ret = 1;
}
} else if (p->type == SYSCTL_STR) {
if (sysctl_read_str(p->path, p->s_new, MAX_STR_SYSCTL_LEN)) {
ret = 1;
} else {
if (strcmp(p->s_old, p->s_new)) {
errno = EINVAL;
pr_perror("%s changed: %s ---> %s", p->path, p->s_old, p->s_new);
ret = 1;
}
}
}
}

Expand Down
Loading