Skip to content
Merged
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
4 changes: 3 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ libcrun_SOURCES = src/libcrun/utils.c \
src/libcrun/linux.c \
src/libcrun/mount_flags.c \
src/libcrun/scheduler.c \
src/libcrun/mempolicy.c \
src/libcrun/seccomp.c \
src/libcrun/seccomp_notify.c \
src/libcrun/signals.c \
Expand Down Expand Up @@ -160,7 +161,7 @@ EXTRA_DIST = COPYING COPYING.libcrun README.md NEWS SECURITY.md rpm/crun.spec au
src/libcrun/custom-handler.h src/libcrun/io_priority.h \
src/libcrun/handlers/handler-utils.h \
src/libcrun/linux.h src/libcrun/utils.h src/libcrun/error.h src/libcrun/criu.h \
src/libcrun/scheduler.h src/libcrun/status.h src/libcrun/terminal.h \
src/libcrun/scheduler.h src/libcrun/mempolicy.h src/libcrun/status.h src/libcrun/terminal.h \
src/libcrun/mount_flags.h src/libcrun/intelrdt.h src/libcrun/ring_buffer.h src/libcrun/string_map.h \
src/libcrun/net_device.h \
crun.1.md crun.1 libcrun.lds \
Expand Down Expand Up @@ -225,6 +226,7 @@ PYTHON_TESTS = tests/test_capabilities.py \
tests/test_hostname.py \
tests/test_limits.py \
tests/test_oci_features.py \
tests/test_mempolicy.py \
tests/test_mounts.py \
tests/test_paths.py \
tests/test_pid.py \
Expand Down
26 changes: 26 additions & 0 deletions src/libcrun/container.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "container.h"
#include "utils.h"
#include "seccomp.h"
#include "mempolicy.h"
#ifdef HAVE_SECCOMP
# include <seccomp.h>
#endif
Expand Down Expand Up @@ -167,6 +168,22 @@ static char *archs[] = {
"SCMP_ARCH_X86_64"
};

static char *mempolicy_modes[] = {
"MPOL_DEFAULT",
"MPOL_PREFERRED",
"MPOL_BIND",
"MPOL_INTERLEAVE",
"MPOL_LOCAL",
"MPOL_PREFERRED_MANY",
"MPOL_WEIGHTED_INTERLEAVE"
};

static char *mempolicy_flags[] = {
"MPOL_F_NUMA_BALANCING",
"MPOL_F_RELATIVE_NODES",
"MPOL_F_STATIC_NODES"
};

static const char spec_file[] = "\
{\n\
\"ociVersion\": \"1.0.0\",\n\
Expand Down Expand Up @@ -2768,6 +2785,10 @@ libcrun_container_run_internal (libcrun_container_t *container, libcrun_context_

umask (0);

ret = libcrun_set_mempolicy (def, err);
if (UNLIKELY (ret < 0))
return ret;

