hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/tools/bpf/bpftool/map.c
....@@ -1,41 +1,12 @@
1
-/*
2
- * Copyright (C) 2017-2018 Netronome Systems, Inc.
3
- *
4
- * This software is dual licensed under the GNU General License Version 2,
5
- * June 1991 as shown in the file COPYING in the top-level directory of this
6
- * source tree or the BSD 2-Clause License provided below. You have the
7
- * option to license this software under the complete terms of either license.
8
- *
9
- * The BSD 2-Clause License:
10
- *
11
- * Redistribution and use in source and binary forms, with or
12
- * without modification, are permitted provided that the following
13
- * conditions are met:
14
- *
15
- * 1. Redistributions of source code must retain the above
16
- * copyright notice, this list of conditions and the following
17
- * disclaimer.
18
- *
19
- * 2. Redistributions in binary form must reproduce the above
20
- * copyright notice, this list of conditions and the following
21
- * disclaimer in the documentation and/or other materials
22
- * provided with the distribution.
23
- *
24
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31
- * SOFTWARE.
32
- */
1
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2
+/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
333
344 #include <assert.h>
355 #include <errno.h>
366 #include <fcntl.h>
377 #include <linux/err.h>
388 #include <linux/kernel.h>
9
+#include <net/if.h>
3910 #include <stdbool.h>
4011 #include <stdio.h>
4112 #include <stdlib.h>
....@@ -44,40 +15,52 @@
4415 #include <sys/types.h>
4516 #include <sys/stat.h>
4617
47
-#include <bpf.h>
18
+#include <bpf/bpf.h>
19
+#include <bpf/btf.h>
4820
49
-#include "btf.h"
5021 #include "json_writer.h"
5122 #include "main.h"
5223
53
-static const char * const map_type_name[] = {
54
- [BPF_MAP_TYPE_UNSPEC] = "unspec",
55
- [BPF_MAP_TYPE_HASH] = "hash",
56
- [BPF_MAP_TYPE_ARRAY] = "array",
57
- [BPF_MAP_TYPE_PROG_ARRAY] = "prog_array",
58
- [BPF_MAP_TYPE_PERF_EVENT_ARRAY] = "perf_event_array",
59
- [BPF_MAP_TYPE_PERCPU_HASH] = "percpu_hash",
60
- [BPF_MAP_TYPE_PERCPU_ARRAY] = "percpu_array",
61
- [BPF_MAP_TYPE_STACK_TRACE] = "stack_trace",
62
- [BPF_MAP_TYPE_CGROUP_ARRAY] = "cgroup_array",
63
- [BPF_MAP_TYPE_LRU_HASH] = "lru_hash",
64
- [BPF_MAP_TYPE_LRU_PERCPU_HASH] = "lru_percpu_hash",
65
- [BPF_MAP_TYPE_LPM_TRIE] = "lpm_trie",
66
- [BPF_MAP_TYPE_ARRAY_OF_MAPS] = "array_of_maps",
67
- [BPF_MAP_TYPE_HASH_OF_MAPS] = "hash_of_maps",
68
- [BPF_MAP_TYPE_DEVMAP] = "devmap",
69
- [BPF_MAP_TYPE_SOCKMAP] = "sockmap",
70
- [BPF_MAP_TYPE_CPUMAP] = "cpumap",
71
- [BPF_MAP_TYPE_XSKMAP] = "xskmap",
72
- [BPF_MAP_TYPE_SOCKHASH] = "sockhash",
73
- [BPF_MAP_TYPE_CGROUP_STORAGE] = "cgroup_storage",
24
+const char * const map_type_name[] = {
25
+ [BPF_MAP_TYPE_UNSPEC] = "unspec",
26
+ [BPF_MAP_TYPE_HASH] = "hash",
27
+ [BPF_MAP_TYPE_ARRAY] = "array",
28
+ [BPF_MAP_TYPE_PROG_ARRAY] = "prog_array",
29
+ [BPF_MAP_TYPE_PERF_EVENT_ARRAY] = "perf_event_array",
30
+ [BPF_MAP_TYPE_PERCPU_HASH] = "percpu_hash",
31
+ [BPF_MAP_TYPE_PERCPU_ARRAY] = "percpu_array",
32
+ [BPF_MAP_TYPE_STACK_TRACE] = "stack_trace",
33
+ [BPF_MAP_TYPE_CGROUP_ARRAY] = "cgroup_array",
34
+ [BPF_MAP_TYPE_LRU_HASH] = "lru_hash",
35
+ [BPF_MAP_TYPE_LRU_PERCPU_HASH] = "lru_percpu_hash",
36
+ [BPF_MAP_TYPE_LPM_TRIE] = "lpm_trie",
37
+ [BPF_MAP_TYPE_ARRAY_OF_MAPS] = "array_of_maps",
38
+ [BPF_MAP_TYPE_HASH_OF_MAPS] = "hash_of_maps",
39
+ [BPF_MAP_TYPE_DEVMAP] = "devmap",
40
+ [BPF_MAP_TYPE_DEVMAP_HASH] = "devmap_hash",
41
+ [BPF_MAP_TYPE_SOCKMAP] = "sockmap",
42
+ [BPF_MAP_TYPE_CPUMAP] = "cpumap",
43
+ [BPF_MAP_TYPE_XSKMAP] = "xskmap",
44
+ [BPF_MAP_TYPE_SOCKHASH] = "sockhash",
45
+ [BPF_MAP_TYPE_CGROUP_STORAGE] = "cgroup_storage",
46
+ [BPF_MAP_TYPE_REUSEPORT_SOCKARRAY] = "reuseport_sockarray",
47
+ [BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE] = "percpu_cgroup_storage",
48
+ [BPF_MAP_TYPE_QUEUE] = "queue",
49
+ [BPF_MAP_TYPE_STACK] = "stack",
50
+ [BPF_MAP_TYPE_SK_STORAGE] = "sk_storage",
51
+ [BPF_MAP_TYPE_STRUCT_OPS] = "struct_ops",
52
+ [BPF_MAP_TYPE_RINGBUF] = "ringbuf",
53
+ [BPF_MAP_TYPE_INODE_STORAGE] = "inode_storage",
7454 };
55
+
56
+const size_t map_type_name_size = ARRAY_SIZE(map_type_name);
7557
7658 static bool map_is_per_cpu(__u32 type)
7759 {
7860 return type == BPF_MAP_TYPE_PERCPU_HASH ||
7961 type == BPF_MAP_TYPE_PERCPU_ARRAY ||
80
- type == BPF_MAP_TYPE_LRU_PERCPU_HASH;
62
+ type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
63
+ type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE;
8164 }
8265
8366 static bool map_is_map_of_maps(__u32 type)
....@@ -91,6 +74,17 @@
9174 return type == BPF_MAP_TYPE_PROG_ARRAY;
9275 }
9376
77
+static int map_type_from_str(const char *type)
78
+{
79
+ unsigned int i;
80
+
81
+ for (i = 0; i < ARRAY_SIZE(map_type_name); i++)
82
+ /* Don't allow prefixing in case of possible future shadowing */
83
+ if (map_type_name[i] && !strcmp(map_type_name[i], type))
84
+ return i;
85
+ return -1;
86
+}
87
+
9488 static void *alloc_value(struct bpf_map_info *info)
9589 {
9690 if (map_is_per_cpu(info->type))
....@@ -100,149 +94,54 @@
10094 return malloc(info->value_size);
10195 }
10296
103
-int map_parse_fd(int *argc, char ***argv)
104
-{
105
- int fd;
106
-
107
- if (is_prefix(**argv, "id")) {
108
- unsigned int id;
109
- char *endptr;
110
-
111
- NEXT_ARGP();
112
-
113
- id = strtoul(**argv, &endptr, 0);
114
- if (*endptr) {
115
- p_err("can't parse %s as ID", **argv);
116
- return -1;
117
- }
118
- NEXT_ARGP();
119
-
120
- fd = bpf_map_get_fd_by_id(id);
121
- if (fd < 0)
122
- p_err("get map by id (%u): %s", id, strerror(errno));
123
- return fd;
124
- } else if (is_prefix(**argv, "pinned")) {
125
- char *path;
126
-
127
- NEXT_ARGP();
128
-
129
- path = **argv;
130
- NEXT_ARGP();
131
-
132
- return open_obj_pinned_any(path, BPF_OBJ_MAP);
133
- }
134
-
135
- p_err("expected 'id' or 'pinned', got: '%s'?", **argv);
136
- return -1;
137
-}
138
-
139
-int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len)
140
-{
141
- int err;
142
- int fd;
143
-
144
- fd = map_parse_fd(argc, argv);
145
- if (fd < 0)
146
- return -1;
147
-
148
- err = bpf_obj_get_info_by_fd(fd, info, info_len);
149
- if (err) {
150
- p_err("can't get map info: %s", strerror(errno));
151
- close(fd);
152
- return err;
153
- }
154
-
155
- return fd;
156
-}
157
-
15897 static int do_dump_btf(const struct btf_dumper *d,
15998 struct bpf_map_info *map_info, void *key,
16099 void *value)
161100 {
162
- int ret;
101
+ __u32 value_id;
102
+ int ret = 0;
163103
164104 /* start of key-value pair */
165105 jsonw_start_object(d->jw);
166106
167
- jsonw_name(d->jw, "key");
107
+ if (map_info->btf_key_type_id) {
108
+ jsonw_name(d->jw, "key");
168109
169
- ret = btf_dumper_type(d, map_info->btf_key_type_id, key);
170
- if (ret)
171
- goto err_end_obj;
110
+ ret = btf_dumper_type(d, map_info->btf_key_type_id, key);
111
+ if (ret)
112
+ goto err_end_obj;
113
+ }
172114
173
- jsonw_name(d->jw, "value");
115
+ value_id = map_info->btf_vmlinux_value_type_id ?
116
+ : map_info->btf_value_type_id;
174117
175
- ret = btf_dumper_type(d, map_info->btf_value_type_id, value);
118
+ if (!map_is_per_cpu(map_info->type)) {
119
+ jsonw_name(d->jw, "value");
120
+ ret = btf_dumper_type(d, value_id, value);
121
+ } else {
122
+ unsigned int i, n, step;
123
+
124
+ jsonw_name(d->jw, "values");
125
+ jsonw_start_array(d->jw);
126
+ n = get_possible_cpus();
127
+ step = round_up(map_info->value_size, 8);
128
+ for (i = 0; i < n; i++) {
129
+ jsonw_start_object(d->jw);
130
+ jsonw_int_field(d->jw, "cpu", i);
131
+ jsonw_name(d->jw, "value");
132
+ ret = btf_dumper_type(d, value_id, value + i * step);
133
+ jsonw_end_object(d->jw);
134
+ if (ret)
135
+ break;
136
+ }
137
+ jsonw_end_array(d->jw);
138
+ }
176139
177140 err_end_obj:
178141 /* end of key-value pair */
179142 jsonw_end_object(d->jw);
180143
181144 return ret;
182
-}
183
-
184
-static int get_btf(struct bpf_map_info *map_info, struct btf **btf)
185
-{
186
- struct bpf_btf_info btf_info = { 0 };
187
- __u32 len = sizeof(btf_info);
188
- __u32 last_size;
189
- int btf_fd;
190
- void *ptr;
191
- int err;
192
-
193
- err = 0;
194
- *btf = NULL;
195
- btf_fd = bpf_btf_get_fd_by_id(map_info->btf_id);
196
- if (btf_fd < 0)
197
- return 0;
198
-
199
- /* we won't know btf_size until we call bpf_obj_get_info_by_fd(). so
200
- * let's start with a sane default - 4KiB here - and resize it only if
201
- * bpf_obj_get_info_by_fd() needs a bigger buffer.
202
- */
203
- btf_info.btf_size = 4096;
204
- last_size = btf_info.btf_size;
205
- ptr = malloc(last_size);
206
- if (!ptr) {
207
- err = -ENOMEM;
208
- goto exit_free;
209
- }
210
-
211
- bzero(ptr, last_size);
212
- btf_info.btf = ptr_to_u64(ptr);
213
- err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len);
214
-
215
- if (!err && btf_info.btf_size > last_size) {
216
- void *temp_ptr;
217
-
218
- last_size = btf_info.btf_size;
219
- temp_ptr = realloc(ptr, last_size);
220
- if (!temp_ptr) {
221
- err = -ENOMEM;
222
- goto exit_free;
223
- }
224
- ptr = temp_ptr;
225
- bzero(ptr, last_size);
226
- btf_info.btf = ptr_to_u64(ptr);
227
- err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len);
228
- }
229
-
230
- if (err || btf_info.btf_size > last_size) {
231
- err = errno;
232
- goto exit_free;
233
- }
234
-
235
- *btf = btf__new((__u8 *)btf_info.btf, btf_info.btf_size, NULL);
236
- if (IS_ERR(*btf)) {
237
- err = PTR_ERR(*btf);
238
- *btf = NULL;
239
- }
240
-
241
-exit_free:
242
- close(btf_fd);
243
- free(ptr);
244
-
245
- return err;
246145 }
247146
248147 static json_writer_t *get_btf_writer(void)
....@@ -299,9 +198,73 @@
299198 jsonw_end_object(json_wtr);
300199 }
301200 jsonw_end_array(json_wtr);
201
+ if (btf) {
202
+ struct btf_dumper d = {
203
+ .btf = btf,
204
+ .jw = json_wtr,
205
+ .is_plain_text = false,
206
+ };
207
+
208
+ jsonw_name(json_wtr, "formatted");
209
+ do_dump_btf(&d, info, key, value);
210
+ }
302211 }
303212
304213 jsonw_end_object(json_wtr);
214
+}
215
+
216
+static void
217
+print_entry_error_msg(struct bpf_map_info *info, unsigned char *key,
218
+ const char *error_msg)
219
+{
220
+ int msg_size = strlen(error_msg);
221
+ bool single_line, break_names;
222
+
223
+ break_names = info->key_size > 16 || msg_size > 16;
224
+ single_line = info->key_size + msg_size <= 24 && !break_names;
225
+
226
+ printf("key:%c", break_names ? '\n' : ' ');
227
+ fprint_hex(stdout, key, info->key_size, " ");
228
+
229
+ printf(single_line ? " " : "\n");
230
+
231
+ printf("value:%c%s", break_names ? '\n' : ' ', error_msg);
232
+
233
+ printf("\n");
234
+}
235
+
236
+static void
237
+print_entry_error(struct bpf_map_info *map_info, void *key, int lookup_errno)
238
+{
239
+ /* For prog_array maps or arrays of maps, failure to lookup the value
240
+ * means there is no entry for that key. Do not print an error message
241
+ * in that case.
242
+ */
243
+ if ((map_is_map_of_maps(map_info->type) ||
244
+ map_is_map_of_progs(map_info->type)) && lookup_errno == ENOENT)
245
+ return;
246
+
247
+ if (json_output) {
248
+ jsonw_start_object(json_wtr); /* entry */
249
+ jsonw_name(json_wtr, "key");
250
+ print_hex_data_json(key, map_info->key_size);
251
+ jsonw_name(json_wtr, "value");
252
+ jsonw_start_object(json_wtr); /* error */
253
+ jsonw_string_field(json_wtr, "error", strerror(lookup_errno));
254
+ jsonw_end_object(json_wtr); /* error */
255
+ jsonw_end_object(json_wtr); /* entry */
256
+ } else {
257
+ const char *msg = NULL;
258
+
259
+ if (lookup_errno == ENOENT)
260
+ msg = "<no entry>";
261
+ else if (lookup_errno == ENOSPC &&
262
+ map_info->type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY)
263
+ msg = "<cannot read>";
264
+
265
+ print_entry_error_msg(map_info, key,
266
+ msg ? : strerror(lookup_errno));
267
+ }
305268 }
306269
307270 static void print_entry_plain(struct bpf_map_info *info, unsigned char *key,
....@@ -314,13 +277,17 @@
314277 single_line = info->key_size + info->value_size <= 24 &&
315278 !break_names;
316279
317
- printf("key:%c", break_names ? '\n' : ' ');
318
- fprint_hex(stdout, key, info->key_size, " ");
280
+ if (info->key_size) {
281
+ printf("key:%c", break_names ? '\n' : ' ');
282
+ fprint_hex(stdout, key, info->key_size, " ");
319283
320
- printf(single_line ? " " : "\n");
284
+ printf(single_line ? " " : "\n");
285
+ }
321286
322
- printf("value:%c", break_names ? '\n' : ' ');
323
- fprint_hex(stdout, value, info->value_size, " ");
287
+ if (info->value_size) {
288
+ printf("value:%c", break_names ? '\n' : ' ');
289
+ fprint_hex(stdout, value, info->value_size, " ");
290
+ }
324291
325292 printf("\n");
326293 } else {
....@@ -329,15 +296,19 @@
329296 n = get_possible_cpus();
330297 step = round_up(info->value_size, 8);
331298
332
- printf("key:\n");
333
- fprint_hex(stdout, key, info->key_size, " ");
334
- printf("\n");
335
- for (i = 0; i < n; i++) {
336
- printf("value (CPU %02d):%c",
337
- i, info->value_size > 16 ? '\n' : ' ');
338
- fprint_hex(stdout, value + i * step,
339
- info->value_size, " ");
299
+ if (info->key_size) {
300
+ printf("key:\n");
301
+ fprint_hex(stdout, key, info->key_size, " ");
340302 printf("\n");
303
+ }
304
+ if (info->value_size) {
305
+ for (i = 0; i < n; i++) {
306
+ printf("value (CPU %02d):%c",
307
+ i, info->value_size > 16 ? '\n' : ' ');
308
+ fprint_hex(stdout, value + i * step,
309
+ info->value_size, " ");
310
+ printf("\n");
311
+ }
341312 }
342313 }
343314 }
....@@ -452,6 +423,9 @@
452423 p_err("not enough value arguments for map of progs");
453424 return -1;
454425 }
426
+ if (is_prefix(*argv, "id"))
427
+ p_info("Warning: updating program array via MAP_ID, make sure this map is kept open\n"
428
+ " by some process or pinned otherwise update will be lost");
455429
456430 fd = prog_parse_fd(&argc, &argv);
457431 if (fd < 0)
....@@ -491,27 +465,32 @@
491465 return -1;
492466 }
493467
468
+static void show_map_header_json(struct bpf_map_info *info, json_writer_t *wtr)
469
+{
470
+ jsonw_uint_field(wtr, "id", info->id);
471
+ if (info->type < ARRAY_SIZE(map_type_name))
472
+ jsonw_string_field(wtr, "type", map_type_name[info->type]);
473
+ else
474
+ jsonw_uint_field(wtr, "type", info->type);
475
+
476
+ if (*info->name)
477
+ jsonw_string_field(wtr, "name", info->name);
478
+
479
+ jsonw_name(wtr, "flags");
480
+ jsonw_printf(wtr, "%d", info->map_flags);
481
+}
482
+
494483 static int show_map_close_json(int fd, struct bpf_map_info *info)
495484 {
496
- char *memlock;
485
+ char *memlock, *frozen_str;
486
+ int frozen = 0;
497487
498488 memlock = get_fdinfo(fd, "memlock");
499
- close(fd);
489
+ frozen_str = get_fdinfo(fd, "frozen");
500490
501491 jsonw_start_object(json_wtr);
502492
503
- jsonw_uint_field(json_wtr, "id", info->id);
504
- if (info->type < ARRAY_SIZE(map_type_name))
505
- jsonw_string_field(json_wtr, "type",
506
- map_type_name[info->type]);
507
- else
508
- jsonw_uint_field(json_wtr, "type", info->type);
509
-
510
- if (*info->name)
511
- jsonw_string_field(json_wtr, "name", info->name);
512
-
513
- jsonw_name(json_wtr, "flags");
514
- jsonw_printf(json_wtr, "%d", info->map_flags);
493
+ show_map_header_json(info, json_wtr);
515494
516495 print_dev_json(info->ifindex, info->netns_dev, info->netns_ino);
517496
....@@ -522,6 +501,38 @@
522501 if (memlock)
523502 jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock));
524503 free(memlock);
504
+
505
+ if (info->type == BPF_MAP_TYPE_PROG_ARRAY) {
506
+ char *owner_prog_type = get_fdinfo(fd, "owner_prog_type");
507
+ char *owner_jited = get_fdinfo(fd, "owner_jited");
508
+
509
+ if (owner_prog_type) {
510
+ unsigned int prog_type = atoi(owner_prog_type);
511
+
512
+ if (prog_type < prog_type_name_size)
513
+ jsonw_string_field(json_wtr, "owner_prog_type",
514
+ prog_type_name[prog_type]);
515
+ else
516
+ jsonw_uint_field(json_wtr, "owner_prog_type",
517
+ prog_type);
518
+ }
519
+ if (owner_jited)
520
+ jsonw_bool_field(json_wtr, "owner_jited",
521
+ !!atoi(owner_jited));
522
+
523
+ free(owner_prog_type);
524
+ free(owner_jited);
525
+ }
526
+ close(fd);
527
+
528
+ if (frozen_str) {
529
+ frozen = atoi(frozen_str);
530
+ free(frozen_str);
531
+ }
532
+ jsonw_int_field(json_wtr, "frozen", frozen);
533
+
534
+ if (info->btf_id)
535
+ jsonw_int_field(json_wtr, "btf_id", info->btf_id);
525536
526537 if (!hash_empty(map_table.table)) {
527538 struct pinned_obj *obj;
....@@ -535,18 +546,15 @@
535546 jsonw_end_array(json_wtr);
536547 }
537548
549
+ emit_obj_refs_json(&refs_table, info->id, json_wtr);
550
+
538551 jsonw_end_object(json_wtr);
539552
540553 return 0;
541554 }
542555
543
-static int show_map_close_plain(int fd, struct bpf_map_info *info)
556
+static void show_map_header_plain(struct bpf_map_info *info)
544557 {
545
- char *memlock;
546
-
547
- memlock = get_fdinfo(fd, "memlock");
548
- close(fd);
549
-
550558 printf("%u: ", info->id);
551559 if (info->type < ARRAY_SIZE(map_type_name))
552560 printf("%s ", map_type_name[info->type]);
....@@ -559,6 +567,17 @@
559567 printf("flags 0x%x", info->map_flags);
560568 print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino);
561569 printf("\n");
570
+}
571
+
572
+static int show_map_close_plain(int fd, struct bpf_map_info *info)
573
+{
574
+ char *memlock, *frozen_str;
575
+ int frozen = 0;
576
+
577
+ memlock = get_fdinfo(fd, "memlock");
578
+ frozen_str = get_fdinfo(fd, "frozen");
579
+
580
+ show_map_header_plain(info);
562581 printf("\tkey %uB value %uB max_entries %u",
563582 info->key_size, info->value_size, info->max_entries);
564583
....@@ -566,16 +585,104 @@
566585 printf(" memlock %sB", memlock);
567586 free(memlock);
568587
569
- printf("\n");
588
+ if (info->type == BPF_MAP_TYPE_PROG_ARRAY) {
589
+ char *owner_prog_type = get_fdinfo(fd, "owner_prog_type");
590
+ char *owner_jited = get_fdinfo(fd, "owner_jited");
591
+
592
+ if (owner_prog_type || owner_jited)
593
+ printf("\n\t");
594
+ if (owner_prog_type) {
595
+ unsigned int prog_type = atoi(owner_prog_type);
596
+
597
+ if (prog_type < prog_type_name_size)
598
+ printf("owner_prog_type %s ",
599
+ prog_type_name[prog_type]);
600
+ else
601
+ printf("owner_prog_type %d ", prog_type);
602
+ }
603
+ if (owner_jited)
604
+ printf("owner%s jited",
605
+ atoi(owner_jited) ? "" : " not");
606
+
607
+ free(owner_prog_type);
608
+ free(owner_jited);
609
+ }
610
+ close(fd);
611
+
570612 if (!hash_empty(map_table.table)) {
571613 struct pinned_obj *obj;
572614
573615 hash_for_each_possible(map_table.table, obj, hash, info->id) {
574616 if (obj->id == info->id)
575
- printf("\tpinned %s\n", obj->path);
617
+ printf("\n\tpinned %s", obj->path);
576618 }
577619 }
620
+ printf("\n");
621
+
622
+ if (frozen_str) {
623
+ frozen = atoi(frozen_str);
624
+ free(frozen_str);
625
+ }
626
+
627
+ if (!info->btf_id && !frozen)
628
+ return 0;
629
+
630
+ printf("\t");
631
+
632
+ if (info->btf_id)
633
+ printf("btf_id %d", info->btf_id);
634
+
635
+ if (frozen)
636
+ printf("%sfrozen", info->btf_id ? " " : "");
637
+
638
+ emit_obj_refs_plain(&refs_table, info->id, "\n\tpids ");
639
+
640
+ printf("\n");
578641 return 0;
642
+}
643
+
644
+static int do_show_subset(int argc, char **argv)
645
+{
646
+ struct bpf_map_info info = {};
647
+ __u32 len = sizeof(info);
648
+ int *fds = NULL;
649
+ int nb_fds, i;
650
+ int err = -1;
651
+
652
+ fds = malloc(sizeof(int));
653
+ if (!fds) {
654
+ p_err("mem alloc failed");
655
+ return -1;
656
+ }
657
+ nb_fds = map_parse_fds(&argc, &argv, &fds);
658
+ if (nb_fds < 1)
659
+ goto exit_free;
660
+
661
+ if (json_output && nb_fds > 1)
662
+ jsonw_start_array(json_wtr); /* root array */
663
+ for (i = 0; i < nb_fds; i++) {
664
+ err = bpf_obj_get_info_by_fd(fds[i], &info, &len);
665
+ if (err) {
666
+ p_err("can't get map info: %s",
667
+ strerror(errno));
668
+ for (; i < nb_fds; i++)
669
+ close(fds[i]);
670
+ break;
671
+ }
672
+
673
+ if (json_output)
674
+ show_map_close_json(fds[i], &info);
675
+ else
676
+ show_map_close_plain(fds[i], &info);
677
+
678
+ close(fds[i]);
679
+ }
680
+ if (json_output && nb_fds > 1)
681
+ jsonw_end_array(json_wtr); /* root array */
682
+
683
+exit_free:
684
+ free(fds);
685
+ return err;
579686 }
580687
581688 static int do_show(int argc, char **argv)
....@@ -588,17 +695,10 @@
588695
589696 if (show_pinned)
590697 build_pinned_obj_table(&map_table, BPF_OBJ_MAP);
698
+ build_obj_refs_table(&refs_table, BPF_OBJ_MAP);
591699
592
- if (argc == 2) {
593
- fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
594
- if (fd < 0)
595
- return -1;
596
-
597
- if (json_output)
598
- return show_map_close_json(fd, &info);
599
- else
600
- return show_map_close_plain(fd, &info);
601
- }
700
+ if (argc == 2)
701
+ return do_show_subset(argc, argv);
602702
603703 if (argc)
604704 return BAD_ARG();
....@@ -639,35 +739,106 @@
639739 if (json_output)
640740 jsonw_end_array(json_wtr);
641741
742
+ delete_obj_refs_table(&refs_table);
743
+
642744 return errno == ENOENT ? 0 : -1;
643745 }
644746
645
-static int do_dump(int argc, char **argv)
747
+static int dump_map_elem(int fd, void *key, void *value,
748
+ struct bpf_map_info *map_info, struct btf *btf,
749
+ json_writer_t *btf_wtr)
646750 {
647
- struct bpf_map_info info = {};
648
- void *key, *value, *prev_key;
649
- unsigned int num_elems = 0;
650
- __u32 len = sizeof(info);
651
- json_writer_t *btf_wtr;
652
- struct btf *btf = NULL;
653
- int err;
654
- int fd;
655
-
656
- if (argc != 2)
657
- usage();
658
-
659
- fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
660
- if (fd < 0)
661
- return -1;
662
-
663
- if (map_is_map_of_maps(info.type) || map_is_map_of_progs(info.type)) {
664
- p_err("Dumping maps of maps and program maps not supported");
665
- close(fd);
751
+ if (bpf_map_lookup_elem(fd, key, value)) {
752
+ print_entry_error(map_info, key, errno);
666753 return -1;
667754 }
668755
669
- key = malloc(info.key_size);
670
- value = alloc_value(&info);
756
+ if (json_output) {
757
+ print_entry_json(map_info, key, value, btf);
758
+ } else if (btf) {
759
+ struct btf_dumper d = {
760
+ .btf = btf,
761
+ .jw = btf_wtr,
762
+ .is_plain_text = true,
763
+ };
764
+
765
+ do_dump_btf(&d, map_info, key, value);
766
+ } else {
767
+ print_entry_plain(map_info, key, value);
768
+ }
769
+
770
+ return 0;
771
+}
772
+
773
+static int maps_have_btf(int *fds, int nb_fds)
774
+{
775
+ struct bpf_map_info info = {};
776
+ __u32 len = sizeof(info);
777
+ int err, i;
778
+
779
+ for (i = 0; i < nb_fds; i++) {
780
+ err = bpf_obj_get_info_by_fd(fds[i], &info, &len);
781
+ if (err) {
782
+ p_err("can't get map info: %s", strerror(errno));
783
+ return -1;
784
+ }
785
+
786
+ if (!info.btf_id)
787
+ return 0;
788
+ }
789
+
790
+ return 1;
791
+}
792
+
793
+static struct btf *btf_vmlinux;
794
+
795
+static struct btf *get_map_kv_btf(const struct bpf_map_info *info)
796
+{
797
+ struct btf *btf = NULL;
798
+
799
+ if (info->btf_vmlinux_value_type_id) {
800
+ if (!btf_vmlinux) {
801
+ btf_vmlinux = libbpf_find_kernel_btf();
802
+ if (IS_ERR(btf_vmlinux))
803
+ p_err("failed to get kernel btf");
804
+ }
805
+ return btf_vmlinux;
806
+ } else if (info->btf_value_type_id) {
807
+ int err;
808
+
809
+ err = btf__get_from_id(info->btf_id, &btf);
810
+ if (err || !btf) {
811
+ p_err("failed to get btf");
812
+ btf = err ? ERR_PTR(err) : ERR_PTR(-ESRCH);
813
+ }
814
+ }
815
+
816
+ return btf;
817
+}
818
+
819
+static void free_map_kv_btf(struct btf *btf)
820
+{
821
+ if (!IS_ERR(btf) && btf != btf_vmlinux)
822
+ btf__free(btf);
823
+}
824
+
825
+static void free_btf_vmlinux(void)
826
+{
827
+ if (!IS_ERR(btf_vmlinux))
828
+ btf__free(btf_vmlinux);
829
+}
830
+
831
+static int
832
+map_dump(int fd, struct bpf_map_info *info, json_writer_t *wtr,
833
+ bool show_header)
834
+{
835
+ void *key, *value, *prev_key;
836
+ unsigned int num_elems = 0;
837
+ struct btf *btf = NULL;
838
+ int err;
839
+
840
+ key = malloc(info->key_size);
841
+ value = alloc_value(info);
671842 if (!key || !value) {
672843 p_err("mem alloc failed");
673844 err = -1;
....@@ -676,26 +847,27 @@
676847
677848 prev_key = NULL;
678849
679
- err = get_btf(&info, &btf);
680
- if (err) {
681
- p_err("failed to get btf");
682
- goto exit_free;
683
- }
684
-
685
- if (json_output)
686
- jsonw_start_array(json_wtr);
687
- else
688
- if (btf) {
689
- btf_wtr = get_btf_writer();
690
- if (!btf_wtr) {
691
- p_info("failed to create json writer for btf. falling back to plain output");
692
- btf__free(btf);
693
- btf = NULL;
694
- } else {
695
- jsonw_start_array(btf_wtr);
696
- }
850
+ if (wtr) {
851
+ btf = get_map_kv_btf(info);
852
+ if (IS_ERR(btf)) {
853
+ err = PTR_ERR(btf);
854
+ goto exit_free;
697855 }
698856
857
+ if (show_header) {
858
+ jsonw_start_object(wtr); /* map object */
859
+ show_map_header_json(info, wtr);
860
+ jsonw_name(wtr, "elements");
861
+ }
862
+ jsonw_start_array(wtr); /* elements */
863
+ } else if (show_header) {
864
+ show_map_header_plain(info);
865
+ }
866
+
867
+ if (info->type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY &&
868
+ info->value_size != 8)
869
+ p_info("Warning: cannot read values from %s map with value_size != 8",
870
+ map_type_name[info->type]);
699871 while (true) {
700872 err = bpf_map_get_next_key(fd, prev_key, key);
701873 if (err) {
....@@ -703,47 +875,15 @@
703875 err = 0;
704876 break;
705877 }
706
-
707
- if (!bpf_map_lookup_elem(fd, key, value)) {
708
- if (json_output)
709
- print_entry_json(&info, key, value, btf);
710
- else
711
- if (btf) {
712
- struct btf_dumper d = {
713
- .btf = btf,
714
- .jw = btf_wtr,
715
- .is_plain_text = true,
716
- };
717
-
718
- do_dump_btf(&d, &info, key, value);
719
- } else {
720
- print_entry_plain(&info, key, value);
721
- }
722
- } else {
723
- if (json_output) {
724
- jsonw_name(json_wtr, "key");
725
- print_hex_data_json(key, info.key_size);
726
- jsonw_name(json_wtr, "value");
727
- jsonw_start_object(json_wtr);
728
- jsonw_string_field(json_wtr, "error",
729
- "can't lookup element");
730
- jsonw_end_object(json_wtr);
731
- } else {
732
- p_info("can't lookup element with key: ");
733
- fprint_hex(stderr, key, info.key_size, " ");
734
- fprintf(stderr, "\n");
735
- }
736
- }
737
-
878
+ if (!dump_map_elem(fd, key, value, info, btf, wtr))
879
+ num_elems++;
738880 prev_key = key;
739
- num_elems++;
740881 }
741882
742
- if (json_output)
743
- jsonw_end_array(json_wtr);
744
- else if (btf) {
745
- jsonw_end_array(btf_wtr);
746
- jsonw_destroy(&btf_wtr);
883
+ if (wtr) {
884
+ jsonw_end_array(wtr); /* elements */
885
+ if (show_header)
886
+ jsonw_end_object(wtr); /* map object */
747887 } else {
748888 printf("Found %u element%s\n", num_elems,
749889 num_elems != 1 ? "s" : "");
....@@ -753,9 +893,102 @@
753893 free(key);
754894 free(value);
755895 close(fd);
756
- btf__free(btf);
896
+ free_map_kv_btf(btf);
757897
758898 return err;
899
+}
900
+
901
+static int do_dump(int argc, char **argv)
902
+{
903
+ json_writer_t *wtr = NULL, *btf_wtr = NULL;
904
+ struct bpf_map_info info = {};
905
+ int nb_fds, i = 0;
906
+ __u32 len = sizeof(info);
907
+ int *fds = NULL;
908
+ int err = -1;
909
+
910
+ if (argc != 2)
911
+ usage();
912
+
913
+ fds = malloc(sizeof(int));
914
+ if (!fds) {
915
+ p_err("mem alloc failed");
916
+ return -1;
917
+ }
918
+ nb_fds = map_parse_fds(&argc, &argv, &fds);
919
+ if (nb_fds < 1)
920
+ goto exit_free;
921
+
922
+ if (json_output) {
923
+ wtr = json_wtr;
924
+ } else {
925
+ int do_plain_btf;
926
+
927
+ do_plain_btf = maps_have_btf(fds, nb_fds);
928
+ if (do_plain_btf < 0)
929
+ goto exit_close;
930
+
931
+ if (do_plain_btf) {
932
+ btf_wtr = get_btf_writer();
933
+ wtr = btf_wtr;
934
+ if (!btf_wtr)
935
+ p_info("failed to create json writer for btf. falling back to plain output");
936
+ }
937
+ }
938
+
939
+ if (wtr && nb_fds > 1)
940
+ jsonw_start_array(wtr); /* root array */
941
+ for (i = 0; i < nb_fds; i++) {
942
+ if (bpf_obj_get_info_by_fd(fds[i], &info, &len)) {
943
+ p_err("can't get map info: %s", strerror(errno));
944
+ break;
945
+ }
946
+ err = map_dump(fds[i], &info, wtr, nb_fds > 1);
947
+ if (!wtr && i != nb_fds - 1)
948
+ printf("\n");
949
+
950
+ if (err)
951
+ break;
952
+ close(fds[i]);
953
+ }
954
+ if (wtr && nb_fds > 1)
955
+ jsonw_end_array(wtr); /* root array */
956
+
957
+ if (btf_wtr)
958
+ jsonw_destroy(&btf_wtr);
959
+exit_close:
960
+ for (; i < nb_fds; i++)
961
+ close(fds[i]);
962
+exit_free:
963
+ free(fds);
964
+ free_btf_vmlinux();
965
+ return err;
966
+}
967
+
968
+static int alloc_key_value(struct bpf_map_info *info, void **key, void **value)
969
+{
970
+ *key = NULL;
971
+ *value = NULL;
972
+
973
+ if (info->key_size) {
974
+ *key = malloc(info->key_size);
975
+ if (!*key) {
976
+ p_err("key mem alloc failed");
977
+ return -1;
978
+ }
979
+ }
980
+
981
+ if (info->value_size) {
982
+ *value = alloc_value(info);
983
+ if (!*value) {
984
+ p_err("value mem alloc failed");
985
+ free(*key);
986
+ *key = NULL;
987
+ return -1;
988
+ }
989
+ }
990
+
991
+ return 0;
759992 }
760993
761994 static int do_update(int argc, char **argv)
....@@ -774,13 +1007,9 @@
7741007 if (fd < 0)
7751008 return -1;
7761009
777
- key = malloc(info.key_size);
778
- value = alloc_value(&info);
779
- if (!key || !value) {
780
- p_err("mem alloc failed");
781
- err = -1;
1010
+ err = alloc_key_value(&info, &key, &value);
1011
+ if (err)
7821012 goto exit_free;
783
- }
7841013
7851014 err = parse_elem(argv, &info, key, value, info.key_size,
7861015 info.value_size, &flags, &value_fd);
....@@ -805,12 +1034,51 @@
8051034 return err;
8061035 }
8071036
1037
+static void print_key_value(struct bpf_map_info *info, void *key,
1038
+ void *value)
1039
+{
1040
+ json_writer_t *btf_wtr;
1041
+ struct btf *btf = NULL;
1042
+ int err;
1043
+
1044
+ err = btf__get_from_id(info->btf_id, &btf);
1045
+ if (err) {
1046
+ p_err("failed to get btf");
1047
+ return;
1048
+ }
1049
+
1050
+ if (json_output) {
1051
+ print_entry_json(info, key, value, btf);
1052
+ } else if (btf) {
1053
+ /* if here json_wtr wouldn't have been initialised,
1054
+ * so let's create separate writer for btf
1055
+ */
1056
+ btf_wtr = get_btf_writer();
1057
+ if (!btf_wtr) {
1058
+ p_info("failed to create json writer for btf. falling back to plain output");
1059
+ btf__free(btf);
1060
+ btf = NULL;
1061
+ print_entry_plain(info, key, value);
1062
+ } else {
1063
+ struct btf_dumper d = {
1064
+ .btf = btf,
1065
+ .jw = btf_wtr,
1066
+ .is_plain_text = true,
1067
+ };
1068
+
1069
+ do_dump_btf(&d, info, key, value);
1070
+ jsonw_destroy(&btf_wtr);
1071
+ }
1072
+ } else {
1073
+ print_entry_plain(info, key, value);
1074
+ }
1075
+ btf__free(btf);
1076
+}
1077
+
8081078 static int do_lookup(int argc, char **argv)
8091079 {
8101080 struct bpf_map_info info = {};
8111081 __u32 len = sizeof(info);
812
- json_writer_t *btf_wtr;
813
- struct btf *btf = NULL;
8141082 void *key, *value;
8151083 int err;
8161084 int fd;
....@@ -822,13 +1090,9 @@
8221090 if (fd < 0)
8231091 return -1;
8241092
825
- key = malloc(info.key_size);
826
- value = alloc_value(&info);
827
- if (!key || !value) {
828
- p_err("mem alloc failed");
829
- err = -1;
1093
+ err = alloc_key_value(&info, &key, &value);
1094
+ if (err)
8301095 goto exit_free;
831
- }
8321096
8331097 err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL);
8341098 if (err)
....@@ -852,43 +1116,12 @@
8521116 }
8531117
8541118 /* here means bpf_map_lookup_elem() succeeded */
855
- err = get_btf(&info, &btf);
856
- if (err) {
857
- p_err("failed to get btf");
858
- goto exit_free;
859
- }
860
-
861
- if (json_output) {
862
- print_entry_json(&info, key, value, btf);
863
- } else if (btf) {
864
- /* if here json_wtr wouldn't have been initialised,
865
- * so let's create separate writer for btf
866
- */
867
- btf_wtr = get_btf_writer();
868
- if (!btf_wtr) {
869
- p_info("failed to create json writer for btf. falling back to plain output");
870
- btf__free(btf);
871
- btf = NULL;
872
- print_entry_plain(&info, key, value);
873
- } else {
874
- struct btf_dumper d = {
875
- .btf = btf,
876
- .jw = btf_wtr,
877
- .is_plain_text = true,
878
- };
879
-
880
- do_dump_btf(&d, &info, key, value);
881
- jsonw_destroy(&btf_wtr);
882
- }
883
- } else {
884
- print_entry_plain(&info, key, value);
885
- }
1119
+ print_key_value(&info, key, value);
8861120
8871121 exit_free:
8881122 free(key);
8891123 free(value);
8901124 close(fd);
891
- btf__free(btf);
8921125
8931126 return err;
8941127 }
....@@ -1007,10 +1240,191 @@
10071240 {
10081241 int err;
10091242
1010
- err = do_pin_any(argc, argv, bpf_map_get_fd_by_id);
1243
+ err = do_pin_any(argc, argv, map_parse_fd);
10111244 if (!err && json_output)
10121245 jsonw_null(json_wtr);
10131246 return err;
1247
+}
1248
+
1249
+static int do_create(int argc, char **argv)
1250
+{
1251
+ struct bpf_create_map_attr attr = { NULL, };
1252
+ const char *pinfile;
1253
+ int err = -1, fd;
1254
+
1255
+ if (!REQ_ARGS(7))
1256
+ return -1;
1257
+ pinfile = GET_ARG();
1258
+
1259
+ while (argc) {
1260
+ if (!REQ_ARGS(2))
1261
+ return -1;
1262
+
1263
+ if (is_prefix(*argv, "type")) {
1264
+ NEXT_ARG();
1265
+
1266
+ if (attr.map_type) {
1267
+ p_err("map type already specified");
1268
+ goto exit;
1269
+ }
1270
+
1271
+ attr.map_type = map_type_from_str(*argv);
1272
+ if ((int)attr.map_type < 0) {
1273
+ p_err("unrecognized map type: %s", *argv);
1274
+ goto exit;
1275
+ }
1276
+ NEXT_ARG();
1277
+ } else if (is_prefix(*argv, "name")) {
1278
+ NEXT_ARG();
1279
+ attr.name = GET_ARG();
1280
+ } else if (is_prefix(*argv, "key")) {
1281
+ if (parse_u32_arg(&argc, &argv, &attr.key_size,
1282
+ "key size"))
1283
+ goto exit;
1284
+ } else if (is_prefix(*argv, "value")) {
1285
+ if (parse_u32_arg(&argc, &argv, &attr.value_size,
1286
+ "value size"))
1287
+ goto exit;
1288
+ } else if (is_prefix(*argv, "entries")) {
1289
+ if (parse_u32_arg(&argc, &argv, &attr.max_entries,
1290
+ "max entries"))
1291
+ goto exit;
1292
+ } else if (is_prefix(*argv, "flags")) {
1293
+ if (parse_u32_arg(&argc, &argv, &attr.map_flags,
1294
+ "flags"))
1295
+ goto exit;
1296
+ } else if (is_prefix(*argv, "dev")) {
1297
+ NEXT_ARG();
1298
+
1299
+ if (attr.map_ifindex) {
1300
+ p_err("offload device already specified");
1301
+ goto exit;
1302
+ }
1303
+
1304
+ attr.map_ifindex = if_nametoindex(*argv);
1305
+ if (!attr.map_ifindex) {
1306
+ p_err("unrecognized netdevice '%s': %s",
1307
+ *argv, strerror(errno));
1308
+ goto exit;
1309
+ }
1310
+ 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;
1324
+ } else {
1325
+ p_err("unknown arg %s", *argv);
1326
+ goto exit;
1327
+ }
1328
+ }
1329
+
1330
+ if (!attr.name) {
1331
+ p_err("map name not specified");
1332
+ goto exit;
1333
+ }
1334
+
1335
+ set_max_rlimit();
1336
+
1337
+ fd = bpf_create_map_xattr(&attr);
1338
+ if (fd < 0) {
1339
+ p_err("map create failed: %s", strerror(errno));
1340
+ goto exit;
1341
+ }
1342
+
1343
+ err = do_pin_fd(fd, pinfile);
1344
+ close(fd);
1345
+ if (err)
1346
+ goto exit;
1347
+
1348
+ if (json_output)
1349
+ jsonw_null(json_wtr);
1350
+
1351
+exit:
1352
+ if (attr.inner_map_fd > 0)
1353
+ close(attr.inner_map_fd);
1354
+
1355
+ return err;
1356
+}
1357
+
1358
+static int do_pop_dequeue(int argc, char **argv)
1359
+{
1360
+ struct bpf_map_info info = {};
1361
+ __u32 len = sizeof(info);
1362
+ void *key, *value;
1363
+ int err;
1364
+ int fd;
1365
+
1366
+ if (argc < 2)
1367
+ usage();
1368
+
1369
+ fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
1370
+ if (fd < 0)
1371
+ return -1;
1372
+
1373
+ err = alloc_key_value(&info, &key, &value);
1374
+ if (err)
1375
+ goto exit_free;
1376
+
1377
+ err = bpf_map_lookup_and_delete_elem(fd, key, value);
1378
+ if (err) {
1379
+ if (errno == ENOENT) {
1380
+ if (json_output)
1381
+ jsonw_null(json_wtr);
1382
+ else
1383
+ printf("Error: empty map\n");
1384
+ } else {
1385
+ p_err("pop failed: %s", strerror(errno));
1386
+ }
1387
+
1388
+ goto exit_free;
1389
+ }
1390
+
1391
+ print_key_value(&info, key, value);
1392
+
1393
+exit_free:
1394
+ free(key);
1395
+ free(value);
1396
+ close(fd);
1397
+
1398
+ return err;
1399
+}
1400
+
1401
+static int do_freeze(int argc, char **argv)
1402
+{
1403
+ int err, fd;
1404
+
1405
+ if (!REQ_ARGS(2))
1406
+ return -1;
1407
+
1408
+ fd = map_parse_fd(&argc, &argv);
1409
+ if (fd < 0)
1410
+ return -1;
1411
+
1412
+ if (argc) {
1413
+ close(fd);
1414
+ return BAD_ARG();
1415
+ }
1416
+
1417
+ err = bpf_map_freeze(fd);
1418
+ close(fd);
1419
+ if (err) {
1420
+ p_err("failed to freeze map: %s", strerror(errno));
1421
+ return err;
1422
+ }
1423
+
1424
+ if (json_output)
1425
+ jsonw_null(json_wtr);
1426
+
1427
+ return 0;
10141428 }
10151429
10161430 static int do_help(int argc, char **argv)
....@@ -1021,26 +1435,39 @@
10211435 }
10221436
10231437 fprintf(stderr,
1024
- "Usage: %s %s { show | list } [MAP]\n"
1025
- " %s %s dump MAP\n"
1026
- " %s %s update MAP key DATA value VALUE [UPDATE_FLAGS]\n"
1027
- " %s %s lookup MAP key DATA\n"
1028
- " %s %s getnext MAP [key DATA]\n"
1029
- " %s %s delete MAP key DATA\n"
1030
- " %s %s pin MAP FILE\n"
1031
- " %s %s event_pipe MAP [cpu N index M]\n"
1032
- " %s %s help\n"
1438
+ "Usage: %1$s %2$s { show | list } [MAP]\n"
1439
+ " %1$s %2$s create FILE type TYPE key KEY_SIZE value VALUE_SIZE \\\n"
1440
+ " entries MAX_ENTRIES name NAME [flags FLAGS] \\\n"
1441
+ " [inner_map MAP] [dev NAME]\n"
1442
+ " %1$s %2$s dump MAP\n"
1443
+ " %1$s %2$s update MAP [key DATA] [value VALUE] [UPDATE_FLAGS]\n"
1444
+ " %1$s %2$s lookup MAP [key DATA]\n"
1445
+ " %1$s %2$s getnext MAP [key DATA]\n"
1446
+ " %1$s %2$s delete MAP key DATA\n"
1447
+ " %1$s %2$s pin MAP FILE\n"
1448
+ " %1$s %2$s event_pipe MAP [cpu N index M]\n"
1449
+ " %1$s %2$s peek MAP\n"
1450
+ " %1$s %2$s push MAP value VALUE\n"
1451
+ " %1$s %2$s pop MAP\n"
1452
+ " %1$s %2$s enqueue MAP value VALUE\n"
1453
+ " %1$s %2$s dequeue MAP\n"
1454
+ " %1$s %2$s freeze MAP\n"
1455
+ " %1$s %2$s help\n"
10331456 "\n"
10341457 " " HELP_SPEC_MAP "\n"
10351458 " DATA := { [hex] BYTES }\n"
10361459 " " HELP_SPEC_PROGRAM "\n"
10371460 " VALUE := { DATA | MAP | PROG }\n"
10381461 " UPDATE_FLAGS := { any | exist | noexist }\n"
1462
+ " TYPE := { hash | array | prog_array | perf_event_array | percpu_hash |\n"
1463
+ " percpu_array | stack_trace | cgroup_array | lru_hash |\n"
1464
+ " lru_percpu_hash | lpm_trie | array_of_maps | hash_of_maps |\n"
1465
+ " devmap | devmap_hash | sockmap | cpumap | xskmap | sockhash |\n"
1466
+ " cgroup_storage | reuseport_sockarray | percpu_cgroup_storage |\n"
1467
+ " queue | stack | sk_storage | struct_ops | ringbuf | inode_storage }\n"
10391468 " " HELP_SPEC_OPTIONS "\n"
10401469 "",
1041
- bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
1042
- bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
1043
- bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]);
1470
+ bin_name, argv[-2]);
10441471
10451472 return 0;
10461473 }
....@@ -1056,6 +1483,13 @@
10561483 { "delete", do_delete },
10571484 { "pin", do_pin },
10581485 { "event_pipe", do_event_pipe },
1486
+ { "create", do_create },
1487
+ { "peek", do_lookup },
1488
+ { "push", do_update },
1489
+ { "enqueue", do_update },
1490
+ { "pop", do_pop_dequeue },
1491
+ { "dequeue", do_pop_dequeue },
1492
+ { "freeze", do_freeze },
10591493 { 0 }
10601494 };
10611495