Commit 638a485c authored by Andrea Righi's avatar Andrea Righi Committed by Andrii Nakryiko
Browse files

selftests/bpf: Add ring_buffer__consume_n test.



Add a testcase for the ring_buffer__consume_n() API.

The test produces multiple samples in a ring buffer, using a
sys_getpid() fentry prog, and consumes them from user-space in batches,
rather than consuming all of them greedily, like ring_buffer__consume()
does.

Signed-off-by: default avatarAndrea Righi <andrea.righi@canonical.com>
Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Acked-by: default avatarJiri Olsa <jolsa@kernel.org>
Link: https://lore.kernel.org/lkml/CAEf4BzaR4zqUpDmj44KNLdpJ=Tpa97GrvzuzVNO5nM6b7oWd1w@mail.gmail.com
Link: https://lore.kernel.org/bpf/20240425140627.112728-1-andrea.righi@canonical.com
parent 8ec3bf5c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -456,7 +456,7 @@ LINKED_SKELS := test_static_linked.skel.h linked_funcs.skel.h \
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
	test_ringbuf_n.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 \
+65 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include <linux/perf_event.h>
#include <linux/ring_buffer.h>
#include "test_ringbuf.lskel.h"
#include "test_ringbuf_n.lskel.h"
#include "test_ringbuf_map_key.lskel.h"

#define EDONE 7777
@@ -326,6 +327,68 @@ static void ringbuf_subtest(void)
	test_ringbuf_lskel__destroy(skel);
}

/*
 * Test ring_buffer__consume_n() by producing N_TOT_SAMPLES samples in the ring
 * buffer, via getpid(), and consuming them in chunks of N_SAMPLES.
 */
#define N_TOT_SAMPLES	32
#define N_SAMPLES	4

/* Sample value to verify the callback validity */
#define SAMPLE_VALUE	42L

static int process_n_sample(void *ctx, void *data, size_t len)
{
	struct sample *s = data;

	ASSERT_EQ(s->value, SAMPLE_VALUE, "sample_value");

	return 0;
}

static void ringbuf_n_subtest(void)
{
	struct test_ringbuf_n_lskel *skel_n;
	int err, i;

	skel_n = test_ringbuf_n_lskel__open();
	if (!ASSERT_OK_PTR(skel_n, "test_ringbuf_n_lskel__open"))
		return;

	skel_n->maps.ringbuf.max_entries = getpagesize();
	skel_n->bss->pid = getpid();

	err = test_ringbuf_n_lskel__load(skel_n);
	if (!ASSERT_OK(err, "test_ringbuf_n_lskel__load"))
		goto cleanup;

	ringbuf = ring_buffer__new(skel_n->maps.ringbuf.map_fd,
				   process_n_sample, NULL, NULL);
	if (!ASSERT_OK_PTR(ringbuf, "ring_buffer__new"))
		goto cleanup;

	err = test_ringbuf_n_lskel__attach(skel_n);
	if (!ASSERT_OK(err, "test_ringbuf_n_lskel__attach"))
		goto cleanup_ringbuf;

	/* Produce N_TOT_SAMPLES samples in the ring buffer by calling getpid() */
	skel_n->bss->value = SAMPLE_VALUE;
	for (i = 0; i < N_TOT_SAMPLES; i++)
		syscall(__NR_getpgid);

	/* Consume all samples from the ring buffer in batches of N_SAMPLES */
	for (i = 0; i < N_TOT_SAMPLES; i += err) {
		err = ring_buffer__consume_n(ringbuf, N_SAMPLES);
		if (!ASSERT_EQ(err, N_SAMPLES, "rb_consume"))
			goto cleanup_ringbuf;
	}

cleanup_ringbuf:
	ring_buffer__free(ringbuf);
cleanup:
	test_ringbuf_n_lskel__destroy(skel_n);
}

static int process_map_key_sample(void *ctx, void *data, size_t len)
{
	struct sample *s;
@@ -384,6 +447,8 @@ void test_ringbuf(void)
{
	if (test__start_subtest("ringbuf"))
		ringbuf_subtest();
	if (test__start_subtest("ringbuf_n"))
		ringbuf_n_subtest();
	if (test__start_subtest("ringbuf_map_key"))
		ringbuf_map_key_subtest();
}
+47 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2024 Andrea Righi <andrea.righi@canonical.com>

#include <linux/bpf.h>
#include <sched.h>
#include <unistd.h>
#include <bpf/bpf_helpers.h>
#include "bpf_misc.h"

char _license[] SEC("license") = "GPL";

#define TASK_COMM_LEN 16

struct sample {
	int pid;
	long value;
	char comm[16];
};

struct {
	__uint(type, BPF_MAP_TYPE_RINGBUF);
} ringbuf SEC(".maps");

int pid = 0;
long value = 0;

SEC("fentry/" SYS_PREFIX "sys_getpgid")
int test_ringbuf_n(void *ctx)
{
	int cur_pid = bpf_get_current_pid_tgid() >> 32;
	struct sample *sample;

	if (cur_pid != pid)
		return 0;

	sample = bpf_ringbuf_reserve(&ringbuf, sizeof(*sample), 0);
	if (!sample)
		return 0;

	sample->pid = pid;
	sample->value = value;
	bpf_get_current_comm(sample->comm, sizeof(sample->comm));

	bpf_ringbuf_submit(sample, 0);

	return 0;
}