Linux Kernel Selftest development
 help / color / mirror / Atom feed
* [PATCH bpf-next v4 0/2] bpftool: Support symbolic map creation flags
@ 2026-09-11  2:50 Tianyi Chen
  2026-09-11  2:50 ` [PATCH bpf-next v4 1/2] bpftool: Accept " Tianyi Chen
  2026-09-11  2:50 ` [PATCH bpf-next v4 2/2] selftests/bpf: Cover symbolic bpftool " Tianyi Chen
  0 siblings, 2 replies; 4+ messages in thread
From: Tianyi Chen @ 2026-09-11  2:50 UTC (permalink / raw)
  To: qmo, bpf; +Cc: andrii, eddyz87, ihor.solodrai, 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 v4:
- Add FLAGS to the map-create synopsis in the manual.
- Rebase onto current bpf-next and shorten the commit descriptions.
- Use Assisted-by: LLM.

The v3 parser, shared feature-list table and completion behavior are
unchanged. Earlier requested functional changes were included in v2/v3.

v3: https://lore.kernel.org/r/178874713816.1519295.5079603775338308680.flags-v3-0@tychen.cc
Request: https://github.com/libbpf/bpftool/issues/57

The previous version's CI PR expired after repeated "Patch is empty"
reports. The revised series applies cleanly to the current tree and is
sent as a new thread using git format-patch and git send-email.

Validation:
- Built bpftool and its manual pages, and built the focused selftest
  runner with LLVM 20.
- All 29 bpftool_map_flags subtests passed with no skips or failures
  in an x86-64 KVM guest running Linux 7.3.0-rc2 from current bpf/master.
- The four bpftool series were tested together: all 69 subtests passed.
  The cpumask suite (36 subtests) and test_maps also passed with no skips.
- Bash syntax and the existing bpftool synchronization checks passed.

This was a focused run; unrelated selftests requiring unavailable kernel
features were excluded from the build with PERMISSIVE=1.

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 |  14 ++-
 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, 226 insertions(+), 13 deletions(-)
 create mode 100644 tools/testing/selftests/bpf/prog_tests/bpftool_map_flags.c


base-commit: af0b84a9215d951d16f26b7ee34353b970cf5d4e
-- 
2.55.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH bpf-next v4 1/2] bpftool: Accept symbolic map creation flags
  2026-09-11  2:50 [PATCH bpf-next v4 0/2] bpftool: Support symbolic map creation flags Tianyi Chen
@ 2026-09-11  2:50 ` Tianyi Chen
  2026-09-11  3:37   ` bot+bpf-ci
  2026-09-11  2:50 ` [PATCH bpf-next v4 2/2] selftests/bpf: Cover symbolic bpftool " Tianyi Chen
  1 sibling, 1 reply; 4+ messages in thread
From: Tianyi Chen @ 2026-09-11  2:50 UTC (permalink / raw)
  To: qmo, bpf; +Cc: andrii, eddyz87, ihor.solodrai, linux-kselftest

From: Tianyi Chen <hi@tychen.cc>

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: LLM
Signed-off-by: Tianyi Chen <hi@tychen.cc>
---
 .../bpftool/Documentation/bpftool-feature.rst | 10 ++-
 .../bpf/bpftool/Documentation/bpftool-map.rst | 14 ++-
 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, 126 insertions(+), 13 deletions(-)

diff --git a/tools/bpf/bpftool/Documentation/bpftool-feature.rst b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
index c7f837898bc7..597f2426d255 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 5daf3de5c744..5a5c26f789cd 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**
@@ -76,9 +77,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 75cbcb512eba..ea3f521b6f08 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 0f6070a0c8e7..b5419d5a661a 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 9315a1db1f7c..3e2856c9f595 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 684a8fb72414..4445014247d6 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] 4+ messages in thread

* [PATCH bpf-next v4 2/2] selftests/bpf: Cover symbolic bpftool map creation flags
  2026-09-11  2:50 [PATCH bpf-next v4 0/2] bpftool: Support symbolic map creation flags Tianyi Chen
  2026-09-11  2:50 ` [PATCH bpf-next v4 1/2] bpftool: Accept " Tianyi Chen
@ 2026-09-11  2:50 ` Tianyi Chen
  1 sibling, 0 replies; 4+ messages in thread
From: Tianyi Chen @ 2026-09-11  2:50 UTC (permalink / raw)
  To: qmo, bpf; +Cc: andrii, eddyz87, ihor.solodrai, linux-kselftest

From: Tianyi Chen <hi@tychen.cc>

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: LLM
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 000000000000..d617b43273a8
--- /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] 4+ messages in thread

* Re: [PATCH bpf-next v4 1/2] bpftool: Accept symbolic map creation flags
  2026-09-11  2:50 ` [PATCH bpf-next v4 1/2] bpftool: Accept " Tianyi Chen
