From b105a82889526e8b7598e13db749388f5a801cc6 Mon Sep 17 00:00:00 2001 From: Sonajeya31 <155615090+Sonajeya31@users.noreply.github.com> Date: Wed, 18 Feb 2026 15:16:09 +0530 Subject: [PATCH 1/5] Update basic_sanity_tests.py --- .../test_runner/basic_sanity_tests.py | 43 ++++++++++--------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/tests/L2_testing/test_runner/basic_sanity_tests.py b/tests/L2_testing/test_runner/basic_sanity_tests.py index f98e60fe9..58acf3cec 100755 --- a/tests/L2_testing/test_runner/basic_sanity_tests.py +++ b/tests/L2_testing/test_runner/basic_sanity_tests.py @@ -85,42 +85,43 @@ def execute_test(): return test_utils.count_print_results(output_table) -# we need to do this asynchronous as if there is no such string we would end in endless loop -def read_asynchronous(proc, string_to_find, timeout): - """Reads asynchronous from process. Ends when found string or timeout occurred. +# Module-level function for multiprocessing compatibility (must be picklable) +def _wait_for_string(proc, string_to_find): + """Waits indefinitely until string is found in process. Must be run with timeout multiprocess. Parameters: proc (process): process in which we want to read string_to_find (string): what we want to find in process - timeout (float): how long we should wait if string not found (seconds) Returns: - found (bool): True if found string_to_find inside proc. + None: Returns nothing if found, never ends if not found """ - # as this function should not be used outside asynchronous read, it is moved inside it - def wait_for_string(proc, string_to_find): - """Waits indefinitely until string is found in process. Must be run with timeout multiprocess. + while True: + # notice that all data are in stderr not in stdout, this is DobbyDaemon design + output = proc.stderr.readline() + if string_to_find in output: + test_utils.print_log("Found string \"%s\"" % string_to_find, test_utils.Severity.debug) + return + - Parameters: - proc (process): process in which we want to read - string_to_find (string): what we want to find in process +# we need to do this asynchronous as if there is no such string we would end in endless loop +def read_asynchronous(proc, string_to_find, timeout): + """Reads asynchronous from process. Ends when found string or timeout occurred. - Returns: - None: Returns nothing if found, never ends if not found + Parameters: + proc (process): process in which we want to read + string_to_find (string): what we want to find in process + timeout (float): how long we should wait if string not found (seconds) - """ + Returns: + found (bool): True if found string_to_find inside proc. - while True: - # notice that all data are in stderr not in stdout, this is DobbyDaemon design - output = proc.stderr.readline() - if string_to_find in output: - test_utils.print_log("Found string \"%s\"" % string_to_find, test_utils.Severity.debug) - return + """ found = False - reader = multiprocessing.Process(target=wait_for_string, args=(proc, string_to_find), kwargs={}) + reader = multiprocessing.Process(target=_wait_for_string, args=(proc, string_to_find), kwargs={}) test_utils.print_log("Starting multithread read", test_utils.Severity.debug) reader.start() reader.join(timeout) From c6f64f9ffa19f5f0732362e063a5914d78c8745b Mon Sep 17 00:00:00 2001 From: Sonajeya31 <155615090+Sonajeya31@users.noreply.github.com> Date: Wed, 18 Feb 2026 15:29:35 +0530 Subject: [PATCH 2/5] Update basic_sanity_tests.py --- tests/L2_testing/test_runner/basic_sanity_tests.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/L2_testing/test_runner/basic_sanity_tests.py b/tests/L2_testing/test_runner/basic_sanity_tests.py index 58acf3cec..ced5d3bd3 100755 --- a/tests/L2_testing/test_runner/basic_sanity_tests.py +++ b/tests/L2_testing/test_runner/basic_sanity_tests.py @@ -19,7 +19,7 @@ from subprocess import check_output import subprocess from time import sleep -import multiprocessing +import threading from os.path import basename tests = ( @@ -121,14 +121,14 @@ def read_asynchronous(proc, string_to_find, timeout): """ found = False - reader = multiprocessing.Process(target=_wait_for_string, args=(proc, string_to_find), kwargs={}) + reader = threading.Thread(target=_wait_for_string, args=(proc, string_to_find)) test_utils.print_log("Starting multithread read", test_utils.Severity.debug) reader.start() reader.join(timeout) # if thread still running if reader.is_alive(): test_utils.print_log("Reader still exists, closing", test_utils.Severity.debug) - reader.terminate() + # Note: threads cannot be forcefully terminated, but the main process will continue test_utils.print_log("Not found string \"%s\"" % string_to_find, test_utils.Severity.error) else: found = True From c9824951b9fad749547ffff52a42de455dbf3090 Mon Sep 17 00:00:00 2001 From: Sonajeya31 <155615090+Sonajeya31@users.noreply.github.com> Date: Wed, 18 Feb 2026 16:01:51 +0530 Subject: [PATCH 3/5] Update DobbySpecConfig.cpp --- bundle/lib/source/DobbySpecConfig.cpp | 56 +++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/bundle/lib/source/DobbySpecConfig.cpp b/bundle/lib/source/DobbySpecConfig.cpp index 326d428a3..648e995e6 100644 --- a/bundle/lib/source/DobbySpecConfig.cpp +++ b/bundle/lib/source/DobbySpecConfig.cpp @@ -31,10 +31,12 @@ #include #include #include +#include #include #include #include #include +#include #include // Compile time generated strings that (in theory) speeds up the processing @@ -63,6 +65,8 @@ static const ctemplate::StaticTemplateString USERNS_DISABLED = static const ctemplate::StaticTemplateString MEM_LIMIT = STS_INIT(MEM_LIMIT, "MEM_LIMIT"); +static const ctemplate::StaticTemplateString SWAPPINESS_ENABLED = + STS_INIT(SWAPPINESS_ENABLED, "SWAPPINESS_ENABLED"); static const ctemplate::StaticTemplateString CPU_SHARES_ENABLED = STS_INIT(CPU_SHARES_ENABLED, "CPU_SHARES_ENABLED"); static const ctemplate::StaticTemplateString CPU_SHARES_VALUE = @@ -190,6 +194,53 @@ static const ctemplate::StaticTemplateString SECCOMP_SYSCALLS = int DobbySpecConfig::mNumCores = -1; + +// ----------------------------------------------------------------------------- +/** + * @brief Detects whether the system is using cgroup v2 (unified hierarchy). + * + * This checks if /sys/fs/cgroup is mounted as cgroup2 filesystem. + * On cgroupv2, memory.swappiness is not supported in OCI config. + * + * @return true if running on cgroupv2, false otherwise (cgroupv1 or hybrid) + */ +static bool isCgroupV2() +{ + static bool checked = false; + static bool isV2 = false; + + if (!checked) + { + checked = true; + + // Check if /sys/fs/cgroup is mounted as cgroup2 + FILE* procMounts = setmntent("/proc/mounts", "r"); + if (procMounts != nullptr) + { + struct mntent mntBuf; + struct mntent* mnt; + char buf[PATH_MAX + 256]; + + while ((mnt = getmntent_r(procMounts, &mntBuf, buf, sizeof(buf))) != nullptr) + { + if (mnt->mnt_dir && strcmp(mnt->mnt_dir, "/sys/fs/cgroup") == 0) + { + if (mnt->mnt_type && strcmp(mnt->mnt_type, "cgroup2") == 0) + { + AI_LOG_INFO("detected cgroup v2 (unified hierarchy)"); + isV2 = true; + } + break; + } + } + endmntent(procMounts); + } + } + + return isV2; +} + + // TODO: should we only allowed these if a network namespace is enabled ? const std::map DobbySpecConfig::mAllowedCaps = { @@ -1274,6 +1325,11 @@ bool DobbySpecConfig::processMemLimit(const Json::Value& value, } dictionary->SetIntValue(MEM_LIMIT, memLimit); + // Only enable swappiness on cgroupv1 - cgroupv2 doesn't support this in OCI config + if (!isCgroupV2()) + { + dictionary->ShowSection(SWAPPINESS_ENABLED); + } return true; } From c00e1c79cf90530c8d395d3bf40e6ed15682a0c1 Mon Sep 17 00:00:00 2001 From: Sonajeya31 <155615090+Sonajeya31@users.noreply.github.com> Date: Wed, 18 Feb 2026 16:03:15 +0530 Subject: [PATCH 4/5] Update OciConfigJson1.0.2-dobby.template --- bundle/lib/source/templates/OciConfigJson1.0.2-dobby.template | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bundle/lib/source/templates/OciConfigJson1.0.2-dobby.template b/bundle/lib/source/templates/OciConfigJson1.0.2-dobby.template index 6cbdabd43..58a5278b2 100644 --- a/bundle/lib/source/templates/OciConfigJson1.0.2-dobby.template +++ b/bundle/lib/source/templates/OciConfigJson1.0.2-dobby.template @@ -328,8 +328,8 @@ static const char* ociJsonTemplate = R"JSON( ], "memory": { "limit": {{MEM_LIMIT}}, - "swap": {{MEM_LIMIT}}, - "swappiness": 60 + "swap": {{MEM_LIMIT}}{{#SWAPPINESS_ENABLED}}, + "swappiness": 60{{/SWAPPINESS_ENABLED}} }, "cpu": { {{#CPU_SHARES_ENABLED}} From 2f480f8103e6f0b4fdc7f0b9a112b47f25b73030 Mon Sep 17 00:00:00 2001 From: Sonajeya31 <155615090+Sonajeya31@users.noreply.github.com> Date: Wed, 18 Feb 2026 16:04:02 +0530 Subject: [PATCH 5/5] Update OciConfigJsonVM1.0.2-dobby.template --- .../lib/source/templates/OciConfigJsonVM1.0.2-dobby.template | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bundle/lib/source/templates/OciConfigJsonVM1.0.2-dobby.template b/bundle/lib/source/templates/OciConfigJsonVM1.0.2-dobby.template index 21fe91d38..420c98895 100644 --- a/bundle/lib/source/templates/OciConfigJsonVM1.0.2-dobby.template +++ b/bundle/lib/source/templates/OciConfigJsonVM1.0.2-dobby.template @@ -339,8 +339,8 @@ static const char* ociJsonTemplate = R"JSON( ], "memory": { "limit": {{MEM_LIMIT}}, - "swap": {{MEM_LIMIT}}, - "swappiness": 60 + "swap": {{MEM_LIMIT}}{{#SWAPPINESS_ENABLED}}, + "swappiness": 60{{/SWAPPINESS_ENABLED}} }, "cpu": { {{#CPU_SHARES_ENABLED}}