ret = setup_seccomp (container, seccomp_bpf_data, &seccomp_gen_ctx, &seccomp_fd, err);
if (UNLIKELY (ret < 0))
return ret;
Expand Down Expand Up @@ -4324,6 +4345,8 @@ libcrun_container_get_features (libcrun_context_t *context, struct features_info
size_t num_unsafe_annotations = sizeof (potentially_unsafe_annotations) / sizeof (potentially_unsafe_annotations[0]);
cleanup_free char **capabilities = NULL;
size_t num_capabilities = 0;
size_t num_mempolicy_modes = sizeof (mempolicy_modes) / sizeof (mempolicy_modes[0]);
size_t num_mempolicy_flags = sizeof (mempolicy_flags) / sizeof (mempolicy_flags[0]);

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

Expand Down Expand Up @@ -4374,6 +4397,9 @@ libcrun_container_get_features (libcrun_context_t *context, struct features_info

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

populate_array_field (&((*info)->linux.memory_policy.mode), mempolicy_modes, num_mempolicy_modes);
populate_array_field (&((*info)->linux.memory_policy.flags), mempolicy_flags, num_mempolicy_flags);

// Put the values for mount extensions
(*info)->linux.mount_ext.idmap.enabled = true;

Expand Down
7 changes: 7 additions & 0 deletions src/libcrun/container.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,12 @@ struct mount_ext_info_s
struct idmap_info_s idmap;
};

struct memory_policy_info_s
{
char **mode;
char **flags;
};

struct linux_info_s
{
char **namespaces;
Expand All @@ -160,6 +166,7 @@ struct linux_info_s
struct mount_ext_info_s mount_ext;
struct intel_rdt_s intel_rdt;
struct net_devices_s net_devices;
struct memory_policy_info_s memory_policy;
};

struct annotations_info_s
Expand Down
154 changes: 154 additions & 0 deletions src/libcrun/mempolicy.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/*
* crun - OCI runtime written in C
*
* Copyright (C) 2017, 2018, 2019 Giuseppe Scrivano <giuseppe@scrivano.org>
* crun is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* crun is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with crun. If not, see <http://www.gnu.org/licenses/>.
*/

#include <config.h>
#include "linux.h"
#include "utils.h"
#include <ocispec/runtime_spec_schema_config_schema.h>

#include <sys/syscall.h>
#include <unistd.h>

/* follow runc go implementation and redefine everything here */
/* Policies */
#define MPOL_DEFAULT 0
#define MPOL_PREFERRED 1
#define MPOL_BIND 2
#define MPOL_INTERLEAVE 3
#define MPOL_LOCAL 4
#define MPOL_PREFERRED_MANY 5
#define MPOL_WEIGHTED_INTERLEAVE 6

/* Flags for set_mempolicy, specified in mode */
#define MPOL_F_NUMA_BALANCING (1 << 13)
#define MPOL_F_RELATIVE_NODES (1 << 14)
#define MPOL_F_STATIC_NODES (1 << 15)

typedef struct
{
const char *name;
int value;
} str2int_map_t;

/* update mpol_mode_map based on numaif.h MPOL_MAX
* the warn in mempolicy.c will indicate that an update is required.
* MPOL_WEIGHTED_INTERLEAVE has been introduced in MPOL_MAX 7 (kernel 6.9+)
* and some distros still has older kernel interfaces */
str2int_map_t mpol_mode_map[] = {
{ "MPOL_DEFAULT", MPOL_DEFAULT },
{ "MPOL_PREFERRED", MPOL_PREFERRED },
{ "MPOL_BIND", MPOL_BIND },
{ "MPOL_INTERLEAVE", MPOL_INTERLEAVE },
{ "MPOL_LOCAL", MPOL_LOCAL },
{ "MPOL_PREFERRED_MANY", MPOL_PREFERRED_MANY },
{ "MPOL_WEIGHTED_INTERLEAVE", MPOL_WEIGHTED_INTERLEAVE },
{ NULL, -1 }
};

/* flags cannot be tracked the same way as mode */
str2int_map_t mpol_flag_map[] = {
{ "MPOL_F_NUMA_BALANCING", MPOL_F_NUMA_BALANCING },
{ "MPOL_F_RELATIVE_NODES", MPOL_F_RELATIVE_NODES },
{ "MPOL_F_STATIC_NODES", MPOL_F_STATIC_NODES },
{ NULL, -1 }
};

#define MAX_NUMA_NODES 4096

static int
mpol_str2int (const char *str, const str2int_map_t *map)
{
int idx = 0;

while (map[idx].name != NULL)
{
if (! strcmp (map[idx].name, str))
return map[idx].value;

idx++;
}

errno = EINVAL;
return -1;
}

int
libcrun_set_mempolicy (runtime_spec_schema_config_schema *def, libcrun_error_t *err)
{
runtime_spec_schema_config_linux_memory_policy *memory_policy = NULL;
int mpol_mode = 0;
int mpol_flag = 0;
size_t i = 0;
unsigned long nmask[MAX_NUMA_NODES / (sizeof (unsigned long) * 8)];
unsigned long *nmask_final = NULL;
int ret = 0;

if (def->linux == NULL || def->linux->memory_policy == NULL)
{
libcrun_debug ("no linux numa mempolicy configuration found");
return ret;
}

libcrun_debug ("Initializing linux numa mempolicy");

memory_policy = def->linux->memory_policy;

libcrun_debug ("Validating linux numa mempolicy");
/* validate memory policy mode */
if (! memory_policy->mode)
return crun_make_error (err, EINVAL, "linux NUMA mempolicy mode is missing from the configuration");

libcrun_debug ("Validating mode: %s", memory_policy->mode);
mpol_mode = mpol_str2int (memory_policy->mode, mpol_mode_map);
if (mpol_mode < 0)
return crun_make_error (err, EINVAL, "requested linux NUMA mempolicy mode '%s' is unknown", memory_policy->mode);

/* validating memory policy flags */
libcrun_debug ("Validating mode flags: %zu configured", memory_policy->flags_len);
for (i = 0; i < memory_policy->flags_len; i++)
{
libcrun_debug ("Validating mode flag: %s", memory_policy->flags[i]);
mpol_flag = mpol_str2int (memory_policy->flags[i], mpol_flag_map);
if (mpol_flag < 0)
return crun_make_error (err, EINVAL, "requested linux NUMA mempolicy flag '%s' is unknown", memory_policy->flags[i]);
mpol_mode = mpol_mode | mpol_flag;
}

/* kernel will take care of validating the nodes */
if (memory_policy->nodes)
{
cleanup_free char *bitmask = NULL;
size_t bitmask_size;

ret = cpuset_string_to_bitmask (memory_policy->nodes, &bitmask, &bitmask_size, err);
if (UNLIKELY (ret < 0))
return ret;

if (bitmask_size > sizeof (nmask))
return crun_make_error (err, EINVAL, "requested NUMA bitmask bigger than kernel supported bitmask");

nmask_final = nmask;
memset (nmask_final, 0, sizeof (nmask));
memcpy (nmask_final, bitmask, bitmask_size);
}

if (syscall (__NR_set_mempolicy, mpol_mode, nmask_final, nmask_final ? MAX_NUMA_NODES - 1 : 0) < 0)
return crun_make_error (err, errno, "set_mempolicy");

return ret;
}
27 changes: 27 additions & 0 deletions src/libcrun/mempolicy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* crun - OCI runtime written in C
*
* Copyright (C) 2017, 2018, 2019, 2021 Giuseppe Scrivano <giuseppe@scrivano.org>
* crun is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* crun is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with crun. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MEMPOLICY_H
#define MEMPOLICY_H
#include <config.h>
#include "error.h"
#include "container.h"
#include "status.h"

int libcrun_set_mempolicy (runtime_spec_schema_config_schema *def, libcrun_error_t *err);

#endif
16 changes: 16 additions & 0 deletions src/oci_features.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,21 @@ crun_features_add_seccomp_info (yajl_gen json_gen, const struct linux_info_s *li
yajl_gen_map_close (json_gen);
}

void
crun_features_add_mempolicy_info (yajl_gen json_gen, const struct linux_info_s *linux)
{
yajl_gen_string (json_gen, (const unsigned char *) "memoryPolicy", strlen ("memoryPolicy"));
yajl_gen_map_open (json_gen);

if (linux->memory_policy.mode)
add_array_to_json (json_gen, "modes", linux->memory_policy.mode);

if (linux->memory_policy.flags)
add_array_to_json (json_gen, "flags", linux->memory_policy.flags);

yajl_gen_map_close (json_gen);
}

void
crun_features_add_apparmor_info (yajl_gen json_gen, const struct linux_info_s *linux)
{
Expand Down Expand Up @@ -219,6 +234,7 @@ crun_features_add_linux_info (yajl_gen json_gen, const struct linux_info_s *linu
crun_features_add_mount_ext_info (json_gen, linux);
crun_features_add_intel_rdt (json_gen, linux);
crun_features_add_net_devices (json_gen, linux);
crun_features_add_mempolicy_info (json_gen, linux);

yajl_gen_map_close (json_gen);
}
Expand Down
Loading