From 99984fbccdfb5a84d06b71a3720d7b04cea3ab95 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 10 Jul 2025 15:37:02 +0200 Subject: [PATCH] Add configurable CPU count option for containerized environments (#1717) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds a new `--cpus` configuration option to address CPU detection issues in virtualized and containerized environments where `_SC_NPROCESSORS_CONF` and `_SC_NPROCESSORS_ONLN` return host CPU counts instead of allocated container CPUs. ## Problem In containerized deployments, coturn detects the host's CPU count (e.g., 128 CPUs) instead of the container's allocated CPUs (e.g., 2 CPUs). This causes the server to create excessive relay threads and database connections, leading to resource exhaustion and performance issues. ## Solution Added a new `cpus` configuration option that allows manual override of CPU detection: ### Command Line Usage ```bash turnserver --cpus 2 ``` ### Configuration File Usage ```ini # Override system CPU count detection for containers cpus=2 ``` ## Key Features - **Backward Compatible**: No changes needed for existing deployments - **Input Validation**: Values must be between 1 and 128 with proper error handling - **Comprehensive Documentation**: Updated man pages and example config files - **Both Interfaces**: Works via command line and configuration file ## Testing The implementation has been thoroughly tested: ```bash # Container with 2 allocated CPUs on 128-CPU host $ turnserver --cpus 2 INFO: System cpu num is 128 # Host detection INFO: System enable num is 128 # Host detection INFO: Configured cpu num is 2 # Override applied INFO: Total General servers: 2 # Correct thread count ``` - ✅ Command line option: `--cpus 8` creates 8 relay servers - ✅ Config file option: `cpus=6` creates 6 relay servers - ✅ Error handling: Invalid values show appropriate errors - ✅ Default behavior: Without option, uses system detection - ✅ RFC5769 tests: All protocol tests still pass ## Files Modified - `src/apps/relay/mainrelay.c` - Core implementation - `src/apps/relay/mainrelay.h` - Added configuration flag - `examples/etc/turnserver.conf` - Added documentation and example - `man/man1/turnserver.1` - Updated man page This change directly addresses the resource consumption issues in containerized environments while maintaining full backward compatibility. Fixes #1628. --- examples/etc/turnserver.conf | 8 +++++ man/man1/turnserver.1 | 8 +++++ src/apps/relay/mainrelay.c | 60 +++++++++++++++++++++++++----------- src/apps/relay/mainrelay.h | 1 + 4 files changed, 59 insertions(+), 18 deletions(-) diff --git a/examples/etc/turnserver.conf b/examples/etc/turnserver.conf index 0e9258f..60f3d87 100644 --- a/examples/etc/turnserver.conf +++ b/examples/etc/turnserver.conf @@ -164,6 +164,14 @@ # #relay-threads=0 +# Override system CPU count detection. Use this number instead of the +# auto-detected CPU count. Useful in virtualized/containerized environments +# where the system reports the host CPU count instead of the allocated +# container CPUs. This affects the default number of relay threads when +# relay-threads is not explicitly specified. +# +#cpus=2 + # Lower and upper bounds of the UDP relay endpoints: # (default values are 49152 and 65535) # diff --git a/man/man1/turnserver.1 b/man/man1/turnserver.1 index d890169..8de55ab 100644 --- a/man/man1/turnserver.1 +++ b/man/man1/turnserver.1 @@ -591,6 +591,14 @@ will be employed (OS\-dependent). In the older Linux systems per network listening endpoint \- unless "\fB\-m\fP 0" or "\fB\-m\fP 1" is set. .TP .B +\fB\-\-cpus\fP +Override system CPU count detection. Use this number instead of the +auto\-detected CPU count. Useful in virtualized/containerized environments +where the system reports the host CPU count instead of the allocated +container CPUs. This affects the default number of relay threads when +\fB\-\-relay\-threads\fP is not explicitly specified. +.TP +.B \fB\-\-min\-port\fP Lower bound of the UDP port range for relay endpoints allocation. diff --git a/src/apps/relay/mainrelay.c b/src/apps/relay/mainrelay.c index e084c85..efe6a18 100644 --- a/src/apps/relay/mainrelay.c +++ b/src/apps/relay/mainrelay.c @@ -225,6 +225,7 @@ turn_params_t turn_params = { ///////////// CPUs ////////////////// DEFAULT_CPUS_NUMBER, + false, /* cpus_configured */ ///////// Encryption ///////// "", /* secret_key_file */ @@ -1024,6 +1025,11 @@ static char Usage[] = " In older systems (pre-Linux 3.9) the number of UDP relay threads " "always equals\n" " the number of listening endpoints (unless -m 0 is set).\n" + " --cpus Override system CPU count detection. Use this number\n" + " instead of the auto-detected CPU count.\n" + " Useful in virtualized/containerized environments where\n" + " the system reports the host CPU count instead of\n" + " the allocated container CPUs.\n" " --min-port Lower bound of the UDP port range for relay endpoints " "allocation.\n" " Default value is 49152, according to RFC 5766.\n" @@ -1506,7 +1512,8 @@ enum EXTRA_OPTS { STUN_BACKWARD_COMPATIBILITY_OPT, RESPONSE_ORIGIN_ONLY_WITH_RFC5780_OPT, RESPOND_HTTP_UNSUPPORTED_OPT, - VERSION_OPT + VERSION_OPT, + CPUS_OPT }; struct myoption { @@ -1652,6 +1659,7 @@ static const struct myoption long_options[] = { {"respond-http-unsupported", optional_argument, NULL, RESPOND_HTTP_UNSUPPORTED_OPT}, {"version", optional_argument, NULL, VERSION_OPT}, {"syslog-facility", required_argument, NULL, SYSLOG_FACILITY_OPT}, + {"cpus", required_argument, NULL, CPUS_OPT}, {NULL, no_argument, NULL, 0}}; static const struct myoption admin_long_options[] = { @@ -2367,6 +2375,20 @@ static void set_option(int c, char *value) { case RESPOND_HTTP_UNSUPPORTED_OPT: turn_params.respond_http_unsupported = get_bool_value(value); break; + case CPUS_OPT: { + int cpus = atoi(value); + if (cpus < 1) { + TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "ERROR: cpus value must be positive\n"); + } else if (cpus > MAX_NUMBER_OF_GENERAL_RELAY_SERVERS) { + TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "WARNING: max number of cpus is %d.\n", + MAX_NUMBER_OF_GENERAL_RELAY_SERVERS); + turn_params.cpus = MAX_NUMBER_OF_GENERAL_RELAY_SERVERS; + turn_params.cpus_configured = true; + } else { + turn_params.cpus = (unsigned long)cpus; + turn_params.cpus_configured = true; + } + } break; /* these options have been already taken care of before: */ case 'l': @@ -3034,23 +3056,6 @@ int main(int argc, char **argv) { // Zero pass apply the log options. read_config_file(argc, argv, 0); - { - unsigned long cpus = get_system_active_number_of_cpus(); - if (cpus > 0) { - turn_params.cpus = cpus; - } - if (turn_params.cpus < DEFAULT_CPUS_NUMBER) { - turn_params.cpus = DEFAULT_CPUS_NUMBER; - } else if (turn_params.cpus > MAX_NUMBER_OF_GENERAL_RELAY_SERVERS) { - turn_params.cpus = MAX_NUMBER_OF_GENERAL_RELAY_SERVERS; - } - - turn_params.general_relay_servers_number = (turnserver_id)turn_params.cpus; - - TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "System cpu num is %lu\n", get_system_number_of_cpus()); - TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "System enable num is %lu\n", get_system_active_number_of_cpus()); - } - // First pass read other config options read_config_file(argc, argv, 1); @@ -3063,6 +3068,25 @@ int main(int argc, char **argv) { } } + // CPU detection and configuration + if (!turn_params.cpus_configured) { + unsigned long cpus = get_system_active_number_of_cpus(); + if (cpus > 0) { + turn_params.cpus = cpus; + } + } + if (turn_params.cpus < DEFAULT_CPUS_NUMBER) { + turn_params.cpus = DEFAULT_CPUS_NUMBER; + } else if (turn_params.cpus > MAX_NUMBER_OF_GENERAL_RELAY_SERVERS) { + turn_params.cpus = MAX_NUMBER_OF_GENERAL_RELAY_SERVERS; + } + + turn_params.general_relay_servers_number = (turnserver_id)turn_params.cpus; + + TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "System cpu num is %lu\n", get_system_number_of_cpus()); + TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "System enable num is %lu\n", get_system_active_number_of_cpus()); + TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Configured cpu num is %lu\n", turn_params.cpus); + // Second pass read -u options read_config_file(argc, argv, 2); diff --git a/src/apps/relay/mainrelay.h b/src/apps/relay/mainrelay.h index 35a0f22..96cf4be 100644 --- a/src/apps/relay/mainrelay.h +++ b/src/apps/relay/mainrelay.h @@ -334,6 +334,7 @@ typedef struct _turn_params_ { /////// CPUs ////////////// unsigned long cpus; + bool cpus_configured; ///////// Encryption ///////// char secret_key_file[1025];