* [PATCH bpf-next 0/2] bpftool: Support symbolic map creation flags
@ 2026-09-06 17:07 Tianyi Chen
2026-09-06 17:07 ` [PATCH bpf-next 1/2] bpftool: Accept " Tianyi Chen
` (2 more replies)
0 siblings, 3 replies; 16+ messages in thread
From: Tianyi Chen @ 2026-09-06 17:07 UTC (permalink / raw)
To: bpf
Cc: Tianyi Chen, Quentin Monnet, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
Emil Tsalapatis, Ihor Solodrai, Shuah Khan, linux-kernel,
linux-kselftest
This series adds comma-separated BPF_F_* names to map create flags,
while retaining base-0 numeric input. It also documents the syntax,
completes names within lists, and tests the resulting kernel map flags
and invalid-input diagnostics.
This addresses the map creation part of:
https://github.com/libbpf/bpftool/issues/57
The series is based on bpf-next and is independent of the ring buffer
and batch-dump series sent alongside it.
Validation:
- Full bpftool build and focused BPF selftests build with LLVM 20.
- All 29 bpftool_map_flags subtests passed in an x86-64 KVM guest
running Linux 7.3.0-rc1, using a bpftool built with only this series.
- Bash syntax and actual completion candidates checked with and without
comma in COMP_WORDBREAKS; bpftool-map man page generated successfully.
Only focused BPF tests were run; this does not claim a full BPF selftest
suite run. Strict checkpatch has no errors or checks; its new-file
warning is covered by the existing BPF/selftests MAINTAINERS patterns.
Integration check: these three independent series also applied and built
together with my previously posted recursive map-dump v2 series. The
combined 64 subtests passed with no skips or failures in the same guest.
Tianyi Chen (2):
bpftool: Accept symbolic map creation flags
selftests/bpf: Cover symbolic bpftool map creation flags
.../bpf/bpftool/Documentation/bpftool-map.rst | 13 ++-
tools/bpf/bpftool/bash-completion/bpftool | 25 ++++-
tools/bpf/bpftool/map.c | 77 ++++++++++++++-
.../bpf/prog_tests/bpftool_map_flags.c | 99 +++++++++++++++++++
4 files changed, 208 insertions(+), 6 deletions(-)
create mode 100644 tools/testing/selftests/bpf/prog_tests/bpftool_map_flags.c
--
2.55.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH bpf-next 1/2] bpftool: Accept symbolic map creation flags
2026-09-06 17:07 [PATCH bpf-next 0/2] bpftool: Support symbolic map creation flags Tianyi Chen
@ 2026-09-06 17:07 ` Tianyi Chen
2026-09-06 18:16 ` bot+bpf-ci
2026-09-06 17:07 ` [PATCH bpf-next 2/2] selftests/bpf: Cover symbolic bpftool " Tianyi Chen
2026-09-07 1:20 ` [PATCH bpf-next v2 0/2] bpftool: Support symbolic " Tianyi Chen
2 siblings, 1 reply; 16+ messages in thread
From: Tianyi Chen @ 2026-09-06 17:07 UTC (permalink / raw)
To: bpf
Cc: Tianyi Chen, Quentin Monnet, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
Emil Tsalapatis, Ihor Solodrai, Shuah Khan, linux-kernel,
linux-kselftest
Accept comma-separated BPF_F_* names for map create flags, so callers
can use the UAPI names without looking up their numeric values. Keep
base-0 numeric input, including bits unknown to this bpftool.
Reject empty names, unknown names, mixed numeric and symbolic lists,
and values outside the unsigned 32-bit range. Limit symbolic names to
map creation flags and let the kernel validate map-specific combinations.
Document the syntax and complete names within comma-separated lists.
Assisted-by: Codex:GPT-6
Signed-off-by: Tianyi Chen <hi@tychen.cc>
---
.../bpf/bpftool/Documentation/bpftool-map.rst | 13 +++-
tools/bpf/bpftool/bash-completion/bpftool | 25 +++++-
tools/bpf/bpftool/map.c | 77 ++++++++++++++++++-
3 files changed, 109 insertions(+), 6 deletions(-)
diff --git a/tools/bpf/bpftool/Documentation/bpftool-map.rst b/tools/bpf/bpftool/Documentation/bpftool-map.rst
index 5daf3de5c74..375321d5582 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-map.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-map.rst
@@ -76,9 +76,16 @@ bpftool map { show | list } [*MAP*]
bpftool map create *FILE* type *TYPE* key *KEY_SIZE* value *VALUE_SIZE* entries *MAX_ENTRIES* name *NAME* [flags *FLAGS*] [inner_map *MAP*] [offload_dev *NAME*]
Create a new map with given parameters and pin it to *bpffs* as *FILE*.
- *FLAGS* should be an integer which is the combination of desired flags,
- e.g. 1024 for **BPF_F_MMAPABLE** (see bpf.h UAPI header for existing
- flags).
+ *FLAGS* accepts an unsigned 32-bit integer combining the desired flags
+ (decimal, hexadecimal with a **0x** prefix, or octal with a **0** prefix),
+ or a comma-separated list of full, case-sensitive map creation flag names
+ from the bpf.h UAPI header. For example, **1024**, **0x400**, and
+ **BPF_F_MMAPABLE** are equivalent. Multiple names are combined with
+ bitwise OR, for example **BPF_F_NO_PREALLOC,BPF_F_RDONLY_PROG**.
+ Repeated names are allowed. Empty list elements, abbreviated names, and
+ lists mixing numbers with names are not accepted. Use **0** for no flags.
+ Numeric values can include bits unknown to bpftool. The kernel checks
+ whether the flags are valid for the requested map type.
To create maps of type array-of-maps or hash-of-maps, the **inner_map**
keyword must be used to pass an inner map. The kernel needs it to collect
diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool
index 75cbcb512eb..95f16fff876 100644
--- a/tools/bpf/bpftool/bash-completion/bpftool
+++ b/tools/bpf/bpftool/bash-completion/bpftool
@@ -718,6 +718,10 @@ _bpftool()
esac
;;
create)
+ # Keep a flags list together if readline splits at commas.
+ if [[ $COMP_WORDBREAKS == *,* && ( $cur == , || $prev == , ) ]]; then
+ _get_comp_words_by_ref -n , cur prev
+ fi
case $prev in
$command)
_filedir
@@ -729,7 +733,26 @@ _bpftool()
COMPREPLY=( $( compgen -W "$BPFTOOL_MAP_CREATE_TYPES" -- "$cur" ) )
return 0
;;
- key|value|flags|entries)
+ flags)
+ local flags='BPF_F_NO_PREALLOC BPF_F_NO_COMMON_LRU
+ BPF_F_NUMA_NODE BPF_F_RDONLY BPF_F_WRONLY
+ BPF_F_STACK_BUILD_ID BPF_F_ZERO_SEED
+ BPF_F_RDONLY_PROG BPF_F_WRONLY_PROG BPF_F_CLONE
+ BPF_F_MMAPABLE BPF_F_PRESERVE_ELEMS BPF_F_INNER_MAP
+ BPF_F_LINK BPF_F_VTYPE_BTF_OBJ_FD BPF_F_TOKEN_FD
+ BPF_F_SEGV_ON_FAULT BPF_F_NO_USER_CONV
+ BPF_F_RB_OVERWRITE'
+ local prefix= flag
+ # Readline replaces only the suffix after a word break.
+ if [[ $cur == *,* && $COMP_WORDBREAKS != *,* ]]; then
+ prefix="${cur%,*},"
+ fi
+ for flag in $(compgen -W "$flags" -- "${cur##*,}"); do
+ COMPREPLY+=( "${prefix}${flag}" )
+ done
+ return 0
+ ;;
+ key|value|entries)
return 0
;;
inner_map)
diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
index 684a8fb7241..d703af60d0b 100644
--- a/tools/bpf/bpftool/map.c
+++ b/tools/bpf/bpftool/map.c
@@ -1250,6 +1250,73 @@ static int do_pin(int argc, char **argv)
return err;
}
+static const struct {
+ const char *name;
+ __u32 value;
+} map_create_flags[] = {
+#define MAP_CREATE_FLAG(flag) { #flag, flag }
+ MAP_CREATE_FLAG(BPF_F_NO_PREALLOC),
+ MAP_CREATE_FLAG(BPF_F_NO_COMMON_LRU),
+ MAP_CREATE_FLAG(BPF_F_NUMA_NODE),
+ MAP_CREATE_FLAG(BPF_F_RDONLY),
+ MAP_CREATE_FLAG(BPF_F_WRONLY),
+ MAP_CREATE_FLAG(BPF_F_STACK_BUILD_ID),
+ MAP_CREATE_FLAG(BPF_F_ZERO_SEED),
+ MAP_CREATE_FLAG(BPF_F_RDONLY_PROG),
+ MAP_CREATE_FLAG(BPF_F_WRONLY_PROG),
+ MAP_CREATE_FLAG(BPF_F_CLONE),
+ MAP_CREATE_FLAG(BPF_F_MMAPABLE),
+ MAP_CREATE_FLAG(BPF_F_PRESERVE_ELEMS),
+ MAP_CREATE_FLAG(BPF_F_INNER_MAP),
+ MAP_CREATE_FLAG(BPF_F_LINK),
+ MAP_CREATE_FLAG(BPF_F_VTYPE_BTF_OBJ_FD),
+ MAP_CREATE_FLAG(BPF_F_TOKEN_FD),
+ MAP_CREATE_FLAG(BPF_F_SEGV_ON_FAULT),
+ MAP_CREATE_FLAG(BPF_F_NO_USER_CONV),
+ MAP_CREATE_FLAG(BPF_F_RB_OVERWRITE),
+#undef MAP_CREATE_FLAG
+};
+
+static int parse_map_create_flags(const char *arg, __u32 *flags)
+{
+ const char *name = arg, *comma;
+ long long value;
+ __u32 parsed = 0;
+ size_t len, i;
+ char *end;
+
+ /* Keep base-0 numeric input, including bits unknown to this bpftool. */
+ if (strncmp(arg, "BPF_F_", 6)) {
+ errno = 0;
+ value = strtoll(arg, &end, 0);
+ if (errno || end == arg || *end || value < 0 || value > UINT32_MAX)
+ goto invalid;
+ *flags = value;
+ return 0;
+ }
+
+ do {
+ comma = strchr(name, ',');
+ len = comma ? (size_t)(comma - name) : strlen(name);
+ for (i = 0; i < ARRAY_SIZE(map_create_flags); i++) {
+ if (strlen(map_create_flags[i].name) == len &&
+ !strncmp(name, map_create_flags[i].name, len))
+ break;
+ }
+ if (i == ARRAY_SIZE(map_create_flags))
+ goto invalid;
+ parsed |= map_create_flags[i].value;
+ if (comma)
+ name = comma + 1;
+ } while (comma);
+
+ *flags = parsed;
+ return 0;
+invalid:
+ p_err("can't parse %s as map creation flags", arg);
+ return -1;
+}
+
static int do_create(int argc, char **argv)
{
LIBBPF_OPTS(bpf_map_create_opts, attr);
@@ -1301,9 +1368,14 @@ static int do_create(int argc, char **argv)
"max entries"))
goto exit;
} else if (is_prefix(*argv, "flags")) {
- if (parse_u32_arg(&argc, &argv, &attr.map_flags,
- "flags"))
+ NEXT_ARG();
+ if (attr.map_flags) {
+ p_err("flags already specified");
+ goto exit;
+ }
+ if (parse_map_create_flags(*argv, &attr.map_flags))
goto exit;
+ NEXT_ARG();
} else if (is_prefix(*argv, "dev")) {
p_info("Warning: 'bpftool map create [...] dev <ifname>' syntax is deprecated.\n"
"Going further, please use 'offload_dev <ifname>' to request hardware offload for the map.");
@@ -1474,6 +1546,7 @@ static int do_help(int argc, char **argv)
" DATA := { [hex] BYTES }\n"
" " HELP_SPEC_PROGRAM "\n"
" VALUE := { DATA | MAP | PROG }\n"
+ " FLAGS := { integer | BPF_F_NAME[,BPF_F_NAME...] }\n"
" UPDATE_FLAGS := { any | exist | noexist }\n"
" TYPE := { hash | array | prog_array | perf_event_array | percpu_hash |\n"
" percpu_array | stack_trace | cgroup_array | lru_hash |\n"
--
2.55.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH bpf-next 2/2] selftests/bpf: Cover symbolic bpftool map creation flags
2026-09-06 17:07 [PATCH bpf-next 0/2] bpftool: Support symbolic map creation flags Tianyi Chen
2026-09-06 17:07 ` [PATCH bpf-next 1/2] bpftool: Accept " Tianyi Chen
@ 2026-09-06 17:07 ` Tianyi Chen
2026-09-07 1:20 ` [PATCH bpf-next v2 0/2] bpftool: Support symbolic " Tianyi Chen
2 siblings, 0 replies; 16+ messages in thread
From: Tianyi Chen @ 2026-09-06 17:07 UTC (permalink / raw)
To: bpf
Cc: Tianyi Chen, Quentin Monnet, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
Emil Tsalapatis, Ihor Solodrai, Shuah Khan, linux-kernel,
linux-kselftest
Check numeric and symbolic map creation flags, including combined and
repeated names, against map information read independently with libbpf.
Exercise malformed names and lists, update-only flags, empty input and
numeric range errors. Verify rejected input leaves no pinned map.
Assisted-by: Codex:GPT-6
Signed-off-by: Tianyi Chen <hi@tychen.cc>
---
.../bpf/prog_tests/bpftool_map_flags.c | 99 +++++++++++++++++++
1 file changed, 99 insertions(+)
create mode 100644 tools/testing/selftests/bpf/prog_tests/bpftool_map_flags.c
diff --git a/tools/testing/selftests/bpf/prog_tests/bpftool_map_flags.c b/tools/testing/selftests/bpf/prog_tests/bpftool_map_flags.c
new file mode 100644
index 00000000000..140401dd254
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/bpftool_map_flags.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <errno.h>
+#include <unistd.h>
+#include <bpf/bpf.h>
+#include <bpftool_helpers.h>
+#include <test_progs.h>
+
+static const struct map_flags_test {
+ const char *name;
+ const char *flags;
+ __u32 expected_flags;
+ const char *error;
+} tests[] = {
+ { "zero", "0", 0 },
+ { "decimal", "129", BPF_F_NO_PREALLOC | BPF_F_RDONLY_PROG },
+ { "hexadecimal", "0x81", BPF_F_NO_PREALLOC | BPF_F_RDONLY_PROG },
+ { "octal", "0201", BPF_F_NO_PREALLOC | BPF_F_RDONLY_PROG },
+ { "positive_sign", "+1", BPF_F_NO_PREALLOC },
+ { "single_name", "BPF_F_NO_PREALLOC", BPF_F_NO_PREALLOC },
+ { "combined_names", "BPF_F_NO_PREALLOC,BPF_F_RDONLY_PROG",
+ BPF_F_NO_PREALLOC | BPF_F_RDONLY_PROG },
+ { "repeated_name", "BPF_F_NO_PREALLOC,BPF_F_NO_PREALLOC", BPF_F_NO_PREALLOC },
+ { "unknown_name", "BPF_F_NOT_A_MAP_FLAG", 0, "can't parse" },
+ { "other_command_flag", "BPF_F_PATH_FD", 0, "can't parse" },
+ { "update_flag", "BPF_F_LOCK", 0, "can't parse" },
+ { "abbreviated_name", "BPF_F_NO_PRE", 0, "can't parse" },
+ { "lowercase_name", "bpf_f_no_prealloc", 0, "can't parse" },
+ { "empty", "", 0, "can't parse" },
+ { "whitespace", " ", 0, "can't parse" },
+ { "empty_list", ",", 0, "can't parse" },
+ { "leading_comma", ",BPF_F_NO_PREALLOC", 0, "can't parse" },
+ { "trailing_comma", "BPF_F_NO_PREALLOC,", 0, "can't parse" },
+ { "empty_element", "BPF_F_NO_PREALLOC,,BPF_F_RDONLY_PROG", 0, "can't parse" },
+ { "number_then_name", "1,BPF_F_RDONLY_PROG", 0, "can't parse" },
+ { "name_then_number", "BPF_F_NO_PREALLOC,128", 0, "can't parse" },
+ { "numeric_list", "1,128", 0, "can't parse" },
+ { "whitespace_in_list", "BPF_F_NO_PREALLOC, BPF_F_RDONLY_PROG", 0, "can't parse" },
+ { "overflow_u32", "4294967296", 0, "can't parse" },
+ { "overflow_hex", "0x100000000", 0, "can't parse" },
+ { "overflow_u64", "18446744073709551616", 0, "can't parse" },
+ { "negative", "-1", 0, "can't parse" },
+ /* Numeric bits unknown to bpftool must still reach the kernel. */
+ { "all_bits", "0xffffffff", 0, "map create failed" },
+ { "invalid_combination", "BPF_F_RDONLY,BPF_F_WRONLY", 0, "map create failed" },
+};
+
+static void test_map_flags(const struct map_flags_test *test, const char *path)
+{
+ char cmd[MAX_BPFTOOL_CMD_LEN], output[1024] = {};
+ struct bpf_map_info info = {};
+ __u32 info_len = sizeof(info);
+ int fd, err;
+
+ /* Let the flags parser handle negative numbers instead of getopt(). */
+ err = snprintf(cmd, sizeof(cmd),
+ "-- map create %s type hash key 4 value 4 entries 1 name flags_test flags '%s' 2>&1",
+ path, test->flags);
+ if (!ASSERT_GT(err, 0, "format_command") ||
+ !ASSERT_LT(err, sizeof(cmd), "command_length"))
+ return;
+
+ err = get_bpftool_command_output(cmd, output, sizeof(output));
+ if (test->error) {
+ ASSERT_NEQ(err, 0, "reject_flags");
+ ASSERT_HAS_SUBSTR(output, test->error, "error_message");
+ err = access(path, F_OK);
+ ASSERT_EQ(err, -1, "no_pin");
+ ASSERT_EQ(errno, ENOENT, "pin_absent");
+ goto cleanup;
+ }
+ if (!ASSERT_OK(err, "create_map"))
+ goto cleanup;
+
+ fd = bpf_obj_get(path);
+ if (!ASSERT_OK_FD(fd, "open_map"))
+ goto cleanup;
+ if (ASSERT_OK(bpf_map_get_info_by_fd(fd, &info, &info_len), "map_info"))
+ ASSERT_EQ(info.map_flags, test->expected_flags, "map_flags");
+ close(fd);
+cleanup:
+ unlink(path);
+}
+
+void test_bpftool_map_flags(void)
+{
+ char dir[] = "/sys/fs/bpf/bpftool_flags_XXXXXX";
+ char path[sizeof(dir) + sizeof("/map")];
+ int i;
+
+ if (!ASSERT_OK_PTR(mkdtemp(dir), "create_pin_dir"))
+ return;
+ snprintf(path, sizeof(path), "%s/map", dir);
+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
+ if (test__start_subtest(tests[i].name))
+ test_map_flags(&tests[i], path);
+ }
+ ASSERT_OK(rmdir(dir), "remove_pin_dir");
+}
--
2.55.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH bpf-next 1/2] bpftool: Accept symbolic map creation flags
2026-09-06 17:07 ` [PATCH bpf-next 1/2] bpftool: Accept " Tianyi Chen
@ 2026-09-06 18:16 ` bot+bpf-ci
0 siblings, 0 replies; 16+ messages in thread
From: bot+bpf-ci @ 2026-09-06 18:16 UTC (permalink / raw)
To: hi, bpf
Cc: hi, qmo, ast, daniel, andrii, eddyz87, memxor, martin.lau, song,
yonghong.song, jolsa, emil, ihor.solodrai, shuah, linux-kernel,
linux-kselftest, ast, andrii, daniel, martin.lau, eddyz87,
yonghong.song, mason, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 3502 bytes --]
> diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool
> index 75cbcb512eba..95f16fff876e 100644
> --- a/tools/bpf/bpftool/bash-completion/bpftool
> +++ b/tools/bpf/bpftool/bash-completion/bpftool
> @@ -718,6 +718,10 @@ _bpftool()
> esac
> ;;
> create)
> + # Keep a flags list together if readline splits at commas.
> + if [[ $COMP_WORDBREAKS == *,* && ( $cur == , || $prev == , ) ]]; then
> + _get_comp_words_by_ref -n , cur prev
> + fi
> case $prev in
> $command)
> _filedir
> @@ -729,7 +733,26 @@ _bpftool()
> COMPREPLY=( $( compgen -W "$BPFTOOL_MAP_CREATE_TYPES" -- "$cur" ) )
> return 0
> ;;
> - key|value|flags|entries)
> + flags)
> + local flags='BPF_F_NO_PREALLOC BPF_F_NO_COMMON_LRU
> + BPF_F_NUMA_NODE BPF_F_RDONLY BPF_F_WRONLY
> + BPF_F_STACK_BUILD_ID BPF_F_ZERO_SEED
> + BPF_F_RDONLY_PROG BPF_F_WRONLY_PROG BPF_F_CLONE
> + BPF_F_MMAPABLE BPF_F_PRESERVE_ELEMS BPF_F_INNER_MAP
> + BPF_F_LINK BPF_F_VTYPE_BTF_OBJ_FD BPF_F_TOKEN_FD
> + BPF_F_SEGV_ON_FAULT BPF_F_NO_USER_CONV
> + BPF_F_RB_OVERWRITE'
> + local prefix= flag
> + # Readline replaces only the suffix after a word break.
> + if [[ $cur == *,* && $COMP_WORDBREAKS != *,* ]]; then
> + prefix="${cur%,*},"
> + fi
> + for flag in $(compgen -W "$flags" -- "${cur##*,}"); do
> + COMPREPLY+=( "${prefix}${flag}" )
> + done
> + return 0
> + ;;
> + key|value|entries)
> return 0
> ;;
Can the comma-separated completion work as written? When bash completes a
single match, it appends a trailing space, which splits the argument into
two words. Example:
$ bpftool map create /sys/fs/bpf/m type hash key 4 value 4 \
entries 1 name m flags BPF_F_MM<TAB>
completes to:
... flags BPF_F_MMAPABLE ,BPF_F_RDONLY
That becomes two argv words (the space before the comma). do_create() in
map.c consumes "flags BPF_F_MMAPABLE" and re-enters its loop with only
",BPF_F_RDONLY" left, so REQ_ARGS(2) fails with the message "'
BPF_F_MMAPABLE' needs at least 2 arguments, 1 found". To build a multi-
flag list the user has to delete the inserted space by hand, which defeats
the prefix-preservation logic at lines 745-749.
The usual fix is `compopt -o nospace` when emitting list elements (guarded
for shells without compopt), or suppressing the space only when more than
one flag remains plausible.
[ ... ]
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/34048916873
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH bpf-next v2 0/2] bpftool: Support symbolic map creation flags
2026-09-06 17:07 [PATCH bpf-next 0/2] bpftool: Support symbolic map creation flags Tianyi Chen
2026-09-06 17:07 ` [PATCH bpf-next 1/2] bpftool: Accept " Tianyi Chen
2026-09-06 17:07 ` [PATCH bpf-next 2/2] selftests/bpf: Cover symbolic bpftool " Tianyi Chen
@ 2026-09-07 1:20 ` Tianyi Chen
2026-09-07 1:20 ` [PATCH bpf-next v2 1/2] bpftool: Accept " Tianyi Chen
` (2 more replies)
2 siblings, 3 replies; 16+ messages in thread
From: Tianyi Chen @ 2026-09-07 1:20 UTC (permalink / raw)
To: bpf; +Cc: Tianyi Chen, Quentin Monnet, linux-kselftest
Add comma-separated BPF_F_* names to map create flags while retaining
base-0 numeric input, with matching documentation, completion and tests.
Changes in v2:
- Complete list elements without adding a trailing space, so the user
can immediately append another comma-separated flag.
Validation:
- Real Bash readline completion checked with default COMP_WORDBREAKS
and with comma included: unique first and second flags stay in one
argument; after an explicit space, entries completion adds its normal
trailing space. Bash syntax and diff checks passed.
- All 29 map_flags subtests passed in the integration run described below.
v1: https://lore.kernel.org/r/20260906170715.1212085-1-hi@tychen.cc
Request: https://github.com/libbpf/bpftool/issues/57
Integration validation: the flags, ring-buffer and batch v2 series plus
recursive dump v3 built together with LLVM 20. All 69 focused BPF subtests
passed in an x86-64 KVM guest running Linux 7.3.0-rc1, with no skips or
failures. The bpftool-map man page also built successfully. This is a
focused run, not the full BPF selftest suite.
Tianyi Chen (2):
bpftool: Accept symbolic map creation flags
selftests/bpf: Cover symbolic bpftool map creation flags
.../bpf/bpftool/Documentation/bpftool-map.rst | 13 ++-
tools/bpf/bpftool/bash-completion/bpftool | 26 ++++-
tools/bpf/bpftool/map.c | 77 ++++++++++++++-
.../bpf/prog_tests/bpftool_map_flags.c | 99 +++++++++++++++++++
4 files changed, 209 insertions(+), 6 deletions(-)
create mode 100644 tools/testing/selftests/bpf/prog_tests/bpftool_map_flags.c
--
2.55.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH bpf-next v2 1/2] bpftool: Accept symbolic map creation flags
2026-09-07 1:20 ` [PATCH bpf-next v2 0/2] bpftool: Support symbolic " Tianyi Chen
@ 2026-09-07 1:20 ` Tianyi Chen
2026-09-07 2:04 ` bot+bpf-ci
2026-09-07 1:20 ` [PATCH bpf-next v2 2/2] selftests/bpf: Cover symbolic bpftool " Tianyi Chen
2026-09-07 2:15 ` [PATCH bpf-next v3 0/2] bpftool: Support symbolic " Tianyi Chen
2 siblings, 1 reply; 16+ messages in thread
From: Tianyi Chen @ 2026-09-07 1:20 UTC (permalink / raw)
To: bpf; +Cc: Tianyi Chen, Quentin Monnet, linux-kselftest
Accept comma-separated BPF_F_* names for map create flags, so callers
can use the UAPI names without looking up their numeric values. Keep
base-0 numeric input, including bits unknown to this bpftool.
Reject empty names, unknown names, mixed numeric and symbolic lists,
and values outside the unsigned 32-bit range. Limit symbolic names to
map creation flags and let the kernel validate map-specific combinations.
Document the syntax and complete names within comma-separated lists.
Avoid appending a space to completed list elements so another flag can
be added to the same argument.
Link: https://github.com/libbpf/bpftool/issues/57
Assisted-by: Codex:GPT-6
Signed-off-by: Tianyi Chen <hi@tychen.cc>
---
.../bpf/bpftool/Documentation/bpftool-map.rst | 13 +++-
tools/bpf/bpftool/bash-completion/bpftool | 26 ++++++-
tools/bpf/bpftool/map.c | 77 ++++++++++++++++++-
3 files changed, 110 insertions(+), 6 deletions(-)
diff --git a/tools/bpf/bpftool/Documentation/bpftool-map.rst b/tools/bpf/bpftool/Documentation/bpftool-map.rst
index 5daf3de5c74..375321d5582 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-map.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-map.rst
@@ -76,9 +76,16 @@ bpftool map { show | list } [*MAP*]
bpftool map create *FILE* type *TYPE* key *KEY_SIZE* value *VALUE_SIZE* entries *MAX_ENTRIES* name *NAME* [flags *FLAGS*] [inner_map *MAP*] [offload_dev *NAME*]
Create a new map with given parameters and pin it to *bpffs* as *FILE*.
- *FLAGS* should be an integer which is the combination of desired flags,
- e.g. 1024 for **BPF_F_MMAPABLE** (see bpf.h UAPI header for existing
- flags).
+ *FLAGS* accepts an unsigned 32-bit integer combining the desired flags
+ (decimal, hexadecimal with a **0x** prefix, or octal with a **0** prefix),
+ or a comma-separated list of full, case-sensitive map creation flag names
+ from the bpf.h UAPI header. For example, **1024**, **0x400**, and
+ **BPF_F_MMAPABLE** are equivalent. Multiple names are combined with
+ bitwise OR, for example **BPF_F_NO_PREALLOC,BPF_F_RDONLY_PROG**.
+ Repeated names are allowed. Empty list elements, abbreviated names, and
+ lists mixing numbers with names are not accepted. Use **0** for no flags.
+ Numeric values can include bits unknown to bpftool. The kernel checks
+ whether the flags are valid for the requested map type.
To create maps of type array-of-maps or hash-of-maps, the **inner_map**
keyword must be used to pass an inner map. The kernel needs it to collect
diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool
index 75cbcb512eb..73f6a811826 100644
--- a/tools/bpf/bpftool/bash-completion/bpftool
+++ b/tools/bpf/bpftool/bash-completion/bpftool
@@ -718,6 +718,10 @@ _bpftool()
esac
;;
create)
+ # Keep a flags list together if readline splits at commas.
+ if [[ $COMP_WORDBREAKS == *,* && ( $cur == , || $prev == , ) ]]; then
+ _get_comp_words_by_ref -n , cur prev
+ fi
case $prev in
$command)
_filedir
@@ -729,7 +733,27 @@ _bpftool()
COMPREPLY=( $( compgen -W "$BPFTOOL_MAP_CREATE_TYPES" -- "$cur" ) )
return 0
;;
- key|value|flags|entries)
+ flags)
+ compopt -o nospace
+ local flags='BPF_F_NO_PREALLOC BPF_F_NO_COMMON_LRU
+ BPF_F_NUMA_NODE BPF_F_RDONLY BPF_F_WRONLY
+ BPF_F_STACK_BUILD_ID BPF_F_ZERO_SEED
+ BPF_F_RDONLY_PROG BPF_F_WRONLY_PROG BPF_F_CLONE
+ BPF_F_MMAPABLE BPF_F_PRESERVE_ELEMS BPF_F_INNER_MAP
+ BPF_F_LINK BPF_F_VTYPE_BTF_OBJ_FD BPF_F_TOKEN_FD
+ BPF_F_SEGV_ON_FAULT BPF_F_NO_USER_CONV
+ BPF_F_RB_OVERWRITE'
+ local prefix= flag
+ # Readline replaces only the suffix after a word break.
+ if [[ $cur == *,* && $COMP_WORDBREAKS != *,* ]]; then
+ prefix="${cur%,*},"
+ fi
+ for flag in $(compgen -W "$flags" -- "${cur##*,}"); do
+ COMPREPLY+=( "${prefix}${flag}" )
+ done
+ return 0
+ ;;
+ key|value|entries)
return 0
;;
inner_map)
diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
index 684a8fb7241..d703af60d0b 100644
--- a/tools/bpf/bpftool/map.c
+++ b/tools/bpf/bpftool/map.c
@@ -1250,6 +1250,73 @@ static int do_pin(int argc, char **argv)
return err;
}
+static const struct {
+ const char *name;
+ __u32 value;
+} map_create_flags[] = {
+#define MAP_CREATE_FLAG(flag) { #flag, flag }
+ MAP_CREATE_FLAG(BPF_F_NO_PREALLOC),
+ MAP_CREATE_FLAG(BPF_F_NO_COMMON_LRU),
+ MAP_CREATE_FLAG(BPF_F_NUMA_NODE),
+ MAP_CREATE_FLAG(BPF_F_RDONLY),
+ MAP_CREATE_FLAG(BPF_F_WRONLY),
+ MAP_CREATE_FLAG(BPF_F_STACK_BUILD_ID),
+ MAP_CREATE_FLAG(BPF_F_ZERO_SEED),
+ MAP_CREATE_FLAG(BPF_F_RDONLY_PROG),
+ MAP_CREATE_FLAG(BPF_F_WRONLY_PROG),
+ MAP_CREATE_FLAG(BPF_F_CLONE),
+ MAP_CREATE_FLAG(BPF_F_MMAPABLE),
+ MAP_CREATE_FLAG(BPF_F_PRESERVE_ELEMS),
+ MAP_CREATE_FLAG(BPF_F_INNER_MAP),
+ MAP_CREATE_FLAG(BPF_F_LINK),
+ MAP_CREATE_FLAG(BPF_F_VTYPE_BTF_OBJ_FD),
+ MAP_CREATE_FLAG(BPF_F_TOKEN_FD),
+ MAP_CREATE_FLAG(BPF_F_SEGV_ON_FAULT),
+ MAP_CREATE_FLAG(BPF_F_NO_USER_CONV),
+ MAP_CREATE_FLAG(BPF_F_RB_OVERWRITE),
+#undef MAP_CREATE_FLAG
+};
+
+static int parse_map_create_flags(const char *arg, __u32 *flags)
+{
+ const char *name = arg, *comma;
+ long long value;
+ __u32 parsed = 0;
+ size_t len, i;
+ char *end;
+
+ /* Keep base-0 numeric input, including bits unknown to this bpftool. */
+ if (strncmp(arg, "BPF_F_", 6)) {
+ errno = 0;
+ value = strtoll(arg, &end, 0);
+ if (errno || end == arg || *end || value < 0 || value > UINT32_MAX)
+ goto invalid;
+ *flags = value;
+ return 0;
+ }
+
+ do {
+ comma = strchr(name, ',');
+ len = comma ? (size_t)(comma - name) : strlen(name);
+ for (i = 0; i < ARRAY_SIZE(map_create_flags); i++) {
+ if (strlen(map_create_flags[i].name) == len &&
+ !strncmp(name, map_create_flags[i].name, len))
+ break;
+ }
+ if (i == ARRAY_SIZE(map_create_flags))
+ goto invalid;
+ parsed |= map_create_flags[i].value;
+ if (comma)
+ name = comma + 1;
+ } while (comma);
+
+ *flags = parsed;
+ return 0;
+invalid:
+ p_err("can't parse %s as map creation flags", arg);
+ return -1;
+}
+
static int do_create(int argc, char **argv)
{
LIBBPF_OPTS(bpf_map_create_opts, attr);
@@ -1301,9 +1368,14 @@ static int do_create(int argc, char **argv)
"max entries"))
goto exit;
} else if (is_prefix(*argv, "flags")) {
- if (parse_u32_arg(&argc, &argv, &attr.map_flags,
- "flags"))
+ NEXT_ARG();
+ if (attr.map_flags) {
+ p_err("flags already specified");
+ goto exit;
+ }
+ if (parse_map_create_flags(*argv, &attr.map_flags))
goto exit;
+ NEXT_ARG();
} else if (is_prefix(*argv, "dev")) {
p_info("Warning: 'bpftool map create [...] dev <ifname>' syntax is deprecated.\n"
"Going further, please use 'offload_dev <ifname>' to request hardware offload for the map.");
@@ -1474,6 +1546,7 @@ static int do_help(int argc, char **argv)
" DATA := { [hex] BYTES }\n"
" " HELP_SPEC_PROGRAM "\n"
" VALUE := { DATA | MAP | PROG }\n"
+ " FLAGS := { integer | BPF_F_NAME[,BPF_F_NAME...] }\n"
" UPDATE_FLAGS := { any | exist | noexist }\n"
" TYPE := { hash | array | prog_array | perf_event_array | percpu_hash |\n"
" percpu_array | stack_trace | cgroup_array | lru_hash |\n"
--
2.55.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH bpf-next v2 2/2] selftests/bpf: Cover symbolic bpftool map creation flags
2026-09-07 1:20 ` [PATCH bpf-next v2 0/2] bpftool: Support symbolic " Tianyi Chen
2026-09-07 1:20 ` [PATCH bpf-next v2 1/2] bpftool: Accept " Tianyi Chen
@ 2026-09-07 1:20 ` Tianyi Chen
2026-09-07 2:04 ` bot+bpf-ci
2026-09-07 2:15 ` [PATCH bpf-next v3 0/2] bpftool: Support symbolic " Tianyi Chen
2 siblings, 1 reply; 16+ messages in thread
From: Tianyi Chen @ 2026-09-07 1:20 UTC (permalink / raw)
To: bpf; +Cc: Tianyi Chen, Quentin Monnet, linux-kselftest
Check numeric and symbolic map creation flags, including combined and
repeated names, against map information read independently with libbpf.
Exercise malformed names and lists, update-only flags, empty input and
numeric range errors. Verify rejected input leaves no pinned map.
Assisted-by: Codex:GPT-6
Signed-off-by: Tianyi Chen <hi@tychen.cc>
---
.../bpf/prog_tests/bpftool_map_flags.c | 99 +++++++++++++++++++
1 file changed, 99 insertions(+)
create mode 100644 tools/testing/selftests/bpf/prog_tests/bpftool_map_flags.c
diff --git a/tools/testing/selftests/bpf/prog_tests/bpftool_map_flags.c b/tools/testing/selftests/bpf/prog_tests/bpftool_map_flags.c
new file mode 100644
index 00000000000..140401dd254
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/bpftool_map_flags.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <errno.h>
+#include <unistd.h>
+#include <bpf/bpf.h>
+#include <bpftool_helpers.h>
+#include <test_progs.h>
+
+static const struct map_flags_test {
+ const char *name;
+ const char *flags;
+ __u32 expected_flags;
+ const char *error;
+} tests[] = {
+ { "zero", "0", 0 },
+ { "decimal", "129", BPF_F_NO_PREALLOC | BPF_F_RDONLY_PROG },
+ { "hexadecimal", "0x81", BPF_F_NO_PREALLOC | BPF_F_RDONLY_PROG },
+ { "octal", "0201", BPF_F_NO_PREALLOC | BPF_F_RDONLY_PROG },
+ { "positive_sign", "+1", BPF_F_NO_PREALLOC },
+ { "single_name", "BPF_F_NO_PREALLOC", BPF_F_NO_PREALLOC },
+ { "combined_names", "BPF_F_NO_PREALLOC,BPF_F_RDONLY_PROG",
+ BPF_F_NO_PREALLOC | BPF_F_RDONLY_PROG },
+ { "repeated_name", "BPF_F_NO_PREALLOC,BPF_F_NO_PREALLOC", BPF_F_NO_PREALLOC },
+ { "unknown_name", "BPF_F_NOT_A_MAP_FLAG", 0, "can't parse" },
+ { "other_command_flag", "BPF_F_PATH_FD", 0, "can't parse" },
+ { "update_flag", "BPF_F_LOCK", 0, "can't parse" },
+ { "abbreviated_name", "BPF_F_NO_PRE", 0, "can't parse" },
+ { "lowercase_name", "bpf_f_no_prealloc", 0, "can't parse" },
+ { "empty", "", 0, "can't parse" },
+ { "whitespace", " ", 0, "can't parse" },
+ { "empty_list", ",", 0, "can't parse" },
+ { "leading_comma", ",BPF_F_NO_PREALLOC", 0, "can't parse" },
+ { "trailing_comma", "BPF_F_NO_PREALLOC,", 0, "can't parse" },
+ { "empty_element", "BPF_F_NO_PREALLOC,,BPF_F_RDONLY_PROG", 0, "can't parse" },
+ { "number_then_name", "1,BPF_F_RDONLY_PROG", 0, "can't parse" },
+ { "name_then_number", "BPF_F_NO_PREALLOC,128", 0, "can't parse" },
+ { "numeric_list", "1,128", 0, "can't parse" },
+ { "whitespace_in_list", "BPF_F_NO_PREALLOC, BPF_F_RDONLY_PROG", 0, "can't parse" },
+ { "overflow_u32", "4294967296", 0, "can't parse" },
+ { "overflow_hex", "0x100000000", 0, "can't parse" },
+ { "overflow_u64", "18446744073709551616", 0, "can't parse" },
+ { "negative", "-1", 0, "can't parse" },
+ /* Numeric bits unknown to bpftool must still reach the kernel. */
+ { "all_bits", "0xffffffff", 0, "map create failed" },
+ { "invalid_combination", "BPF_F_RDONLY,BPF_F_WRONLY", 0, "map create failed" },
+};
+
+static void test_map_flags(const struct map_flags_test *test, const char *path)
+{
+ char cmd[MAX_BPFTOOL_CMD_LEN], output[1024] = {};
+ struct bpf_map_info info = {};
+ __u32 info_len = sizeof(info);
+ int fd, err;
+
+ /* Let the flags parser handle negative numbers instead of getopt(). */
+ err = snprintf(cmd, sizeof(cmd),
+ "-- map create %s type hash key 4 value 4 entries 1 name flags_test flags '%s' 2>&1",
+ path, test->flags);
+ if (!ASSERT_GT(err, 0, "format_command") ||
+ !ASSERT_LT(err, sizeof(cmd), "command_length"))
+ return;
+
+ err = get_bpftool_command_output(cmd, output, sizeof(output));
+ if (test->error) {
+ ASSERT_NEQ(err, 0, "reject_flags");
+ ASSERT_HAS_SUBSTR(output, test->error, "error_message");
+ err = access(path, F_OK);
+ ASSERT_EQ(err, -1, "no_pin");
+ ASSERT_EQ(errno, ENOENT, "pin_absent");
+ goto cleanup;
+ }
+ if (!ASSERT_OK(err, "create_map"))
+ goto cleanup;
+
+ fd = bpf_obj_get(path);
+ if (!ASSERT_OK_FD(fd, "open_map"))
+ goto cleanup;
+ if (ASSERT_OK(bpf_map_get_info_by_fd(fd, &info, &info_len), "map_info"))
+ ASSERT_EQ(info.map_flags, test->expected_flags, "map_flags");
+ close(fd);
+cleanup:
+ unlink(path);
+}
+
+void test_bpftool_map_flags(void)
+{
+ char dir[] = "/sys/fs/bpf/bpftool_flags_XXXXXX";
+ char path[sizeof(dir) + sizeof("/map")];
+ int i;
+
+ if (!ASSERT_OK_PTR(mkdtemp(dir), "create_pin_dir"))
+ return;
+ snprintf(path, sizeof(path), "%s/map", dir);
+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
+ if (test__start_subtest(tests[i].name))
+ test_map_flags(&tests[i], path);
+ }
+ ASSERT_OK(rmdir(dir), "remove_pin_dir");
+}
--
2.55.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH bpf-next v2 2/2] selftests/bpf: Cover symbolic bpftool map creation flags
2026-09-07 1:20 ` [PATCH bpf-next v2 2/2] selftests/bpf: Cover symbolic bpftool " Tianyi Chen
@ 2026-09-07 2:04 ` bot+bpf-ci
0 siblings, 0 replies; 16+ messages in thread
From: bot+bpf-ci @ 2026-09-07 2:04 UTC (permalink / raw)
To: hi, bpf
Cc: hi, qmo, linux-kselftest, ast, andrii, daniel, martin.lau,
eddyz87, yonghong.song, mason, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 3075 bytes --]
> diff --git a/tools/testing/selftests/bpf/prog_tests/bpftool_map_flags.c b/tools/testing/selftests/bpf/prog_tests/bpftool_map_flags.c
> new file mode 100644
> index 000000000000..140401dd2548
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/prog_tests/bpftool_map_flags.c
> @@ -0,0 +1,99 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +#include <errno.h>
> +#include <unistd.h>
> +#include <bpf/bpf.h>
> +#include <bpftool_helpers.h>
> +#include <test_progs.h>
> +
> +static const struct map_flags_test {
> + const char *name;
> + const char *flags;
> + __u32 expected_flags;
> + const char *error;
> +} tests[] = {
> + { "zero", "0", 0 },
> + { "decimal", "129", BPF_F_NO_PREALLOC | BPF_F_RDONLY_PROG },
> + { "hexadecimal", "0x81", BPF_F_NO_PREALLOC | BPF_F_RDONLY_PROG },
> + { "octal", "0201", BPF_F_NO_PREALLOC | BPF_F_RDONLY_PROG },
> + { "positive_sign", "+1", BPF_F_NO_PREALLOC },
> + { "single_name", "BPF_F_NO_PREALLOC", BPF_F_NO_PREALLOC },
> + { "combined_names", "BPF_F_NO_PREALLOC,BPF_F_RDONLY_PROG",
> + BPF_F_NO_PREALLOC | BPF_F_RDONLY_PROG },
> + { "repeated_name", "BPF_F_NO_PREALLOC,BPF_F_NO_PREALLOC", BPF_F_NO_PREALLOC },
> + { "unknown_name", "BPF_F_NOT_A_MAP_FLAG", 0, "can't parse" },
> + { "other_command_flag", "BPF_F_PATH_FD", 0, "can't parse" },
> + { "update_flag", "BPF_F_LOCK", 0, "can't parse" },
> + { "abbreviated_name", "BPF_F_NO_PRE", 0, "can't parse" },
> + { "lowercase_name", "bpf_f_no_prealloc", 0, "can't parse" },
> + { "empty", "", 0, "can't parse" },
> + { "whitespace", " ", 0, "can't parse" },
> + { "empty_list", ",", 0, "can't parse" },
> + { "leading_comma", ",BPF_F_NO_PREALLOC", 0, "can't parse" },
> + { "trailing_comma", "BPF_F_NO_PREALLOC,", 0, "can't parse" },
> + { "empty_element", "BPF_F_NO_PREALLOC,,BPF_F_RDONLY_PROG", 0, "can't parse" },
> + { "number_then_name", "1,BPF_F_RDONLY_PROG", 0, "can't parse" },
> + { "name_then_number", "BPF_F_NO_PREALLOC,128", 0, "can't parse" },
> + { "numeric_list", "1,128", 0, "can't parse" },
> + { "whitespace_in_list", "BPF_F_NO_PREALLOC, BPF_F_RDONLY_PROG", 0, "can't parse" },
> + { "overflow_u32", "4294967296", 0, "can't parse" },
> + { "overflow_hex", "0x100000000", 0, "can't parse" },
> + { "overflow_u64", "18446744073709551616", 0, "can't parse" },
> + { "negative", "-1", 0, "can't parse" },
> + /* Numeric bits unknown to bpftool must still reach the kernel. */
> + { "all_bits", "0xffffffff", 0, "map create failed" },
> + { "invalid_combination", "BPF_F_RDONLY,BPF_F_WRONLY", 0, "map create failed" },
This isn't a bug, but is the comment meant to cover both of the following
rows? The "invalid_combination" test uses a symbolic list rather than
unknown numeric bits, so it might read more clearly as something like
"bpftool does not validate map-specific flag combinations; the kernel
does".
> +};
[ ... ]
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/34073340278
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH bpf-next v2 1/2] bpftool: Accept symbolic map creation flags
2026-09-07 1:20 ` [PATCH bpf-next v2 1/2] bpftool: Accept " Tianyi Chen
@ 2026-09-07 2:04 ` bot+bpf-ci
0 siblings, 0 replies; 16+ messages in thread
From: bot+bpf-ci @ 2026-09-07 2:04 UTC (permalink / raw)
To: hi, bpf
Cc: hi, qmo, linux-kselftest, ast, andrii, daniel, martin.lau,
eddyz87, yonghong.song, mason, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 3266 bytes --]
> diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool
> index 75cbcb512eba..73f6a8118267 100644
> --- a/tools/bpf/bpftool/bash-completion/bpftool
> +++ b/tools/bpf/bpftool/bash-completion/bpftool
> @@ -718,6 +718,10 @@ _bpftool()
> esac
> ;;
> create)
> + # Keep a flags list together if readline splits at commas.
> + if [[ $COMP_WORDBREAKS == *,* && ( $cur == , || $prev == , ) ]]; then
> + _get_comp_words_by_ref -n , cur prev
> + fi
> case $prev in
> $command)
> _filedir
> @@ -729,7 +733,27 @@ _bpftool()
> COMPREPLY=( $( compgen -W "$BPFTOOL_MAP_CREATE_TYPES" -- "$cur" ) )
> return 0
> ;;
> - key|value|flags|entries)
> + flags)
> + compopt -o nospace
> + local flags='BPF_F_NO_PREALLOC BPF_F_NO_COMMON_LRU
> + BPF_F_NUMA_NODE BPF_F_RDONLY BPF_F_WRONLY
> + BPF_F_STACK_BUILD_ID BPF_F_ZERO_SEED
> + BPF_F_RDONLY_PROG BPF_F_WRONLY_PROG BPF_F_CLONE
> + BPF_F_MMAPABLE BPF_F_PRESERVE_ELEMS BPF_F_INNER_MAP
> + BPF_F_LINK BPF_F_VTYPE_BTF_OBJ_FD BPF_F_TOKEN_FD
> + BPF_F_SEGV_ON_FAULT BPF_F_NO_USER_CONV
> + BPF_F_RB_OVERWRITE'
^^^^
This isn't a bug, but the flag names are spelled out both here and in
map_create_flags[] in map.c. Since the `type)` branch just above already
sources its list from `bpftool feature list_builtins map_types`, would
it be worth exposing the flag names the same way so the two copies cannot
drift?
> + local prefix= flag
> + # Readline replaces only the suffix after a word break.
> + if [[ $cur == *,* && $COMP_WORDBREAKS != *,* ]]; then
^^^^
This isn't a bug, but would it read more directly if this comment named
the case the branch handles, that when a comma is not a word break,
readline replaces the whole word and the already-typed prefix has to be
repeated?
> + prefix="${cur%,*},"
> + fi
> + for flag in $(compgen -W "$flags" -- "${cur##*,}"); do
> + COMPREPLY+=( "${prefix}${flag}" )
> + done
> + return 0
> + ;;
> + key|value|entries)
> return 0
> ;;
> inner_map)
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/34073340278
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH bpf-next v3 0/2] bpftool: Support symbolic map creation flags
2026-09-07 1:20 ` [PATCH bpf-next v2 0/2] bpftool: Support symbolic " Tianyi Chen
2026-09-07 1:20 ` [PATCH bpf-next v2 1/2] bpftool: Accept " Tianyi Chen
2026-09-07 1:20 ` [PATCH bpf-next v2 2/2] selftests/bpf: Cover symbolic bpftool " Tianyi Chen
@ 2026-09-07 2:15 ` Tianyi Chen
2026-09-07 2:15 ` [PATCH bpf-next v3 1/2] bpftool: Accept " Tianyi Chen
2026-09-07 2:15 ` [PATCH bpf-next v3 2/2] selftests/bpf: Cover symbolic bpftool " Tianyi Chen
2 siblings, 2 replies; 16+ messages in thread
From: Tianyi Chen @ 2026-09-07 2:15 UTC (permalink / raw)
To: bpf; +Cc: qmo, linux-kselftest, hi
Add comma-separated BPF_F_* names to map create flags while retaining
base-0 numeric input, with matching documentation, completion and tests.
Changes in v3:
- Expose the parser's existing flag table through feature list_builtins
map_create_flags, and use that command for Bash completion. Update the
feature help, manual and group completion for the new group.
- Explain that when comma is not a word break, Readline replaces the whole
word and completion must repeat the already-entered flag prefix.
- Give invalid_combination its own comment: the kernel validates
combinations of known flags; the preceding all_bits case instead checks
that unknown numeric bits are passed through to the kernel.
These address the v2 review comments:
https://lore.kernel.org/r/693f57c4fee08005c6e67811a2fbc497e95fbb7373154e9ecdb1f9a76afaba60@mail.kernel.org
https://lore.kernel.org/r/7dbfef853aacc32527a352d59861e86f00b7a1e4634c070e569aed415792b926@mail.kernel.org
Validation of v3:
- Built bpftool and the focused BPF selftest runner with LLVM 20, alongside
the ring-buffer and batch v2 series and recursive dump v3.
- All 29 bpftool_map_flags subtests passed in an x86-64 KVM guest running
Linux 7.3.0-rc1, with no skips or failures.
- Plain, JSON and pretty-JSON list_builtins output contains exactly the 19
names in the parser table. The existing map shorthand still selects
map_types.
- Real Bash Readline completion checked with default COMP_WORDBREAKS and
with comma included: first and subsequent flags remain in one argument;
after an explicit space, entries gets its normal trailing space. The new
list_builtins group also completes correctly.
- Bash syntax, bpftool synchronization checks, diff checks and feature/map
manual generation passed.
Changes in v2:
- Complete list elements without adding a trailing space, so the user
can immediately append another comma-separated flag.
v2: https://lore.kernel.org/r/178874362959.1415955.5742268739057412911.flags-v2-0@tychen.cc
v1: https://lore.kernel.org/r/20260906170715.1212085-1-hi@tychen.cc
Request: https://github.com/libbpf/bpftool/issues/57
Tianyi Chen (2):
bpftool: Accept symbolic map creation flags
selftests/bpf: Cover symbolic bpftool map creation flags
.../bpftool/Documentation/bpftool-feature.rst | 10 +-
.../bpf/bpftool/Documentation/bpftool-map.rst | 13 ++-
tools/bpf/bpftool/bash-completion/bpftool | 22 +++-
tools/bpf/bpftool/feature.c | 7 +-
tools/bpf/bpftool/main.h | 1 +
tools/bpf/bpftool/map.c | 85 ++++++++++++++-
.../bpf/prog_tests/bpftool_map_flags.c | 100 ++++++++++++++++++
7 files changed, 225 insertions(+), 13 deletions(-)
create mode 100644 tools/testing/selftests/bpf/prog_tests/bpftool_map_flags.c
--
2.55.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH bpf-next v3 1/2] bpftool: Accept symbolic map creation flags
2026-09-07 2:15 ` [PATCH bpf-next v3 0/2] bpftool: Support symbolic " Tianyi Chen
@ 2026-09-07 2:15 ` Tianyi Chen
2026-09-07 4:25 ` bot+bpf-ci
2026-09-07 2:15 ` [PATCH bpf-next v3 2/2] selftests/bpf: Cover symbolic bpftool " Tianyi Chen
1 sibling, 1 reply; 16+ messages in thread
From: Tianyi Chen @ 2026-09-07 2:15 UTC (permalink / raw)
To: bpf; +Cc: qmo, linux-kselftest, hi
Accept comma-separated BPF_F_* names for map create flags, so callers
can use the UAPI names without looking up their numeric values. Keep
base-0 numeric input, including bits unknown to this bpftool.
Reject empty names, unknown names, mixed numeric and symbolic lists,
and values outside the unsigned 32-bit range. Limit symbolic names to
map creation flags and let the kernel validate map-specific combinations.
Document the syntax and complete names within comma-separated lists.
Avoid appending a space to completed list elements so another flag can
be added to the same argument.
Link: https://github.com/libbpf/bpftool/issues/57
Assisted-by: Codex:GPT-6
Signed-off-by: Tianyi Chen <hi@tychen.cc>
---
.../bpftool/Documentation/bpftool-feature.rst | 10 ++-
.../bpf/bpftool/Documentation/bpftool-map.rst | 13 ++-
tools/bpf/bpftool/bash-completion/bpftool | 22 ++++-
tools/bpf/bpftool/feature.c | 7 +-
tools/bpf/bpftool/main.h | 1 +
tools/bpf/bpftool/map.c | 85 ++++++++++++++++++-
6 files changed, 125 insertions(+), 13 deletions(-)
diff --git a/tools/bpf/bpftool/Documentation/bpftool-feature.rst b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
index c7f837898bc..597f2426d25 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-feature.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
@@ -28,7 +28,7 @@ FEATURE COMMANDS
| **bpftool** **feature help**
|
| *COMPONENT* := { **kernel** | **dev** *NAME* }
-| *GROUP* := { **prog_types** | **map_types** | **attach_types** | **link_types** | **helpers** }
+| *GROUP* := { **prog_types** | **map_types** | **map_create_flags** | **attach_types** | **link_types** | **helpers** }
DESCRIPTION
===========
@@ -68,12 +68,14 @@ bpftool feature probe dev *NAME* [full] [macros [prefix *PREFIX*]]
bpftool feature list_builtins *GROUP*
List items known to bpftool. These can be BPF program types
- (**prog_types**), BPF map types (**map_types**), attach types
+ (**prog_types**), BPF map types (**map_types**), map creation flags
+ (**map_create_flags**), attach types
(**attach_types**), link types (**link_types**), or BPF helper functions
(**helpers**). The command does not probe the system, but simply lists the
elements that bpftool knows from compilation time, as provided from libbpf
- (for all object types) or from the BPF UAPI header (list of helpers). This
- can be used in scripts to iterate over BPF types or helpers.
+ (for all object types) or from the BPF UAPI header (helpers and map creation
+ flags). This can be used in scripts to iterate over BPF types, helpers, or
+ the symbolic flags accepted by **map create**.
bpftool feature help
Print short help message.
diff --git a/tools/bpf/bpftool/Documentation/bpftool-map.rst b/tools/bpf/bpftool/Documentation/bpftool-map.rst
index 5daf3de5c74..375321d5582 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-map.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-map.rst
@@ -76,9 +76,16 @@ bpftool map { show | list } [*MAP*]
bpftool map create *FILE* type *TYPE* key *KEY_SIZE* value *VALUE_SIZE* entries *MAX_ENTRIES* name *NAME* [flags *FLAGS*] [inner_map *MAP*] [offload_dev *NAME*]
Create a new map with given parameters and pin it to *bpffs* as *FILE*.
- *FLAGS* should be an integer which is the combination of desired flags,
- e.g. 1024 for **BPF_F_MMAPABLE** (see bpf.h UAPI header for existing
- flags).
+ *FLAGS* accepts an unsigned 32-bit integer combining the desired flags
+ (decimal, hexadecimal with a **0x** prefix, or octal with a **0** prefix),
+ or a comma-separated list of full, case-sensitive map creation flag names
+ from the bpf.h UAPI header. For example, **1024**, **0x400**, and
+ **BPF_F_MMAPABLE** are equivalent. Multiple names are combined with
+ bitwise OR, for example **BPF_F_NO_PREALLOC,BPF_F_RDONLY_PROG**.
+ Repeated names are allowed. Empty list elements, abbreviated names, and
+ lists mixing numbers with names are not accepted. Use **0** for no flags.
+ Numeric values can include bits unknown to bpftool. The kernel checks
+ whether the flags are valid for the requested map type.
To create maps of type array-of-maps or hash-of-maps, the **inner_map**
keyword must be used to pass an inner map. The kernel needs it to collect
diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool
index 75cbcb512eb..ea3f521b6f0 100644
--- a/tools/bpf/bpftool/bash-completion/bpftool
+++ b/tools/bpf/bpftool/bash-completion/bpftool
@@ -718,6 +718,10 @@ _bpftool()
esac
;;
create)
+ # Keep a flags list together if readline splits at commas.
+ if [[ $COMP_WORDBREAKS == *,* && ( $cur == , || $prev == , ) ]]; then
+ _get_comp_words_by_ref -n , cur prev
+ fi
case $prev in
$command)
_filedir
@@ -729,7 +733,21 @@ _bpftool()
COMPREPLY=( $( compgen -W "$BPFTOOL_MAP_CREATE_TYPES" -- "$cur" ) )
return 0
;;
- key|value|flags|entries)
+ flags)
+ compopt -o nospace
+ local flags="$(bpftool feature list_builtins map_create_flags 2>/dev/null)"
+ local prefix= flag
+ # If comma is not a word break, Readline replaces the whole
+ # word, so preserve the flags before the last comma.
+ if [[ $cur == *,* && $COMP_WORDBREAKS != *,* ]]; then
+ prefix="${cur%,*},"
+ fi
+ for flag in $(compgen -W "$flags" -- "${cur##*,}"); do
+ COMPREPLY+=( "${prefix}${flag}" )
+ done
+ return 0
+ ;;
+ key|value|entries)
return 0
;;
inner_map)
@@ -1192,7 +1210,7 @@ _bpftool()
;;
list_builtins)
[[ $prev != "$command" ]] && return 0
- COMPREPLY=( $( compgen -W 'prog_types map_types \
+ COMPREPLY=( $( compgen -W 'prog_types map_types map_create_flags \
attach_types link_types helpers' -- "$cur" ) )
;;
*)
diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
index 0f6070a0c8e..b5419d5a661 100644
--- a/tools/bpf/bpftool/feature.c
+++ b/tools/bpf/bpftool/feature.c
@@ -1220,6 +1220,8 @@ static int do_list_builtins(int argc, char **argv)
get_name = (const char *(*)(unsigned int))libbpf_bpf_prog_type_str;
} else if (is_prefix(*argv, "map_types")) {
get_name = (const char *(*)(unsigned int))libbpf_bpf_map_type_str;
+ } else if (is_prefix(*argv, "map_create_flags")) {
+ get_name = map_create_flag_name;
} else if (is_prefix(*argv, "attach_types")) {
get_name = (const char *(*)(unsigned int))libbpf_bpf_attach_type_str;
} else if (is_prefix(*argv, "link_types")) {
@@ -1227,7 +1229,7 @@ static int do_list_builtins(int argc, char **argv)
} else if (is_prefix(*argv, "helpers")) {
get_name = get_helper_name;
} else {
- p_err("expected 'prog_types', 'map_types', 'attach_types', 'link_types' or 'helpers', got: %s", *argv);
+ p_err("expected 'prog_types', 'map_types', 'map_create_flags', 'attach_types', 'link_types' or 'helpers', got: %s", *argv);
return -1;
}
@@ -1265,7 +1267,8 @@ static int do_help(int argc, char **argv)
" %1$s %2$s help\n"
"\n"
" COMPONENT := { kernel | dev NAME }\n"
- " GROUP := { prog_types | map_types | attach_types | link_types | helpers }\n"
+ " GROUP := { prog_types | map_types | map_create_flags |\n"
+ " attach_types | link_types | helpers }\n"
" " HELP_SPEC_OPTIONS " }\n"
"",
bin_name, argv[-2]);
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index 9315a1db1f7..3e2856c9f59 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -180,6 +180,7 @@ int do_token(int argc, char **argv) __weak;
int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what);
int prog_parse_fd(int *argc, char ***argv);
int prog_parse_fds(int *argc, char ***argv, int **fds);
+const char *map_create_flag_name(unsigned int id);
int map_parse_fd(int *argc, char ***argv, __u32 open_flags);
int map_parse_fds(int *argc, char ***argv, int **fds, __u32 open_flags);
int map_parse_fd_and_info(int *argc, char ***argv, struct bpf_map_info *info,
diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
index 684a8fb7241..4445014247d 100644
--- a/tools/bpf/bpftool/map.c
+++ b/tools/bpf/bpftool/map.c
@@ -1250,6 +1250,81 @@ static int do_pin(int argc, char **argv)
return err;
}
+static const struct {
+ const char *name;
+ __u32 value;
+} map_create_flags[] = {
+#define MAP_CREATE_FLAG(flag) { #flag, flag }
+ MAP_CREATE_FLAG(BPF_F_NO_PREALLOC),
+ MAP_CREATE_FLAG(BPF_F_NO_COMMON_LRU),
+ MAP_CREATE_FLAG(BPF_F_NUMA_NODE),
+ MAP_CREATE_FLAG(BPF_F_RDONLY),
+ MAP_CREATE_FLAG(BPF_F_WRONLY),
+ MAP_CREATE_FLAG(BPF_F_STACK_BUILD_ID),
+ MAP_CREATE_FLAG(BPF_F_ZERO_SEED),
+ MAP_CREATE_FLAG(BPF_F_RDONLY_PROG),
+ MAP_CREATE_FLAG(BPF_F_WRONLY_PROG),
+ MAP_CREATE_FLAG(BPF_F_CLONE),
+ MAP_CREATE_FLAG(BPF_F_MMAPABLE),
+ MAP_CREATE_FLAG(BPF_F_PRESERVE_ELEMS),
+ MAP_CREATE_FLAG(BPF_F_INNER_MAP),
+ MAP_CREATE_FLAG(BPF_F_LINK),
+ MAP_CREATE_FLAG(BPF_F_VTYPE_BTF_OBJ_FD),
+ MAP_CREATE_FLAG(BPF_F_TOKEN_FD),
+ MAP_CREATE_FLAG(BPF_F_SEGV_ON_FAULT),
+ MAP_CREATE_FLAG(BPF_F_NO_USER_CONV),
+ MAP_CREATE_FLAG(BPF_F_RB_OVERWRITE),
+#undef MAP_CREATE_FLAG
+};
+
+const char *map_create_flag_name(unsigned int id)
+{
+ if (id >= ARRAY_SIZE(map_create_flags))
+ return NULL;
+
+ return map_create_flags[id].name;
+}
+
+static int parse_map_create_flags(const char *arg, __u32 *flags)
+{
+ const char *name = arg, *comma;
+ long long value;
+ __u32 parsed = 0;
+ size_t len, i;
+ char *end;
+
+ /* Keep base-0 numeric input, including bits unknown to this bpftool. */
+ if (strncmp(arg, "BPF_F_", 6)) {
+ errno = 0;
+ value = strtoll(arg, &end, 0);
+ if (errno || end == arg || *end || value < 0 || value > UINT32_MAX)
+ goto invalid;
+ *flags = value;
+ return 0;
+ }
+
+ do {
+ comma = strchr(name, ',');
+ len = comma ? (size_t)(comma - name) : strlen(name);
+ for (i = 0; i < ARRAY_SIZE(map_create_flags); i++) {
+ if (strlen(map_create_flags[i].name) == len &&
+ !strncmp(name, map_create_flags[i].name, len))
+ break;
+ }
+ if (i == ARRAY_SIZE(map_create_flags))
+ goto invalid;
+ parsed |= map_create_flags[i].value;
+ if (comma)
+ name = comma + 1;
+ } while (comma);
+
+ *flags = parsed;
+ return 0;
+invalid:
+ p_err("can't parse %s as map creation flags", arg);
+ return -1;
+}
+
static int do_create(int argc, char **argv)
{
LIBBPF_OPTS(bpf_map_create_opts, attr);
@@ -1301,9 +1376,14 @@ static int do_create(int argc, char **argv)
"max entries"))
goto exit;
} else if (is_prefix(*argv, "flags")) {
- if (parse_u32_arg(&argc, &argv, &attr.map_flags,
- "flags"))
+ NEXT_ARG();
+ if (attr.map_flags) {
+ p_err("flags already specified");
goto exit;
+ }
+ if (parse_map_create_flags(*argv, &attr.map_flags))
+ goto exit;
+ NEXT_ARG();
} else if (is_prefix(*argv, "dev")) {
p_info("Warning: 'bpftool map create [...] dev <ifname>' syntax is deprecated.\n"
"Going further, please use 'offload_dev <ifname>' to request hardware offload for the map.");
@@ -1474,6 +1554,7 @@ static int do_help(int argc, char **argv)
" DATA := { [hex] BYTES }\n"
" " HELP_SPEC_PROGRAM "\n"
" VALUE := { DATA | MAP | PROG }\n"
+ " FLAGS := { integer | BPF_F_NAME[,BPF_F_NAME...] }\n"
" UPDATE_FLAGS := { any | exist | noexist }\n"
" TYPE := { hash | array | prog_array | perf_event_array | percpu_hash |\n"
" percpu_array | stack_trace | cgroup_array | lru_hash |\n"
--
2.55.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH bpf-next v3 2/2] selftests/bpf: Cover symbolic bpftool map creation flags
2026-09-07 2:15 ` [PATCH bpf-next v3 0/2] bpftool: Support symbolic " Tianyi Chen
2026-09-07 2:15 ` [PATCH bpf-next v3 1/2] bpftool: Accept " Tianyi Chen
@ 2026-09-07 2:15 ` Tianyi Chen
[not found] ` <88e01da6d4b68aae7b8df6c0956b78f082bcedab7eb588631405031f1425b146@mail.kernel.org>
1 sibling, 1 reply; 16+ messages in thread
From: Tianyi Chen @ 2026-09-07 2:15 UTC (permalink / raw)
To: bpf; +Cc: qmo, linux-kselftest, hi
Check numeric and symbolic map creation flags, including combined and
repeated names, against map information read independently with libbpf.
Exercise malformed names and lists, update-only flags, empty input and
numeric range errors. Verify rejected input leaves no pinned map.
Assisted-by: Codex:GPT-6
Signed-off-by: Tianyi Chen <hi@tychen.cc>
---
.../bpf/prog_tests/bpftool_map_flags.c | 100 ++++++++++++++++++
1 file changed, 100 insertions(+)
create mode 100644 tools/testing/selftests/bpf/prog_tests/bpftool_map_flags.c
diff --git a/tools/testing/selftests/bpf/prog_tests/bpftool_map_flags.c b/tools/testing/selftests/bpf/prog_tests/bpftool_map_flags.c
new file mode 100644
index 00000000000..d617b43273a
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/bpftool_map_flags.c
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <errno.h>
+#include <unistd.h>
+#include <bpf/bpf.h>
+#include <bpftool_helpers.h>
+#include <test_progs.h>
+
+static const struct map_flags_test {
+ const char *name;
+ const char *flags;
+ __u32 expected_flags;
+ const char *error;
+} tests[] = {
+ { "zero", "0", 0 },
+ { "decimal", "129", BPF_F_NO_PREALLOC | BPF_F_RDONLY_PROG },
+ { "hexadecimal", "0x81", BPF_F_NO_PREALLOC | BPF_F_RDONLY_PROG },
+ { "octal", "0201", BPF_F_NO_PREALLOC | BPF_F_RDONLY_PROG },
+ { "positive_sign", "+1", BPF_F_NO_PREALLOC },
+ { "single_name", "BPF_F_NO_PREALLOC", BPF_F_NO_PREALLOC },
+ { "combined_names", "BPF_F_NO_PREALLOC,BPF_F_RDONLY_PROG",
+ BPF_F_NO_PREALLOC | BPF_F_RDONLY_PROG },
+ { "repeated_name", "BPF_F_NO_PREALLOC,BPF_F_NO_PREALLOC", BPF_F_NO_PREALLOC },
+ { "unknown_name", "BPF_F_NOT_A_MAP_FLAG", 0, "can't parse" },
+ { "other_command_flag", "BPF_F_PATH_FD", 0, "can't parse" },
+ { "update_flag", "BPF_F_LOCK", 0, "can't parse" },
+ { "abbreviated_name", "BPF_F_NO_PRE", 0, "can't parse" },
+ { "lowercase_name", "bpf_f_no_prealloc", 0, "can't parse" },
+ { "empty", "", 0, "can't parse" },
+ { "whitespace", " ", 0, "can't parse" },
+ { "empty_list", ",", 0, "can't parse" },
+ { "leading_comma", ",BPF_F_NO_PREALLOC", 0, "can't parse" },
+ { "trailing_comma", "BPF_F_NO_PREALLOC,", 0, "can't parse" },
+ { "empty_element", "BPF_F_NO_PREALLOC,,BPF_F_RDONLY_PROG", 0, "can't parse" },
+ { "number_then_name", "1,BPF_F_RDONLY_PROG", 0, "can't parse" },
+ { "name_then_number", "BPF_F_NO_PREALLOC,128", 0, "can't parse" },
+ { "numeric_list", "1,128", 0, "can't parse" },
+ { "whitespace_in_list", "BPF_F_NO_PREALLOC, BPF_F_RDONLY_PROG", 0, "can't parse" },
+ { "overflow_u32", "4294967296", 0, "can't parse" },
+ { "overflow_hex", "0x100000000", 0, "can't parse" },
+ { "overflow_u64", "18446744073709551616", 0, "can't parse" },
+ { "negative", "-1", 0, "can't parse" },
+ /* Numeric bits unknown to bpftool must still reach the kernel. */
+ { "all_bits", "0xffffffff", 0, "map create failed" },
+ /* The kernel validates combinations of known map creation flags. */
+ { "invalid_combination", "BPF_F_RDONLY,BPF_F_WRONLY", 0, "map create failed" },
+};
+
+static void test_map_flags(const struct map_flags_test *test, const char *path)
+{
+ char cmd[MAX_BPFTOOL_CMD_LEN], output[1024] = {};
+ struct bpf_map_info info = {};
+ __u32 info_len = sizeof(info);
+ int fd, err;
+
+ /* Let the flags parser handle negative numbers instead of getopt(). */
+ err = snprintf(cmd, sizeof(cmd),
+ "-- map create %s type hash key 4 value 4 entries 1 name flags_test flags '%s' 2>&1",
+ path, test->flags);
+ if (!ASSERT_GT(err, 0, "format_command") ||
+ !ASSERT_LT(err, sizeof(cmd), "command_length"))
+ return;
+
+ err = get_bpftool_command_output(cmd, output, sizeof(output));
+ if (test->error) {
+ ASSERT_NEQ(err, 0, "reject_flags");
+ ASSERT_HAS_SUBSTR(output, test->error, "error_message");
+ err = access(path, F_OK);
+ ASSERT_EQ(err, -1, "no_pin");
+ ASSERT_EQ(errno, ENOENT, "pin_absent");
+ goto cleanup;
+ }
+ if (!ASSERT_OK(err, "create_map"))
+ goto cleanup;
+
+ fd = bpf_obj_get(path);
+ if (!ASSERT_OK_FD(fd, "open_map"))
+ goto cleanup;
+ if (ASSERT_OK(bpf_map_get_info_by_fd(fd, &info, &info_len), "map_info"))
+ ASSERT_EQ(info.map_flags, test->expected_flags, "map_flags");
+ close(fd);
+cleanup:
+ unlink(path);
+}
+
+void test_bpftool_map_flags(void)
+{
+ char dir[] = "/sys/fs/bpf/bpftool_flags_XXXXXX";
+ char path[sizeof(dir) + sizeof("/map")];
+ int i;
+
+ if (!ASSERT_OK_PTR(mkdtemp(dir), "create_pin_dir"))
+ return;
+ snprintf(path, sizeof(path), "%s/map", dir);
+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
+ if (test__start_subtest(tests[i].name))
+ test_map_flags(&tests[i], path);
+ }
+ ASSERT_OK(rmdir(dir), "remove_pin_dir");
+}
--
2.55.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH bpf-next v3 1/2] bpftool: Accept symbolic map creation flags
2026-09-07 2:15 ` [PATCH bpf-next v3 1/2] bpftool: Accept " Tianyi Chen
@ 2026-09-07 4:25 ` bot+bpf-ci
2026-09-07 5:14 ` Tianyi Chen
0 siblings, 1 reply; 16+ messages in thread
From: bot+bpf-ci @ 2026-09-07 4:25 UTC (permalink / raw)
To: hi, bpf
Cc: qmo, linux-kselftest, hi, ast, andrii, daniel, martin.lau,
eddyz87, yonghong.song, mason, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 3094 bytes --]
> diff --git a/tools/bpf/bpftool/Documentation/bpftool-map.rst b/tools/bpf/bpftool/Documentation/bpftool-map.rst
> index 5daf3de5c744..375321d55823 100644
> --- a/tools/bpf/bpftool/Documentation/bpftool-map.rst
> +++ b/tools/bpf/bpftool/Documentation/bpftool-map.rst
> @@ -76,9 +76,16 @@ bpftool map { show | list } [*MAP*]
> bpftool map create *FILE* type *TYPE* key *KEY_SIZE* value *VALUE_SIZE* entries *MAX_ENTRIES* name *NAME* [flags *FLAGS*] [inner_map *MAP*] [offload_dev *NAME*]
> Create a new map with given parameters and pin it to *bpffs* as *FILE*.
>
> - *FLAGS* should be an integer which is the combination of desired flags,
> - e.g. 1024 for **BPF_F_MMAPABLE** (see bpf.h UAPI header for existing
> - flags).
> + *FLAGS* accepts an unsigned 32-bit integer combining the desired flags
> + (decimal, hexadecimal with a **0x** prefix, or octal with a **0** prefix),
> + or a comma-separated list of full, case-sensitive map creation flag names
> + from the bpf.h UAPI header. For example, **1024**, **0x400**, and
> + **BPF_F_MMAPABLE** are equivalent. Multiple names are combined with
> + bitwise OR, for example **BPF_F_NO_PREALLOC,BPF_F_RDONLY_PROG**.
> + Repeated names are allowed. Empty list elements, abbreviated names, and
> + lists mixing numbers with names are not accepted. Use **0** for no flags.
> + Numeric values can include bits unknown to bpftool. The kernel checks
> + whether the flags are valid for the requested map type.
[ ... ]
> diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
> index 684a8fb72414..4445014247d6 100644
> --- a/tools/bpf/bpftool/map.c
> +++ b/tools/bpf/bpftool/map.c
[ ... ]
> @@ -1474,6 +1554,7 @@ static int do_help(int argc, char **argv)
> " DATA := { [hex] BYTES }\n"
> " " HELP_SPEC_PROGRAM "\n"
> " VALUE := { DATA | MAP | PROG }\n"
> + " FLAGS := { integer | BPF_F_NAME[,BPF_F_NAME...] }\n"
> " UPDATE_FLAGS := { any | exist | noexist }\n"
> " TYPE := { hash | array | prog_array | perf_event_array | percpu_hash |\n"
> " percpu_array | stack_trace | cgroup_array | lru_hash |\n"
The help text gained a FLAGS metavariable production, but the man page
synopsis did not. Looking at bpftool-map.rst, the synopsis section lists
metavariable productions like:
| *MAP* := { ... }
| *DATA* := { [**hex**] *BYTES* }
| *PROG* := { ... }
| *VALUE* := { *DATA* | *MAP* | *PROG* }
| *UPDATE_FLAGS* := { **any** | **exist** | **noexist** }
| *TYPE* := { **hash** | ... }
Should there be a corresponding line for FLAGS in the synopsis? Before
this patch, every metavariable in the map.c help block had a matching
production in the rst synopsis. The FLAGS metavariable is now the only
one that appears in the help text but not in the synopsis.
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/34075962636
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH bpf-next v3 1/2] bpftool: Accept symbolic map creation flags
2026-09-07 4:25 ` bot+bpf-ci
@ 2026-09-07 5:14 ` Tianyi Chen
0 siblings, 0 replies; 16+ messages in thread
From: Tianyi Chen @ 2026-09-07 5:14 UTC (permalink / raw)
To: bpf; +Cc: qmo, linux-kselftest, hi
Thanks, agreed: the synopsis should have the same FLAGS production as
map help. I have added the line below locally and checked the generated
man page and the bpftool synchronization test.
This is the complete correction; I will fold it into the next full
revision rather than repost the series just for this documentation line.
diff --git a/tools/bpf/bpftool/Documentation/bpftool-map.rst b/tools/bpf/bpftool/Documentation/bpftool-map.rst
index 375321d5582..5a5c26f789c 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-map.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-map.rst
@@ -48,6 +48,7 @@ MAP COMMANDS
| *DATA* := { [**hex**] *BYTES* }
| *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* | **name** *PROG_NAME* }
| *VALUE* := { *DATA* | *MAP* | *PROG* }
+| *FLAGS* := { integer | **BPF_F_NAME[,BPF_F_NAME...]** }
| *UPDATE_FLAGS* := { **any** | **exist** | **noexist** }
| *TYPE* := { **hash** | **array** | **prog_array** | **perf_event_array** | **percpu_hash**
| | **percpu_array** | **stack_trace** | **cgroup_array** | **lru_hash**
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [bpf-next,v3,1/2] bpftool: Accept symbolic map creation flags
[not found] ` <88e01da6d4b68aae7b8df6c0956b78f082bcedab7eb588631405031f1425b146@mail.kernel.org>
@ 2026-09-07 5:15 ` Tianyi Chen
2026-09-11 2:53 ` Tianyi Chen
0 siblings, 1 reply; 16+ messages in thread
From: Tianyi Chen @ 2026-09-07 5:15 UTC (permalink / raw)
To: kernel-ci; +Cc: bpf, hi
Hi Kernel CI team,
Several previously successful bpftool submissions are now receiving
repeated CONFLICT reports. I cannot reproduce a patch conflict against
current bpf-next; the available evidence points to a Patchwork mailbox
download/access failure being classified as a merge conflict.
The four current series are:
- 1159274: symbolic map flags v3 (PRs 13654 and 13669)
- 1159257: ring buffer event_pipe v2 (PRs 13651 and 13670)
- 1159258: recursive dump v3 (PRs 13649 and 13671)
- 1159259: batch dump v2 (PRs 13652 and 13672)
The application logs say "Patch is empty." rather than identifying
conflicting hunks. Two examples:
https://github.com/kernel-patches/bpf/pull/13654#issuecomment-5565136560
https://github.com/kernel-patches/bpf/pull/13669#issuecomment-5565265918
From my client, the series and individual-patch mbox URLs redirect to
/user/login/ and return HTTP 200 text/html containing the sign-in page,
not an mbox. For example:
https://patchwork.kernel.org/series/1159274/mbox/
The REST series metadata is still readable. Replacement PR 13669 contains
only a Dummy commit, so its new checks do not exercise the flags patches.
The daemon's get_blob() path appears to return the downloaded body
without verifying that it is a mailbox, and the git-am error handler
labels application failures as conflicts:
https://github.com/kernel-patches/kernel-patches-daemon/blob/main/kernel_patches_daemon/patchwork.py#L652
https://github.com/kernel-patches/kernel-patches-daemon/blob/main/kernel_patches_daemon/branch_worker.py#L1100
I fetched bpf-next/master and checked each of the four posted series
against 1b7415bf70be95b9a1e7e87d544867881065613f with git apply --cached
--check on a fresh index. All four apply cleanly. The earlier flags
build/selftest run also succeeded:
https://github.com/kernel-patches/bpf/actions/runs/34075962833
Could you check the worker's mailbox downloads/authentication, then
rerun the current series when access is restored? Rejecting login/HTML
responses as download errors would also avoid misleading rebase requests.
I cannot inspect the daemon's actual downloaded payload, so the endpoint
behavior above is supporting evidence rather than a server-side trace.
The obsolete v1 series are receiving the same repeated notifications;
they have already been superseded by the versions listed above. I am
not reposting those or rebasing solely on these empty-patch reports.
Thanks,
Tianyi
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [bpf-next,v3,1/2] bpftool: Accept symbolic map creation flags
2026-09-07 5:15 ` [bpf-next,v3,1/2] bpftool: Accept symbolic " Tianyi Chen
@ 2026-09-11 2:53 ` Tianyi Chen
0 siblings, 0 replies; 16+ messages in thread
From: Tianyi Chen @ 2026-09-11 2:53 UTC (permalink / raw)
To: kernel-ci; +Cc: bpf
Hi Kernel CI team,
Following up on the empty-patch reports: the affected PRs expired, and I
have now rebased and resubmitted the six pending topics with the remaining
review corrections. These are the current versions:
- cpumask v2:
https://lore.kernel.org/r/20260911025029.190453-1-diannaaav@gmail.com
- batch-key validators v3:
https://lore.kernel.org/r/20260911025036.190487-1-diannaaav@gmail.com
- symbolic map flags v4:
https://lore.kernel.org/r/20260911025044.190540-1-diannaaav@gmail.com
- recursive dump v4:
https://lore.kernel.org/r/20260911025100.190706-1-diannaaav@gmail.com
- ring buffer event_pipe v3:
https://lore.kernel.org/r/20260911025114.190899-1-diannaaav@gmail.com
- batched dump v3:
https://lore.kernel.org/r/20260911025130.191011-1-diannaaav@gmail.com
All ten patches apply cleanly to their current bpf or bpf-next base.
The 69 bpftool and 36 cpumask subtests passed in an x86-64 KVM guest
running the rebuilt bpf/master kernel (7.3.0-rc2); test_maps also passed,
with no skips in these runs. This was focused validation, not the full
BPF suite.
The emails were generated by git format-patch and sent using git
send-email, with a new thread for each version. The BPF test changes are
unchanged apart from rebasing; their previous "Patch is empty" reports
did not identify conflicting hunks.
Please use these versions for subsequent CI runs. If the empty-patch
failure recurs, please check the mailbox download/access path described
in my earlier report before treating it as a source conflict. I still
cannot inspect the daemon's downloaded payload directly.
Thanks,
Tianyi
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2026-09-11 2:53 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-06 17:07 [PATCH bpf-next 0/2] bpftool: Support symbolic map creation flags Tianyi Chen
2026-09-06 17:07 ` [PATCH bpf-next 1/2] bpftool: Accept " Tianyi Chen
2026-09-06 18:16 ` bot+bpf-ci
2026-09-06 17:07 ` [PATCH bpf-next 2/2] selftests/bpf: Cover symbolic bpftool " Tianyi Chen
2026-09-07 1:20 ` [PATCH bpf-next v2 0/2] bpftool: Support symbolic " Tianyi Chen
2026-09-07 1:20 ` [PATCH bpf-next v2 1/2] bpftool: Accept " Tianyi Chen
2026-09-07 2:04 ` bot+bpf-ci
2026-09-07 1:20 ` [PATCH bpf-next v2 2/2] selftests/bpf: Cover symbolic bpftool " Tianyi Chen
2026-09-07 2:04 ` bot+bpf-ci
2026-09-07 2:15 ` [PATCH bpf-next v3 0/2] bpftool: Support symbolic " Tianyi Chen
2026-09-07 2:15 ` [PATCH bpf-next v3 1/2] bpftool: Accept " Tianyi Chen
2026-09-07 4:25 ` bot+bpf-ci
2026-09-07 5:14 ` Tianyi Chen
2026-09-07 2:15 ` [PATCH bpf-next v3 2/2] selftests/bpf: Cover symbolic bpftool " Tianyi Chen
[not found] ` <88e01da6d4b68aae7b8df6c0956b78f082bcedab7eb588631405031f1425b146@mail.kernel.org>
2026-09-07 5:15 ` [bpf-next,v3,1/2] bpftool: Accept symbolic " Tianyi Chen
2026-09-11 2:53 ` Tianyi Chen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox