From: Tianyi Chen <diannaaav@gmail.com>
To: qmo@kernel.org, bpf@vger.kernel.org
Cc: andrii@kernel.org, eddyz87@gmail.com, ihor.solodrai@linux.dev,
linux-kselftest@vger.kernel.org
Subject: [PATCH bpf-next v4 1/2] bpftool: Accept symbolic map creation flags
Date: Fri, 11 Sep 2026 10:50:43 +0800 [thread overview]
Message-ID: <20260911025044.190540-2-diannaaav@gmail.com> (raw)
In-Reply-To: <20260911025044.190540-1-diannaaav@gmail.com>
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
next prev parent reply other threads:[~2026-09-11 2:50 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
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 [this message]
2026-09-11 3:37 ` [PATCH bpf-next v4 1/2] bpftool: Accept " bot+bpf-ci
2026-09-11 2:50 ` [PATCH bpf-next v4 2/2] selftests/bpf: Cover symbolic bpftool " Tianyi Chen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260911025044.190540-2-diannaaav@gmail.com \
--to=diannaaav@gmail.com \
--cc=andrii@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=eddyz87@gmail.com \
--cc=ihor.solodrai@linux.dev \
--cc=linux-kselftest@vger.kernel.org \
--cc=qmo@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.