Commit 9f239f68 authored by Daniel Borkmann's avatar Daniel Borkmann

Merge branch 'bpf-tests-probe-kernel-support'

Stanislav Fomichev says:

====================
If test_maps/test_verifier is running against the kernel which doesn't
have _all_ BPF features enabled, it fails with an error. This patch
series tries to probe kernel support for each failed test and skip
it instead. This lets users run BPF selftests in the not-all-bpf-yes
environments and received correct PASS/NON-PASS result.

See https://www.spinics.net/lists/netdev/msg539331.html for more
context.

The series goes like this:

* patch #1 skips sockmap tests in test_maps.c if BPF_MAP_TYPE_SOCKMAP
  map is not supported (if bpf_create_map fails, we probe the kernel
  for support)
* patch #2 skips verifier tests if test->prog_type is not supported (if
  bpf_verify_program fails, we probe the kernel for support)
* patch #3 skips verifier tests if test fixup map is not supported (if
  create_map fails, we probe the kernel for support)
* next patches fix various small issues that arise from the first four:
  * patch #4 sets "unknown func bpf_trace_printk#6" prog_type to
    BPF_PROG_TYPE_TRACEPOINT so it is correctly skipped in
    CONFIG_BPF_EVENTS=n case
  * patch #5 exposes BPF_PROG_TYPE_CGROUP_{SKB,SOCK,SOCK_ADDR} only when
    CONFIG_CGROUP_BPF=y, this makes verifier correctly skip appropriate
    tests

v3 changes:
* rebased on top of Quentin's series which adds probes to libbpf

v2 changes:
* don't sprinkle "ifdef CONFIG_CGROUP_BPF" all around net/core/filter.c,
  doing it only in the bpf_types.h is enough to disable
  BPF_PROG_TYPE_CGROUP_{SKB,SOCK,SOCK_ADDR} prog types for non-cgroup
  enabled kernels
