Skip to content

Commit e3b9626

Browse files
qmonnetAlexei Starovoitov
authored and
Alexei Starovoitov
committed
tools: bpftool: Add "inner_map" to "bpftool map create" outer maps
There is no support for creating maps of types array-of-map or hash-of-map in bpftool. This is because the kernel needs an inner_map_fd to collect metadata on the inner maps to be supported by the new map, but bpftool does not provide a way to pass this file descriptor. Add a new optional "inner_map" keyword that can be used to pass a reference to a map, retrieve a fd to that map, and pass it as the inner_map_fd. Add related documentation and bash completion. Note that we can reference the inner map by its name, meaning we can have several times the keyword "name" with different meanings (mandatory outer map name, and possibly a name to use to find the inner_map_fd). The bash completion will offer it just once, and will not suggest "name" on the following command: # bpftool map create /sys/fs/bpf/my_outer_map type hash_of_maps \ inner_map name my_inner_map [TAB] Fixing that specific case seems too convoluted. Completion will work as expected, however, if the outer map name comes first and the "inner_map name ..." is passed second. Signed-off-by: Quentin Monnet <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Acked-by: Andrii Nakryiko <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 86233ce commit e3b9626

File tree

3 files changed

+62
-18
lines changed

3 files changed

+62
-18
lines changed

tools/bpf/bpftool/Documentation/bpftool-map.rst

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ MAP COMMANDS
2323

2424
| **bpftool** **map** { **show** | **list** } [*MAP*]
2525
| **bpftool** **map create** *FILE* **type** *TYPE* **key** *KEY_SIZE* **value** *VALUE_SIZE* \
26-
| **entries** *MAX_ENTRIES* **name** *NAME* [**flags** *FLAGS*] [**dev** *NAME*]
26+
| **entries** *MAX_ENTRIES* **name** *NAME* [**flags** *FLAGS*] [**inner_map** *MAP*] \
27+
| [**dev** *NAME*]
2728
| **bpftool** **map dump** *MAP*
2829
| **bpftool** **map update** *MAP* [**key** *DATA*] [**value** *VALUE*] [*UPDATE_FLAGS*]
2930
| **bpftool** **map lookup** *MAP* [**key** *DATA*]
@@ -67,14 +68,19 @@ DESCRIPTION
6768
maps. On such kernels bpftool will automatically emit this
6869
information as well.
6970

70-
**bpftool map create** *FILE* **type** *TYPE* **key** *KEY_SIZE* **value** *VALUE_SIZE* **entries** *MAX_ENTRIES* **name** *NAME* [**flags** *FLAGS*] [**dev** *NAME*]
71+
**bpftool map create** *FILE* **type** *TYPE* **key** *KEY_SIZE* **value** *VALUE_SIZE* **entries** *MAX_ENTRIES* **name** *NAME* [**flags** *FLAGS*] [**inner_map** *MAP*] [**dev** *NAME*]
7172
Create a new map with given parameters and pin it to *bpffs*
7273
as *FILE*.
7374

7475
*FLAGS* should be an integer which is the combination of
7576
desired flags, e.g. 1024 for **BPF_F_MMAPABLE** (see bpf.h
7677
UAPI header for existing flags).
7778

79+
To create maps of type array-of-maps or hash-of-maps, the
80+
**inner_map** keyword must be used to pass an inner map. The
81+
kernel needs it to collect metadata related to the inner maps
82+
that the new map will work with.
83+
7884
Keyword **dev** expects a network interface name, and is used
7985
to request hardware offload for the map.
8086

tools/bpf/bpftool/bash-completion/bpftool

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -709,16 +709,36 @@ _bpftool()
709709
"$cur" ) )
710710
return 0
711711
;;
712-
key|value|flags|name|entries)
712+
key|value|flags|entries)
713713
return 0
714714
;;
715+
inner_map)
716+
COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
717+
return 0
718+
;;
719+
id)
720+
_bpftool_get_map_ids
721+
;;
722+
name)
723+
case $pprev in
724+
inner_map)
725+
_bpftool_get_map_names
726+
;;
727+
*)
728+
return 0
729+
;;
730+
esac
731+
;;
715732
*)
716733
_bpftool_once_attr 'type'
717734
_bpftool_once_attr 'key'
718735
_bpftool_once_attr 'value'
719736
_bpftool_once_attr 'entries'
720737
_bpftool_once_attr 'name'
721738
_bpftool_once_attr 'flags'
739+
if _bpftool_search_list 'array_of_maps' 'hash_of_maps'; then
740+
_bpftool_once_attr 'inner_map'
741+
fi
722742
_bpftool_once_attr 'dev'
723743
return 0
724744
;;

