blob: 3ec82904ccec6aa974353d20f96875267a20ffee [file] [log] [blame]
Jakub Kicinski02ff58d2018-12-12 19:59:25 -08001// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
Jakub Kicinski71bb4282017-10-04 20:10:04 -07003
Jakub Kicinski71bb4282017-10-04 20:10:04 -07004#include <assert.h>
Jakub Kicinski71bb4282017-10-04 20:10:04 -07005#include <errno.h>
6#include <fcntl.h>
Okash Khawaja2d3feca2018-07-13 21:57:04 -07007#include <linux/err.h>
Yonghong Song573b3aa2018-07-30 08:49:03 -07008#include <linux/kernel.h>
Jakub Kicinski0b592b5a2018-10-15 16:30:36 -07009#include <net/if.h>
Jakub Kicinski71bb4282017-10-04 20:10:04 -070010#include <stdbool.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <unistd.h>
15#include <sys/types.h>
16#include <sys/stat.h>
17
18#include <bpf.h>
19
Okash Khawaja2d3feca2018-07-13 21:57:04 -070020#include "btf.h"
21#include "json_writer.h"
Jakub Kicinski71bb4282017-10-04 20:10:04 -070022#include "main.h"
23
Quentin Monnetf99e1662019-01-17 15:27:54 +000024const char * const map_type_name[] = {
David Calaveraffac28f2018-11-23 15:58:39 -080025 [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_SOCKMAP] = "sockmap",
41 [BPF_MAP_TYPE_CPUMAP] = "cpumap",
42 [BPF_MAP_TYPE_XSKMAP] = "xskmap",
43 [BPF_MAP_TYPE_SOCKHASH] = "sockhash",
44 [BPF_MAP_TYPE_CGROUP_STORAGE] = "cgroup_storage",
45 [BPF_MAP_TYPE_REUSEPORT_SOCKARRAY] = "reuseport_sockarray",
Roman Gushchine5487092018-09-28 14:45:51 +000046 [BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE] = "percpu_cgroup_storage",
David Calaveraffac28f2018-11-23 15:58:39 -080047 [BPF_MAP_TYPE_QUEUE] = "queue",
48 [BPF_MAP_TYPE_STACK] = "stack",
Martin KaFai Laua19f89f2019-04-26 16:39:44 -070049 [BPF_MAP_TYPE_SK_STORAGE] = "sk_storage",
Jakub Kicinski71bb4282017-10-04 20:10:04 -070050};
51
Quentin Monnetf99e1662019-01-17 15:27:54 +000052const size_t map_type_name_size = ARRAY_SIZE(map_type_name);
53
Jakub Kicinski71bb4282017-10-04 20:10:04 -070054static bool map_is_per_cpu(__u32 type)
55{
56 return type == BPF_MAP_TYPE_PERCPU_HASH ||
57 type == BPF_MAP_TYPE_PERCPU_ARRAY ||
Roman Gushchine5487092018-09-28 14:45:51 +000058 type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
59 type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE;
Jakub Kicinski71bb4282017-10-04 20:10:04 -070060}
61
62static bool map_is_map_of_maps(__u32 type)
63{
64 return type == BPF_MAP_TYPE_ARRAY_OF_MAPS ||
65 type == BPF_MAP_TYPE_HASH_OF_MAPS;
66}
67
68static bool map_is_map_of_progs(__u32 type)
69{
70 return type == BPF_MAP_TYPE_PROG_ARRAY;
71}
72
Jakub Kicinski0b592b5a2018-10-15 16:30:36 -070073static int map_type_from_str(const char *type)
74{
75 unsigned int i;
76
77 for (i = 0; i < ARRAY_SIZE(map_type_name); i++)
78 /* Don't allow prefixing in case of possible future shadowing */
79 if (map_type_name[i] && !strcmp(map_type_name[i], type))
80 return i;
81 return -1;
82}
83
Jakub Kicinski71bb4282017-10-04 20:10:04 -070084static void *alloc_value(struct bpf_map_info *info)
85{
86 if (map_is_per_cpu(info->type))
Yonghong Song573b3aa2018-07-30 08:49:03 -070087 return malloc(round_up(info->value_size, 8) *
88 get_possible_cpus());
Jakub Kicinski71bb4282017-10-04 20:10:04 -070089 else
90 return malloc(info->value_size);
91}
92
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -070093int map_parse_fd(int *argc, char ***argv)
Jakub Kicinski71bb4282017-10-04 20:10:04 -070094{
95 int fd;
96
97 if (is_prefix(**argv, "id")) {
98 unsigned int id;
99 char *endptr;
100
101 NEXT_ARGP();
102
103 id = strtoul(**argv, &endptr, 0);
104 if (*endptr) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700105 p_err("can't parse %s as ID", **argv);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700106 return -1;
107 }
108 NEXT_ARGP();
109
110 fd = bpf_map_get_fd_by_id(id);
111 if (fd < 0)
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700112 p_err("get map by id (%u): %s", id, strerror(errno));
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700113 return fd;
114 } else if (is_prefix(**argv, "pinned")) {
115 char *path;
116
117 NEXT_ARGP();
118
119 path = **argv;
120 NEXT_ARGP();
121
122 return open_obj_pinned_any(path, BPF_OBJ_MAP);
123 }
124
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700125 p_err("expected 'id' or 'pinned', got: '%s'?", **argv);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700126 return -1;
127}
128
Jakub Kicinskif412eed2018-05-03 18:37:16 -0700129int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len)
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700130{
131 int err;
132 int fd;
133
134 fd = map_parse_fd(argc, argv);
135 if (fd < 0)
136 return -1;
137
138 err = bpf_obj_get_info_by_fd(fd, info, info_len);
139 if (err) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700140 p_err("can't get map info: %s", strerror(errno));
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700141 close(fd);
142 return err;
143 }
144
145 return fd;
146}
147
Okash Khawaja2d3feca2018-07-13 21:57:04 -0700148static int do_dump_btf(const struct btf_dumper *d,
149 struct bpf_map_info *map_info, void *key,
150 void *value)
151{
152 int ret;
153
154 /* start of key-value pair */
155 jsonw_start_object(d->jw);
156
Daniel Borkmann817998a2019-04-09 23:20:15 +0200157 if (map_info->btf_key_type_id) {
158 jsonw_name(d->jw, "key");
Okash Khawaja2d3feca2018-07-13 21:57:04 -0700159
Daniel Borkmann817998a2019-04-09 23:20:15 +0200160 ret = btf_dumper_type(d, map_info->btf_key_type_id, key);
161 if (ret)
162 goto err_end_obj;
163 }
Okash Khawaja2d3feca2018-07-13 21:57:04 -0700164
Yonghong Song1a86ad82018-08-29 14:43:15 -0700165 if (!map_is_per_cpu(map_info->type)) {
166 jsonw_name(d->jw, "value");
167 ret = btf_dumper_type(d, map_info->btf_value_type_id, value);
168 } else {
169 unsigned int i, n, step;
Okash Khawaja2d3feca2018-07-13 21:57:04 -0700170
Yonghong Song1a86ad82018-08-29 14:43:15 -0700171 jsonw_name(d->jw, "values");
172 jsonw_start_array(d->jw);
173 n = get_possible_cpus();
174 step = round_up(map_info->value_size, 8);
175 for (i = 0; i < n; i++) {
176 jsonw_start_object(d->jw);
177 jsonw_int_field(d->jw, "cpu", i);
178 jsonw_name(d->jw, "value");
179 ret = btf_dumper_type(d, map_info->btf_value_type_id,
180 value + i * step);
181 jsonw_end_object(d->jw);
182 if (ret)
183 break;
184 }
185 jsonw_end_array(d->jw);
186 }
Okash Khawaja2d3feca2018-07-13 21:57:04 -0700187
188err_end_obj:
189 /* end of key-value pair */
190 jsonw_end_object(d->jw);
191
192 return ret;
193}
194
Okash Khawaja2d3feca2018-07-13 21:57:04 -0700195static json_writer_t *get_btf_writer(void)
196{
197 json_writer_t *jw = jsonw_new(stdout);
198
199 if (!jw)
200 return NULL;
201 jsonw_pretty(jw, true);
202
203 return jw;
204}
205
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700206static void print_entry_json(struct bpf_map_info *info, unsigned char *key,
Okash Khawaja2d3feca2018-07-13 21:57:04 -0700207 unsigned char *value, struct btf *btf)
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700208{
209 jsonw_start_object(json_wtr);
210
211 if (!map_is_per_cpu(info->type)) {
212 jsonw_name(json_wtr, "key");
213 print_hex_data_json(key, info->key_size);
214 jsonw_name(json_wtr, "value");
215 print_hex_data_json(value, info->value_size);
Okash Khawaja2d3feca2018-07-13 21:57:04 -0700216 if (btf) {
217 struct btf_dumper d = {
218 .btf = btf,
219 .jw = json_wtr,
220 .is_plain_text = false,
221 };
222
223 jsonw_name(json_wtr, "formatted");
224 do_dump_btf(&d, info, key, value);
225 }
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700226 } else {
Yonghong Song573b3aa2018-07-30 08:49:03 -0700227 unsigned int i, n, step;
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700228
229 n = get_possible_cpus();
Yonghong Song573b3aa2018-07-30 08:49:03 -0700230 step = round_up(info->value_size, 8);
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700231
232 jsonw_name(json_wtr, "key");
233 print_hex_data_json(key, info->key_size);
234
235 jsonw_name(json_wtr, "values");
236 jsonw_start_array(json_wtr);
237 for (i = 0; i < n; i++) {
238 jsonw_start_object(json_wtr);
239
240 jsonw_int_field(json_wtr, "cpu", i);
241
242 jsonw_name(json_wtr, "value");
Yonghong Song573b3aa2018-07-30 08:49:03 -0700243 print_hex_data_json(value + i * step,
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700244 info->value_size);
245
246 jsonw_end_object(json_wtr);
247 }
248 jsonw_end_array(json_wtr);
Yonghong Song1a86ad82018-08-29 14:43:15 -0700249 if (btf) {
250 struct btf_dumper d = {
251 .btf = btf,
252 .jw = json_wtr,
253 .is_plain_text = false,
254 };
255
256 jsonw_name(json_wtr, "formatted");
257 do_dump_btf(&d, info, key, value);
258 }
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700259 }
260
261 jsonw_end_object(json_wtr);
262}
263
Prashant Bhole8ec92dc2018-10-09 10:04:52 +0900264static void print_entry_error(struct bpf_map_info *info, unsigned char *key,
Benjamin Poirier0478c3b2019-04-15 16:15:35 +0900265 const char *error_msg)
Prashant Bhole8ec92dc2018-10-09 10:04:52 +0900266{
Benjamin Poirier0478c3b2019-04-15 16:15:35 +0900267 int msg_size = strlen(error_msg);
Prashant Bhole8ec92dc2018-10-09 10:04:52 +0900268 bool single_line, break_names;
269
Benjamin Poirier0478c3b2019-04-15 16:15:35 +0900270 break_names = info->key_size > 16 || msg_size > 16;
271 single_line = info->key_size + msg_size <= 24 && !break_names;
Prashant Bhole8ec92dc2018-10-09 10:04:52 +0900272
273 printf("key:%c", break_names ? '\n' : ' ');
274 fprint_hex(stdout, key, info->key_size, " ");
275
276 printf(single_line ? " " : "\n");
277
Benjamin Poirier0478c3b2019-04-15 16:15:35 +0900278 printf("value:%c%s", break_names ? '\n' : ' ', error_msg);
Prashant Bhole8ec92dc2018-10-09 10:04:52 +0900279
280 printf("\n");
281}
282
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700283static void print_entry_plain(struct bpf_map_info *info, unsigned char *key,
284 unsigned char *value)
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700285{
286 if (!map_is_per_cpu(info->type)) {
287 bool single_line, break_names;
288
289 break_names = info->key_size > 16 || info->value_size > 16;
290 single_line = info->key_size + info->value_size <= 24 &&
291 !break_names;
292
Stanislav Fomichev04a5d322019-01-16 11:10:01 -0800293 if (info->key_size) {
294 printf("key:%c", break_names ? '\n' : ' ');
295 fprint_hex(stdout, key, info->key_size, " ");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700296
Stanislav Fomichev04a5d322019-01-16 11:10:01 -0800297 printf(single_line ? " " : "\n");
298 }
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700299
Stanislav Fomichev04a5d322019-01-16 11:10:01 -0800300 if (info->value_size) {
301 printf("value:%c", break_names ? '\n' : ' ');
Benjamin Poirier0478c3b2019-04-15 16:15:35 +0900302 fprint_hex(stdout, value, info->value_size, " ");
Stanislav Fomichev04a5d322019-01-16 11:10:01 -0800303 }
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700304
305 printf("\n");
306 } else {
Yonghong Song573b3aa2018-07-30 08:49:03 -0700307 unsigned int i, n, step;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700308
309 n = get_possible_cpus();
Yonghong Song573b3aa2018-07-30 08:49:03 -0700310 step = round_up(info->value_size, 8);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700311
Stanislav Fomichev04a5d322019-01-16 11:10:01 -0800312 if (info->key_size) {
313 printf("key:\n");
314 fprint_hex(stdout, key, info->key_size, " ");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700315 printf("\n");
316 }
Stanislav Fomichev04a5d322019-01-16 11:10:01 -0800317 if (info->value_size) {
318 for (i = 0; i < n; i++) {
319 printf("value (CPU %02d):%c",
320 i, info->value_size > 16 ? '\n' : ' ');
Benjamin Poirier0478c3b2019-04-15 16:15:35 +0900321 fprint_hex(stdout, value + i * step,
322 info->value_size, " ");
Stanislav Fomichev04a5d322019-01-16 11:10:01 -0800323 printf("\n");
324 }
325 }
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700326 }
327}
328
329static char **parse_bytes(char **argv, const char *name, unsigned char *val,
330 unsigned int n)
331{
Quentin Monnet0c90f222018-04-17 19:46:34 -0700332 unsigned int i = 0, base = 0;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700333 char *endptr;
334
Quentin Monnet0c90f222018-04-17 19:46:34 -0700335 if (is_prefix(*argv, "hex")) {
336 base = 16;
337 argv++;
338 }
339
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700340 while (i < n && argv[i]) {
Quentin Monnet0c90f222018-04-17 19:46:34 -0700341 val[i] = strtoul(argv[i], &endptr, base);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700342 if (*endptr) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700343 p_err("error parsing byte: %s", argv[i]);
Quentin Monnetd9c0b482017-10-19 15:46:23 -0700344 return NULL;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700345 }
346 i++;
347 }
348
349 if (i != n) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700350 p_err("%s expected %d bytes got %d", name, n, i);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700351 return NULL;
352 }
353
354 return argv + i;
355}
356
Paolo Abenib0ca5ec2019-01-21 12:36:12 +0100357/* on per cpu maps we must copy the provided value on all value instances */
358static void fill_per_cpu_value(struct bpf_map_info *info, void *value)
359{
360 unsigned int i, n, step;
361
362 if (!map_is_per_cpu(info->type))
363 return;
364
365 n = get_possible_cpus();
366 step = round_up(info->value_size, 8);
367 for (i = 1; i < n; i++)
368 memcpy(value + i * step, value, info->value_size);
369}
370
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700371static int parse_elem(char **argv, struct bpf_map_info *info,
372 void *key, void *value, __u32 key_size, __u32 value_size,
373 __u32 *flags, __u32 **value_fd)
374{
375 if (!*argv) {
376 if (!key && !value)
377 return 0;
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700378 p_err("did not find %s", key ? "key" : "value");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700379 return -1;
380 }
381
382 if (is_prefix(*argv, "key")) {
383 if (!key) {
384 if (key_size)
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700385 p_err("duplicate key");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700386 else
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700387 p_err("unnecessary key");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700388 return -1;
389 }
390
391 argv = parse_bytes(argv + 1, "key", key, key_size);
392 if (!argv)
393 return -1;
394
395 return parse_elem(argv, info, NULL, value, key_size, value_size,
396 flags, value_fd);
397 } else if (is_prefix(*argv, "value")) {
398 int fd;
399
400 if (!value) {
401 if (value_size)
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700402 p_err("duplicate value");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700403 else
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700404 p_err("unnecessary value");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700405 return -1;
406 }
407
408 argv++;
409
410 if (map_is_map_of_maps(info->type)) {
411 int argc = 2;
412
413 if (value_size != 4) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700414 p_err("value smaller than 4B for map in map?");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700415 return -1;
416 }
417 if (!argv[0] || !argv[1]) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700418 p_err("not enough value arguments for map in map");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700419 return -1;
420 }
421
422 fd = map_parse_fd(&argc, &argv);
423 if (fd < 0)
424 return -1;
425
426 *value_fd = value;
427 **value_fd = fd;
428 } else if (map_is_map_of_progs(info->type)) {
429 int argc = 2;
430
431 if (value_size != 4) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700432 p_err("value smaller than 4B for map of progs?");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700433 return -1;
434 }
435 if (!argv[0] || !argv[1]) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700436 p_err("not enough value arguments for map of progs");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700437 return -1;
438 }
Jakub Kicinskid76198b2019-01-28 10:29:15 -0800439 if (is_prefix(*argv, "id"))
440 p_info("Warning: updating program array via MAP_ID, make sure this map is kept open\n"
441 " by some process or pinned otherwise update will be lost");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700442
443 fd = prog_parse_fd(&argc, &argv);
444 if (fd < 0)
445 return -1;
446
447 *value_fd = value;
448 **value_fd = fd;
449 } else {
450 argv = parse_bytes(argv, "value", value, value_size);
451 if (!argv)
452 return -1;
Paolo Abenib0ca5ec2019-01-21 12:36:12 +0100453
454 fill_per_cpu_value(info, value);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700455 }
456
457 return parse_elem(argv, info, key, NULL, key_size, value_size,
458 flags, NULL);
459 } else if (is_prefix(*argv, "any") || is_prefix(*argv, "noexist") ||
460 is_prefix(*argv, "exist")) {
461 if (!flags) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700462 p_err("flags specified multiple times: %s", *argv);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700463 return -1;
464 }
465
466 if (is_prefix(*argv, "any"))
467 *flags = BPF_ANY;
468 else if (is_prefix(*argv, "noexist"))
469 *flags = BPF_NOEXIST;
470 else if (is_prefix(*argv, "exist"))
471 *flags = BPF_EXIST;
472
473 return parse_elem(argv + 1, info, key, value, key_size,
474 value_size, NULL, value_fd);
475 }
476
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700477 p_err("expected key or value, got: %s", *argv);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700478 return -1;
479}
480
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700481static int show_map_close_json(int fd, struct bpf_map_info *info)
482{
483 char *memlock;
484
485 memlock = get_fdinfo(fd, "memlock");
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700486
487 jsonw_start_object(json_wtr);
488
489 jsonw_uint_field(json_wtr, "id", info->id);
490 if (info->type < ARRAY_SIZE(map_type_name))
491 jsonw_string_field(json_wtr, "type",
492 map_type_name[info->type]);
493 else
494 jsonw_uint_field(json_wtr, "type", info->type);
495
496 if (*info->name)
497 jsonw_string_field(json_wtr, "name", info->name);
498
499 jsonw_name(json_wtr, "flags");
Jakub Kicinski4b6eca92018-03-23 19:45:12 -0700500 jsonw_printf(json_wtr, "%d", info->map_flags);
Jakub Kicinski064a07c2018-01-17 19:13:29 -0800501
502 print_dev_json(info->ifindex, info->netns_dev, info->netns_ino);
503
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700504 jsonw_uint_field(json_wtr, "bytes_key", info->key_size);
505 jsonw_uint_field(json_wtr, "bytes_value", info->value_size);
506 jsonw_uint_field(json_wtr, "max_entries", info->max_entries);
507
508 if (memlock)
509 jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock));
510 free(memlock);
511
Quentin Monnet99a44bef2018-11-30 16:25:48 +0000512 if (info->type == BPF_MAP_TYPE_PROG_ARRAY) {
513 char *owner_prog_type = get_fdinfo(fd, "owner_prog_type");
514 char *owner_jited = get_fdinfo(fd, "owner_jited");
515
516 if (owner_prog_type) {
517 unsigned int prog_type = atoi(owner_prog_type);
518
519 if (prog_type < ARRAY_SIZE(prog_type_name))
520 jsonw_string_field(json_wtr, "owner_prog_type",
521 prog_type_name[prog_type]);
522 else
523 jsonw_uint_field(json_wtr, "owner_prog_type",
524 prog_type);
525 }
Jakub Kicinski8c79b352019-01-28 10:01:21 -0800526 if (owner_jited)
527 jsonw_bool_field(json_wtr, "owner_jited",
528 !!atoi(owner_jited));
Quentin Monnet99a44bef2018-11-30 16:25:48 +0000529
530 free(owner_prog_type);
531 free(owner_jited);
532 }
533 close(fd);
534
Prashant Bholed1b77252019-04-17 09:22:59 +0900535 if (info->btf_id)
536 jsonw_int_field(json_wtr, "btf_id", info->btf_id);
537
Prashant Bhole4990f1f2017-11-08 13:55:48 +0900538 if (!hash_empty(map_table.table)) {
539 struct pinned_obj *obj;
540
541 jsonw_name(json_wtr, "pinned");
542 jsonw_start_array(json_wtr);
543 hash_for_each_possible(map_table.table, obj, hash, info->id) {
544 if (obj->id == info->id)
545 jsonw_string(json_wtr, obj->path);
546 }
547 jsonw_end_array(json_wtr);
548 }
549
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700550 jsonw_end_object(json_wtr);
551
552 return 0;
553}
554
555static int show_map_close_plain(int fd, struct bpf_map_info *info)
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700556{
557 char *memlock;
558
559 memlock = get_fdinfo(fd, "memlock");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700560
561 printf("%u: ", info->id);
562 if (info->type < ARRAY_SIZE(map_type_name))
563 printf("%s ", map_type_name[info->type]);
564 else
565 printf("type %u ", info->type);
566
567 if (*info->name)
568 printf("name %s ", info->name);
569
Jakub Kicinski064a07c2018-01-17 19:13:29 -0800570 printf("flags 0x%x", info->map_flags);
571 print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino);
572 printf("\n");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700573 printf("\tkey %uB value %uB max_entries %u",
574 info->key_size, info->value_size, info->max_entries);
575
576 if (memlock)
577 printf(" memlock %sB", memlock);
578 free(memlock);
579
Quentin Monnet99a44bef2018-11-30 16:25:48 +0000580 if (info->type == BPF_MAP_TYPE_PROG_ARRAY) {
581 char *owner_prog_type = get_fdinfo(fd, "owner_prog_type");
582 char *owner_jited = get_fdinfo(fd, "owner_jited");
583
Jakub Kicinski8c79b352019-01-28 10:01:21 -0800584 if (owner_prog_type || owner_jited)
585 printf("\n\t");
Quentin Monnet99a44bef2018-11-30 16:25:48 +0000586 if (owner_prog_type) {
587 unsigned int prog_type = atoi(owner_prog_type);
588
589 if (prog_type < ARRAY_SIZE(prog_type_name))
590 printf("owner_prog_type %s ",
591 prog_type_name[prog_type]);
592 else
593 printf("owner_prog_type %d ", prog_type);
594 }
Jakub Kicinski8c79b352019-01-28 10:01:21 -0800595 if (owner_jited)
596 printf("owner%s jited",
597 atoi(owner_jited) ? "" : " not");
Quentin Monnet99a44bef2018-11-30 16:25:48 +0000598
599 free(owner_prog_type);
600 free(owner_jited);
601 }
602 close(fd);
603
Prashant Bhole4990f1f2017-11-08 13:55:48 +0900604 if (!hash_empty(map_table.table)) {
605 struct pinned_obj *obj;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700606
Prashant Bhole4990f1f2017-11-08 13:55:48 +0900607 hash_for_each_possible(map_table.table, obj, hash, info->id) {
608 if (obj->id == info->id)
Prashant Bholed459b592019-04-17 09:22:58 +0900609 printf("\n\tpinned %s", obj->path);
Prashant Bhole4990f1f2017-11-08 13:55:48 +0900610 }
611 }
Prashant Bholed459b592019-04-17 09:22:58 +0900612
Prashant Bholed1b77252019-04-17 09:22:59 +0900613 if (info->btf_id)
614 printf("\n\tbtf_id %d", info->btf_id);
615
Prashant Bholed459b592019-04-17 09:22:58 +0900616 printf("\n");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700617 return 0;
618}
619
620static int do_show(int argc, char **argv)
621{
622 struct bpf_map_info info = {};
623 __u32 len = sizeof(info);
624 __u32 id = 0;
625 int err;
626 int fd;
627
Prashant Bholec541b732017-11-08 13:55:49 +0900628 if (show_pinned)
629 build_pinned_obj_table(&map_table, BPF_OBJ_MAP);
Prashant Bhole4990f1f2017-11-08 13:55:48 +0900630
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700631 if (argc == 2) {
632 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
633 if (fd < 0)
634 return -1;
635
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700636 if (json_output)
637 return show_map_close_json(fd, &info);
638 else
639 return show_map_close_plain(fd, &info);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700640 }
641
642 if (argc)
643 return BAD_ARG();
644
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700645 if (json_output)
646 jsonw_start_array(json_wtr);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700647 while (true) {
648 err = bpf_map_get_next_id(id, &id);
649 if (err) {
650 if (errno == ENOENT)
651 break;
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700652 p_err("can't get next map: %s%s", strerror(errno),
653 errno == EINVAL ? " -- kernel too old?" : "");
Jakub Kicinskib3b1b652017-12-22 11:36:05 -0800654 break;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700655 }
656
657 fd = bpf_map_get_fd_by_id(id);
658 if (fd < 0) {
Jakub Kicinski8207c6d2017-12-22 11:36:06 -0800659 if (errno == ENOENT)
660 continue;
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700661 p_err("can't get map by id (%u): %s",
662 id, strerror(errno));
Jakub Kicinskib3b1b652017-12-22 11:36:05 -0800663 break;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700664 }
665
666 err = bpf_obj_get_info_by_fd(fd, &info, &len);
667 if (err) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700668 p_err("can't get map info: %s", strerror(errno));
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700669 close(fd);
Jakub Kicinskib3b1b652017-12-22 11:36:05 -0800670 break;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700671 }
672
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700673 if (json_output)
674 show_map_close_json(fd, &info);
675 else
676 show_map_close_plain(fd, &info);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700677 }
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700678 if (json_output)
679 jsonw_end_array(json_wtr);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700680
681 return errno == ENOENT ? 0 : -1;
682}
683
Prashant Bhole18a781d2018-10-09 10:04:51 +0900684static int dump_map_elem(int fd, void *key, void *value,
685 struct bpf_map_info *map_info, struct btf *btf,
686 json_writer_t *btf_wtr)
687{
688 int num_elems = 0;
Prashant Bhole8ec92dc2018-10-09 10:04:52 +0900689 int lookup_errno;
Prashant Bhole18a781d2018-10-09 10:04:51 +0900690
691 if (!bpf_map_lookup_elem(fd, key, value)) {
692 if (json_output) {
693 print_entry_json(map_info, key, value, btf);
694 } else {
695 if (btf) {
696 struct btf_dumper d = {
697 .btf = btf,
698 .jw = btf_wtr,
699 .is_plain_text = true,
700 };
701
702 do_dump_btf(&d, map_info, key, value);
703 } else {
704 print_entry_plain(map_info, key, value);
705 }
706 num_elems++;
707 }
708 return num_elems;
709 }
710
711 /* lookup error handling */
Prashant Bhole8ec92dc2018-10-09 10:04:52 +0900712 lookup_errno = errno;
713
Prashant Bhole18a781d2018-10-09 10:04:51 +0900714 if (map_is_map_of_maps(map_info->type) ||
715 map_is_map_of_progs(map_info->type))
716 return 0;
717
718 if (json_output) {
719 jsonw_name(json_wtr, "key");
720 print_hex_data_json(key, map_info->key_size);
721 jsonw_name(json_wtr, "value");
722 jsonw_start_object(json_wtr);
Prashant Bhole8ec92dc2018-10-09 10:04:52 +0900723 jsonw_string_field(json_wtr, "error", strerror(lookup_errno));
Prashant Bhole18a781d2018-10-09 10:04:51 +0900724 jsonw_end_object(json_wtr);
725 } else {
Benjamin Poirier0478c3b2019-04-15 16:15:35 +0900726 const char *msg = NULL;
727
Benjamin Poirier77d76422019-04-11 17:03:32 +0900728 if (lookup_errno == ENOENT)
Benjamin Poirier0478c3b2019-04-15 16:15:35 +0900729 msg = "<no entry>";
Benjamin Poirier3da6e7e2019-04-15 16:15:36 +0900730 else if (lookup_errno == ENOSPC &&
731 map_info->type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY)
732 msg = "<cannot read>";
Benjamin Poirier0478c3b2019-04-15 16:15:35 +0900733
734 print_entry_error(map_info, key,
735 msg ? : strerror(lookup_errno));
Prashant Bhole18a781d2018-10-09 10:04:51 +0900736 }
737
738 return 0;
739}
740
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700741static int do_dump(int argc, char **argv)
742{
Okash Khawaja2d3feca2018-07-13 21:57:04 -0700743 struct bpf_map_info info = {};
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700744 void *key, *value, *prev_key;
745 unsigned int num_elems = 0;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700746 __u32 len = sizeof(info);
Okash Khawaja2d3feca2018-07-13 21:57:04 -0700747 json_writer_t *btf_wtr;
748 struct btf *btf = NULL;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700749 int err;
750 int fd;
751
752 if (argc != 2)
753 usage();
754
755 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
756 if (fd < 0)
757 return -1;
758
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700759 key = malloc(info.key_size);
760 value = alloc_value(&info);
761 if (!key || !value) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700762 p_err("mem alloc failed");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700763 err = -1;
764 goto exit_free;
765 }
766
767 prev_key = NULL;
Okash Khawaja2d3feca2018-07-13 21:57:04 -0700768
Martin KaFai Lau1d2f44c2018-11-23 16:44:32 -0800769 err = btf__get_from_id(info.btf_id, &btf);
Okash Khawaja2d3feca2018-07-13 21:57:04 -0700770 if (err) {
771 p_err("failed to get btf");
772 goto exit_free;
773 }
774
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700775 if (json_output)
776 jsonw_start_array(json_wtr);
Okash Khawaja2d3feca2018-07-13 21:57:04 -0700777 else
778 if (btf) {
779 btf_wtr = get_btf_writer();
780 if (!btf_wtr) {
781 p_info("failed to create json writer for btf. falling back to plain output");
782 btf__free(btf);
783 btf = NULL;
784 } else {
785 jsonw_start_array(btf_wtr);
786 }
787 }
788
Benjamin Poirier3da6e7e2019-04-15 16:15:36 +0900789 if (info.type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY &&
790 info.value_size != 8)
791 p_info("Warning: cannot read values from %s map with value_size != 8",
792 map_type_name[info.type]);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700793 while (true) {
794 err = bpf_map_get_next_key(fd, prev_key, key);
795 if (err) {
796 if (errno == ENOENT)
797 err = 0;
798 break;
799 }
Prashant Bhole18a781d2018-10-09 10:04:51 +0900800 num_elems += dump_map_elem(fd, key, value, &info, btf, btf_wtr);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700801 prev_key = key;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700802 }
803
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700804 if (json_output)
805 jsonw_end_array(json_wtr);
Okash Khawaja2d3feca2018-07-13 21:57:04 -0700806 else if (btf) {
807 jsonw_end_array(btf_wtr);
808 jsonw_destroy(&btf_wtr);
809 } else {
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700810 printf("Found %u element%s\n", num_elems,
811 num_elems != 1 ? "s" : "");
Okash Khawaja2d3feca2018-07-13 21:57:04 -0700812 }
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700813
814exit_free:
815 free(key);
816 free(value);
817 close(fd);
Okash Khawaja2d3feca2018-07-13 21:57:04 -0700818 btf__free(btf);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700819
820 return err;
821}
822
Stanislav Fomichev7d7209c2019-01-16 11:09:59 -0800823static int alloc_key_value(struct bpf_map_info *info, void **key, void **value)
824{
825 *key = NULL;
826 *value = NULL;
827
828 if (info->key_size) {
829 *key = malloc(info->key_size);
830 if (!*key) {
831 p_err("key mem alloc failed");
832 return -1;
833 }
834 }
835
836 if (info->value_size) {
837 *value = alloc_value(info);
838 if (!*value) {
839 p_err("value mem alloc failed");
840 free(*key);
841 *key = NULL;
842 return -1;
843 }
844 }
845
846 return 0;
847}
848
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700849static int do_update(int argc, char **argv)
850{
851 struct bpf_map_info info = {};
852 __u32 len = sizeof(info);
853 __u32 *value_fd = NULL;
854 __u32 flags = BPF_ANY;
855 void *key, *value;
856 int fd, err;
857
858 if (argc < 2)
859 usage();
860
861 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
862 if (fd < 0)
863 return -1;
864
Stanislav Fomichev7d7209c2019-01-16 11:09:59 -0800865 err = alloc_key_value(&info, &key, &value);
866 if (err)
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700867 goto exit_free;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700868
869 err = parse_elem(argv, &info, key, value, info.key_size,
870 info.value_size, &flags, &value_fd);
871 if (err)
872 goto exit_free;
873
874 err = bpf_map_update_elem(fd, key, value, flags);
875 if (err) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700876 p_err("update failed: %s", strerror(errno));
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700877 goto exit_free;
878 }
879
880exit_free:
881 if (value_fd)
882 close(*value_fd);
883 free(key);
884 free(value);
885 close(fd);
886
Quentin Monnet004b45c2017-10-23 09:24:14 -0700887 if (!err && json_output)
888 jsonw_null(json_wtr);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700889 return err;
890}
891
Stanislav Fomichev74f312e2019-01-16 11:10:04 -0800892static void print_key_value(struct bpf_map_info *info, void *key,
893 void *value)
894{
895 json_writer_t *btf_wtr;
896 struct btf *btf = NULL;
897 int err;
898
899 err = btf__get_from_id(info->btf_id, &btf);
900 if (err) {
901 p_err("failed to get btf");
902 return;
903 }
904
905 if (json_output) {
906 print_entry_json(info, key, value, btf);
907 } else if (btf) {
908 /* if here json_wtr wouldn't have been initialised,
909 * so let's create separate writer for btf
910 */
911 btf_wtr = get_btf_writer();
912 if (!btf_wtr) {
913 p_info("failed to create json writer for btf. falling back to plain output");
914 btf__free(btf);
915 btf = NULL;
916 print_entry_plain(info, key, value);
917 } else {
918 struct btf_dumper d = {
919 .btf = btf,
920 .jw = btf_wtr,
921 .is_plain_text = true,
922 };
923
924 do_dump_btf(&d, info, key, value);
925 jsonw_destroy(&btf_wtr);
926 }
927 } else {
928 print_entry_plain(info, key, value);
929 }
930 btf__free(btf);
931}
932
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700933static int do_lookup(int argc, char **argv)
934{
935 struct bpf_map_info info = {};
936 __u32 len = sizeof(info);
937 void *key, *value;
938 int err;
939 int fd;
940
941 if (argc < 2)
942 usage();
943
944 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
945 if (fd < 0)
946 return -1;
947
Stanislav Fomichev8a89fff2019-01-16 11:10:00 -0800948 err = alloc_key_value(&info, &key, &value);
949 if (err)
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700950 goto exit_free;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700951
952 err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL);
953 if (err)
954 goto exit_free;
955
956 err = bpf_map_lookup_elem(fd, key, value);
Okash Khawaja2d3feca2018-07-13 21:57:04 -0700957 if (err) {
958 if (errno == ENOENT) {
959 if (json_output) {
960 jsonw_null(json_wtr);
961 } else {
962 printf("key:\n");
963 fprint_hex(stdout, key, info.key_size, " ");
964 printf("\n\nNot found\n");
965 }
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700966 } else {
Okash Khawaja2d3feca2018-07-13 21:57:04 -0700967 p_err("lookup failed: %s", strerror(errno));
968 }
969
970 goto exit_free;
971 }
972
973 /* here means bpf_map_lookup_elem() succeeded */
Stanislav Fomichev74f312e2019-01-16 11:10:04 -0800974 print_key_value(&info, key, value);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700975
976exit_free:
977 free(key);
978 free(value);
979 close(fd);
980
981 return err;
982}
983
984static int do_getnext(int argc, char **argv)
985{
986 struct bpf_map_info info = {};
987 __u32 len = sizeof(info);
988 void *key, *nextkey;
989 int err;
990 int fd;
991
992 if (argc < 2)
993 usage();
994
995 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
996 if (fd < 0)
997 return -1;
998
999 key = malloc(info.key_size);
1000 nextkey = malloc(info.key_size);
1001 if (!key || !nextkey) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -07001002 p_err("mem alloc failed");
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001003 err = -1;
1004 goto exit_free;
1005 }
1006
1007 if (argc) {
1008 err = parse_elem(argv, &info, key, NULL, info.key_size, 0,
1009 NULL, NULL);
1010 if (err)
1011 goto exit_free;
1012 } else {
1013 free(key);
1014 key = NULL;
1015 }
1016
1017 err = bpf_map_get_next_key(fd, key, nextkey);
1018 if (err) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -07001019 p_err("can't get next key: %s", strerror(errno));
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001020 goto exit_free;
1021 }
1022
Quentin Monnet831a0aa2017-10-23 09:24:11 -07001023 if (json_output) {
1024 jsonw_start_object(json_wtr);
1025 if (key) {
1026 jsonw_name(json_wtr, "key");
1027 print_hex_data_json(key, info.key_size);
1028 } else {
1029 jsonw_null_field(json_wtr, "key");
1030 }
1031 jsonw_name(json_wtr, "next_key");
1032 print_hex_data_json(nextkey, info.key_size);
1033 jsonw_end_object(json_wtr);
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001034 } else {
Quentin Monnet831a0aa2017-10-23 09:24:11 -07001035 if (key) {
1036 printf("key:\n");
1037 fprint_hex(stdout, key, info.key_size, " ");
1038 printf("\n");
1039 } else {
1040 printf("key: None\n");
1041 }
1042 printf("next key:\n");
1043 fprint_hex(stdout, nextkey, info.key_size, " ");
1044 printf("\n");
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001045 }
1046
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001047exit_free:
1048 free(nextkey);
1049 free(key);
1050 close(fd);
1051
1052 return err;
1053}
1054
1055static int do_delete(int argc, char **argv)
1056{
1057 struct bpf_map_info info = {};
1058 __u32 len = sizeof(info);
1059 void *key;
1060 int err;
1061 int fd;
1062
1063 if (argc < 2)
1064 usage();
1065
1066 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
1067 if (fd < 0)
1068 return -1;
1069
1070 key = malloc(info.key_size);
1071 if (!key) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -07001072 p_err("mem alloc failed");
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001073 err = -1;
1074 goto exit_free;
1075 }
1076
1077 err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL);
1078 if (err)
1079 goto exit_free;
1080
1081 err = bpf_map_delete_elem(fd, key);
1082 if (err)
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -07001083 p_err("delete failed: %s", strerror(errno));
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001084
1085exit_free:
1086 free(key);
1087 close(fd);
1088
Quentin Monnet004b45c2017-10-23 09:24:14 -07001089 if (!err && json_output)
1090 jsonw_null(json_wtr);
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001091 return err;
1092}
1093
1094static int do_pin(int argc, char **argv)
1095{
Quentin Monnet004b45c2017-10-23 09:24:14 -07001096 int err;
1097
1098 err = do_pin_any(argc, argv, bpf_map_get_fd_by_id);
1099 if (!err && json_output)
1100 jsonw_null(json_wtr);
1101 return err;
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001102}
1103
Jakub Kicinski0b592b5a2018-10-15 16:30:36 -07001104static int do_create(int argc, char **argv)
1105{
1106 struct bpf_create_map_attr attr = { NULL, };
1107 const char *pinfile;
1108 int err, fd;
1109
1110 if (!REQ_ARGS(7))
1111 return -1;
1112 pinfile = GET_ARG();
1113
1114 while (argc) {
1115 if (!REQ_ARGS(2))
1116 return -1;
1117
1118 if (is_prefix(*argv, "type")) {
1119 NEXT_ARG();
1120
1121 if (attr.map_type) {
1122 p_err("map type already specified");
1123 return -1;
1124 }
1125
1126 attr.map_type = map_type_from_str(*argv);
1127 if ((int)attr.map_type < 0) {
1128 p_err("unrecognized map type: %s", *argv);
1129 return -1;
1130 }
1131 NEXT_ARG();
1132 } else if (is_prefix(*argv, "name")) {
1133 NEXT_ARG();
1134 attr.name = GET_ARG();
1135 } else if (is_prefix(*argv, "key")) {
1136 if (parse_u32_arg(&argc, &argv, &attr.key_size,
1137 "key size"))
1138 return -1;
1139 } else if (is_prefix(*argv, "value")) {
1140 if (parse_u32_arg(&argc, &argv, &attr.value_size,
1141 "value size"))
1142 return -1;
1143 } else if (is_prefix(*argv, "entries")) {
1144 if (parse_u32_arg(&argc, &argv, &attr.max_entries,
1145 "max entries"))
1146 return -1;
1147 } else if (is_prefix(*argv, "flags")) {
1148 if (parse_u32_arg(&argc, &argv, &attr.map_flags,
1149 "flags"))
1150 return -1;
1151 } else if (is_prefix(*argv, "dev")) {
1152 NEXT_ARG();
1153
1154 if (attr.map_ifindex) {
1155 p_err("offload device already specified");
1156 return -1;
1157 }
1158
1159 attr.map_ifindex = if_nametoindex(*argv);
1160 if (!attr.map_ifindex) {
1161 p_err("unrecognized netdevice '%s': %s",
1162 *argv, strerror(errno));
1163 return -1;
1164 }
1165 NEXT_ARG();
Alban Crequy8694d8c2019-04-12 14:40:50 +02001166 } else {
1167 p_err("unknown arg %s", *argv);
1168 return -1;
Jakub Kicinski0b592b5a2018-10-15 16:30:36 -07001169 }
1170 }
1171
1172 if (!attr.name) {
1173 p_err("map name not specified");
1174 return -1;
1175 }
1176
Quentin Monnet8302b9b2018-11-07 12:29:30 +00001177 set_max_rlimit();
1178
Jakub Kicinski0b592b5a2018-10-15 16:30:36 -07001179 fd = bpf_create_map_xattr(&attr);
1180 if (fd < 0) {
1181 p_err("map create failed: %s", strerror(errno));
1182 return -1;
1183 }
1184
1185 err = do_pin_fd(fd, pinfile);
1186 close(fd);
1187 if (err)
1188 return err;
1189
1190 if (json_output)
1191 jsonw_null(json_wtr);
1192 return 0;
1193}
1194
Stanislav Fomichev74f312e2019-01-16 11:10:04 -08001195static int do_pop_dequeue(int argc, char **argv)
1196{
1197 struct bpf_map_info info = {};
1198 __u32 len = sizeof(info);
1199 void *key, *value;
1200 int err;
1201 int fd;
1202
1203 if (argc < 2)
1204 usage();
1205
1206 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
1207 if (fd < 0)
1208 return -1;
1209
1210 err = alloc_key_value(&info, &key, &value);
1211 if (err)
1212 goto exit_free;
1213
1214 err = bpf_map_lookup_and_delete_elem(fd, key, value);
1215 if (err) {
1216 if (errno == ENOENT) {
1217 if (json_output)
1218 jsonw_null(json_wtr);
1219 else
1220 printf("Error: empty map\n");
1221 } else {
1222 p_err("pop failed: %s", strerror(errno));
1223 }
1224
1225 goto exit_free;
1226 }
1227
1228 print_key_value(&info, key, value);
1229
1230exit_free:
1231 free(key);
1232 free(value);
1233 close(fd);
1234
1235 return err;
1236}
1237
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001238static int do_help(int argc, char **argv)
1239{
Quentin Monnet004b45c2017-10-23 09:24:14 -07001240 if (json_output) {
1241 jsonw_null(json_wtr);
1242 return 0;
1243 }
1244
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001245 fprintf(stderr,
Jakub Kicinski6ebe6db2018-01-02 14:48:36 -08001246 "Usage: %s %s { show | list } [MAP]\n"
Jakub Kicinski0b592b5a2018-10-15 16:30:36 -07001247 " %s %s create FILE type TYPE key KEY_SIZE value VALUE_SIZE \\\n"
1248 " entries MAX_ENTRIES name NAME [flags FLAGS] \\\n"
1249 " [dev NAME]\n"
Jakub Kicinskif412eed2018-05-03 18:37:16 -07001250 " %s %s dump MAP\n"
Stanislav Fomichev7d7209c2019-01-16 11:09:59 -08001251 " %s %s update MAP [key DATA] [value VALUE] [UPDATE_FLAGS]\n"
Stanislav Fomichev8a89fff2019-01-16 11:10:00 -08001252 " %s %s lookup MAP [key DATA]\n"
Jakub Kicinskif412eed2018-05-03 18:37:16 -07001253 " %s %s getnext MAP [key DATA]\n"
1254 " %s %s delete MAP key DATA\n"
1255 " %s %s pin MAP FILE\n"
1256 " %s %s event_pipe MAP [cpu N index M]\n"
Stanislav Fomichev66cf6e02019-01-16 11:10:02 -08001257 " %s %s peek MAP\n"
Stanislav Fomichev549d4d32019-01-16 11:10:03 -08001258 " %s %s push MAP value VALUE\n"
Stanislav Fomichev74f312e2019-01-16 11:10:04 -08001259 " %s %s pop MAP\n"
Stanislav Fomichev549d4d32019-01-16 11:10:03 -08001260 " %s %s enqueue MAP value VALUE\n"
Stanislav Fomichev74f312e2019-01-16 11:10:04 -08001261 " %s %s dequeue MAP\n"
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001262 " %s %s help\n"
1263 "\n"
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -07001264 " " HELP_SPEC_MAP "\n"
Jakub Kicinskic642ea22018-05-03 18:37:14 -07001265 " DATA := { [hex] BYTES }\n"
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001266 " " HELP_SPEC_PROGRAM "\n"
Jakub Kicinskic642ea22018-05-03 18:37:14 -07001267 " VALUE := { DATA | MAP | PROG }\n"
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001268 " UPDATE_FLAGS := { any | exist | noexist }\n"
Jakub Kicinski0b592b5a2018-10-15 16:30:36 -07001269 " TYPE := { hash | array | prog_array | perf_event_array | percpu_hash |\n"
1270 " percpu_array | stack_trace | cgroup_array | lru_hash |\n"
1271 " lru_percpu_hash | lpm_trie | array_of_maps | hash_of_maps |\n"
1272 " devmap | sockmap | cpumap | xskmap | sockhash |\n"
1273 " cgroup_storage | reuseport_sockarray | percpu_cgroup_storage }\n"
Quentin Monnet0641c3c2017-10-23 09:24:16 -07001274 " " HELP_SPEC_OPTIONS "\n"
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001275 "",
1276 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
1277 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
Jakub Kicinski0b592b5a2018-10-15 16:30:36 -07001278 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
Stanislav Fomichev549d4d32019-01-16 11:10:03 -08001279 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
Stanislav Fomichev74f312e2019-01-16 11:10:04 -08001280 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]);
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001281
1282 return 0;
1283}
1284
1285static const struct cmd cmds[] = {
1286 { "show", do_show },
Jakub Kicinski6ebe6db2018-01-02 14:48:36 -08001287 { "list", do_show },
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001288 { "help", do_help },
1289 { "dump", do_dump },
1290 { "update", do_update },
1291 { "lookup", do_lookup },
1292 { "getnext", do_getnext },
1293 { "delete", do_delete },
1294 { "pin", do_pin },
Jakub Kicinskif412eed2018-05-03 18:37:16 -07001295 { "event_pipe", do_event_pipe },
Jakub Kicinski0b592b5a2018-10-15 16:30:36 -07001296 { "create", do_create },
Stanislav Fomichev66cf6e02019-01-16 11:10:02 -08001297 { "peek", do_lookup },
Stanislav Fomichev549d4d32019-01-16 11:10:03 -08001298 { "push", do_update },
1299 { "enqueue", do_update },
Stanislav Fomichev74f312e2019-01-16 11:10:04 -08001300 { "pop", do_pop_dequeue },
1301 { "dequeue", do_pop_dequeue },
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001302 { 0 }
1303};
1304
1305int do_map(int argc, char **argv)
1306{
1307 return cmd_select(cmds, argc, argv, do_help);
1308}