diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 32ddff35c9..0ff68d0e82 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -35,7 +35,7 @@ jobs: - run: | sudo apt-get update - sudo apt-get install -y make git gcc build-essential pkgconf libtool libsystemd-dev libcap-dev libseccomp-dev libyajl-dev go-md2man libtool autoconf python3 automake libprotobuf-c-dev + sudo apt-get install -y make git gcc build-essential pkgconf libtool libsystemd-dev libcap-dev libseccomp-dev libyajl-dev go-md2man libtool autoconf python3 automake libprotobuf-c-dev libnuma-dev ./autogen.sh ./configure make -j $(nproc) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 70e5a9142d..3495fc5f93 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -19,7 +19,7 @@ jobs: - run: sudo apt-get update - - run: sudo apt-get install -y make git gcc build-essential pkgconf libtool libsystemd-dev libcap-dev libseccomp-dev libyajl-dev go-md2man libtool autoconf python3 automake libprotobuf-c-dev + - run: sudo apt-get install -y make git gcc build-essential pkgconf libtool libsystemd-dev libcap-dev libseccomp-dev libyajl-dev go-md2man libtool autoconf python3 automake libprotobuf-c-dev libnuma-dev - run: | set -ex diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index b23e2837ed..d0b5881a2a 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -40,7 +40,7 @@ jobs: install: | apt-get update -y - apt-get install -y automake libtool autotools-dev libseccomp-dev git make libcap-dev cmake pkg-config gcc wget go-md2man libsystemd-dev gperf clang-format libyajl-dev libprotobuf-c-dev clang mawk + apt-get install -y automake libtool autotools-dev libseccomp-dev git make libcap-dev cmake pkg-config gcc wget go-md2man libsystemd-dev gperf clang-format libyajl-dev libprotobuf-c-dev clang mawk libnuma-dev run: | find $(pwd) -name '.git' -exec bash -c 'git config --global --add safe.directory ${0%/.git}' {} \; @@ -94,7 +94,7 @@ jobs: sudo add-apt-repository -y ppa:criu/ppa # add-apt-repository runs apt-get update so we don't have to. - sudo apt-get install -q -y criu automake libtool autotools-dev libseccomp-dev git make libcap-dev cmake pkg-config gcc wget go-md2man libsystemd-dev gperf clang-format libyajl-dev containerd runc libasan6 libprotobuf-c-dev mawk + sudo apt-get install -q -y criu automake libtool autotools-dev libseccomp-dev git make libcap-dev cmake pkg-config gcc wget go-md2man libsystemd-dev gperf clang-format libyajl-dev containerd runc libasan6 libprotobuf-c-dev mawk libnuma-dev - name: run autogen.sh run: | @@ -210,7 +210,7 @@ jobs: - name: install dependencies run: | sudo apt-get update -q -y - sudo apt-get install -q -y automake libtool autotools-dev libseccomp-dev git make libcap-dev cmake pkg-config gcc wget go-md2man libsystemd-dev gperf clang-format libyajl-dev libprotobuf-c-dev mawk + sudo apt-get install -q -y automake libtool autotools-dev libseccomp-dev git make libcap-dev cmake pkg-config gcc wget go-md2man libsystemd-dev gperf clang-format libyajl-dev libprotobuf-c-dev mawk libnuma-dev - uses: lumaxis/shellcheck-problem-matchers@v2 - name: shellcheck run: | diff --git a/Makefile.am b/Makefile.am index f09afa20fd..b315b7d4ac 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 \ @@ -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/mempolicy_internal.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 \ @@ -179,7 +180,7 @@ noinst_PROGRAMS = crun endif if BUILD_TESTS -check_PROGRAMS = tests/init $(UNIT_TESTS) tests/tests_libcrun_fuzzer +check_PROGRAMS = tests/init $(UNIT_TESTS) tests/tests_libcrun_fuzzer tests/tests_mempolicy_helper TESTS_LDADD = libcrun_testing.la $(FOUND_LIBS) $(maybe_libyajl.la) @@ -212,6 +213,11 @@ tests_tests_libcrun_errors_SOURCES = tests/tests_libcrun_errors.c tests_tests_libcrun_errors_LDADD = $(TESTS_LDADD) tests_tests_libcrun_errors_LDFLAGS = $(crun_LDFLAGS) +tests_tests_mempolicy_helper_CFLAGS = -I $(abs_top_builddir)/libocispec/src -I $(abs_top_srcdir)/libocispec/src -I $(abs_top_builddir)/src/libcrun -I $(abs_top_srcdir)/src/libcrun +tests_tests_mempolicy_helper_SOURCES = tests/tests_mempolicy_helper.c +tests_tests_mempolicy_helper_LDADD = $(TESTS_LDADD) +tests_tests_mempolicy_helper_LDFLAGS = $(crun_LDFLAGS) + endif TEST_EXTENSIONS = .py PY_LOG_COMPILER = $(PYTHON) @@ -225,6 +231,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 \ diff --git a/README.md b/README.md index 05c3cac56d..a6b6cbcbf2 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,8 @@ These dependencies are required for the build: $ sudo dnf install -y \ autoconf automake gcc git-core glibc-static go-md2man \ libcap-devel libseccomp-devel libtool make pkg-config \ - python python-libmount systemd-devel yajl-devel + python python-libmount systemd-devel yajl-devel \ + numactl-devel ``` ### RHEL/CentOS Stream 9 @@ -69,7 +70,8 @@ $ sudo dnf config-manager --set-enabled crb $ sudo dnf install -y \ autoconf automake gcc git-core glibc-static go-md2man \ libcap-devel libseccomp-devel libtool make pkg-config \ - python python-libmount systemd-devel yajl-devel + python python-libmount systemd-devel yajl-devel \ + numactl-devel ``` ### RHEL/CentOS Stream 10 @@ -79,7 +81,7 @@ $ sudo dnf config-manager --set-enabled crb $ sudo dnf install -y \ autoconf automake gcc git-core glibc-static go-md2man \ libcap-devel libseccomp-devel libtool make pkg-config \ - python python-libmount systemd-devel + python python-libmount systemd-devel numactl-devel ``` NOTE that you need to add `--enable-embedded-yajl` to `./configure` flags below. @@ -89,22 +91,23 @@ NOTE that you need to add `--enable-embedded-yajl` to `./configure` flags below. ```console $ sudo apt-get install -y make git gcc build-essential pkgconf libtool \ libsystemd-dev libprotobuf-c-dev libcap-dev libseccomp-dev libyajl-dev \ - go-md2man autoconf python3 automake + go-md2man autoconf python3 automake libnuma-dev ``` ### Alpine ```console # apk add gcc automake autoconf libtool gettext pkgconf git make musl-dev \ - python3 libcap-dev libseccomp-dev yajl-dev argp-standalone go-md2man + python3 libcap-dev libseccomp-dev yajl-dev argp-standalone go-md2man \ + numactl-dev ``` ### Tumbleweed ```console # zypper install make automake autoconf gettext libtool gcc libcap-devel \ -systemd-devel libyajl-devel libseccomp-devel python3 go-md2man \ -glibc-static; + systemd-devel libyajl-devel libseccomp-devel python3 go-md2man \ + glibc-static libnuma-devel ``` Note that Tumbleweed requires you to specify libseccomp's header file location diff --git a/configure.ac b/configure.ac index 5f39279d35..dfce718437 100644 --- a/configure.ac +++ b/configure.ac @@ -173,6 +173,17 @@ AS_IF([test "x$enable_systemd" != "xno"], [ ]) ]) +dnl numa +AC_ARG_ENABLE([numa], + AS_HELP_STRING([--disable-numa], [Ignore numa and disable support])) +AS_IF([test "x$enable_numa" != "xno"], [ + AC_CHECK_HEADERS([numa.h], [], [AC_MSG_ERROR([*** Missing numa headers])]) + AC_CHECK_HEADERS([numaif.h], [], [AC_MSG_ERROR([*** Missing numa interface headers])]) + AS_IF([test "$ac_cv_header_numaif_h" = "yes"], [ + AC_SEARCH_LIBS(set_mempolicy, [numa], [AC_DEFINE([HAVE_NUMA], 1, [Define if libnuma is available])], [AC_MSG_ERROR([*** Failed to find libnuma])]) + ]) +]) + dnl ebpf AC_ARG_ENABLE([bpf], AS_HELP_STRING([--disable-bpf], [Ignore eBPF and disable support])) diff --git a/nix/derivation.nix b/nix/derivation.nix index 698ee4f608..0362fc12e5 100644 --- a/nix/derivation.nix +++ b/nix/derivation.nix @@ -30,6 +30,7 @@ with pkgs; stdenv.mkDerivation { libseccomp libsystemd yajl + numactl ] ++ lib.optionals enableCriu [ criu ]; configureFlags = [ "--enable-static" ] ++ lib.optional (!enableSystemd) [ "--disable-systemd" ]; prePatch = '' diff --git a/nix/overlay.nix b/nix/overlay.nix index 851ac40a7c..4b6788f570 100644 --- a/nix/overlay.nix +++ b/nix/overlay.nix @@ -28,6 +28,7 @@ self: super: libassuan = (static super.libassuan); libgpgerror = (static super.libgpgerror); libseccomp = (static super.libseccomp); + numactl = (static super.numactl); libcap = (static super.libcap).overrideAttrs (x: { postInstall = '' mkdir -p "$doc/share/doc/${x.pname}-${x.version}" diff --git a/rpm/Makefile b/rpm/Makefile index b4c1a11a1a..6fef2e6325 100644 --- a/rpm/Makefile +++ b/rpm/Makefile @@ -10,7 +10,7 @@ endif srpm-dep: $(SUDO_CMD) dnf -y install autoconf automake git git-archive-all \ libcap-devel libseccomp-devel libtool m4 rpm-build systemd-devel \ - yajl-devel + yajl-devel numactl-devel .ONESHELL: tarball-prep: srpm-dep diff --git a/rpm/crun.spec b/rpm/crun.spec index 7881bb8954..fca87623e3 100644 --- a/rpm/crun.spec +++ b/rpm/crun.spec @@ -74,6 +74,7 @@ BuildRequires: wasmedge-devel %endif BuildRequires: python BuildRequires: glibc-static +BuildRequires: numactl-devel Provides: oci-runtime %description diff --git a/src/libcrun/container.c b/src/libcrun/container.c index 851f4a1555..26388332f6 100644 --- a/src/libcrun/container.c +++ b/src/libcrun/container.c @@ -23,6 +23,7 @@ #include "container.h" #include "utils.h" #include "seccomp.h" +#include "mempolicy.h" #ifdef HAVE_SECCOMP # include #endif @@ -2805,6 +2806,10 @@ libcrun_container_run_internal (libcrun_container_t *container, libcrun_context_ if (UNLIKELY (ret < 0)) return ret; + ret = libcrun_set_mempolicy (def, err); + if (UNLIKELY (ret < 0)) + return ret; + ret = libcrun_configure_handler (container_args.context->handler_manager, container_args.context, container, diff --git a/src/libcrun/error.c b/src/libcrun/error.c index 6f57d1f7ae..2572917648 100644 --- a/src/libcrun/error.c +++ b/src/libcrun/error.c @@ -480,6 +480,23 @@ libcrun_warning (const char *msg, ...) va_end (args_list); } +#ifdef HAVE_NUMA +/* override libnuma internal numa_warn implementation + * that is defined as WEAK to allow consumers to define + * their own behavior. + * symbol has to be public for linker to use our version + * and allow to convert numa messages into libcrun messages */ +LIBCRUN_PUBLIC +void +numa_warn (int number arg_unused, char *msg, ...) +{ + va_list args_list; + va_start (args_list, msg); + write_log (0, LIBCRUN_VERBOSITY_WARNING, msg, args_list); + va_end (args_list); +} +#endif + void libcrun_error (int errno_, const char *msg, ...) { diff --git a/src/libcrun/mempolicy.c b/src/libcrun/mempolicy.c new file mode 100644 index 0000000000..507ca8b4eb --- /dev/null +++ b/src/libcrun/mempolicy.c @@ -0,0 +1,172 @@ +/* + * crun - OCI runtime written in C + * + * Copyright (C) 2017, 2018, 2019 Giuseppe Scrivano + * 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 . + */ + +#include +#include "linux.h" +#include "utils.h" +#include + +#ifdef HAVE_NUMA +# include +# include +# include "mempolicy_internal.h" + +# define CRUN_NUMA_API_VERSION 2 /* numa.h LIBNUMA_API_VERSION at the time of writing */ +# define CRUN_NUMA_MPOL_MAX 7 /* numaif.h MPOL_MAX at the time of writing */ + +# ifndef LIBNUMA_API_VERSION +# error "Unable to determine libnuma api version" +# else +# if LIBNUMA_API_VERSION > CRUN_NUMA_API_VERSION +# warning "This code was written with libnuma API version 2. numa.h reports a higher version" +# endif +# endif +# ifndef MPOL_MAX +# error "Unable to determine numaif interface version" +# else +# if MPOL_MAX > CRUN_NUMA_MPOL_MAX +# warning "This code was written with numaif MPOL_MAX 7. numaif.h reports a higher version" +# endif +# endif + +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; +} +#endif + +int +libcrun_set_mempolicy (runtime_spec_schema_config_schema *def, libcrun_error_t *err) +{ +#ifdef HAVE_NUMA + runtime_spec_schema_config_linux_memory_policy *memory_policy = NULL; + int mpol_mode = 0; + int mpol_flag = 0; + int mpol_mode_flags = 0; + struct bitmask *nodemask = NULL; + size_t i = 0; + int ret = 0; + int savederrno = 0; + + libcrun_debug ("Initializing linux numa mempolicy"); + + if (def->linux && def->linux->memory_policy) + { + memory_policy = def->linux->memory_policy; + + libcrun_debug ("Checking hardware numa availability"); + if (numa_available () < 0) + { + return crun_make_error (err, ENOENT, "linux numa not supported on current hardware"); + } + + 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); + } + mpol_mode_flags = mpol_mode; + + /* both MPOL_DEFAULT and MPOL_LOCAL calls to set_mempolicy expects only + * the mpol_mode, no nodemask or flags */ + if (mpol_mode != MPOL_DEFAULT && mpol_mode != MPOL_LOCAL) + { + /* 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_flags = mpol_mode_flags | mpol_flag; + } + + /* sanity check mode and flags combinations */ +# if defined MPOL_F_NUMA_BALANCING + if ((mpol_mode_flags & MPOL_F_NUMA_BALANCING) && mpol_mode != MPOL_BIND) + { + return crun_make_error (err, EINVAL, "Requested linux numa mempolicy flag MPOL_F_NUMA_BALANCING is incompatible with %s", memory_policy->mode); + } +# endif +# if defined MPOL_F_RELATIVE_NODES && defined MPOL_F_STATIC_NODES + if ((mpol_mode_flags & MPOL_F_RELATIVE_NODES) && (mpol_mode_flags & MPOL_F_STATIC_NODES)) + { + return crun_make_error (err, EINVAL, "Requested linux numa mempolicy flag MPOL_F_RELATIVE_NODES and MPOL_F_STATIC_NODES cannot be combined"); + } +# endif + /* validate memory nodes */ + if (! memory_policy->nodes) + { + return crun_make_error (err, EINVAL, "linux numa mempolicy nodes is missing from the configuration"); + } + libcrun_debug ("Validating nodes: %s", memory_policy->nodes); + /* validation is done by libnuma based on hw environment + * and numa_warn symbol is overridden in error.c to convert + * numa logging to libcrun logging */ + nodemask = numa_parse_nodestring_all (memory_policy->nodes); + if (! nodemask) + { + return crun_make_error (err, EINVAL, "numa_parse_nodestring_all validation failed"); + } + + ret = set_mempolicy (mpol_mode_flags, nodemask->maskp, nodemask->size - 1); + savederrno = errno; + numa_bitmask_free (nodemask); + errno = savederrno; + } + else + { + ret = set_mempolicy (mpol_mode, NULL, 0); + } + + if (ret < 0) + { + return crun_make_error (err, errno, "set_mempolicy: %d errno: %d\n", ret, errno); + } + } + else + { + libcrun_debug ("no linux numa mempolicy configuration found"); + } +#endif + return ret; +} diff --git a/src/libcrun/mempolicy.h b/src/libcrun/mempolicy.h new file mode 100644 index 0000000000..db00e231e7 --- /dev/null +++ b/src/libcrun/mempolicy.h @@ -0,0 +1,27 @@ +/* + * crun - OCI runtime written in C + * + * Copyright (C) 2017, 2018, 2019, 2021 Giuseppe Scrivano + * 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 . + */ +#ifndef MEMPOLICY_H +#define MEMPOLICY_H +#include +#include "error.h" +#include "container.h" +#include "status.h" + +int libcrun_set_mempolicy (runtime_spec_schema_config_schema *def, libcrun_error_t *err); + +#endif diff --git a/src/libcrun/mempolicy_internal.h b/src/libcrun/mempolicy_internal.h new file mode 100644 index 0000000000..4b3e0043ed --- /dev/null +++ b/src/libcrun/mempolicy_internal.h @@ -0,0 +1,60 @@ +/* + * crun - OCI runtime written in C + * + * Copyright (C) 2017, 2018, 2019, 2021 Giuseppe Scrivano + * 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 . + */ +#ifndef MEMPOLICY_INTERNAL_H +#define MEMPOLICY_INTERNAL_H + +#include + +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 }, +#ifdef MPOL_WEIGHTED_INTERLEAVE + { "MPOL_WEIGHTED_INTERLEAVE", MPOL_WEIGHTED_INTERLEAVE }, +#endif + { NULL, -1 } +}; + +/* flags cannot be tracked the same way as mode */ +str2int_map_t mpol_flag_map[] = { +#ifdef MPOL_F_NUMA_BALANCING + { "MPOL_F_NUMA_BALANCING", MPOL_F_NUMA_BALANCING }, +#endif +#ifdef MPOL_F_RELATIVE_NODES + { "MPOL_F_RELATIVE_NODES", MPOL_F_RELATIVE_NODES }, +#endif +#ifdef MPOL_F_STATIC_NODES + { "MPOL_F_STATIC_NODES", MPOL_F_STATIC_NODES }, +#endif + { NULL, -1 } +}; + +#endif diff --git a/tests/alpine-build/Dockerfile b/tests/alpine-build/Dockerfile index a76cb40b45..66d50375ff 100644 --- a/tests/alpine-build/Dockerfile +++ b/tests/alpine-build/Dockerfile @@ -1,7 +1,8 @@ FROM alpine RUN apk add gcc automake autoconf libtool gettext pkgconf git make musl-dev \ - python3 libcap-dev libseccomp-dev yajl-dev argp-standalone go-md2man gperf + python3 libcap-dev libseccomp-dev yajl-dev argp-standalone go-md2man gperf \ + numactl-dev COPY run-tests.sh /usr/local/bin diff --git a/tests/centos10-build/Dockerfile b/tests/centos10-build/Dockerfile index e4d1ceeb9c..12a5206940 100644 --- a/tests/centos10-build/Dockerfile +++ b/tests/centos10-build/Dockerfile @@ -2,7 +2,8 @@ FROM quay.io/centos/centos:stream10-development RUN yum --enablerepo='appstream' --enablerepo='baseos' --enablerepo='crb' install -y make \ automake autoconf gettext criu-devel libtool gcc libcap-devel systemd-devel \ - libseccomp-devel python3 libtool git protobuf-c protobuf-c-devel xz glibc-static + libseccomp-devel python3 libtool git protobuf-c protobuf-c-devel xz glibc-static \ + numactl-devel COPY run-tests.sh /usr/local/bin diff --git a/tests/centos8-build/Dockerfile b/tests/centos8-build/Dockerfile index 4b810e3fd2..19f330a63f 100644 --- a/tests/centos8-build/Dockerfile +++ b/tests/centos8-build/Dockerfile @@ -3,7 +3,7 @@ FROM quay.io/centos/centos:stream8 RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* && \ yum --enablerepo='powertools' install -y make automake autoconf gettext \ criu-devel libtool gcc libcap-devel systemd-devel yajl-devel \ - libseccomp-devel python36 libtool git glibc-static + libseccomp-devel python36 libtool git glibc-static numactl-devel COPY run-tests.sh /usr/local/bin diff --git a/tests/centos9-build/Dockerfile b/tests/centos9-build/Dockerfile index da3b22e3fd..dfeafd28a3 100644 --- a/tests/centos9-build/Dockerfile +++ b/tests/centos9-build/Dockerfile @@ -2,7 +2,8 @@ FROM quay.io/centos/centos:stream9 RUN yum --enablerepo='appstream' --enablerepo='baseos' --enablerepo='crb' install -y make \ automake autoconf gettext criu-devel libtool gcc libcap-devel systemd-devel yajl-devel \ - libseccomp-devel python3 libtool git protobuf-c protobuf-c-devel glibc-static + libseccomp-devel python3 libtool git protobuf-c protobuf-c-devel glibc-static \ + numactl-devel COPY run-tests.sh /usr/local/bin diff --git a/tests/clang-check/Dockerfile b/tests/clang-check/Dockerfile index 5c0bfaa32a..6cdc673d69 100644 --- a/tests/clang-check/Dockerfile +++ b/tests/clang-check/Dockerfile @@ -1,6 +1,6 @@ FROM fedora:latest -RUN dnf install -y awk git protobuf-c protobuf-c-devel make clang-tools-extra clang python3-pip glibc-static 'dnf-command(builddep)' && \ +RUN dnf install -y awk git protobuf-c protobuf-c-devel make clang-tools-extra clang python3-pip glibc-static numactl-devel 'dnf-command(builddep)' && \ dnf builddep -y crun && pip install scan-build COPY run-tests.sh /usr/local/bin diff --git a/tests/clang-format/Dockerfile b/tests/clang-format/Dockerfile index 5829ef9606..002770f94d 100644 --- a/tests/clang-format/Dockerfile +++ b/tests/clang-format/Dockerfile @@ -1,6 +1,6 @@ FROM fedora:latest -RUN dnf install -y awk git make clang-tools-extra glibc-static 'dnf-command(builddep)' && dnf builddep -y crun +RUN dnf install -y awk git make clang-tools-extra glibc-static numactl-devel 'dnf-command(builddep)' && dnf builddep -y crun COPY run-tests.sh /usr/local/bin ENTRYPOINT /usr/local/bin/run-tests.sh diff --git a/tests/containerd/Dockerfile b/tests/containerd/Dockerfile index ce967144ab..4960010586 100644 --- a/tests/containerd/Dockerfile +++ b/tests/containerd/Dockerfile @@ -9,7 +9,7 @@ RUN apt-get update \ protobuf-c-compiler libcap-dev libaio-dev \ curl libprotobuf-c-dev libprotobuf-dev socat libseccomp-dev \ pigz lsof make git gcc build-essential pkgconf libtool \ - libsystemd-dev libcap-dev libyajl-dev \ + libsystemd-dev libcap-dev libyajl-dev libnuma-dev \ go-md2man libtool autoconf python3 automake sudo \ && update-alternatives --install /usr/bin/go go /usr/lib/go-1.22/bin/go 0 \ && mkdir -p /root/go/src/github.com/containerd \ diff --git a/tests/cri-o/Dockerfile b/tests/cri-o/Dockerfile index db1cd09c2f..24d84ba3ce 100644 --- a/tests/cri-o/Dockerfile +++ b/tests/cri-o/Dockerfile @@ -6,7 +6,7 @@ ENV PATH=/usr/bin:/usr/sbin:/root/go/bin:/usr/local/bin::/usr/local/sbin RUN dnf install -y awk python git gcc automake autoconf libcap-devel \ systemd-devel yajl-devel libseccomp-devel go-md2man conntrack-tools which \ glibc-static python3-libmount libtool make podman xz nmap-ncat jq bats \ - iproute openssl iputils socat criu-libs irqbalance && \ + iproute openssl iputils socat criu-libs irqbalance numactl-devel && \ dnf install -y awk 'dnf-command(builddep)' && dnf builddep -y podman && \ dnf remove -y golang && \ sudo dnf update -y && \ diff --git a/tests/fuzzing/Dockerfile b/tests/fuzzing/Dockerfile index 21f1203abd..94c45cc590 100644 --- a/tests/fuzzing/Dockerfile +++ b/tests/fuzzing/Dockerfile @@ -1,8 +1,9 @@ FROM fedora:latest RUN dnf install -y awk golang python git automake autoconf libcap-devel \ - systemd-devel yajl-devel libseccomp-devel go-md2man \ - glibc-static python3-libmount libtool make honggfuzz git + systemd-devel yajl-devel libseccomp-devel go-md2man \ + glibc-static python3-libmount libtool make honggfuzz git \ + numactl-devel RUN git clone https://github.com/giuseppe/containers-fuzzing-corpus /testcases diff --git a/tests/oci-validation/Dockerfile b/tests/oci-validation/Dockerfile index 760e0c6251..5b6a1b717e 100644 --- a/tests/oci-validation/Dockerfile +++ b/tests/oci-validation/Dockerfile @@ -5,7 +5,8 @@ ENV PATH=/usr/bin:/usr/sbin:/root/go/bin:/usr/local/bin::/usr/local/sbin RUN dnf install -y awk golang python git gcc automake autoconf libcap-devel \ systemd-devel yajl-devel libseccomp-devel libselinux-devel \ - glibc-static python3-libmount libtool make go-md2man perl-Test2-Harness + glibc-static python3-libmount libtool make go-md2man perl-Test2-Harness \ + numactl-devel COPY run-tests.sh /usr/local/bin diff --git a/tests/podman/Dockerfile b/tests/podman/Dockerfile index 8094b036c0..15b4190d84 100644 --- a/tests/podman/Dockerfile +++ b/tests/podman/Dockerfile @@ -6,7 +6,7 @@ ENV PATH=/usr/bin:/usr/sbin:/root/go/bin:/usr/local/bin::/usr/local/sbin RUN dnf install -y awk golang python git gcc automake autoconf libcap-devel \ systemd-devel yajl-devel libseccomp-devel go-md2man catatonit \ glibc-static python3-libmount libtool make podman xz nmap-ncat procps-ng slirp4netns \ - device-mapper-devel containernetworking-plugins 'dnf-command(builddep)' && \ + device-mapper-devel containernetworking-plugins numactl-devel 'dnf-command(builddep)' && \ dnf builddep -y podman && \ chmod 755 /root && \ git clone --depth=1 https://github.com/containers/podman /root/go/src/github.com/containers/podman && \ diff --git a/tests/test_mempolicy.py b/tests/test_mempolicy.py new file mode 100755 index 0000000000..28c39961a2 --- /dev/null +++ b/tests/test_mempolicy.py @@ -0,0 +1,493 @@ +#!/bin/env python3 +# crun - OCI runtime written in C +# +# Copyright (C) 2017, 2018, 2019 Giuseppe Scrivano +# crun is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with crun. If not, see . + +import subprocess +import sys +import json +import os +from tests_utils import * + +def check_numaif_capabilities(feature: str): + result = subprocess.run(['tests/tests_mempolicy_helper'], capture_output=True, text=True) + return True if feature in result.stdout.splitlines() else False + +def check_numa_hw(): + return subprocess.run(['numactl', '--show'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode + +def check_mempolicy_prerequisites(): + """Check all prerequisites for numa mempolicy tests. Returns 77 (skip) if not met, 0 if OK""" + if check_numa_hw(): + return 77 + +def test_mempolicy_no_conf(): + """Test numa mempolicy without configuration""" + if check_mempolicy_prerequisites(): + return 77 + + conf = base_config() + conf['process']['args'] = ['/init', 'cat', '/proc/self/numa_maps'] + add_all_namespaces(conf) + conf['linux']['memoryPolicy'] = { } + + cid = None + try: + _, cid = run_and_get_output(conf, command='run') + sys.stderr.write("# unexpected success\n") + return -1 + except: + pass + finally: + if cid is not None: + run_crun_command(["delete", "-f", cid]) + + return 0 + +def test_mempolicy_bad_mode(): + """Test numa mempolicy with bad mode""" + if check_mempolicy_prerequisites(): + return 77 + + conf = base_config() + conf['process']['args'] = ['/init', 'cat', '/proc/self/numa_maps'] + add_all_namespaces(conf) + conf['linux']['memoryPolicy'] = { "mode": "BAD_MODE" } + + cid = None + try: + _, cid = run_and_get_output(conf, command='run') + sys.stderr.write("# unexpected success\n") + return -1 + except: + pass + finally: + if cid is not None: + run_crun_command(["delete", "-f", cid]) + + return 0 + +def test_mempolicy_bad_flag(): + """Test numa mempolicy with bad flag""" + if check_mempolicy_prerequisites(): + return 77 + + conf = base_config() + conf['process']['args'] = ['/init', 'cat', '/proc/self/numa_maps'] + add_all_namespaces(conf) + conf['linux']['memoryPolicy'] = { "mode": "MPOL_PREFERRED", "flags": ["BADFLAG"] } + + cid = None + try: + _, cid = run_and_get_output(conf, command='run') + sys.stderr.write("# unexpected success\n") + return -1 + except: + pass + finally: + if cid is not None: + run_crun_command(["delete", "-f", cid]) + + return 0 + +def test_mempolicy_numa_balancing_flag(): + """Test numa mempolicy preferred with numa_balancing flag""" + if check_mempolicy_prerequisites(): + return 77 + + if not check_numaif_capabilities("MPOL_F_NUMA_BALANCING"): + return 77 + + conf = base_config() + conf['process']['args'] = ['/init', 'cat', '/proc/self/numa_maps'] + add_all_namespaces(conf) + conf['linux']['memoryPolicy'] = { "mode": "MPOL_PREFERRED", "flags": ["MPOL_F_NUMA_BALANCING"] } + + cid = None + try: + _, cid = run_and_get_output(conf, command='run') + sys.stderr.write("# unexpected success\n") + return -1 + except: + pass + finally: + if cid is not None: + run_crun_command(["delete", "-f", cid]) + + return 0 + +def test_mempolicy_static_relative_nodes_flags(): + """Test numa mempolicy preferred with numa_balancing flag""" + if check_mempolicy_prerequisites(): + return 77 + + if not check_numaif_capabilities("MPOL_F_RELATIVE_NODES") or not check_numaif_capabilities("MPOL_F_STATIC_NODES"): + return 77 + + conf = base_config() + conf['process']['args'] = ['/init', 'cat', '/proc/self/numa_maps'] + add_all_namespaces(conf) + conf['linux']['memoryPolicy'] = { "mode": "MPOL_PREFERRED", "flags": ["MPOL_F_RELATIVE_NODES", "MPOL_F_STATIC_NODES"] } + + cid = None + try: + _, cid = run_and_get_output(conf, command='run') + sys.stderr.write("# unexpected success\n") + return -1 + except: + pass + finally: + if cid is not None: + run_crun_command(["delete", "-f", cid]) + + return 0 + +def test_mempolicy_no_nodes(): + """Test numa mempolicy without nodes configuration""" + if check_mempolicy_prerequisites(): + return 77 + + conf = base_config() + conf['process']['args'] = ['/init', 'cat', '/proc/self/numa_maps'] + add_all_namespaces(conf) + conf['linux']['memoryPolicy'] = { "mode": "MPOL_PREFERRED" } + + cid = None + try: + _, cid = run_and_get_output(conf, command='run') + sys.stderr.write("# unexpected success\n") + return -1 + except: + pass + finally: + if cid is not None: + run_crun_command(["delete", "-f", cid]) + + return 0 + +def test_mempolicy_bad_nodes_string(): + """Test numa mempolicy without nodes configuration""" + if check_mempolicy_prerequisites(): + return 77 + + conf = base_config() + conf['process']['args'] = ['/init', 'cat', '/proc/self/numa_maps'] + add_all_namespaces(conf) + conf['linux']['memoryPolicy'] = { "mode": "MPOL_PREFERRED", "nodes": "bad" } + + cid = None + try: + _, cid = run_and_get_output(conf, command='run') + sys.stderr.write("# unexpected success\n") + return -1 + except: + pass + finally: + if cid is not None: + run_crun_command(["delete", "-f", cid]) + + return 0 + +def test_mempolicy_bad_nodes_number(): + """Test numa mempolicy without nodes configuration""" + if check_mempolicy_prerequisites(): + return 77 + + conf = base_config() + conf['process']['args'] = ['/init', 'cat', '/proc/self/numa_maps'] + add_all_namespaces(conf) + conf['linux']['memoryPolicy'] = { "mode": "MPOL_PREFERRED", "nodes": "10284838" } + + cid = None + try: + _, cid = run_and_get_output(conf, command='run') + sys.stderr.write("# unexpected success\n") + return -1 + except: + pass + finally: + if cid is not None: + run_crun_command(["delete", "-f", cid]) + + return 0 + +def test_mempolicy_default_mode(): + """Test numa mempolicy default mode""" + if check_mempolicy_prerequisites(): + return 77 + + conf = base_config() + conf['process']['args'] = ['/init', 'cat', '/proc/self/numa_maps'] + add_all_namespaces(conf) + conf['linux']['memoryPolicy'] = { "mode": "MPOL_DEFAULT" } + + cid = None + try: + out, cid = run_and_get_output(conf, command='run') + if " default " not in out.splitlines()[1]: + sys.stderr.write("# Unable to find ' default ' in /proc/self/numa_maps\n") + sys.stderr.write(out) + return -1 + except Exception as e: + sys.stderr.write("# Test failed with exception: %s\n" % str(e)) + return -1 + finally: + if cid is not None: + run_crun_command(["delete", "-f", cid]) + + return 0 + +def test_mempolicy_local_mode(): + """Test numa mempolicy local mode""" + if check_mempolicy_prerequisites(): + return 77 + + conf = base_config() + conf['process']['args'] = ['/init', 'cat', '/proc/self/numa_maps'] + add_all_namespaces(conf) + conf['linux']['memoryPolicy'] = { "mode": "MPOL_LOCAL" } + + cid = None + try: + out, cid = run_and_get_output(conf, command='run') + if " local " not in out.splitlines()[1]: + sys.stderr.write("# Unable to find ' local ' in /proc/self/numa_maps\n") + sys.stderr.write(out) + return -1 + except Exception as e: + sys.stderr.write("# Test failed with exception: %s\n" % str(e)) + return -1 + finally: + if cid is not None: + run_crun_command(["delete", "-f", cid]) + + return 0 + +def test_mempolicy_bind_mode(): + """Test numa mempolicy bind mode""" + if check_mempolicy_prerequisites(): + return 77 + + conf = base_config() + conf['process']['args'] = ['/init', 'cat', '/proc/self/numa_maps'] + add_all_namespaces(conf) + conf['linux']['memoryPolicy'] = { "mode": "MPOL_BIND", "nodes": "0" } + + cid = None + try: + out, cid = run_and_get_output(conf, command='run') + if " bind:0 " not in out.splitlines()[1]: + sys.stderr.write("# Unable to find ' local ' in /proc/self/numa_maps\n") + sys.stderr.write(out) + return -1 + except Exception as e: + sys.stderr.write("# Test failed with exception: %s\n" % str(e)) + return -1 + finally: + if cid is not None: + run_crun_command(["delete", "-f", cid]) + + return 0 + +def test_mempolicy_bind_mode_balancing(): + """Test numa mempolicy bind mode balancing""" + if check_mempolicy_prerequisites(): + return 77 + + if not check_numaif_capabilities("MPOL_F_NUMA_BALANCING"): + return 77 + + conf = base_config() + conf['process']['args'] = ['/init', 'cat', '/proc/self/numa_maps'] + add_all_namespaces(conf) + conf['linux']['memoryPolicy'] = { "mode": "MPOL_BIND", "nodes": "0", "flags": ["MPOL_F_NUMA_BALANCING"]} + + cid = None + try: + out, cid = run_and_get_output(conf, command='run') + if " bind=balancing:0 " not in out.splitlines()[1]: + sys.stderr.write("# Unable to find ' local ' in /proc/self/numa_maps\n") + sys.stderr.write(out) + return -1 + except Exception as e: + sys.stderr.write("# Test failed with exception: %s\n" % str(e)) + return -1 + finally: + if cid is not None: + run_crun_command(["delete", "-f", cid]) + + return 0 + +def test_mempolicy_bind_mode_balancing_relative(): + """Test numa mempolicy bind mode balancing with relative nodes""" + if check_mempolicy_prerequisites(): + return 77 + + if not check_numaif_capabilities("MPOL_F_NUMA_BALANCING") or not check_numaif_capabilities("MPOL_F_RELATIVE_NODES"): + return 77 + + conf = base_config() + conf['process']['args'] = ['/init', 'cat', '/proc/self/numa_maps'] + add_all_namespaces(conf) + conf['linux']['memoryPolicy'] = { "mode": "MPOL_BIND", "nodes": "0", "flags": ["MPOL_F_NUMA_BALANCING", "MPOL_F_RELATIVE_NODES"]} + + cid = None + try: + out, cid = run_and_get_output(conf, command='run') + if " bind=relative|balancing:0 " not in out.splitlines()[1]: + sys.stderr.write("# Unable to find ' local ' in /proc/self/numa_maps\n") + sys.stderr.write(out) + return -1 + except Exception as e: + sys.stderr.write("# Test failed with exception: %s\n" % str(e)) + return -1 + finally: + if cid is not None: + run_crun_command(["delete", "-f", cid]) + + return 0 + +def test_mempolicy_preferred_mode_static(): + """Test numa mempolicy preferred mode with static nodes""" + if check_mempolicy_prerequisites(): + return 77 + + if not check_numaif_capabilities("MPOL_F_STATIC_NODES"): + return 77 + + conf = base_config() + conf['process']['args'] = ['/init', 'cat', '/proc/self/numa_maps'] + add_all_namespaces(conf) + conf['linux']['memoryPolicy'] = { "mode": "MPOL_PREFERRED", "nodes": "0", "flags": ["MPOL_F_STATIC_NODES"]} + + cid = None + try: + out, cid = run_and_get_output(conf, command='run') + if " prefer=static:0 " not in out.splitlines()[1]: + sys.stderr.write("# Unable to find ' local ' in /proc/self/numa_maps\n") + sys.stderr.write(out) + return -1 + except Exception as e: + sys.stderr.write("# Test failed with exception: %s\n" % str(e)) + return -1 + finally: + if cid is not None: + run_crun_command(["delete", "-f", cid]) + + return 0 + +def test_mempolicy_preferred_many_mode_all_nodes(): + """Test numa mempolicy preferred many mode with all nodes""" + if check_mempolicy_prerequisites(): + return 77 + + conf = base_config() + conf['process']['args'] = ['/init', 'cat', '/proc/self/numa_maps'] + add_all_namespaces(conf) + conf['linux']['memoryPolicy'] = { "mode": "MPOL_PREFERRED_MANY", "nodes": "all" } + + cid = None + try: + out, cid = run_and_get_output(conf, command='run') + if " prefer (many):0 " not in out.splitlines()[1]: + sys.stderr.write("# Unable to find ' local ' in /proc/self/numa_maps\n") + sys.stderr.write(out) + return -1 + except Exception as e: + sys.stderr.write("# Test failed with exception: %s\n" % str(e)) + return -1 + finally: + if cid is not None: + run_crun_command(["delete", "-f", cid]) + + return 0 + +def test_mempolicy_interleave_mode(): + """Test numa mempolicy interleave mode""" + if check_mempolicy_prerequisites(): + return 77 + + conf = base_config() + conf['process']['args'] = ['/init', 'cat', '/proc/self/numa_maps'] + add_all_namespaces(conf) + conf['linux']['memoryPolicy'] = { "mode": "MPOL_INTERLEAVE", "nodes": "0" } + + cid = None + try: + out, cid = run_and_get_output(conf, command='run') + if " interleave:0 " not in out.splitlines()[1]: + sys.stderr.write("# Unable to find ' local ' in /proc/self/numa_maps\n") + sys.stderr.write(out) + return -1 + except Exception as e: + sys.stderr.write("# Test failed with exception: %s\n" % str(e)) + return -1 + finally: + if cid is not None: + run_crun_command(["delete", "-f", cid]) + + return 0 + +def test_mempolicy_weighted_interleave_mode(): + """Test numa mempolicy weighted interleave mode""" + if check_mempolicy_prerequisites(): + return 77 + + if not check_numaif_capabilities("MPOL_WEIGHTED_INTERLEAVE"): + return 77 + + conf = base_config() + conf['process']['args'] = ['/init', 'cat', '/proc/self/numa_maps'] + add_all_namespaces(conf) + conf['linux']['memoryPolicy'] = { "mode": "MPOL_WEIGHTED_INTERLEAVE", "nodes": "0" } + + cid = None + try: + out, cid = run_and_get_output(conf, command='run') + if " weighted interleave:0 " not in out.splitlines()[1]: + sys.stderr.write("# Unable to find ' local ' in /proc/self/numa_maps\n") + sys.stderr.write(out) + return -1 + except Exception as e: + sys.stderr.write("# Test failed with exception: %s\n" % str(e)) + return -1 + finally: + if cid is not None: + run_crun_command(["delete", "-f", cid]) + + return 0 + +all_tests = { + "mempolicy-no-conf": test_mempolicy_no_conf, + "mempolicy-bad-mode": test_mempolicy_bad_mode, + "mempolicy-bad-flag": test_mempolicy_bad_flag, + "mempolicy-numa-balancing-flag": test_mempolicy_numa_balancing_flag, + "mempolicy-static-relative-nodes-flags": test_mempolicy_static_relative_nodes_flags, + "mempolicy-no-nodes": test_mempolicy_no_nodes, + "mempolicy-bad-nodes-string": test_mempolicy_bad_nodes_string, + "mempolicy-bad-nodes-number": test_mempolicy_bad_nodes_number, + "mempolicy-default-mode": test_mempolicy_default_mode, + "mempolicy-local-mode": test_mempolicy_local_mode, + "mempolicy-bind-mode": test_mempolicy_bind_mode, + "mempolicy-bind-mode-balancing": test_mempolicy_bind_mode_balancing, + "mempolicy-bind-mode-balancing-relative": test_mempolicy_bind_mode_balancing_relative, + "mempolicy-preferred-mode-static": test_mempolicy_preferred_mode_static, + "mempolicy-preferred-many-mode-all-nodes": test_mempolicy_preferred_many_mode_all_nodes, + "mempolicy-interleave-mode": test_mempolicy_interleave_mode, + "mempolicy-weighted-interleave-mode": test_mempolicy_weighted_interleave_mode, +} + +if __name__ == "__main__": + tests_main(all_tests) diff --git a/tests/tests_mempolicy_helper.c b/tests/tests_mempolicy_helper.c new file mode 100644 index 0000000000..87d34efb61 --- /dev/null +++ b/tests/tests_mempolicy_helper.c @@ -0,0 +1,48 @@ +/* + * crun - OCI runtime written in C + * + * Copyright (C) 2017, 2018, 2019 Giuseppe Scrivano + * 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 . + */ + +#include + +#ifdef HAVE_NUMA +# include +# include +# include "mempolicy_internal.h" + +static void +mpol_print_features (const str2int_map_t *map) +{ + int idx = 0; + + while (map[idx].name != NULL) + { + printf ("%s\n", map[idx].name); + idx++; + } + return; +} +#endif + +int +main () +{ +#ifdef HAVE_NUMA + mpol_print_features (mpol_mode_map); + mpol_print_features (mpol_flag_map); +#endif + return 0; +} diff --git a/tests/wasmedge-build/Dockerfile b/tests/wasmedge-build/Dockerfile index 45349d591f..c4398bfb58 100644 --- a/tests/wasmedge-build/Dockerfile +++ b/tests/wasmedge-build/Dockerfile @@ -5,8 +5,8 @@ ARG WASM_EDGE_VERSION="0.14.0" # Install the deps for building crun RUN dnf update -y && dnf install -y awk make python git gcc automake autoconf libcap-devel \ systemd-devel yajl-devel libseccomp-devel pkg-config diffutils \ - systemd-devel yajl-devel libseccomp-devel pkg-config \ - go-md2man glibc-static python3-libmount libtool buildah podman which + go-md2man glibc-static python3-libmount libtool buildah podman which \ + numactl-devel # Install WasmEdge RUN curl -sSf -o install.sh https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh