From: Hungyu Lin <dennylin0707@gmail.com>
To: ast@kernel.org, bpf@vger.kernel.org
Cc: andrii@kernel.org, qmo@kernel.org, daniel@iogearbox.net,
yonghong.song@linux.dev, eddyz87@gmail.com,
ihor.solodrai@linux.dev, shuah@kernel.org,
linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org,
Hungyu Lin <dennylin0707@gmail.com>
Subject: [PATCH bpf-next v5 3/3] selftests/bpf: Cover enum signedness in data dumps and map fields
Date: Sun, 8 Nov 2026 02:56:32 +0000 [thread overview]
Message-ID: <20261108025632.10799-4-dennylin0707@gmail.com> (raw)
In-Reply-To: <20261108025632.10799-1-dennylin0707@gmail.com>
Check unsigned and signed enumerator names in libbpf's existing enum
data test. Create a new dumper after adding the test types, as the data
dumper does not resize its per-type state for newly added types.
Extend bpftool_map_dump with one BTF-backed array map containing four
enum fields. A single JSON dump checks unsigned and signed names and
unsigned numeric output for ordinary enums and ENUM64. Plain output
uses the same enum dumper and does not need another invocation.
Also use an open-only arena skeleton to check an enum-backed map_extra
value with bit 31 set. The object is not loaded into the kernel, so the
test needs neither arena support nor mmap.
Suggested-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Quentin Monnet <qmo@kernel.org>
Signed-off-by: Hungyu Lin <dennylin0707@gmail.com>
---
.../bpf/prog_tests/bpftool_map_dump.c | 76 +++++++++++++++++++
.../selftests/bpf/prog_tests/btf_dump.c | 20 +++++
| 19 +++++
| 12 +++
4 files changed, 127 insertions(+)
create mode 100644 tools/testing/selftests/bpf/prog_tests/map_extra.c
create mode 100644 tools/testing/selftests/bpf/progs/test_map_extra.c
diff --git a/tools/testing/selftests/bpf/prog_tests/bpftool_map_dump.c b/tools/testing/selftests/bpf/prog_tests/bpftool_map_dump.c
index 187b3f784307..a9584c83023c 100644
--- a/tools/testing/selftests/bpf/prog_tests/bpftool_map_dump.c
+++ b/tools/testing/selftests/bpf/prog_tests/bpftool_map_dump.c
@@ -7,6 +7,7 @@
#define PIN_PATH "/sys/fs/bpf/test_bpftool_map_dump_sk_storage"
#define QUEUE_PIN_PATH "/sys/fs/bpf/test_bpftool_map_dump_queue"
+#define ENUM_PIN_PATH "/sys/fs/bpf/test_bpftool_map_dump_enum"
#define JSON_ERROR "{\"error\":\"can't dump sk_storage map"
/* An empty socket storage map with an int value. */
@@ -124,10 +125,85 @@ static void test_queue(void)
close(map_fd);
}
+struct enums {
+ __u8 u8_name;
+ __s8 s8_name;
+ __u32 u32_num;
+ __u64 u64_num;
+};
+
+/* An array map. Its value is struct enums with an enum behind every member. */
+static int create_enum_map(void)
+{
+ LIBBPF_OPTS(bpf_map_create_opts, opts);
+ struct btf *btf;
+ int fd = -1;
+
+ btf = btf__new_empty();
+ if (!ASSERT_OK_PTR(btf, "btf__new_empty"))
+ return -1;
+
+ btf__add_int(btf, "int", 4, BTF_INT_SIGNED); /* [1] */
+ btf__add_enum(btf, "u8", 1); /* [2] */
+ btf__add_enum_value(btf, "U8_MAX", 0xff);
+ btf__add_enum(btf, "s8", 1); /* [3] */
+ btf__add_enum_value(btf, "S8_NEG", -1);
+ btf__add_enum(btf, "u32", 4); /* [4] */
+ btf__add_enum_value(btf, "U32_ONE", 1);
+ btf__add_enum64(btf, "u64", 8, false); /* [5] */
+ btf__add_enum64_value(btf, "U64_ONE", 1);
+ btf__add_struct(btf, "enums", sizeof(struct enums)); /* [6] */
+ btf__add_field(btf, "u8_name", 2, 0, 0);
+ btf__add_field(btf, "s8_name", 3, 8, 0);
+ btf__add_field(btf, "u32_num", 4, 32, 0);
+ btf__add_field(btf, "u64_num", 5, 64, 0);
+ if (!ASSERT_OK(btf__load_into_kernel(btf), "btf__load_into_kernel"))
+ goto out;
+
+ opts.btf_fd = btf__fd(btf);
+ opts.btf_key_type_id = 1;
+ opts.btf_value_type_id = 6;
+ fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "enums", sizeof(int),
+ sizeof(struct enums), 1, &opts);
+ ASSERT_OK_FD(fd, "bpf_map_create");
+out:
+ btf__free(btf);
+ return fd;
+}
+
+static void test_enum(void)
+{
+ struct enums value = { 0xff, -1, (__u32)-22, (1ULL << 63) | 1 };
+ char output[1024] = {};
+ int map_fd, key = 0, ret;
+
+ map_fd = create_enum_map();
+ if (map_fd < 0)
+ return;
+ if (!ASSERT_OK(bpf_map_update_elem(map_fd, &key, &value, BPF_ANY),
+ "update map"))
+ goto out;
+ if (!ASSERT_OK(bpf_obj_pin(map_fd, ENUM_PIN_PATH), "pin map"))
+ goto out;
+
+ ret = get_bpftool_command_output("-j map dump pinned " ENUM_PIN_PATH,
+ output, sizeof(output));
+ ASSERT_OK(ret, "json dump");
+ ASSERT_HAS_SUBSTR(output,
+ "{\"u8_name\":\"U8_MAX\",\"s8_name\":\"S8_NEG\","
+ "\"u32_num\":4294967274,\"u64_num\":9223372036854775809}",
+ "enum values");
+out:
+ unlink(ENUM_PIN_PATH);
+ close(map_fd);
+}
+
void test_bpftool_map_dump(void)
{
if (test__start_subtest("sk_storage"))
test_sk_storage();
if (test__start_subtest("queue"))
test_queue();
+ if (test__start_subtest("enum"))
+ test_enum();
}
diff --git a/tools/testing/selftests/bpf/prog_tests/btf_dump.c b/tools/testing/selftests/bpf/prog_tests/btf_dump.c
index bfa74db17987..b5c90f729339 100644
--- a/tools/testing/selftests/bpf/prog_tests/btf_dump.c
+++ b/tools/testing/selftests/bpf/prog_tests/btf_dump.c
@@ -944,6 +944,9 @@ static void test_btf_dump_typedef_data(struct btf *btf, struct btf_dump *d,
static void test_btf_dump_enum_data(struct btf *btf, struct btf_dump *d,
char *str)
{
+ __u32 high = 0x80000000;
+ __s32 neg = -1;
+
/* enum where enum value does (and does not) exist */
TEST_BTF_DUMP_DATA_C(btf, d, "enum", str, enum bpf_cmd, BTF_F_COMPACT,
BPF_MAP_CREATE);
@@ -975,6 +978,23 @@ static void test_btf_dump_enum_data(struct btf *btf, struct btf_dump *d,
TEST_BTF_DUMP_DATA_OVER(btf, d, "enum", str, enum bpf_cmd,
sizeof(enum bpf_cmd) - 1, "", BPF_MAP_CREATE);
+
+ /* enumerators with bit 31 set in unsigned and in signed enum */
+ ASSERT_GT(btf__add_enum(btf, "test_enum_u32", 4), 0, "add unsigned enum");
+ ASSERT_OK(btf__add_enum_value(btf, "TEST_ENUM_HIGH", 0x80000000),
+ "add TEST_ENUM_HIGH");
+ ASSERT_GT(btf__add_enum(btf, "test_enum_s32", 4), 0, "add signed enum");
+ ASSERT_OK(btf__add_enum_value(btf, "TEST_ENUM_NEG", -1), "add TEST_ENUM_NEG");
+
+ /* btf_dump__dump_type_data() doesn't resize 'd' for the new types */
+ d = btf_dump__new(btf, btf_dump_snprintf, str, NULL);
+ if (!ASSERT_OK_PTR(d, "btf_dump__new"))
+ return;
+ ASSERT_OK(btf_dump_data(btf, d, "test_enum_u32", NULL, 0, &high, 4, str,
+ "(enum test_enum_u32)TEST_ENUM_HIGH"), "dump unsigned enum");
+ ASSERT_OK(btf_dump_data(btf, d, "test_enum_s32", NULL, 0, &neg, 4, str,
+ "(enum test_enum_s32)TEST_ENUM_NEG"), "dump signed enum");
+ btf_dump__free(d);
}
static void test_btf_dump_struct_data(struct btf *btf, struct btf_dump *d,
--git a/tools/testing/selftests/bpf/prog_tests/map_extra.c b/tools/testing/selftests/bpf/prog_tests/map_extra.c
new file mode 100644
index 000000000000..cbb1881ba693
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/map_extra.c
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <test_progs.h>
+#include "test_map_extra.skel.h"
+
+void test_map_extra(void)
+{
+ struct test_map_extra *skel;
+
+ if (!test__start_subtest("enum32_high"))
+ return;
+
+ skel = test_map_extra__open();
+ if (!ASSERT_OK_PTR(skel, "test_map_extra__open"))
+ return;
+
+ ASSERT_EQ(bpf_map__map_extra(skel->maps.arena), 0x80000000ULL,
+ "map_extra");
+ test_map_extra__destroy(skel);
+}
--git a/tools/testing/selftests/bpf/progs/test_map_extra.c b/tools/testing/selftests/bpf/progs/test_map_extra.c
new file mode 100644
index 000000000000..b6aa2341c115
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/test_map_extra.c
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/bpf.h>
+#include <bpf/bpf_helpers.h>
+
+struct {
+ __uint(type, BPF_MAP_TYPE_ARENA);
+ __uint(map_flags, BPF_F_MMAPABLE);
+ __uint(max_entries, 1);
+ __ulong(map_extra, 0x80000000U);
+} arena SEC(".maps");
+
+char LICENSE[] SEC("license") = "GPL";
--
2.43.0
prev parent reply other threads:[~2026-11-08 2:57 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-08 2:56 [PATCH bpf-next v5 0/3] Normalize enum values in libbpf and bpftool Hungyu Lin
2026-11-08 2:56 ` [PATCH bpf-next v5 1/3] libbpf: Normalize enum values according to signedness Hungyu Lin
2026-11-08 2:56 ` [PATCH bpf-next v5 2/3] bpftool: Preserve unsigned enum values in data dumps Hungyu Lin
2026-11-08 2:56 ` Hungyu Lin [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261108025632.10799-4-dennylin0707@gmail.com \
--to=dennylin0707@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=ihor.solodrai@linux.dev \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=qmo@kernel.org \
--cc=shuah@kernel.org \
--cc=yonghong.song@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®