1 // SPDX-License-Identifier: GPL-2.0 2 /* 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 8 struct kconfig_t { 9 int _errno; /* the returned error if not supported */ 10 int (*check_kconfig)(int *error); 11 }; 12 13 static 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 25 static 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 42 static 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 73 static 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 with 86 * 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 100 static 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 119 static pthread_mutex_t kconfig_lock = PTHREAD_MUTEX_INITIALIZER; 120 static struct kconfig_t kconfig[__KCONFIG_LAST__] = { 121 { -1, has_net_ns }, 122 { -1, has_veth }, 123 { -1, has_tcp_ao }, 124 { -1, has_tcp_md5 }, 125 { -1, has_vrfs }, 126 }; 127 128 const char *tests_skip_reason[__KCONFIG_LAST__] = { 129 "Tests require network namespaces support (CONFIG_NET_NS)", 130 "Tests require veth support (CONFIG_VETH)", 131 "Tests require TCP-AO support (CONFIG_TCP_AO)", 132 "setsockopt(TCP_MD5SIG_EXT) is not supported (CONFIG_TCP_MD5)", 133 "VRFs are not supported (CONFIG_NET_VRF)", 134 }; 135 136 bool kernel_config_has(enum test_needs_kconfig k) 137 { 138 bool ret; 139 140 pthread_mutex_lock(&kconfig_lock); 141 if (kconfig[k]._errno == -1) { 142 if (kconfig[k].check_kconfig(&kconfig[k]._errno)) 143 test_error("Failed to initialize kconfig %u", k); 144 } 145 ret = kconfig[k]._errno == 0; 146 pthread_mutex_unlock(&kconfig_lock); 147 return ret; 148 } 149
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.