tools/bpf/bpftool/map.c

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,7 +1250,7 @@ static int do_create(int argc, char **argv)
12501250
{
12511251
struct bpf_create_map_attr attr = { NULL, };
12521252
const char *pinfile;
1253-
int err, fd;
1253+
int err = -1, fd;
12541254

12551255
if (!REQ_ARGS(7))
12561256
return -1;
@@ -1265,13 +1265,13 @@ static int do_create(int argc, char **argv)
12651265

12661266
if (attr.map_type) {
12671267
p_err("map type already specified");
1268-
return -1;
1268+
goto exit;
12691269
}
12701270

12711271
attr.map_type = map_type_from_str(*argv);
12721272
if ((int)attr.map_type < 0) {
12731273
p_err("unrecognized map type: %s", *argv);
1274-
return -1;
1274+
goto exit;
12751275
}
12761276
NEXT_ARG();
12771277
} else if (is_prefix(*argv, "name")) {
@@ -1280,61 +1280,79 @@ static int do_create(int argc, char **argv)
12801280
} else if (is_prefix(*argv, "key")) {
12811281
if (parse_u32_arg(&argc, &argv, &attr.key_size,
12821282
"key size"))
1283-
return -1;
1283+
goto exit;
12841284
} else if (is_prefix(*argv, "value")) {
12851285
if (parse_u32_arg(&argc, &argv, &attr.value_size,
12861286
"value size"))
1287-
return -1;
1287+
goto exit;
12881288
} else if (is_prefix(*argv, "entries")) {
12891289
if (parse_u32_arg(&argc, &argv, &attr.max_entries,
12901290
"max entries"))
1291-
return -1;
1291+
goto exit;
12921292
} else if (is_prefix(*argv, "flags")) {
12931293
if (parse_u32_arg(&argc, &argv, &attr.map_flags,
12941294
"flags"))
1295-
return -1;
1295+
goto exit;
12961296
} else if (is_prefix(*argv, "dev")) {
12971297
NEXT_ARG();
12981298

12991299
if (attr.map_ifindex) {
13001300
p_err("offload device already specified");
1301-
return -1;
1301+
goto exit;
13021302
}
13031303

13041304
attr.map_ifindex = if_nametoindex(*argv);
13051305
if (!attr.map_ifindex) {
13061306
p_err("unrecognized netdevice '%s': %s",
13071307
*argv, strerror(errno));
1308-
return -1;
1308+
goto exit;
13091309
}
13101310
NEXT_ARG();
1311+
} else if (is_prefix(*argv, "inner_map")) {
1312+
struct bpf_map_info info = {};
1313+
__u32 len = sizeof(info);
1314+
int inner_map_fd;
1315+
1316+
NEXT_ARG();
1317+
if (!REQ_ARGS(2))
1318+
usage();
1319+
inner_map_fd = map_parse_fd_and_info(&argc, &argv,
1320+
&info, &len);
1321+
if (inner_map_fd < 0)
1322+
return -1;
1323+
attr.inner_map_fd = inner_map_fd;
13111324
} else {
13121325
p_err("unknown arg %s", *argv);
1313-
return -1;
1326+
goto exit;
13141327
}
13151328
}
13161329

13171330
if (!attr.name) {
13181331
p_err("map name not specified");
1319-
return -1;
1332+
goto exit;
13201333
}
13211334

13221335
set_max_rlimit();
13231336

13241337
fd = bpf_create_map_xattr(&attr);
13251338
if (fd < 0) {
13261339
p_err("map create failed: %s", strerror(errno));
1327-
return -1;
1340+
goto exit;
13281341
}
13291342

13301343
err = do_pin_fd(fd, pinfile);
13311344
close(fd);
13321345
if (err)
1333-
return err;
1346+
goto exit;
13341347

13351348
if (json_output)
13361349
jsonw_null(json_wtr);
1337-
return 0;
1350+
1351+
exit:
1352+
if (attr.inner_map_fd > 0)
1353+
close(attr.inner_map_fd);
1354+
1355+
return err;
13381356
}
13391357

13401358
static int do_pop_dequeue(int argc, char **argv)
@@ -1420,7 +1438,7 @@ static int do_help(int argc, char **argv)
14201438
"Usage: %1$s %2$s { show | list } [MAP]\n"
14211439
" %1$s %2$s create FILE type TYPE key KEY_SIZE value VALUE_SIZE \\\n"
14221440
" entries MAX_ENTRIES name NAME [flags FLAGS] \\\n"
1423-
" [dev NAME]\n"
1441+
" [inner_map MAP] [dev NAME]\n"
14241442
" %1$s %2$s dump MAP\n"
14251443
" %1$s %2$s update MAP [key DATA] [value VALUE] [UPDATE_FLAGS]\n"
14261444
" %1$s %2$s lookup MAP [key DATA]\n"

0 commit comments

Comments
 (0)