X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-relayd%2Ftcp_keep_alive.c;fp=src%2Fbin%2Flttng-relayd%2Ftcp_keep_alive.c;h=0000000000000000000000000000000000000000;hp=94bf4ab9332742f42ea3c8e8872f6ea545f253f9;hb=ac497a37018f3c253d2e50397294f58d33f7f24f;hpb=7966af5763c4aaca39df9bbfa9277ff15715c720 diff --git a/src/bin/lttng-relayd/tcp_keep_alive.c b/src/bin/lttng-relayd/tcp_keep_alive.c deleted file mode 100644 index 94bf4ab93..000000000 --- a/src/bin/lttng-relayd/tcp_keep_alive.c +++ /dev/null @@ -1,597 +0,0 @@ -/* - * Copyright (C) 2017 Jonathan Rajotte - * - * SPDX-License-Identifier: GPL-2.0-only - * - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "tcp_keep_alive.h" - -#define SOLARIS_IDLE_TIME_MIN_S 10 -#define SOLARIS_IDLE_TIME_MAX_S 864000 /* 10 days */ -#define SOLARIS_ABORT_THRESHOLD_MIN_S 1 -#define SOLARIS_ABORT_THRESHOLD_MAX_S 480 /* 8 minutes */ - -/* Per-platform definitions of TCP socket options. */ -#if defined (__linux__) - -#define COMPAT_TCP_LEVEL SOL_TCP -#define COMPAT_TCP_ABORT_THRESHOLD 0 /* Does not exist on linux. */ -#define COMPAT_TCP_KEEPIDLE TCP_KEEPIDLE -#define COMPAT_TCP_KEEPINTVL TCP_KEEPINTVL -#define COMPAT_TCP_KEEPCNT TCP_KEEPCNT - -#elif defined (__sun__) /* ! defined (__linux__) */ - -#define COMPAT_TCP_LEVEL IPPROTO_TCP - -#ifdef TCP_KEEPALIVE_THRESHOLD -#define COMPAT_TCP_KEEPIDLE TCP_KEEPALIVE_THRESHOLD -#else /* ! defined (TCP_KEEPALIVE_THRESHOLD) */ -#define COMPAT_TCP_KEEPIDLE 0 -#endif /* TCP_KEEPALIVE_THRESHOLD */ - -#ifdef TCP_KEEPALIVE_ABORT_THRESHOLD -#define COMPAT_TCP_ABORT_THRESHOLD TCP_KEEPALIVE_ABORT_THRESHOLD -#else /* ! defined (TCP_KEEPALIVE_ABORT_THRESHOLD) */ -#define COMPAT_TCP_ABORT_THRESHOLD 0 -#endif /* TCP_KEEPALIVE_ABORT_THRESHOLD */ - -#define COMPAT_TCP_KEEPINTVL 0 /* Does not exist on Solaris. */ -#define COMPAT_TCP_KEEPCNT 0 /* Does not exist on Solaris. */ - -#else /* ! defined (__linux__) && ! defined (__sun__) */ - -#define COMPAT_TCP_LEVEL 0 -#define COMPAT_TCP_ABORT_THRESHOLD 0 -#define COMPAT_TCP_KEEPIDLE 0 -#define COMPAT_TCP_KEEPINTVL 0 -#define COMPAT_TCP_KEEPCNT 0 - -#endif /* ! defined (__linux__) && ! defined (__sun__) */ - -struct tcp_keep_alive_support { - /* TCP keep-alive is supported by this platform. */ - bool supported; - /* Overriding idle-time per socket is supported by this platform. */ - bool idle_time_supported; - /* - * Overriding probe interval per socket is supported by this - * platform. - */ - bool probe_interval_supported; - /* - * Configuring max probe count per socket is supported by this - * platform. - */ - bool max_probe_count_supported; - /* Overriding on a per-socket basis is supported by this platform. */ - bool abort_threshold_supported; -}; - -struct tcp_keep_alive_config { - /* Maps to the LTTNG_RELAYD_TCP_KEEP_ALIVE_ENV environment variable. */ - bool enabled; - /* - * Maps to the LTTNG_RELAYD_TCP_KEEP_ALIVE_IDLE_TIME_ENV environment - * variable. - */ - int idle_time; - /* - * Maps to the LTTNG_RELAYD_TCP_KEEP_ALIVE_PROBE_INTERVAL_ENV - * environment variable. - */ - int probe_interval; - /* - * Maps to the LTTNG_RELAYD_TCP_KEEP_ALIVE_MAX_PROBE_COUNT_ENV - * environment variable. - */ - int max_probe_count; - /* - * Maps to the LTTNG_RELAYD_TCP_KEEP_ALIVE_ABORT_THRESHOLD_ENV - * environment variable. - */ - int abort_threshold; -}; - -static struct tcp_keep_alive_config the_config = {.enabled = false, - .idle_time = -1, - .probe_interval = -1, - .max_probe_count = -1, - .abort_threshold = -1}; - -static struct tcp_keep_alive_support the_support = {.supported = false, - .idle_time_supported = false, - .probe_interval_supported = false, - .max_probe_count_supported = false, - .abort_threshold_supported = false}; - -/* - * Common parser for string to positive int conversion where the value must be - * in range [-1, INT_MAX]. - * - * Returns -2 on invalid value. - */ -static -int get_env_int(const char *env_var, - const char *value) -{ - int ret; - long tmp; - char *endptr = NULL; - - errno = 0; - tmp = strtol(value, &endptr, 0); - if (errno != 0) { - ERR("%s cannot be parsed.", env_var); - PERROR("errno for previous parsing failure"); - ret = -2; - goto end; - } - - if (endptr == value || *endptr != '\0') { - ERR("%s is not a valid number", env_var); - ret = -1; - goto end; - } - - if (tmp < -1) { - ERR("%s must be greater or equal to -1", env_var); - ret = -2; - goto end; - } - if (tmp > INT_MAX){ - ERR("%s is too big. Maximum value is %d", env_var, INT_MAX); - ret = -2; - goto end; - } - - ret = (int) tmp; -end: - return ret; -} - -/* - * Per-platform implementation of tcp_keep_alive_idle_time_modifier. - * Returns -2 on invalid value. - */ -#ifdef __sun__ - -static -int convert_idle_time(int value) -{ - int ret; - unsigned int tmp_ms; - - if (value == -1 || value == 0) { - /* Use system defaults */ - ret = value; - goto end; - } - - if (value < 0) { - ERR("Invalid tcp keep-alive idle time (%i)", value); - ret = -2; - goto end; - } - - /* - * Additional constraints for Solaris 11. - * Minimum 10s, maximum 10 days. Defined by - * https://docs.oracle.com/cd/E23824_01/html/821-1475/tcp-7p.html#REFMAN7tcp-7p - */ - if ((value < SOLARIS_IDLE_TIME_MIN_S || - value > SOLARIS_IDLE_TIME_MAX_S)) { - ERR("%s must be comprised between %d and %d inclusively on Solaris", - DEFAULT_LTTNG_RELAYD_TCP_KEEP_ALIVE_IDLE_TIME_ENV, - SOLARIS_IDLE_TIME_MIN_S, - SOLARIS_IDLE_TIME_MAX_S); - ret = -2; - goto end; - } - - /* On Solaris idle time is given in milliseconds. */ - tmp_ms = ((unsigned int) value) * MSEC_PER_SEC; - if ((value != 0 && (tmp_ms / ((unsigned int) value)) != MSEC_PER_SEC) - || tmp_ms > INT_MAX) { - /* Overflow. */ - const int max_value = INT_MAX / MSEC_PER_SEC; - - ERR("%s is too big: maximum supported value is %d", - DEFAULT_LTTNG_RELAYD_TCP_KEEP_ALIVE_IDLE_TIME_ENV, - max_value); - ret = -2; - goto end; - } - - /* tmp_ms is >= 0 and <= INT_MAX. Cast is safe. */ - ret = (int) tmp_ms; -end: - return ret; -} - -#else /* ! defined(__sun__) */ - -static -int convert_idle_time(int value) -{ - return value; -} - -#endif /* ! defined(__sun__) */ - -/* Per-platform support of tcp_keep_alive functionality. */ -#if defined (__linux__) - -static -void tcp_keep_alive_init_support(struct tcp_keep_alive_support *support) -{ - support->supported = true; - support->idle_time_supported = true; - support->probe_interval_supported = true; - support->max_probe_count_supported = true; - /* Solaris specific */ - support->abort_threshold_supported = false; -} - -#elif defined(__sun__) /* ! defined (__linux__) */ - -static -void tcp_keep_alive_init_support(struct tcp_keep_alive_support *support) -{ - support->supported = true; -#ifdef TCP_KEEPALIVE_THRESHOLD - support->idle_time_supported = true; -#else - support->idle_time_supported = false;; -#endif /* TCP_KEEPALIVE_THRESHOLD */ - - /* - * Solaris does not support either tcp_keepalive_probes or - * tcp_keepalive_intvl. - * Inferring a value for TCP_KEEP_ALIVE_ABORT_THRESHOLD using - * (tcp_keepalive_probes * tcp_keepalive_intvl) could yield a good - * alternative, but Solaris does not detail the algorithm used (such as - * constant time retry like Linux). - * - * Ignore those settings on Solaris 11. We prefer exposing an - * environment variable only used on Solaris for the abort threshold. - */ - support->probe_interval_supported = false; - support->max_probe_count_supported = false; -#ifdef TCP_KEEPALIVE_ABORT_THRESHOLD - support->abort_threshold_supported = true; -#else - support->abort_threshold_supported = false; -#endif /* TCP_KEEPALIVE_THRESHOLD */ -} - -#else /* ! defined(__sun__) && ! defined(__linux__) */ - -/* Assume nothing is supported on other platforms. */ -static -void tcp_keep_alive_init_support(struct tcp_keep_alive_support *support) -{ - support->supported = false; - support->idle_time_supported = false; - support->probe_interval_supported = false; - support->max_probe_count_supported = false; - support->abort_threshold_supported = false; -} - -#endif /* ! defined(__sun__) && ! defined(__linux__) */ - -#ifdef __sun__ - -/* - * Solaris specific modifier for abort threshold. - * Return -2 on error. - */ -static -int convert_abort_threshold(int value) -{ - int ret; - unsigned int tmp_ms; - - if (value == -1) { - /* Use system defaults */ - ret = value; - goto end; - } - - if (value < 0) { - ERR("Invalid tcp keep-alive abort threshold (%i)", value); - ret = -2; - goto end; - } - - /* - * Additional constraints for Solaris 11. - * - * Between 0 and 8 minutes. - * https://docs.oracle.com/cd/E19120-01/open.solaris/819-2724/fsvdh/index.html - * - * Restrict from 1 seconds to 8 minutes sice the 0 value goes against - * the purpose of dead peers detection by never timing out when probing. - * It does NOT mean that the connection times out immediately. - */ - if ((value < SOLARIS_ABORT_THRESHOLD_MIN_S || value > SOLARIS_ABORT_THRESHOLD_MAX_S)) { - ERR("%s must be comprised between %d and %d inclusively on Solaris", - DEFAULT_LTTNG_RELAYD_TCP_KEEP_ALIVE_ABORT_THRESHOLD_ENV, - SOLARIS_ABORT_THRESHOLD_MIN_S, - SOLARIS_ABORT_THRESHOLD_MAX_S); - ret = -2; - goto end; - } - - /* Abort threshold is given in milliseconds. */ - tmp_ms = ((unsigned int) value) * MSEC_PER_SEC; - if ((value != 0 && (tmp_ms / ((unsigned int) value)) != MSEC_PER_SEC) - || tmp_ms > INT_MAX) { - /* Overflow */ - const int max_value = INT_MAX / MSEC_PER_SEC; - - ERR("%s is too big: maximum supported value is %d", - DEFAULT_LTTNG_RELAYD_TCP_KEEP_ALIVE_ABORT_THRESHOLD_ENV, - max_value); - ret = -2; - goto end; - } - - /* tmp_ms is >= 0 and <= INT_MAX. Cast is safe. */ - ret = (int) tmp_ms; -end: - return ret; -} - -#else - -static -int convert_abort_threshold(int value) -{ - return value; -} - -#endif /* defined (__sun__) */ - -/* - * Retrieve settings from environment variables and warn for settings not - * supported by the platform. - */ -static -int tcp_keep_alive_init_config(struct tcp_keep_alive_support *support, - struct tcp_keep_alive_config *config) -{ - int ret; - const char *value; - - value = lttng_secure_getenv(DEFAULT_LTTNG_RELAYD_TCP_KEEP_ALIVE_ENV); - if (!support->supported) { - if (value) { - WARN("Using per-socket TCP keep-alive mechanism is not supported by this platform. Ignoring the %s environment variable.", - DEFAULT_LTTNG_RELAYD_TCP_KEEP_ALIVE_ENV); - } - config->enabled = false; - } else if (value) { - ret = config_parse_value(value); - if (ret < 0 || ret > 1) { - ERR("Invalid value for %s", DEFAULT_LTTNG_RELAYD_TCP_KEEP_ALIVE_ENV); - ret = 1; - goto error; - } - config->enabled = ret; - } - DBG("TCP keep-alive mechanism %s", config->enabled ? "enabled": "disabled"); - - /* Get value for tcp_keepalive_time in seconds. */ - value = lttng_secure_getenv(DEFAULT_LTTNG_RELAYD_TCP_KEEP_ALIVE_IDLE_TIME_ENV); - if (!support->idle_time_supported && value) { - WARN("Overriding the TCP keep-alive idle time threshold per-socket is not supported by this platform. Ignoring the %s environment variable.", - DEFAULT_LTTNG_RELAYD_TCP_KEEP_ALIVE_IDLE_TIME_ENV); - config->idle_time = -1; - } else if (value) { - int idle_time_platform; - int idle_time_seconds; - - idle_time_seconds = get_env_int( - DEFAULT_LTTNG_RELAYD_TCP_KEEP_ALIVE_IDLE_TIME_ENV, - value); - if (idle_time_seconds < -1) { - ret = 1; - goto error; - } - - idle_time_platform = convert_idle_time(idle_time_seconds); - if (idle_time_platform < -1) { - ret = 1; - goto error; - } - - config->idle_time = idle_time_platform; - DBG("Overriding %s to %d", - DEFAULT_LTTNG_RELAYD_TCP_KEEP_ALIVE_IDLE_TIME_ENV, - idle_time_seconds); - } - - /* Get value for tcp_keepalive_intvl in seconds. */ - value = lttng_secure_getenv( - DEFAULT_LTTNG_RELAYD_TCP_KEEP_ALIVE_PROBE_INTERVAL_ENV); - if (!support->probe_interval_supported && value) { - WARN("Overriding the TCP keep-alive probe interval time per-socket is not supported by this platform. Ignoring the %s environment variable.", - DEFAULT_LTTNG_RELAYD_TCP_KEEP_ALIVE_PROBE_INTERVAL_ENV); - config->probe_interval = -1; - } else if (value) { - int probe_interval; - - probe_interval = get_env_int(DEFAULT_LTTNG_RELAYD_TCP_KEEP_ALIVE_PROBE_INTERVAL_ENV, - value); - if (probe_interval < -1) { - ret = 1; - goto error; - } - - config->probe_interval = probe_interval; - DBG("Overriding %s to %d", - DEFAULT_LTTNG_RELAYD_TCP_KEEP_ALIVE_PROBE_INTERVAL_ENV, - config->probe_interval); - } - - /* Get value for tcp_keepalive_probes. */ - value = lttng_secure_getenv(DEFAULT_LTTNG_RELAYD_TCP_KEEP_ALIVE_MAX_PROBE_COUNT_ENV); - if (!support->max_probe_count_supported && value) { - WARN("Overriding the TCP keep-alive maximum probe count per-socket is not supported by this platform. Ignoring the %s environment variable.", - DEFAULT_LTTNG_RELAYD_TCP_KEEP_ALIVE_MAX_PROBE_COUNT_ENV); - config->max_probe_count = -1; - } else if (value) { - int max_probe_count; - - max_probe_count = get_env_int(DEFAULT_LTTNG_RELAYD_TCP_KEEP_ALIVE_MAX_PROBE_COUNT_ENV, - value); - if (max_probe_count < -1) { - ret = 1; - goto error; - } - - config->max_probe_count = max_probe_count; - DBG("Overriding %s to %d", - DEFAULT_LTTNG_RELAYD_TCP_KEEP_ALIVE_MAX_PROBE_COUNT_ENV, - config->max_probe_count); - } - - /* Get value for tcp_keepalive_abort_interval. */ - value = lttng_secure_getenv( - DEFAULT_LTTNG_RELAYD_TCP_KEEP_ALIVE_ABORT_THRESHOLD_ENV); - if (!support->abort_threshold_supported && value) { - WARN("Overriding the TCP keep-alive abort threshold per-socket is not supported by this platform. Ignoring the %s environment variable.", - DEFAULT_LTTNG_RELAYD_TCP_KEEP_ALIVE_ABORT_THRESHOLD_ENV); - config->abort_threshold = -1; - } else if (value) { - int abort_threshold_platform; - int abort_threshold_seconds; - - abort_threshold_seconds = get_env_int( - DEFAULT_LTTNG_RELAYD_TCP_KEEP_ALIVE_MAX_PROBE_COUNT_ENV, - value); - if (abort_threshold_seconds < -1) { - ret = 1; - goto error; - } - - abort_threshold_platform = convert_abort_threshold( - abort_threshold_seconds); - if (abort_threshold_platform < -1) { - ret = 1; - goto error; - } - - config->abort_threshold = abort_threshold_platform; - DBG("Overriding %s to %d", - DEFAULT_LTTNG_RELAYD_TCP_KEEP_ALIVE_ABORT_THRESHOLD_ENV, - config->abort_threshold); - } - - ret = 0; - -error: - return ret; -} - -/* Initialize the TCP keep-alive configuration. */ -__attribute__((constructor)) static -void tcp_keep_alive_init(void) -{ - tcp_keep_alive_init_support(&the_support); - (void) tcp_keep_alive_init_config(&the_support, &the_config); -} - -/* - * Set the socket options regarding TCP keep-alive. - */ -int socket_apply_keep_alive_config(int socket_fd) -{ - int ret; - int val = 1; - - /* TCP keep-alive */ - if (!the_support.supported || !the_config.enabled) { - ret = 0; - goto end; - } - - DBG("TCP keep-alive enabled for socket %d", socket_fd); - ret = setsockopt(socket_fd, SOL_SOCKET, SO_KEEPALIVE, &val, - sizeof(val)); - if (ret < 0) { - PERROR("setsockopt so_keepalive"); - goto end; - } - - /* TCP keep-alive idle time */ - if (the_support.idle_time_supported && the_config.idle_time > 0) { - DBG("TCP keep-alive keep idle: %d enabled for socket %d", - the_config.idle_time, socket_fd); - ret = setsockopt(socket_fd, COMPAT_TCP_LEVEL, - COMPAT_TCP_KEEPIDLE, &the_config.idle_time, - sizeof(the_config.idle_time)); - if (ret < 0) { - PERROR("setsockopt TCP_KEEPIDLE"); - goto end; - } - } - /* TCP keep-alive probe interval */ - if (the_support.probe_interval_supported && - the_config.probe_interval > 0) { - DBG("TCP keep-alive probe_interval: %d enabled for socket %d", - the_config.probe_interval, socket_fd); - ret = setsockopt(socket_fd, COMPAT_TCP_LEVEL, - COMPAT_TCP_KEEPINTVL, - &the_config.probe_interval, - sizeof(the_config.probe_interval)); - if (ret < 0) { - PERROR("setsockopt TCP_KEEPINTVL"); - goto end; - } - } - - /* TCP keep-alive max probe count */ - if (the_support.max_probe_count_supported && - the_config.max_probe_count > 0) { - DBG("TCP keep-alive max_probe: %d enabled for socket %d", - the_config.max_probe_count, socket_fd); - ret = setsockopt(socket_fd, COMPAT_TCP_LEVEL, - COMPAT_TCP_KEEPCNT, &the_config.max_probe_count, - sizeof(the_config.max_probe_count)); - if (ret < 0) { - PERROR("setsockopt TCP_KEEPCNT"); - goto end; - } - } - - /* TCP keep-alive abort threshold */ - if (the_support.abort_threshold_supported && - the_config.abort_threshold > 0) { - DBG("TCP keep-alive abort threshold: %d enabled for socket %d", - the_config.abort_threshold, socket_fd); - ret = setsockopt(socket_fd, COMPAT_TCP_LEVEL, - COMPAT_TCP_ABORT_THRESHOLD, - &the_config.abort_threshold, - sizeof(the_config.max_probe_count)); - if (ret < 0) { - PERROR("setsockopt TCP_KEEPALIVE_ABORT_THRESHOLD"); - goto end; - } - } -end: - return ret; -}