selftests/bpf: Add test verifying bpf_ringbuf_reserve retval use in map ops

Add a test_ringbuf_map_key test prog, borrowing heavily from extant
test_ringbuf.c. The program tries to use the result of
bpf_ringbuf_reserve as map_key, which was not possible before previouis
commits in this series. The test runner added to prog_tests/ringbuf.c
verifies that the program loads and does basic sanity checks to confirm
that it runs as expected.

Also, refactor test_ringbuf such that runners for existing test_ringbuf
and newly-added test_ringbuf_map_key are subtests of 'ringbuf' top-level
test.

Signed-off-by: Dave Marchevsky <davemarchevsky@fb.com>
Acked-by: Yonghong Song <yhs@fb.com>
Acked-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/r/20221020160721.4030492-3-davemarchevsky@fb.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Dave Marchevsky 2022-10-20 09:07:20 -07:00 committed by Alexei Starovoitov
parent d167330409
commit 51ee71d38d
3 changed files with 140 additions and 4 deletions

View File

@ -359,9 +359,11 @@ LINKED_SKELS := test_static_linked.skel.h linked_funcs.skel.h \
test_subskeleton.skel.h test_subskeleton_lib.skel.h \
test_usdt.skel.h
LSKELS := fentry_test.c fexit_test.c fexit_sleep.c \
test_ringbuf.c atomics.c trace_printk.c trace_vprintk.c \
map_ptr_kern.c core_kern.c core_kern_overflow.c
LSKELS := fentry_test.c fexit_test.c fexit_sleep.c atomics.c \
trace_printk.c trace_vprintk.c map_ptr_kern.c \
core_kern.c core_kern_overflow.c test_ringbuf.c \
test_ringbuf_map_key.c
# Generate both light skeleton and libbpf skeleton for these
LSKELS_EXTRA := test_ksyms_module.c test_ksyms_weak.c kfunc_call_test.c \
kfunc_call_test_subprog.c

View File

@ -13,6 +13,7 @@
#include <linux/perf_event.h>
#include <linux/ring_buffer.h>
#include "test_ringbuf.lskel.h"
#include "test_ringbuf_map_key.lskel.h"
#define EDONE 7777
@ -58,6 +59,7 @@ static int process_sample(void *ctx, void *data, size_t len)
}
}
static struct test_ringbuf_map_key_lskel *skel_map_key;
static struct test_ringbuf_lskel *skel;
static struct ring_buffer *ringbuf;
@ -81,7 +83,7 @@ static void *poll_thread(void *input)
return (void *)(long)ring_buffer__poll(ringbuf, timeout);
}
void test_ringbuf(void)
static void ringbuf_subtest(void)
{
const size_t rec_sz = BPF_RINGBUF_HDR_SZ + sizeof(struct sample);
pthread_t thread;
@ -297,3 +299,65 @@ cleanup:
ring_buffer__free(ringbuf);
test_ringbuf_lskel__destroy(skel);
}
static int process_map_key_sample(void *ctx, void *data, size_t len)
{
struct sample *s;
int err, val;
s = data;
switch (s->seq) {
case 1:
ASSERT_EQ(s->value, 42, "sample_value");
err = bpf_map_lookup_elem(skel_map_key->maps.hash_map.map_fd,
s, &val);
ASSERT_OK(err, "hash_map bpf_map_lookup_elem");
ASSERT_EQ(val, 1, "hash_map val");
return -EDONE;
default:
return 0;
}
}
static void ringbuf_map_key_subtest(void)
{
int err;
skel_map_key = test_ringbuf_map_key_lskel__open();
if (!ASSERT_OK_PTR(skel_map_key, "test_ringbuf_map_key_lskel__open"))
return;
skel_map_key->maps.ringbuf.max_entries = getpagesize();
skel_map_key->bss->pid = getpid();
err = test_ringbuf_map_key_lskel__load(skel_map_key);
if (!ASSERT_OK(err, "test_ringbuf_map_key_lskel__load"))
goto cleanup;
ringbuf = ring_buffer__new(skel_map_key->maps.ringbuf.map_fd,
process_map_key_sample, NULL, NULL);
if (!ASSERT_OK_PTR(ringbuf, "ring_buffer__new"))
goto cleanup;
err = test_ringbuf_map_key_lskel__attach(skel_map_key);
if (!ASSERT_OK(err, "test_ringbuf_map_key_lskel__attach"))
goto cleanup_ringbuf;
syscall(__NR_getpgid);
ASSERT_EQ(skel_map_key->bss->seq, 1, "skel_map_key->bss->seq");
err = ring_buffer__poll(ringbuf, -1);
ASSERT_EQ(err, -EDONE, "ring_buffer__poll");
cleanup_ringbuf:
ring_buffer__free(ringbuf);
cleanup:
test_ringbuf_map_key_lskel__destroy(skel_map_key);
}
void test_ringbuf(void)
{
if (test__start_subtest("ringbuf"))
ringbuf_subtest();
if (test__start_subtest("ringbuf_map_key"))
ringbuf_map_key_subtest();
}

View File

@ -0,0 +1,70 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include "bpf_misc.h"
char _license[] SEC("license") = "GPL";
struct sample {
int pid;
int seq;
long value;
char comm[16];
};
struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
} ringbuf SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1000);
__type(key, struct sample);
__type(value, int);
} hash_map SEC(".maps");
/* inputs */
int pid = 0;
/* inner state */
long seq = 0;
SEC("fentry/" SYS_PREFIX "sys_getpgid")
int test_ringbuf_mem_map_key(void *ctx)
{
int cur_pid = bpf_get_current_pid_tgid() >> 32;
struct sample *sample, sample_copy;
int *lookup_val;
if (cur_pid != pid)
return 0;
sample = bpf_ringbuf_reserve(&ringbuf, sizeof(*sample), 0);
if (!sample)
return 0;
sample->pid = pid;
bpf_get_current_comm(sample->comm, sizeof(sample->comm));
sample->seq = ++seq;
sample->value = 42;
/* test using 'sample' (PTR_TO_MEM | MEM_ALLOC) as map key arg
*/
lookup_val = (int *)bpf_map_lookup_elem(&hash_map, sample);
/* workaround - memcpy is necessary so that verifier doesn't
* complain with:
* verifier internal error: more than one arg with ref_obj_id R3
* when trying to do bpf_map_update_elem(&hash_map, sample, &sample->seq, BPF_ANY);
*
* Since bpf_map_lookup_elem above uses 'sample' as key, test using
* sample field as value below
*/
__builtin_memcpy(&sample_copy, sample, sizeof(struct sample));
bpf_map_update_elem(&hash_map, &sample_copy, &sample->seq, BPF_ANY);
bpf_ringbuf_submit(sample, 0);
return 0;
}