====================
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
parents 630afc77 befa6181
...@@ -6,9 +6,11 @@ BPF_PROG_TYPE(BPF_PROG_TYPE_SOCKET_FILTER, sk_filter) ...@@ -6,9 +6,11 @@ BPF_PROG_TYPE(BPF_PROG_TYPE_SOCKET_FILTER, sk_filter)
BPF_PROG_TYPE(BPF_PROG_TYPE_SCHED_CLS, tc_cls_act) BPF_PROG_TYPE(BPF_PROG_TYPE_SCHED_CLS, tc_cls_act)
BPF_PROG_TYPE(BPF_PROG_TYPE_SCHED_ACT, tc_cls_act) BPF_PROG_TYPE(BPF_PROG_TYPE_SCHED_ACT, tc_cls_act)
BPF_PROG_TYPE(BPF_PROG_TYPE_XDP, xdp) BPF_PROG_TYPE(BPF_PROG_TYPE_XDP, xdp)
#ifdef CONFIG_CGROUP_BPF
BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_SKB, cg_skb) BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_SKB, cg_skb)
BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_SOCK, cg_sock) BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_SOCK, cg_sock)
BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_SOCK_ADDR, cg_sock_addr) BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_SOCK_ADDR, cg_sock_addr)
#endif
BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_IN, lwt_in) BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_IN, lwt_in)
BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_OUT, lwt_out) BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_OUT, lwt_out)
BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_XMIT, lwt_xmit) BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_XMIT, lwt_xmit)
......
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
#define ENOTSUPP 524 #define ENOTSUPP 524
#endif #endif
static int skips;
static int map_flags; static int map_flags;
#define CHECK(condition, tag, format...) ({ \ #define CHECK(condition, tag, format...) ({ \
...@@ -724,6 +726,15 @@ static void test_sockmap(int tasks, void *data) ...@@ -724,6 +726,15 @@ static void test_sockmap(int tasks, void *data)
sizeof(key), sizeof(value), sizeof(key), sizeof(value),
6, 0); 6, 0);
if (fd < 0) { if (fd < 0) {
if (!bpf_probe_map_type(BPF_MAP_TYPE_SOCKMAP, 0)) {
printf("%s SKIP (unsupported map type BPF_MAP_TYPE_SOCKMAP)\n",
__func__);
skips++;
for (i = 0; i < 6; i++)
close(sfd[i]);
return;
}
printf("Failed to create sockmap %i\n", fd); printf("Failed to create sockmap %i\n", fd);
goto out_sockmap; goto out_sockmap;
} }
...@@ -1701,6 +1712,6 @@ int main(void) ...@@ -1701,6 +1712,6 @@ int main(void)
map_flags = BPF_F_NO_PREALLOC; map_flags = BPF_F_NO_PREALLOC;
run_all_tests(); run_all_tests();
printf("test_maps: OK\n"); printf("test_maps: OK, %d SKIPPED\n", skips);
return 0; return 0;
} }
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <bpf/bpf.h> #include <bpf/bpf.h>
#include <bpf/libbpf.h>
#ifdef HAVE_GENHDR #ifdef HAVE_GENHDR
# include "autoconf.h" # include "autoconf.h"
...@@ -59,6 +60,7 @@ ...@@ -59,6 +60,7 @@
#define UNPRIV_SYSCTL "kernel/unprivileged_bpf_disabled" #define UNPRIV_SYSCTL "kernel/unprivileged_bpf_disabled"
static bool unpriv_disabled = false; static bool unpriv_disabled = false;
static int skips;
struct bpf_test { struct bpf_test {
const char *descr; const char *descr;
...@@ -263,6 +265,16 @@ static int probe_filter_length(const struct bpf_insn *fp) ...@@ -263,6 +265,16 @@ static int probe_filter_length(const struct bpf_insn *fp)
return len + 1; return len + 1;
} }
static bool skip_unsupported_map(enum bpf_map_type map_type)
{
if (!bpf_probe_map_type(map_type, 0)) {
printf("SKIP (unsupported map type %d)\n", map_type);
skips++;
return true;
}
return false;
}
static int create_map(uint32_t type, uint32_t size_key, static int create_map(uint32_t type, uint32_t size_key,
uint32_t size_value, uint32_t max_elem) uint32_t size_value, uint32_t max_elem)
{ {
...@@ -270,8 +282,11 @@ static int create_map(uint32_t type, uint32_t size_key, ...@@ -270,8 +282,11 @@ static int create_map(uint32_t type, uint32_t size_key,
fd = bpf_create_map(type, size_key, size_value, max_elem, fd = bpf_create_map(type, size_key, size_value, max_elem,
type == BPF_MAP_TYPE_HASH ? BPF_F_NO_PREALLOC : 0); type == BPF_MAP_TYPE_HASH ? BPF_F_NO_PREALLOC : 0);
if (fd < 0) if (fd < 0) {
if (skip_unsupported_map(type))
return -1;
printf("Failed to create hash map '%s'!\n", strerror(errno)); printf("Failed to create hash map '%s'!\n", strerror(errno));
}
return fd; return fd;
} }
...@@ -321,6 +336,8 @@ static int create_prog_array(enum bpf_prog_type prog_type, uint32_t max_elem, ...@@ -321,6 +336,8 @@ static int create_prog_array(enum bpf_prog_type prog_type, uint32_t max_elem,
mfd = bpf_create_map(BPF_MAP_TYPE_PROG_ARRAY, sizeof(int), mfd = bpf_create_map(BPF_MAP_TYPE_PROG_ARRAY, sizeof(int),
sizeof(int), max_elem, 0); sizeof(int), max_elem, 0);
if (mfd < 0) { if (mfd < 0) {
if (skip_unsupported_map(BPF_MAP_TYPE_PROG_ARRAY))
return -1;
printf("Failed to create prog array '%s'!\n", strerror(errno)); printf("Failed to create prog array '%s'!\n", strerror(errno));
return -1; return -1;
} }
...@@ -351,15 +368,20 @@ static int create_map_in_map(void) ...@@ -351,15 +368,20 @@ static int create_map_in_map(void)
inner_map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(int), inner_map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(int),
sizeof(int), 1, 0); sizeof(int), 1, 0);
if (inner_map_fd < 0) { if (inner_map_fd < 0) {
if (skip_unsupported_map(BPF_MAP_TYPE_ARRAY))
return -1;
printf("Failed to create array '%s'!\n", strerror(errno)); printf("Failed to create array '%s'!\n", strerror(errno));
return inner_map_fd; return inner_map_fd;
} }
outer_map_fd = bpf_create_map_in_map(BPF_MAP_TYPE_ARRAY_OF_MAPS, NULL, outer_map_fd = bpf_create_map_in_map(BPF_MAP_TYPE_ARRAY_OF_MAPS, NULL,
sizeof(int), inner_map_fd, 1, 0); sizeof(int), inner_map_fd, 1, 0);
if (outer_map_fd < 0) if (outer_map_fd < 0) {
if (skip_unsupported_map(BPF_MAP_TYPE_ARRAY_OF_MAPS))
return -1;
printf("Failed to create array of maps '%s'!\n", printf("Failed to create array of maps '%s'!\n",
strerror(errno)); strerror(errno));
}
close(inner_map_fd); close(inner_map_fd);
...@@ -374,9 +396,12 @@ static int create_cgroup_storage(bool percpu) ...@@ -374,9 +396,12 @@ static int create_cgroup_storage(bool percpu)
fd = bpf_create_map(type, sizeof(struct bpf_cgroup_storage_key), fd = bpf_create_map(type, sizeof(struct bpf_cgroup_storage_key),
TEST_DATA_LEN, 0, 0); TEST_DATA_LEN, 0, 0);
if (fd < 0) if (fd < 0) {
if (skip_unsupported_map(type))
return -1;
printf("Failed to create cgroup storage '%s'!\n", printf("Failed to create cgroup storage '%s'!\n",
strerror(errno)); strerror(errno));
}
return fd; return fd;
} }
...@@ -580,6 +605,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv, ...@@ -580,6 +605,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
int run_errs, run_successes; int run_errs, run_successes;
int map_fds[MAX_NR_MAPS]; int map_fds[MAX_NR_MAPS];
const char *expected_err; const char *expected_err;
int fixup_skips;
__u32 pflags; __u32 pflags;
int i, err; int i, err;
...@@ -588,7 +614,13 @@ static void do_test_single(struct bpf_test *test, bool unpriv, ...@@ -588,7 +614,13 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
if (!prog_type) if (!prog_type)
prog_type = BPF_PROG_TYPE_SOCKET_FILTER; prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
fixup_skips = skips;
do_test_fixup(test, prog_type, prog, map_fds); do_test_fixup(test, prog_type, prog, map_fds);
/* If there were some map skips during fixup due to missing bpf
* features, skip this test.
*/
if (fixup_skips != skips)
return;
prog_len = probe_filter_length(prog); prog_len = probe_filter_length(prog);
pflags = 0; pflags = 0;
...@@ -598,6 +630,11 @@ static void do_test_single(struct bpf_test *test, bool unpriv, ...@@ -598,6 +630,11 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
pflags |= BPF_F_ANY_ALIGNMENT; pflags |= BPF_F_ANY_ALIGNMENT;
fd_prog = bpf_verify_program(prog_type, prog, prog_len, pflags, fd_prog = bpf_verify_program(prog_type, prog, prog_len, pflags,
"GPL", 0, bpf_vlog, sizeof(bpf_vlog), 1); "GPL", 0, bpf_vlog, sizeof(bpf_vlog), 1);
if (fd_prog < 0 && !bpf_probe_prog_type(prog_type, 0)) {
printf("SKIP (unsupported program type %d)\n", prog_type);
skips++;
goto close_fds;
}
expected_ret = unpriv && test->result_unpriv != UNDEF ? expected_ret = unpriv && test->result_unpriv != UNDEF ?
test->result_unpriv : test->result; test->result_unpriv : test->result;
...@@ -751,7 +788,7 @@ static bool test_as_unpriv(struct bpf_test *test) ...@@ -751,7 +788,7 @@ static bool test_as_unpriv(struct bpf_test *test)
static int do_test(bool unpriv, unsigned int from, unsigned int to) static int do_test(bool unpriv, unsigned int from, unsigned int to)
{ {
int i, passes = 0, errors = 0, skips = 0; int i, passes = 0, errors = 0;
for (i = from; i < to; i++) { for (i = from; i < to; i++) {
struct bpf_test *test = &tests[i]; struct bpf_test *test = &tests[i];
......
...@@ -76,6 +76,7 @@ ...@@ -76,6 +76,7 @@
.errstr_unpriv = "unknown func bpf_trace_printk#6", .errstr_unpriv = "unknown func bpf_trace_printk#6",
.result_unpriv = REJECT, .result_unpriv = REJECT,
.result = ACCEPT, .result = ACCEPT,
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
}, },
{ {
"unpriv: pass pointer to helper function", "unpriv: pass pointer to helper function",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment