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.
9 int _error
; /* negative errno if not supported */
10 int (*check_kconfig
)(int *error
);
13 static int has_net_ns(int *err
)
15 if (access("/proc/self/ns/net", F_OK
) < 0) {
19 test_print("Unable to access /proc/self/ns/net: %m");
22 return *err
= errno
= 0;
25 static int has_veth(int *err
)
27 int orig_netns
, ns_a
, ns_b
;
29 orig_netns
= open_netns();
30 ns_a
= unshare_open_netns();
31 ns_b
= unshare_open_netns();
33 *err
= add_veth("check_veth", ns_a
, ns_b
);
35 switch_ns(orig_netns
);
42 static int has_tcp_ao(int *err
)
44 struct sockaddr_in addr
= {
45 .sin_family
= test_family
,
47 struct tcp_ao_add tmp
= {};
48 const char *password
= DEFAULT_TEST_PASSWORD
;
51 sk
= socket(test_family
, SOCK_STREAM
, IPPROTO_TCP
);
53 test_print("socket(): %m");
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
));
64 if (setsockopt(sk
, IPPROTO_TCP
, TCP_AO_ADD_KEY
, &tmp
, sizeof(tmp
)) < 0) {
66 if (errno
!= ENOPROTOOPT
)
73 static int has_tcp_md5(int *err
)
75 union tcp_addr addr_any
= {};
78 sk
= socket(AF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
80 test_print("socket(): %m");
85 * Under CONFIG_CRYPTO_FIPS=y it fails with ENOMEM, rather with
86 * anything more descriptive. Oh well.
89 if (test_set_md5(sk
, addr_any
, 0, -1, DEFAULT_TEST_PASSWORD
)) {
91 if (errno
!= ENOPROTOOPT
&& errno
== ENOMEM
) {
92 test_print("setsockopt(TCP_MD5SIG_EXT): %m");
100 static int has_vrfs(int *err
)
102 int orig_netns
, ns_test
, ret
= 0;
104 orig_netns
= open_netns();
105 ns_test
= unshare_open_netns();
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
);
113 switch_ns(orig_netns
);
119 static int has_ftrace(int *err
)
121 *err
= test_setup_tracing();
125 #define KCONFIG_UNKNOWN 1
126 static pthread_mutex_t kconfig_lock
= PTHREAD_MUTEX_INITIALIZER
;
127 static 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
},
136 const 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)",
145 bool kernel_config_has(enum test_needs_kconfig k
)
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
);
154 ret
= kconfig
[k
]._error
== 0;
155 pthread_mutex_unlock(&kconfig_lock
);