@ 2026-09-11  3:37   ` bot+bpf-ci
  0 siblings, 0 replies; 4+ messages in thread
From: bot+bpf-ci @ 2026-09-11  3:37 UTC (permalink / raw)
  To: diannaaav, qmo, bpf
  Cc: andrii, eddyz87, ihor.solodrai, linux-kselftest, ast, andrii,
	daniel, martin.lau, eddyz87, yonghong.song, mason, ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 7163 bytes --]

> diff --git a/tools/bpf/bpftool/Documentation/bpftool-feature.rst b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
> index c7f837898bc7..597f2426d255 100644
> --- a/tools/bpf/bpftool/Documentation/bpftool-feature.rst
> +++ b/tools/bpf/bpftool/Documentation/bpftool-feature.rst

[ ... ]

> @@ -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**.

This isn't a bug, but could this paragraph be re-wrapped so the new
group folds in at the same width as the surrounding lines? The second
half was re-flowed to match the file's usual 78-column width, but the
first half wasn't, leaving "(**map_create_flags**), attach types" about
half as wide as the lines around it.

> diff --git a/tools/bpf/bpftool/Documentation/bpftool-map.rst b/tools/bpf/bpftool/Documentation/bpftool-map.rst
> index 5daf3de5c744..5a5c26f789cd 100644
> --- a/tools/bpf/bpftool/Documentation/bpftool-map.rst
> +++ b/tools/bpf/bpftool/Documentation/bpftool-map.rst

[ ... ]

> diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool
> index 75cbcb512eba..ea3f521b6f08 100644
> --- a/tools/bpf/bpftool/bash-completion/bpftool
> +++ b/tools/bpf/bpftool/bash-completion/bpftool

[ ... ]

> diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
> index 0f6070a0c8e7..b5419d5a661a 100644
> --- a/tools/bpf/bpftool/feature.c
> +++ b/tools/bpf/bpftool/feature.c

[ ... ]

> diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
> index 9315a1db1f7c..3e2856c9f595 100644
> --- a/tools/bpf/bpftool/main.h
> +++ b/tools/bpf/bpftool/main.h

[ ... ]

> 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
> @@ -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
> +};

This isn't a bug, but the table walks bits 0-19 of the map creation
flags in include/uapi/linux/bpf.h in order, except bit 14
(BPF_F_PATH_FD) is left out between BPF_F_LINK and BPF_F_VTYPE_BTF_OBJ_FD,
with nothing in the source recording why.

The omission looks deliberate (BPF_F_PATH_FD's comment says it is for
BPF_OBJ_PIN/BPF_OBJ_GET, and the follow-up selftest asserts that
`flags BPF_F_PATH_FD` is rejected), but nothing marks it as intentional,
so the next person adding a flag to that enum has no way to tell a
skipped bit from a forgotten one.

The wording added to bpftool-map.rst - "full, case-sensitive map
creation flag names from the bpf.h UAPI header" - also reads as
covering the whole enum, so a user who finds BPF_F_PATH_FD there and
passes it by name gets "can't parse" while `flags 16384` is accepted.

Would a one-line comment next to the gap (something like
"BPF_F_PATH_FD is an OBJ_PIN/OBJ_GET flag, not a map creation flag")
help, and should the manpage wording narrow "from the bpf.h UAPI
header" a little so BPF_F_PATH_FD doesn't look like an accepted name?

> +
> +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;
> +}

[ ... ]

The changelog presents the new rejections as added validation, but
three of them are inputs the old parser accepted, so they are a
user-visible behaviour change rather than new strictness.

The previous branch was parse_u32_arg() -> strtoul(**argv, &endptr, 0)
with only `if (*endptr)` checked, so `flags ""` quietly became 0,
`flags 0x100000000` quietly truncated to 0, and `flags -1` quietly
wrapped to 0xffffffff. The new strtoll() path rejects all three.

That compatibility note is the part a reviewer would most want spelled
out, and it is the one thing the message leaves implicit while the
closing paragraphs restate the documentation and bash-completion hunks.

Could the changelog say that these numeric forms were previously
accepted (empty string and out-of-range values were silently
truncated), so the tightening is visible as an intentional behaviour
change?


---
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/34557157318

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-09-11  3:37 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-11  2:50 [PATCH bpf-next v4 0/2] bpftool: Support symbolic map creation flags Tianyi Chen
2026-09-11  2:50 ` [PATCH bpf-next v4 1/2] bpftool: Accept " Tianyi Chen
2026-09-11  3:37   ` bot+bpf-ci
2026-09-11  2:50 ` [PATCH bpf-next v4 2/2] selftests/bpf: Cover symbolic bpftool " Tianyi Chen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox