Skip to content

Commit 6ead513

Browse files
committed
linux: add support for numa set_mempolicy(2)
Closes: #1844 Signed-off-by: Fabio M. Di Nitto <[email protected]>
1 parent 1f7b794 commit 6ead513

File tree

7 files changed

+711
-1
lines changed

7 files changed

+711
-1
lines changed

Makefile.am

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ libcrun_SOURCES = src/libcrun/utils.c \
6767
src/libcrun/linux.c \
6868
src/libcrun/mount_flags.c \
6969
src/libcrun/scheduler.c \
70+
src/libcrun/mempolicy.c \
7071
src/libcrun/seccomp.c \
7172
src/libcrun/seccomp_notify.c \
7273
src/libcrun/signals.c \
@@ -160,7 +161,7 @@ EXTRA_DIST = COPYING COPYING.libcrun README.md NEWS SECURITY.md rpm/crun.spec au
160161
src/libcrun/custom-handler.h src/libcrun/io_priority.h \
161162
src/libcrun/handlers/handler-utils.h \
162163
src/libcrun/linux.h src/libcrun/utils.h src/libcrun/error.h src/libcrun/criu.h \
163-
src/libcrun/scheduler.h src/libcrun/status.h src/libcrun/terminal.h \
164+
src/libcrun/scheduler.h src/libcrun/mempolicy.h src/libcrun/status.h src/libcrun/terminal.h \
164165
src/libcrun/mount_flags.h src/libcrun/intelrdt.h src/libcrun/ring_buffer.h src/libcrun/string_map.h \
165166
src/libcrun/net_device.h \
166167
crun.1.md crun.1 libcrun.lds \
@@ -225,6 +226,7 @@ PYTHON_TESTS = tests/test_capabilities.py \
225226
tests/test_hostname.py \
226227
tests/test_limits.py \
227228
tests/test_oci_features.py \
229+
tests/test_mempolicy.py \
228230
tests/test_mounts.py \
229231
tests/test_paths.py \
230232
tests/test_pid.py \

src/libcrun/container.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "container.h"
2424
#include "utils.h"
2525
#include "seccomp.h"
26+
#include "mempolicy.h"
2627
#ifdef HAVE_SECCOMP
2728
# include <seccomp.h>
2829
#endif
@@ -167,6 +168,22 @@ static char *archs[] = {
167168
"SCMP_ARCH_X86_64"
168169
};
169170

171+
static char *mempolicy_modes[] = {
172+
"MPOL_DEFAULT",
173+
"MPOL_PREFERRED",
174+
"MPOL_BIND",
175+
"MPOL_INTERLEAVE",
176+
"MPOL_LOCAL",
177+
"MPOL_PREFERRED_MANY",
178+
"MPOL_WEIGHTED_INTERLEAVE"
179+
};
180+
181+
static char *mempolicy_flags[] = {
182+
"MPOL_F_NUMA_BALANCING",
183+
"MPOL_F_RELATIVE_NODES",
184+
"MPOL_F_STATIC_NODES"
185+
};
186+
170187
static const char spec_file[] = "\
171188
{\n\
172189
\"ociVersion\": \"1.0.0\",\n\
@@ -2768,6 +2785,10 @@ libcrun_container_run_internal (libcrun_container_t *container, libcrun_context_
27682785

27692786
umask (0);
27702787

2788+
ret = libcrun_set_mempolicy (def, err);
2789+
if (UNLIKELY (ret < 0))
2790+
return ret;
2791+
27712792
ret = setup_seccomp (container, seccomp_bpf_data, &seccomp_gen_ctx, &seccomp_fd, err);
27722793
if (UNLIKELY (ret < 0))
27732794
return ret;
@@ -4324,6 +4345,8 @@ libcrun_container_get_features (libcrun_context_t *context, struct features_info
43244345
size_t num_unsafe_annotations = sizeof (potentially_unsafe_annotations) / sizeof (potentially_unsafe_annotations[0]);
43254346
cleanup_free char **capabilities = NULL;
43264347
size_t num_capabilities = 0;
4348+
size_t num_mempolicy_modes = sizeof (mempolicy_modes) / sizeof (mempolicy_modes[0]);
4349+
size_t num_mempolicy_flags = sizeof (mempolicy_flags) / sizeof (mempolicy_flags[0]);
43274350

43284351
*info = xmalloc0 (sizeof (struct features_info_s));
43294352

@@ -4374,6 +4397,9 @@ libcrun_container_get_features (libcrun_context_t *context, struct features_info
43744397

43754398
(*info)->linux.net_devices.enabled = true;
43764399

4400+
populate_array_field (&((*info)->linux.memory_policy.mode), mempolicy_modes, num_mempolicy_modes);
4401+
populate_array_field (&((*info)->linux.memory_policy.flags), mempolicy_flags, num_mempolicy_flags);
4402+
43774403
// Put the values for mount extensions
43784404
(*info)->linux.mount_ext.idmap.enabled = true;
43794405

src/libcrun/container.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,12 @@ struct mount_ext_info_s
149149
struct idmap_info_s idmap;
150150
};
151151

152+
struct memory_policy_info_s
153+
{
154+
char **mode;
155+
char **flags;
156+
};
157+
152158
struct linux_info_s
153159
{
154160
char **namespaces;
@@ -160,6 +166,7 @@ struct linux_info_s
160166
struct mount_ext_info_s mount_ext;
161167
struct intel_rdt_s intel_rdt;
162168
struct net_devices_s net_devices;
169+
struct memory_policy_info_s memory_policy;
163170
};
164171

165172
struct annotations_info_s

src/libcrun/mempolicy.c

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*
2+
* crun - OCI runtime written in C
3+
*
4+
* Copyright (C) 2017, 2018, 2019 Giuseppe Scrivano <[email protected]>
5+
* crun is free software; you can redistribute it and/or modify
6+
* it under the terms of the GNU Lesser General Public License as published by
7+
* the Free Software Foundation; either version 2.1 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* crun is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public License
16+
* along with crun. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
#include <config.h>
20+
#include "linux.h"
21+
#include "utils.h"
22+
#include <ocispec/runtime_spec_schema_config_schema.h>
23+
24+
#include <sys/syscall.h>
25+
#include <unistd.h>
26+
27+
/* follow runc go implementation and redefine everything here */
28+
/* Policies */
29+
#define MPOL_DEFAULT 0
30+
#define MPOL_PREFERRED 1
31+
#define MPOL_BIND 2
32+
#define MPOL_INTERLEAVE 3
33+
#define MPOL_LOCAL 4
34+
#define MPOL_PREFERRED_MANY 5
35+
#define MPOL_WEIGHTED_INTERLEAVE 6
36+
37+
/* Flags for set_mempolicy, specified in mode */
38+
#define MPOL_F_NUMA_BALANCING (1 << 13)
39+
#define MPOL_F_RELATIVE_NODES (1 << 14)
40+
#define MPOL_F_STATIC_NODES (1 << 15)
41+
42+
typedef struct
43+
{
44+
const char *name;
45+
int value;
46+
} str2int_map_t;
47+
48+
/* update mpol_mode_map based on numaif.h MPOL_MAX
49+
* the warn in mempolicy.c will indicate that an update is required.
50+
* MPOL_WEIGHTED_INTERLEAVE has been introduced in MPOL_MAX 7 (kernel 6.9+)
51+
* and some distros still has older kernel interfaces */
52+
str2int_map_t mpol_mode_map[] = {
53+
{ "MPOL_DEFAULT", MPOL_DEFAULT },
54+
{ "MPOL_PREFERRED", MPOL_PREFERRED },
55+
{ "MPOL_BIND", MPOL_BIND },
56+
{ "MPOL_INTERLEAVE", MPOL_INTERLEAVE },
57+
{ "MPOL_LOCAL", MPOL_LOCAL },
58+
{ "MPOL_PREFERRED_MANY", MPOL_PREFERRED_MANY },
59+
{ "MPOL_WEIGHTED_INTERLEAVE", MPOL_WEIGHTED_INTERLEAVE },
60+
{ NULL, -1 }
61+
};
62+
63+
/* flags cannot be tracked the same way as mode */
64+
str2int_map_t mpol_flag_map[] = {
65+
{ "MPOL_F_NUMA_BALANCING", MPOL_F_NUMA_BALANCING },
66+
{ "MPOL_F_RELATIVE_NODES", MPOL_F_RELATIVE_NODES },
67+
{ "MPOL_F_STATIC_NODES", MPOL_F_STATIC_NODES },
68+
{ NULL, -1 }
69+
};
70+
71+
#define MAX_NUMA_NODES 4096
72+
73+
static int
74+
mpol_str2int (const char *str, const str2int_map_t *map)
75+
{
76+
int idx = 0;
77+
78+
while (map[idx].name != NULL)
79+
{
80+
if (! strcmp (map[idx].name, str))
81+
return map[idx].value;
82+
83+
idx++;
84+
}
85+
86+
errno = EINVAL;
87+
return -1;
88+
}
89+
90+
int
91+
libcrun_set_mempolicy (runtime_spec_schema_config_schema *def, libcrun_error_t *err)
92+
{
93+
runtime_spec_schema_config_linux_memory_policy *memory_policy = NULL;
94+
int mpol_mode = 0;
95+
int mpol_flag = 0;
96+
size_t i = 0;
97+
unsigned long nmask[MAX_NUMA_NODES / (sizeof (unsigned long) * 8)];
98+
unsigned long *nmask_final = NULL;
99+
int ret = 0;
100+
101+
if (def->linux == NULL || def->linux->memory_policy == NULL)
102+
{
103+
libcrun_debug ("no linux numa mempolicy configuration found");
104+
return ret;
105+
}
106+
107+
libcrun_debug ("Initializing linux numa mempolicy");
108+
109+
memory_policy = def->linux->memory_policy;
110+
111+
libcrun_debug ("Validating linux numa mempolicy");
112+
/* validate memory policy mode */
113+
if (! memory_policy->mode)
114+
return crun_make_error (err, EINVAL, "linux NUMA mempolicy mode is missing from the configuration");
115+
116+
libcrun_debug ("Validating mode: %s", memory_policy->mode);
117+
mpol_mode = mpol_str2int (memory_policy->mode, mpol_mode_map);
118+
if (mpol_mode < 0)
119+
return crun_make_error (err, EINVAL, "requested linux NUMA mempolicy mode '%s' is unknown", memory_policy->mode);
120+
121+
/* validating memory policy flags */
122+
libcrun_debug ("Validating mode flags: %zu configured", memory_policy->flags_len);
123+
for (i = 0; i < memory_policy->flags_len; i++)
124+
{
125+
libcrun_debug ("Validating mode flag: %s", memory_policy->flags[i]);
126+
mpol_flag = mpol_str2int (memory_policy->flags[i], mpol_flag_map);
127+
if (mpol_flag < 0)
128+
return crun_make_error (err, EINVAL, "requested linux NUMA mempolicy flag '%s' is unknown", memory_policy->flags[i]);
129+
mpol_mode = mpol_mode | mpol_flag;
130+
}
131+
132+
/* kernel will take care of validating the nodes */
133+
if (memory_policy->nodes)
134+
{
135+
cleanup_free char *bitmask = NULL;
136+
size_t bitmask_size;
137+
138+
ret = cpuset_string_to_bitmask (memory_policy->nodes, &bitmask, &bitmask_size, err);
139+
if (UNLIKELY (ret < 0))
140+
return ret;
141+
142+
if (bitmask_size > sizeof (nmask))
143+
return crun_make_error (err, EINVAL, "requested NUMA bitmask bigger than kernel supported bitmask");
144+
145+
nmask_final = nmask;
146+
memset (nmask_final, 0, sizeof (nmask));
147+
memcpy (nmask_final, bitmask, bitmask_size);
148+
}
149+
150+
if (syscall (__NR_set_mempolicy, mpol_mode, nmask_final, nmask_final ? MAX_NUMA_NODES - 1 : 0) < 0)
151+
return crun_make_error (err, errno, "set_mempolicy");
152+
153+
return ret;
154+
}

src/libcrun/mempolicy.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* crun - OCI runtime written in C
3+
*
4+
* Copyright (C) 2017, 2018, 2019, 2021 Giuseppe Scrivano <[email protected]>
5+
* crun is free software; you can redistribute it and/or modify
6+
* it under the terms of the GNU Lesser General Public License as published by
7+
* the Free Software Foundation; either version 2.1 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* crun is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public License
16+
* along with crun. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
#ifndef MEMPOLICY_H
19+
#define MEMPOLICY_H
20+
#include <config.h>
21+
#include "error.h"
22+
#include "container.h"
23+
#include "status.h"
24+
25+
int libcrun_set_mempolicy (runtime_spec_schema_config_schema *def, libcrun_error_t *err);
26+
27+
#endif

src/oci_features.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,21 @@ crun_features_add_seccomp_info (yajl_gen json_gen, const struct linux_info_s *li
150150
yajl_gen_map_close (json_gen);
151151
}
152152

153+
void
154+
crun_features_add_mempolicy_info (yajl_gen json_gen, const struct linux_info_s *linux)
155+
{
156+
yajl_gen_string (json_gen, (const unsigned char *) "memoryPolicy", strlen ("memoryPolicy"));
157+
yajl_gen_map_open (json_gen);
158+
159+
if (linux->memory_policy.mode)
160+
add_array_to_json (json_gen, "modes", linux->memory_policy.mode);
161+
162+
if (linux->memory_policy.flags)
163+
add_array_to_json (json_gen, "flags", linux->memory_policy.flags);
164+
165+
yajl_gen_map_close (json_gen);
166+
}
167+
153168
void
154169
crun_features_add_apparmor_info (yajl_gen json_gen, const struct linux_info_s *linux)
155170
{
@@ -219,6 +234,7 @@ crun_features_add_linux_info (yajl_gen json_gen, const struct linux_info_s *linu
219234
crun_features_add_mount_ext_info (json_gen, linux);
220235
crun_features_add_intel_rdt (json_gen, linux);
221236
crun_features_add_net_devices (json_gen, linux);
237+
crun_features_add_mempolicy_info (json_gen, linux);
222238

223239
yajl_gen_map_close (json_gen);
224240
}

0 commit comments

Comments
 (0)