Skip to content

Commit

Permalink
Merge branch 'bpf-tests-probe-kernel-support'
Browse files Browse the repository at this point in the history
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: Daniel Borkmann <daniel@iogearbox.net>
  • Loading branch information
Daniel Borkmann committed Jan 31, 2019
2 parents 630afc7 + befa618 commit 9f239f6
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 5 deletions.
2 changes: 2 additions & 0 deletions include/linux/bpf_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_ACT, tc_cls_act)
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_SOCK, cg_sock)
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_OUT, lwt_out)
BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_XMIT, lwt_xmit)
Expand Down
13 changes: 12 additions & 1 deletion tools/testing/selftests/bpf/test_maps.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
#define ENOTSUPP 524
#endif

static int skips;

static int map_flags;

#define CHECK(condition, tag, format...) ({ \
Expand Down Expand Up @@ -724,6 +726,15 @@ static void test_sockmap(int tasks, void *data)
sizeof(key), sizeof(value),
6, 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);
goto out_sockmap;
}
Expand Down Expand Up @@ -1701,6 +1712,6 @@ int main(void)
map_flags = BPF_F_NO_PREALLOC;
run_all_tests();

printf("test_maps: OK\n");
printf("test_maps: OK, %d SKIPPED\n", skips);
return 0;
}
45 changes: 41 additions & 4 deletions tools/testing/selftests/bpf/test_verifier.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <linux/if_ether.h>

#include <bpf/bpf.h>
#include <bpf/libbpf.h>

#ifdef HAVE_GENHDR
# include "autoconf.h"
Expand All @@ -59,6 +60,7 @@

#define UNPRIV_SYSCTL "kernel/unprivileged_bpf_disabled"
static bool unpriv_disabled = false;
static int skips;

struct bpf_test {
const char *descr;
Expand Down Expand Up @@ -263,15 +265,28 @@ static int probe_filter_length(const struct bpf_insn *fp)
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,
uint32_t size_value, uint32_t max_elem)
{
int fd;

fd = bpf_create_map(type, size_key, size_value, max_elem,
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));
}

return fd;
}
Expand Down Expand Up @@ -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),
sizeof(int), max_elem, 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));
return -1;
}
Expand Down Expand Up @@ -351,15 +368,20 @@ static int create_map_in_map(void)
inner_map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(int),
sizeof(int), 1, 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));
return inner_map_fd;
}

outer_map_fd = bpf_create_map_in_map(BPF_MAP_TYPE_ARRAY_OF_MAPS, NULL,
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",
strerror(errno));
}

close(inner_map_fd);

Expand All @@ -374,9 +396,12 @@ static int create_cgroup_storage(bool percpu)

fd = bpf_create_map(type, sizeof(struct bpf_cgroup_storage_key),
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",
strerror(errno));
}

return fd;
}
Expand Down Expand Up @@ -580,6 +605,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
int run_errs, run_successes;
int map_fds[MAX_NR_MAPS];
const char *expected_err;
int fixup_skips;
__u32 pflags;
int i, err;

Expand All @@ -588,7 +614,13 @@ static void do_test_single(struct bpf_test *test, bool unpriv,

if (!prog_type)
prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
fixup_skips = skips;
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);

pflags = 0;
Expand All @@ -598,6 +630,11 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
pflags |= BPF_F_ANY_ALIGNMENT;
fd_prog = bpf_verify_program(prog_type, prog, prog_len, pflags,
"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 ?
test->result_unpriv : test->result;
Expand Down Expand Up @@ -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)
{
int i, passes = 0, errors = 0, skips = 0;
int i, passes = 0, errors = 0;

for (i = from; i < to; i++) {
struct bpf_test *test = &tests[i];
Expand Down
1 change: 1 addition & 0 deletions tools/testing/selftests/bpf/verifier/unpriv.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
.errstr_unpriv = "unknown func bpf_trace_printk#6",
.result_unpriv = REJECT,
.result = ACCEPT,
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
},
{
"unpriv: pass pointer to helper function",
Expand Down

0 comments on commit 9f239f6

Please sign in to comment.