[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20220128223312.1253169-10-mauricio@kinvolk.io>
Date: Fri, 28 Jan 2022 17:33:12 -0500
From: Mauricio Vásquez <mauricio@...volk.io>
To: netdev@...r.kernel.org, bpf@...r.kernel.org
Cc: Alexei Starovoitov <ast@...nel.org>,
Daniel Borkmann <daniel@...earbox.net>,
Andrii Nakryiko <andrii@...nel.org>,
Quentin Monnet <quentin@...valent.com>,
Rafael David Tinoco <rafaeldtinoco@...il.com>,
Lorenzo Fontana <lorenzo.fontana@...stic.co>,
Leonardo Di Donato <leonardo.didonato@...stic.co>
Subject: [PATCH bpf-next v5 9/9] selftest/bpf: Implement tests for bpftool gen min_core_btf
This commit implements some integration tests for "BTFGen". The goal
of such tests is to verify that the generated BTF file contains the
expected types.
Signed-off-by: Mauricio Vásquez <mauricio@...volk.io>
Signed-off-by: Rafael David Tinoco <rafael.tinoco@...asec.com>
Signed-off-by: Lorenzo Fontana <lorenzo.fontana@...stic.co>
Signed-off-by: Leonardo Di Donato <leonardo.didonato@...stic.co>
---
tools/testing/selftests/bpf/.gitignore | 1 +
tools/testing/selftests/bpf/Makefile | 4 +-
.../selftests/bpf/progs/btfgen_btf_source.c | 12 +
.../bpf/progs/btfgen_primitives_array.c | 39 +++
.../bpf/progs/btfgen_primitives_struct.c | 40 +++
.../bpf/progs/btfgen_primitives_struct2.c | 44 ++++
.../bpf/progs/btfgen_primitives_union.c | 32 +++
tools/testing/selftests/bpf/test_bpftool.c | 228 ++++++++++++++++++
8 files changed, 399 insertions(+), 1 deletion(-)
create mode 100644 tools/testing/selftests/bpf/progs/btfgen_btf_source.c
create mode 100644 tools/testing/selftests/bpf/progs/btfgen_primitives_array.c
create mode 100644 tools/testing/selftests/bpf/progs/btfgen_primitives_struct.c
create mode 100644 tools/testing/selftests/bpf/progs/btfgen_primitives_struct2.c
create mode 100644 tools/testing/selftests/bpf/progs/btfgen_primitives_union.c
create mode 100644 tools/testing/selftests/bpf/test_bpftool.c
diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore
index 1dad8d617da8..308cd5b9cfc4 100644
--- a/tools/testing/selftests/bpf/.gitignore
+++ b/tools/testing/selftests/bpf/.gitignore
@@ -41,3 +41,4 @@ test_cpp
*.tmp
xdpxceiver
xdp_redirect_multi
+test_bpftool
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 945f92d71db3..afc9bff6545d 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -38,7 +38,8 @@ TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test
test_sock test_sockmap get_cgroup_id_user \
test_cgroup_storage \
test_tcpnotify_user test_sysctl \
- test_progs-no_alu32
+ test_progs-no_alu32 \
+ test_bpftool
# Also test bpf-gcc, if present
ifneq ($(BPF_GCC),)
@@ -212,6 +213,7 @@ $(OUTPUT)/xdping: $(TESTING_HELPERS)
$(OUTPUT)/flow_dissector_load: $(TESTING_HELPERS)
$(OUTPUT)/test_maps: $(TESTING_HELPERS)
$(OUTPUT)/test_verifier: $(TESTING_HELPERS)
+$(OUTPUT)/test_bpftool:
BPFTOOL ?= $(DEFAULT_BPFTOOL)
$(DEFAULT_BPFTOOL): $(wildcard $(BPFTOOLDIR)/*.[ch] $(BPFTOOLDIR)/Makefile) \
diff --git a/tools/testing/selftests/bpf/progs/btfgen_btf_source.c b/tools/testing/selftests/bpf/progs/btfgen_btf_source.c
new file mode 100644
index 000000000000..772d5d1e2788
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btfgen_btf_source.c
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "core_reloc_types.h"
+
+// structure made of primitive types
+void f0(struct core_reloc_primitives x) {}
+
+// union made of primite types
+void f1(union a_union x) {}
+
+// arrays
+void f2(struct core_reloc_arrays x) {}
diff --git a/tools/testing/selftests/bpf/progs/btfgen_primitives_array.c b/tools/testing/selftests/bpf/progs/btfgen_primitives_array.c
new file mode 100644
index 000000000000..aa514d1bcd96
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btfgen_primitives_array.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/bpf.h>
+#include <stdint.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_core_read.h>
+
+char _license[] SEC("license") = "GPL";
+
+struct {
+ char in[256];
+ char out[256];
+} data = {};
+
+struct core_reloc_arrays_substruct {
+ int c;
+ int d;
+};
+
+struct core_reloc_arrays {
+ int a[5];
+ char b[2][3][4];
+ struct core_reloc_arrays_substruct c[3];
+ struct core_reloc_arrays_substruct d[1][2];
+ struct core_reloc_arrays_substruct f[][2];
+};
+#define CORE_READ(dst, src) bpf_core_read(dst, sizeof(*(dst)), src)
+
+SEC("raw_tracepoint/sys_enter")
+int test_btfgen_primitives(void *ctx)
+{
+ struct core_reloc_arrays *in = (void *)&data.in;
+ struct core_reloc_arrays *out = (void *)&data.out;
+
+ if (CORE_READ(&out->a[0], &in->a[0]))
+ return 1;
+
+ return 0;
+}
diff --git a/tools/testing/selftests/bpf/progs/btfgen_primitives_struct.c b/tools/testing/selftests/bpf/progs/btfgen_primitives_struct.c
new file mode 100644
index 000000000000..b761d020fa4d
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btfgen_primitives_struct.c
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/bpf.h>
+#include <stdint.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_core_read.h>
+
+char _license[] SEC("license") = "GPL";
+
+struct {
+ char in[256];
+ char out[256];
+} data = {};
+
+enum core_reloc_primitives_enum {
+ A = 0,
+ B = 1,
+};
+
+struct core_reloc_primitives {
+ char a;
+ int b;
+ enum core_reloc_primitives_enum c;
+ void *d;
+ int (*f)(const char *);
+};
+
+#define CORE_READ(dst, src) bpf_core_read(dst, sizeof(*(dst)), src)
+
+SEC("raw_tracepoint/sys_enter")
+int test_btfgen_primitives(void *ctx)
+{
+ struct core_reloc_primitives *in = (void *)&data.in;
+ struct core_reloc_primitives *out = (void *)&data.out;
+
+ if (CORE_READ(&out->a, &in->a))
+ return 1;
+
+ return 0;
+}
diff --git a/tools/testing/selftests/bpf/progs/btfgen_primitives_struct2.c b/tools/testing/selftests/bpf/progs/btfgen_primitives_struct2.c
new file mode 100644
index 000000000000..fe67c9a24a7f
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btfgen_primitives_struct2.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* This is almost the same as btfgen_primitives_struct.c but in this one
+ * a different field is accessed
+ */
+
+#include <linux/bpf.h>
+#include <stdint.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_core_read.h>
+
+char _license[] SEC("license") = "GPL";
+
+struct {
+ char in[256];
+ char out[256];
+} data = {};
+
+enum core_reloc_primitives_enum {
+ A = 0,
+ B = 1,
+};
+
+struct core_reloc_primitives {
+ char a;
+ int b;
+ enum core_reloc_primitives_enum c;
+ void *d;
+ int (*f)(const char *);
+};
+
+#define CORE_READ(dst, src) bpf_core_read(dst, sizeof(*(dst)), src)
+
+SEC("raw_tracepoint/sys_enter")
+int test_btfgen_primitives(void *ctx)
+{
+ struct core_reloc_primitives *in = (void *)&data.in;
+ struct core_reloc_primitives *out = (void *)&data.out;
+
+ if (CORE_READ(&out->b, &in->b))
+ return 1;
+
+ return 0;
+}
diff --git a/tools/testing/selftests/bpf/progs/btfgen_primitives_union.c b/tools/testing/selftests/bpf/progs/btfgen_primitives_union.c
new file mode 100644
index 000000000000..d4690c9e963c
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btfgen_primitives_union.c
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/bpf.h>
+#include <stdint.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_core_read.h>
+
+char _license[] SEC("license") = "GPL";
+
+struct {
+ char in[256];
+ char out[256];
+} data = {};
+
+union a_union {
+ int y;
+ int z;
+};
+
+#define CORE_READ(dst, src) bpf_core_read(dst, sizeof(*(dst)), src)
+
+SEC("raw_tracepoint/sys_enter")
+int test_btfgen_primitives(void *ctx)
+{
+ union a_union *in = (void *)&data.in;
+ union a_union *out = (void *)&data.out;
+
+ if (CORE_READ(&out->y, &in->y))
+ return 1;
+
+ return 0;
+}
diff --git a/tools/testing/selftests/bpf/test_bpftool.c b/tools/testing/selftests/bpf/test_bpftool.c
new file mode 100644
index 000000000000..ca7facc582d5
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_bpftool.c
@@ -0,0 +1,228 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <linux/limits.h>
+
+#include <bpf/libbpf.h>
+#include <bpf/btf.h>
+
+#include "bpf_util.h"
+
+static int run_btfgen(const char *src_btf, const char *dst_btf, const char *objspaths[])
+{
+ char command[4096];
+ int ret, i, n;
+
+ n = snprintf(command, sizeof(command),
+ "./tools/build/bpftool/bpftool gen min_core_btf %s %s", src_btf, dst_btf);
+ assert(n >= 0 && n < sizeof(command));
+
+ for (i = 0; objspaths[i] != NULL; i++) {
+ assert(sizeof(command) - strlen(command) > strlen(objspaths[i]) + 1);
+ strcat(command, " ");
+ strcat(command, objspaths[i]);
+ }
+
+ printf("Executing bpftool: %s\n", command);
+ printf("---\n");
+ ret = system(command);
+ printf("---\n");
+ return ret;
+}
+
+struct btfgen_test {
+ const char *descr;
+ const char *src_btf;
+ const char *bpfobj[16];
+ void (*run_test)(struct btf *btf);
+};
+
+static void check_btfgen_primitive_struct(struct btf *btf)
+{
+ struct btf_member *members;
+ const struct btf_type *t;
+ int id;
+
+ assert(btf__type_cnt(btf) == 3);
+
+ id = btf__find_by_name_kind(btf, "core_reloc_primitives", BTF_KIND_STRUCT);
+ assert(id > 0);
+
+ t = btf__type_by_id(btf, id);
+ assert(btf_vlen(t) == 1);
+
+ members = btf_members(t);
+
+ id = btf__find_by_name_kind(btf, "char", BTF_KIND_INT);
+ assert(id > 0);
+
+ /* the type of the struct member must be the char */
+ assert(members[0].type == id);
+}
+
+static void check_btfgen_primitive_union(struct btf *btf)
+{
+ struct btf_member *members;
+ const struct btf_type *t;
+ int id;
+
+ /* void, a_union and int*/
+ assert(btf__type_cnt(btf) == 3);
+
+ id = btf__find_by_name_kind(btf, "a_union", BTF_KIND_UNION);
+ assert(id > 0);
+
+ t = btf__type_by_id(btf, id);
+ assert(btf_vlen(t) == 1);
+
+ members = btf_members(t);
+
+ id = btf__find_by_name_kind(btf, "int", BTF_KIND_INT);
+ assert(id > 0);
+
+ /* the type of the union member must be the integer */
+ assert(members[0].type == id);
+}
+
+static void check_btfgen_primitive_array(struct btf *btf)
+{
+ int array_id, array_type_id, array_index_type_id;
+ struct btf_array *array;
+
+ /* void, struct, array, int (array index type) and int (array type) */
+ assert(btf__type_cnt(btf) == 5);
+
+ array_id = btf__find_by_name_kind(btf, "", BTF_KIND_ARRAY);
+ assert(array_id > 0);
+
+ array = btf_array(btf__type_by_id(btf, array_id));
+
+ array_type_id = btf__find_by_name_kind(btf, "int", BTF_KIND_INT);
+ assert(array_type_id > 0);
+
+ array_index_type_id = btf__find_by_name_kind(btf, "__ARRAY_SIZE_TYPE__", BTF_KIND_INT);
+ assert(array_index_type_id > 0);
+
+ /* check that array types are the correct ones */
+ assert(array->type == array_type_id);
+ assert(array->index_type == array_index_type_id);
+}
+
+/* If there are relocations in two different BPF objects involving
+ * different members of the same struct, then the generated BTF should
+ * contain a single instance of such struct with both fields.
+ */
+static void check_btfgen_primitive_structs_different_objects(struct btf *btf)
+{
+ struct btf_member *members;
+ const struct btf_type *t;
+ int struct_id, char_id, int_id;
+
+ /* void, struct, int and char */
+ assert(btf__type_cnt(btf) == 4);
+
+ struct_id = btf__find_by_name_kind(btf, "core_reloc_primitives", BTF_KIND_STRUCT);
+ assert(struct_id > 0);
+
+ t = btf__type_by_id(btf, struct_id);
+ assert(btf_vlen(t) == 2);
+
+ members = btf_members(t);
+
+ char_id = btf__find_by_name_kind(btf, "char", BTF_KIND_INT);
+ assert(char_id > 0);
+
+ int_id = btf__find_by_name_kind(btf, "int", BTF_KIND_INT);
+ assert(int_id > 0);
+
+ for (int i = 0; i < btf_vlen(t); i++) {
+ const char *name = btf__str_by_offset(btf, members[i].name_off);
+
+ if (!strcmp("a", name))
+ assert(members[i].type == char_id);
+ else if (!strcmp("b", name))
+ assert(members[i].type == int_id);
+ }
+}
+
+static struct btfgen_test btfgen_tests[] = {
+ {
+ "primitive struct",
+ "btfgen_btf_source.o",
+ {
+ "btfgen_primitives_struct.o",
+ },
+ check_btfgen_primitive_struct,
+ },
+ {
+ "primitive union",
+ "btfgen_btf_source.o",
+ {
+ "btfgen_primitives_union.o",
+ },
+ check_btfgen_primitive_union,
+ },
+ {
+ "primitive array",
+ "btfgen_btf_source.o",
+ {
+ "btfgen_primitives_array.o",
+ },
+ check_btfgen_primitive_array,
+ },
+ {
+ "primitive structs in different objects",
+ "btfgen_btf_source.o",
+ {
+ "btfgen_primitives_struct.o",
+ "btfgen_primitives_struct2.o",
+ },
+ check_btfgen_primitive_structs_different_objects,
+ },
+};
+
+void test_gen_min_core_btf(void)
+{
+ char target_path[PATH_MAX];
+ struct btfgen_test *test;
+ struct btf *dst_btf;
+ int ret;
+
+ for (int i = 0; i < ARRAY_SIZE(btfgen_tests); i++) {
+ char dir_path[] = "/tmp/btfgen-XXXXXX";
+
+ test = &btfgen_tests[i];
+
+ printf("Running %s\n", test->descr);
+
+ mkdtemp(dir_path);
+
+ snprintf(target_path, sizeof(target_path), "%s/foo.btf", dir_path);
+
+ ret = run_btfgen(test->src_btf, target_path, test->bpfobj);
+ assert(ret == 0);
+
+ dst_btf = btf__parse(target_path, NULL);
+ assert(dst_btf != NULL);
+
+ test->run_test(dst_btf);
+
+ printf("Test %s: PASS\n", test->descr);
+ }
+
+ printf("%s: PASS\n", __func__);
+}
+
+int main(void)
+{
+ libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+
+ test_gen_min_core_btf();
+
+ printf("test_bpftool: OK\n");
+
+ return 0;
+}
--
2.25.1
Powered by blists - more mailing lists