158 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Check what features does the kernel support (where the selftest is running).3 * Somewhat inspired by CRIU kerndat/kdat kernel features detector.4 */5#include <pthread.h>6#include "aolib.h"7 8struct kconfig_t {9 int _error; /* negative errno if not supported */10 int (*check_kconfig)(int *error);11};12 13static int has_net_ns(int *err)14{15 if (access("/proc/self/ns/net", F_OK) < 0) {16 *err = errno;17 if (errno == ENOENT)18 return 0;19 test_print("Unable to access /proc/self/ns/net: %m");20 return -errno;21 }22 return *err = errno = 0;23}24 25static int has_veth(int *err)26{27 int orig_netns, ns_a, ns_b;28 29 orig_netns = open_netns();30 ns_a = unshare_open_netns();31 ns_b = unshare_open_netns();32 33 *err = add_veth("check_veth", ns_a, ns_b);34 35 switch_ns(orig_netns);36 close(orig_netns);37 close(ns_a);38 close(ns_b);39 return 0;40}41 42static int has_tcp_ao(int *err)43{44 struct sockaddr_in addr = {45 .sin_family = test_family,46 };47 struct tcp_ao_add tmp = {};48 const char *password = DEFAULT_TEST_PASSWORD;49 int sk, ret = 0;50 51 sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);52 if (sk < 0) {53 test_print("socket(): %m");54 return -errno;55 }56 57 tmp.sndid = 100;58 tmp.rcvid = 100;59 tmp.keylen = strlen(password);60 memcpy(tmp.key, password, strlen(password));61 strcpy(tmp.alg_name, "hmac(sha1)");62 memcpy(&tmp.addr, &addr, sizeof(addr));63 *err = 0;64 if (setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &tmp, sizeof(tmp)) < 0) {65 *err = -errno;66 if (errno != ENOPROTOOPT)67 ret = -errno;68 }69 close(sk);70 return ret;71}72 73static int has_tcp_md5(int *err)74{75 union tcp_addr addr_any = {};76 int sk, ret = 0;77 78 sk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);79 if (sk < 0) {80 test_print("socket(): %m");81 return -errno;82 }83 84 /*85 * Under CONFIG_CRYPTO_FIPS=y it fails with ENOMEM, rather with86 * anything more descriptive. Oh well.87 */88 *err = 0;89 if (test_set_md5(sk, addr_any, 0, -1, DEFAULT_TEST_PASSWORD)) {90 *err = -errno;91 if (errno != ENOPROTOOPT && errno == ENOMEM) {92 test_print("setsockopt(TCP_MD5SIG_EXT): %m");93 ret = -errno;94 }95 }96 close(sk);97 return ret;98}99 100static int has_vrfs(int *err)101{102 int orig_netns, ns_test, ret = 0;103 104 orig_netns = open_netns();105 ns_test = unshare_open_netns();106 107 *err = add_vrf("ksft-check", 55, 101, ns_test);108 if (*err && *err != -EOPNOTSUPP) {109 test_print("Failed to add a VRF: %d", *err);110 ret = *err;111 }112 113 switch_ns(orig_netns);114 close(orig_netns);115 close(ns_test);116 return ret;117}118 119static int has_ftrace(int *err)120{121 *err = test_setup_tracing();122 return 0;123}124 125#define KCONFIG_UNKNOWN 1126static pthread_mutex_t kconfig_lock = PTHREAD_MUTEX_INITIALIZER;127static struct kconfig_t kconfig[__KCONFIG_LAST__] = {128 { KCONFIG_UNKNOWN, has_net_ns },129 { KCONFIG_UNKNOWN, has_veth },130 { KCONFIG_UNKNOWN, has_tcp_ao },131 { KCONFIG_UNKNOWN, has_tcp_md5 },132 { KCONFIG_UNKNOWN, has_vrfs },133 { KCONFIG_UNKNOWN, has_ftrace },134};135 136const char *tests_skip_reason[__KCONFIG_LAST__] = {137 "Tests require network namespaces support (CONFIG_NET_NS)",138 "Tests require veth support (CONFIG_VETH)",139 "Tests require TCP-AO support (CONFIG_TCP_AO)",140 "setsockopt(TCP_MD5SIG_EXT) is not supported (CONFIG_TCP_MD5)",141 "VRFs are not supported (CONFIG_NET_VRF)",142 "Ftrace points are not supported (CONFIG_TRACEPOINTS)",143};144 145bool kernel_config_has(enum test_needs_kconfig k)146{147 bool ret;148 149 pthread_mutex_lock(&kconfig_lock);150 if (kconfig[k]._error == KCONFIG_UNKNOWN) {151 if (kconfig[k].check_kconfig(&kconfig[k]._error))152 test_error("Failed to initialize kconfig %u", k);153 }154 ret = kconfig[k]._error == 0;155 pthread_mutex_unlock(&kconfig_lock);156 return ret;157}158