diff mbox series

[RFC,bpf-next,2/2] selftests/bpf: Add tests for open-coded style bpf dynamic pointer iterator

Message ID AM6PR03MB58485BE1C0964BFD3C3657D899932@AM6PR03MB5848.eurprd03.prod.outlook.com (mailing list archive)
State RFC
Delegated to: BPF
Headers show
Series [RFC,bpf-next,1/2] bpf: Add open-coded style iterator kfuncs for bpf dynamic pointers | expand

Checks

Context Check Description
bpf/vmtest-bpf-next-PR success PR summary
bpf/vmtest-bpf-next-VM_Test-0 success Logs for Lint
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-2 success Logs for Unittests
bpf/vmtest-bpf-next-VM_Test-3 success Logs for Validate matrix.py
bpf/vmtest-bpf-next-VM_Test-5 success Logs for aarch64-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-4 success Logs for aarch64-gcc / build / build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-9 success Logs for aarch64-gcc / test (test_verifier, false, 360) / test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-10 success Logs for aarch64-gcc / veristat
bpf/vmtest-bpf-next-VM_Test-11 success Logs for s390x-gcc / build / build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-12 success Logs for s390x-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-15 success Logs for s390x-gcc / test (test_verifier, false, 360) / test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-16 success Logs for s390x-gcc / veristat
bpf/vmtest-bpf-next-VM_Test-17 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-18 success Logs for x86_64-gcc / build / build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-19 success Logs for x86_64-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-20 success Logs for x86_64-gcc / test (test_maps, false, 360) / test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-25 success Logs for x86_64-gcc / test (test_verifier, false, 360) / test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-27 success Logs for x86_64-llvm-17 / build / build for x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-28 success Logs for x86_64-llvm-17 / build-release / build for x86_64 with llvm-17-O2
bpf/vmtest-bpf-next-VM_Test-29 success Logs for x86_64-llvm-17 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-33 success Logs for x86_64-llvm-17 / veristat
bpf/vmtest-bpf-next-VM_Test-34 success Logs for x86_64-llvm-18 / build / build for x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-35 success Logs for x86_64-llvm-18 / build-release / build for x86_64 with llvm-18-O2
bpf/vmtest-bpf-next-VM_Test-32 success Logs for x86_64-llvm-17 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-36 success Logs for x86_64-llvm-18 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-40 success Logs for x86_64-llvm-18 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-41 success Logs for x86_64-llvm-18 / veristat
bpf/vmtest-bpf-next-VM_Test-7 success Logs for aarch64-gcc / test (test_progs, false, 360) / test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-6 success Logs for aarch64-gcc / test (test_maps, false, 360) / test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-8 success Logs for aarch64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-22 success Logs for x86_64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-21 success Logs for x86_64-gcc / test (test_progs, false, 360) / test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-23 success Logs for x86_64-gcc / test (test_progs_no_alu32_parallel, true, 30) / test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-24 success Logs for x86_64-gcc / test (test_progs_parallel, true, 30) / test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-30 success Logs for x86_64-llvm-17 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-31 success Logs for x86_64-llvm-17 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-26 success Logs for x86_64-gcc / veristat / veristat on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-38 success Logs for x86_64-llvm-18 / test (test_progs_cpuv4, false, 360) / test_progs_cpuv4 on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-39 success Logs for x86_64-llvm-18 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-37 success Logs for x86_64-llvm-18 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-13 success Logs for s390x-gcc / test (test_progs, false, 360) / test_progs on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-14 success Logs for s390x-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on s390x with gcc
netdev/series_format success Single patches do not need cover letters
netdev/tree_selection success Clearly marked for bpf-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 16 this patch: 16
netdev/build_tools success Errors and warnings before: 0 this patch: 0
netdev/cc_maintainers warning 4 maintainers not CCed: shuah@kernel.org zhouchuyi@bytedance.com mykolal@fb.com linux-kselftest@vger.kernel.org
netdev/build_clang success Errors and warnings before: 17 this patch: 17
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 22 this patch: 22
netdev/checkpatch warning CHECK: Alignment should match open parenthesis CHECK: Comparison to NULL could be written "!read_len" CHECK: Comparison to NULL could be written "read_len" CHECK: extern prototypes should be avoided in .h files WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? WARNING: line length of 81 exceeds 80 columns WARNING: line length of 84 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Juntong Deng Sept. 3, 2024, 10:09 p.m. UTC
This patch adds test cases for open-coded style bpf dynamic pointer
iterator.

bpf_iter_dynptr_buffer_fit is used to test the case where the buffer
will be filled in every iteration.

bpf_iter_dynptr_buffer_remain is used to test the case where the buffer
will be remaining in the last iteration.

Both of the above test cases check that the offset, read data length,
and read data content are all correct in each iteration, and that the
iteration loop ends correctly.

In addition, this patch adds test cases for failures caused by dynptr
uninitialized, iterator uninitialized and buffer is NULL.

Signed-off-by: Juntong Deng <juntong.deng@outlook.com>
---
 .../testing/selftests/bpf/bpf_experimental.h  |   9 ++
 .../testing/selftests/bpf/prog_tests/iters.c  |  50 +++++++
 .../selftests/bpf/progs/iters_dynptr.c        | 140 ++++++++++++++++++
 .../bpf/progs/iters_dynptr_failure.c          | 108 ++++++++++++++
 4 files changed, 307 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/progs/iters_dynptr.c
 create mode 100644 tools/testing/selftests/bpf/progs/iters_dynptr_failure.c
diff mbox series

Patch

diff --git a/tools/testing/selftests/bpf/bpf_experimental.h b/tools/testing/selftests/bpf/bpf_experimental.h
index b0668f29f7b3..acbc6a1916bd 100644
--- a/tools/testing/selftests/bpf/bpf_experimental.h
+++ b/tools/testing/selftests/bpf/bpf_experimental.h
@@ -575,6 +575,15 @@  extern int bpf_iter_css_new(struct bpf_iter_css *it,
 extern struct cgroup_subsys_state *bpf_iter_css_next(struct bpf_iter_css *it) __weak __ksym;
 extern void bpf_iter_css_destroy(struct bpf_iter_css *it) __weak __ksym;
 
+struct bpf_iter_dynptr;
+extern int bpf_iter_dynptr_new(struct bpf_iter_dynptr *it, struct bpf_dynptr *p,
+			       u32 offset, void *buffer, u32 buffer__szk) __ksym;
+extern int *bpf_iter_dynptr_next(struct bpf_iter_dynptr *it) __ksym;
+extern int bpf_iter_dynptr_set_buffer(struct bpf_iter_dynptr *it__iter,
+				      void *buffer, u32 buffer__szk) __ksym;
+extern u32 bpf_iter_dynptr_get_last_offset(struct bpf_iter_dynptr *it__iter) __ksym;
+extern void bpf_iter_dynptr_destroy(struct bpf_iter_dynptr *it) __ksym;
+
 extern int bpf_wq_init(struct bpf_wq *wq, void *p__map, unsigned int flags) __weak __ksym;
 extern int bpf_wq_start(struct bpf_wq *wq, unsigned int flags) __weak __ksym;
 extern int bpf_wq_set_callback_impl(struct bpf_wq *wq,
diff --git a/tools/testing/selftests/bpf/prog_tests/iters.c b/tools/testing/selftests/bpf/prog_tests/iters.c
index 89ff23c4a8bc..7c17ef8eea70 100644
--- a/tools/testing/selftests/bpf/prog_tests/iters.c
+++ b/tools/testing/selftests/bpf/prog_tests/iters.c
@@ -21,6 +21,8 @@ 
 #include "iters_css_task.skel.h"
 #include "iters_css.skel.h"
 #include "iters_task_failure.skel.h"
+#include "iters_dynptr.skel.h"
+#include "iters_dynptr_failure.skel.h"
 
 static void subtest_num_iters(void)
 {
@@ -291,6 +293,50 @@  static void subtest_css_iters(void)
 	iters_css__destroy(skel);
 }
 
+static int subtest_dynptr_iters(struct iters_dynptr *skel, const char *prog_name)
+{
+	struct bpf_program *prog;
+	int prog_fd;
+
+	prog = bpf_object__find_program_by_name(skel->obj, prog_name);
+	if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name"))
+		return -1;
+
+	prog_fd = bpf_program__fd(prog);
+	if (!ASSERT_GT(prog_fd, 0, "bpf_program__fd"))
+		return -1;
+
+	if (test__start_subtest(prog_name)) {
+		bpf_prog_test_run_opts(prog_fd, NULL);
+		ASSERT_EQ(skel->bss->iter_step_match, 0, "step_match");
+		ASSERT_EQ(skel->bss->iter_content_match, 0, "content_match");
+	}
+
+	return 0;
+}
+
+const char *dynptr_iter_tests[] = {
+	"bpf_iter_dynptr_buffer_fit",
+	"bpf_iter_dynptr_buffer_remain"
+};
+
+static void test_dynptr_iters(void)
+{
+	struct iters_dynptr *skel = NULL;
+	int i;
+
+	skel = iters_dynptr__open_and_load();
+	if (!ASSERT_OK_PTR(skel, "skel_open_and_load"))
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(dynptr_iter_tests); i++) {
+		if (subtest_dynptr_iters(skel, dynptr_iter_tests[i]))
+			break;
+	}
+
+	iters_dynptr__destroy(skel);
+}
+
 void test_iters(void)
 {
 	RUN_TESTS(iters_state_safety);
@@ -315,5 +361,9 @@  void test_iters(void)
 		subtest_css_task_iters();
 	if (test__start_subtest("css"))
 		subtest_css_iters();
+
+	test_dynptr_iters();
+
 	RUN_TESTS(iters_task_failure);
+	RUN_TESTS(iters_dynptr_failure);
 }
diff --git a/tools/testing/selftests/bpf/progs/iters_dynptr.c b/tools/testing/selftests/bpf/progs/iters_dynptr.c
new file mode 100644
index 000000000000..29a44b96f5fe
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/iters_dynptr.c
@@ -0,0 +1,140 @@ 
+// SPDX-License-Identifier: GPL-2.0
+
+#include "vmlinux.h"
+#include <errno.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+#include "bpf_misc.h"
+#include "bpf_experimental.h"
+
+char _license[] SEC("license") = "GPL";
+
+struct {
+	__uint(type, BPF_MAP_TYPE_RINGBUF);
+	__uint(max_entries, 4096);
+} ringbuf SEC(".maps");
+
+int iter_content_match = 0;
+int iter_step_match = 0;
+
+SEC("syscall")
+int bpf_iter_dynptr_buffer_fit(const void *ctx)
+{
+	struct bpf_iter_dynptr dynptr_it;
+	struct bpf_dynptr ptr;
+
+	char write_data[5] = {'a', 'b', 'c', 'd', 'e'};
+	char read_data1[2], read_data2[3];
+	int *read_len, offset;
+
+	bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(write_data), 0, &ptr);
+
+	bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0);
+
+	bpf_iter_dynptr_new(&dynptr_it, &ptr, 0, read_data1, sizeof(read_data1));
+
+	read_len = bpf_iter_dynptr_next(&dynptr_it);
+	offset = bpf_iter_dynptr_get_last_offset(&dynptr_it);
+
+	if (read_len == NULL) {
+		iter_step_match = -1;
+		goto out;
+	}
+
+	if (*read_len != sizeof(read_data1)) {
+		iter_step_match = -1;
+		goto out;
+	}
+
+	if (offset != 0) {
+		iter_step_match = -1;
+		goto out;
+	}
+
+	if (read_data1[0] != write_data[0] || read_data1[1] != write_data[1]) {
+		iter_content_match = -1;
+		goto out;
+	}
+
+	bpf_iter_dynptr_set_buffer(&dynptr_it, read_data2, sizeof(read_data2));
+
+	read_len = bpf_iter_dynptr_next(&dynptr_it);
+	offset = bpf_iter_dynptr_get_last_offset(&dynptr_it);
+
+	if (read_len == NULL) {
+		iter_step_match = -1;
+		goto out;
+	}
+
+	if (*read_len != sizeof(read_data2)) {
+		iter_step_match = -1;
+		goto out;
+	}
+
+	if (offset != 2) {
+		iter_step_match = -1;
+		goto out;
+	}
+
+	if (read_data2[0] != write_data[2] || read_data2[1] != write_data[3] ||
+	   read_data2[2] != write_data[4]) {
+		iter_content_match = -1;
+		goto out;
+	}
+
+	read_len = bpf_iter_dynptr_next(&dynptr_it);
+	if (read_len != NULL)
+		iter_step_match = -1;
+out:
+	bpf_iter_dynptr_destroy(&dynptr_it);
+	bpf_ringbuf_discard_dynptr(&ptr, 0);
+	return 0;
+}
+
+SEC("syscall")
+int bpf_iter_dynptr_buffer_remain(const void *ctx)
+{
+	struct bpf_iter_dynptr dynptr_it;
+	struct bpf_dynptr ptr;
+
+	char write_data[1] = {'a'};
+	char read_data[2];
+	int *read_len, offset;
+
+	bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(write_data), 0, &ptr);
+
+	bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0);
+
+	bpf_iter_dynptr_new(&dynptr_it, &ptr, 0, read_data, sizeof(read_data));
+
+	read_len = bpf_iter_dynptr_next(&dynptr_it);
+	offset = bpf_iter_dynptr_get_last_offset(&dynptr_it);
+
+	if (read_len == NULL) {
+		iter_step_match = -1;
+		goto out;
+	}
+
+	if (*read_len != 1) {
+		iter_step_match = -1;
+		goto out;
+	}
+
+	if (offset != 0) {
+		iter_step_match = -1;
+		goto out;
+	}
+
+	if (read_data[0] != write_data[0]) {
+		iter_content_match = -1;
+		goto out;
+	}
+
+	read_len = bpf_iter_dynptr_next(&dynptr_it);
+	if (read_len != NULL)
+		iter_step_match = -1;
+out:
+	bpf_iter_dynptr_destroy(&dynptr_it);
+	bpf_ringbuf_discard_dynptr(&ptr, 0);
+	return 0;
+}
diff --git a/tools/testing/selftests/bpf/progs/iters_dynptr_failure.c b/tools/testing/selftests/bpf/progs/iters_dynptr_failure.c
new file mode 100644
index 000000000000..97bec2f39f62
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/iters_dynptr_failure.c
@@ -0,0 +1,108 @@ 
+// SPDX-License-Identifier: GPL-2.0
+
+#include "vmlinux.h"
+#include <errno.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+#include "bpf_misc.h"
+#include "bpf_experimental.h"
+
+char _license[] SEC("license") = "GPL";
+
+struct {
+	__uint(type, BPF_MAP_TYPE_RINGBUF);
+	__uint(max_entries, 4096);
+} ringbuf SEC(".maps");
+
+SEC("raw_tp/sys_enter")
+__failure __msg("Expected an initialized dynptr as arg #2")
+int bpf_iter_dynptr_new_uninit_dynptr(void *ctx)
+{
+	struct bpf_iter_dynptr dynptr_it;
+	struct bpf_dynptr ptr;
+	char read_data[5];
+
+	bpf_iter_dynptr_new(&dynptr_it, &ptr, 0, read_data, sizeof(read_data));
+
+	return 0;
+}
+
+SEC("raw_tp/sys_enter")
+__failure __msg("arg#3 arg#4 memory, len pair leads to invalid memory access")
+int bpf_iter_dynptr_new_null_buffer(void *ctx)
+{
+	struct bpf_iter_dynptr dynptr_it;
+	struct bpf_dynptr ptr;
+	char *read_data = NULL;
+
+	bpf_ringbuf_reserve_dynptr(&ringbuf, 10, 0, &ptr);
+
+	bpf_iter_dynptr_new(&dynptr_it, &ptr, 0, read_data, 10);
+
+	bpf_ringbuf_discard_dynptr(&ptr, 0);
+	return 0;
+}
+
+SEC("raw_tp/sys_enter")
+__failure __msg("expected an initialized iter_dynptr as arg #1")
+int bpf_iter_dynptr_next_uninit_iter(void *ctx)
+{
+	struct bpf_iter_dynptr dynptr_it;
+
+	bpf_iter_dynptr_next(&dynptr_it);
+
+	return 0;
+}
+
+SEC("raw_tp/sys_enter")
+__failure __msg("expected an initialized iter_dynptr as arg #1")
+int bpf_iter_dynptr_get_last_offset_uninit_iter(void *ctx)
+{
+	struct bpf_iter_dynptr dynptr_it;
+
+	bpf_iter_dynptr_get_last_offset(&dynptr_it);
+
+	return 0;
+}
+
+SEC("raw_tp/sys_enter")
+__failure __msg("expected an initialized iter_dynptr as arg #1")
+int bpf_iter_dynptr_set_buffer_uninit_iter(void *ctx)
+{
+	struct bpf_iter_dynptr dynptr_it;
+	char read_data[5];
+
+	bpf_iter_dynptr_set_buffer(&dynptr_it, read_data, sizeof(read_data));
+
+	return 0;
+}
+
+SEC("raw_tp/sys_enter")
+__failure __msg("arg#1 arg#2 memory, len pair leads to invalid memory access")
+int bpf_iter_dynptr_set_buffer_null_buffer(void *ctx)
+{
+	struct bpf_iter_dynptr dynptr_it;
+	struct bpf_dynptr ptr;
+	char *null_data = NULL;
+	char read_data[5];
+
+	bpf_ringbuf_reserve_dynptr(&ringbuf, 10, 0, &ptr);
+
+	bpf_iter_dynptr_new(&dynptr_it, &ptr, 0, read_data, sizeof(read_data));
+
+	bpf_iter_dynptr_set_buffer(&dynptr_it, null_data, 10);
+
+	bpf_ringbuf_discard_dynptr(&ptr, 0);
+	return 0;
+}
+
+SEC("raw_tp/sys_enter")
+__failure __msg("expected an initialized iter_dynptr as arg #1")
+int bpf_iter_dynptr_destroy_uninit_iter(void *ctx)
+{
+	struct bpf_iter_dynptr dynptr_it;
+
+	bpf_iter_dynptr_destroy(&dynptr_it);
+
+	return 0;
+}