blob: af6766e956bafe3e18dd7d8a8e33bbf479de7d3c [file] [log] [blame]
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001/*
Jakub Kicinskic642ea22018-05-03 18:37:14 -07002 * Copyright (C) 2017-2018 Netronome Systems, Inc.
Jakub Kicinski71bb4282017-10-04 20:10:04 -07003 *
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 */
33
34/* Author: Jakub Kicinski <kubakici@wp.pl> */
35
36#include <assert.h>
Jakub Kicinski71bb4282017-10-04 20:10:04 -070037#include <errno.h>
38#include <fcntl.h>
39#include <stdbool.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include <unistd.h>
44#include <sys/types.h>
45#include <sys/stat.h>
46
47#include <bpf.h>
48
49#include "main.h"
50
51static const char * const map_type_name[] = {
52 [BPF_MAP_TYPE_UNSPEC] = "unspec",
53 [BPF_MAP_TYPE_HASH] = "hash",
54 [BPF_MAP_TYPE_ARRAY] = "array",
55 [BPF_MAP_TYPE_PROG_ARRAY] = "prog_array",
56 [BPF_MAP_TYPE_PERF_EVENT_ARRAY] = "perf_event_array",
57 [BPF_MAP_TYPE_PERCPU_HASH] = "percpu_hash",
58 [BPF_MAP_TYPE_PERCPU_ARRAY] = "percpu_array",
59 [BPF_MAP_TYPE_STACK_TRACE] = "stack_trace",
60 [BPF_MAP_TYPE_CGROUP_ARRAY] = "cgroup_array",
61 [BPF_MAP_TYPE_LRU_HASH] = "lru_hash",
62 [BPF_MAP_TYPE_LRU_PERCPU_HASH] = "lru_percpu_hash",
63 [BPF_MAP_TYPE_LPM_TRIE] = "lpm_trie",
64 [BPF_MAP_TYPE_ARRAY_OF_MAPS] = "array_of_maps",
65 [BPF_MAP_TYPE_HASH_OF_MAPS] = "hash_of_maps",
66 [BPF_MAP_TYPE_DEVMAP] = "devmap",
67 [BPF_MAP_TYPE_SOCKMAP] = "sockmap",
Roman Gushchina55aaf62018-01-19 14:17:45 +000068 [BPF_MAP_TYPE_CPUMAP] = "cpumap",
Jakub Kicinski71bb4282017-10-04 20:10:04 -070069};
70
Jakub Kicinski71bb4282017-10-04 20:10:04 -070071static bool map_is_per_cpu(__u32 type)
72{
73 return type == BPF_MAP_TYPE_PERCPU_HASH ||
74 type == BPF_MAP_TYPE_PERCPU_ARRAY ||
75 type == BPF_MAP_TYPE_LRU_PERCPU_HASH;
76}
77
78static bool map_is_map_of_maps(__u32 type)
79{
80 return type == BPF_MAP_TYPE_ARRAY_OF_MAPS ||
81 type == BPF_MAP_TYPE_HASH_OF_MAPS;
82}
83
84static bool map_is_map_of_progs(__u32 type)
85{
86 return type == BPF_MAP_TYPE_PROG_ARRAY;
87}
88
89static void *alloc_value(struct bpf_map_info *info)
90{
91 if (map_is_per_cpu(info->type))
92 return malloc(info->value_size * get_possible_cpus());
93 else
94 return malloc(info->value_size);
95}
96
97static int map_parse_fd(int *argc, char ***argv)
98{
99 int fd;
100
101 if (is_prefix(**argv, "id")) {
102 unsigned int id;
103 char *endptr;
104
105 NEXT_ARGP();
106
107 id = strtoul(**argv, &endptr, 0);
108 if (*endptr) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700109 p_err("can't parse %s as ID", **argv);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700110 return -1;
111 }
112 NEXT_ARGP();
113
114 fd = bpf_map_get_fd_by_id(id);
115 if (fd < 0)
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700116 p_err("get map by id (%u): %s", id, strerror(errno));
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700117 return fd;
118 } else if (is_prefix(**argv, "pinned")) {
119 char *path;
120
121 NEXT_ARGP();
122
123 path = **argv;
124 NEXT_ARGP();
125
126 return open_obj_pinned_any(path, BPF_OBJ_MAP);
127 }
128
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700129 p_err("expected 'id' or 'pinned', got: '%s'?", **argv);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700130 return -1;
131}
132
Jakub Kicinskif412eed2018-05-03 18:37:16 -0700133int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len)
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700134{
135 int err;
136 int fd;
137
138 fd = map_parse_fd(argc, argv);
139 if (fd < 0)
140 return -1;
141
142 err = bpf_obj_get_info_by_fd(fd, info, info_len);
143 if (err) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700144 p_err("can't get map info: %s", strerror(errno));
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700145 close(fd);
146 return err;
147 }
148
149 return fd;
150}
151
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700152static void print_entry_json(struct bpf_map_info *info, unsigned char *key,
153 unsigned char *value)
154{
155 jsonw_start_object(json_wtr);
156
157 if (!map_is_per_cpu(info->type)) {
158 jsonw_name(json_wtr, "key");
159 print_hex_data_json(key, info->key_size);
160 jsonw_name(json_wtr, "value");
161 print_hex_data_json(value, info->value_size);
162 } else {
163 unsigned int i, n;
164
165 n = get_possible_cpus();
166
167 jsonw_name(json_wtr, "key");
168 print_hex_data_json(key, info->key_size);
169
170 jsonw_name(json_wtr, "values");
171 jsonw_start_array(json_wtr);
172 for (i = 0; i < n; i++) {
173 jsonw_start_object(json_wtr);
174
175 jsonw_int_field(json_wtr, "cpu", i);
176
177 jsonw_name(json_wtr, "value");
178 print_hex_data_json(value + i * info->value_size,
179 info->value_size);
180
181 jsonw_end_object(json_wtr);
182 }
183 jsonw_end_array(json_wtr);
184 }
185
186 jsonw_end_object(json_wtr);
187}
188
189static void print_entry_plain(struct bpf_map_info *info, unsigned char *key,
190 unsigned char *value)
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700191{
192 if (!map_is_per_cpu(info->type)) {
193 bool single_line, break_names;
194
195 break_names = info->key_size > 16 || info->value_size > 16;
196 single_line = info->key_size + info->value_size <= 24 &&
197 !break_names;
198
199 printf("key:%c", break_names ? '\n' : ' ');
Quentin Monnet9cbe1f582017-10-19 15:46:19 -0700200 fprint_hex(stdout, key, info->key_size, " ");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700201
202 printf(single_line ? " " : "\n");
203
204 printf("value:%c", break_names ? '\n' : ' ');
Quentin Monnet9cbe1f582017-10-19 15:46:19 -0700205 fprint_hex(stdout, value, info->value_size, " ");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700206
207 printf("\n");
208 } else {
209 unsigned int i, n;
210
211 n = get_possible_cpus();
212
213 printf("key:\n");
Quentin Monnet9cbe1f582017-10-19 15:46:19 -0700214 fprint_hex(stdout, key, info->key_size, " ");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700215 printf("\n");
216 for (i = 0; i < n; i++) {
217 printf("value (CPU %02d):%c",
218 i, info->value_size > 16 ? '\n' : ' ');
Quentin Monnet9cbe1f582017-10-19 15:46:19 -0700219 fprint_hex(stdout, value + i * info->value_size,
220 info->value_size, " ");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700221 printf("\n");
222 }
223 }
224}
225
226static char **parse_bytes(char **argv, const char *name, unsigned char *val,
227 unsigned int n)
228{
Quentin Monnet0c90f222018-04-17 19:46:34 -0700229 unsigned int i = 0, base = 0;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700230 char *endptr;
231
Quentin Monnet0c90f222018-04-17 19:46:34 -0700232 if (is_prefix(*argv, "hex")) {
233 base = 16;
234 argv++;
235 }
236
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700237 while (i < n && argv[i]) {
Quentin Monnet0c90f222018-04-17 19:46:34 -0700238 val[i] = strtoul(argv[i], &endptr, base);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700239 if (*endptr) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700240 p_err("error parsing byte: %s", argv[i]);
Quentin Monnetd9c0b482017-10-19 15:46:23 -0700241 return NULL;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700242 }
243 i++;
244 }
245
246 if (i != n) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700247 p_err("%s expected %d bytes got %d", name, n, i);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700248 return NULL;
249 }
250
251 return argv + i;
252}
253
254static int parse_elem(char **argv, struct bpf_map_info *info,
255 void *key, void *value, __u32 key_size, __u32 value_size,
256 __u32 *flags, __u32 **value_fd)
257{
258 if (!*argv) {
259 if (!key && !value)
260 return 0;
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700261 p_err("did not find %s", key ? "key" : "value");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700262 return -1;
263 }
264
265 if (is_prefix(*argv, "key")) {
266 if (!key) {
267 if (key_size)
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700268 p_err("duplicate key");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700269 else
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700270 p_err("unnecessary key");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700271 return -1;
272 }
273
274 argv = parse_bytes(argv + 1, "key", key, key_size);
275 if (!argv)
276 return -1;
277
278 return parse_elem(argv, info, NULL, value, key_size, value_size,
279 flags, value_fd);
280 } else if (is_prefix(*argv, "value")) {
281 int fd;
282
283 if (!value) {
284 if (value_size)
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700285 p_err("duplicate value");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700286 else
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700287 p_err("unnecessary value");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700288 return -1;
289 }
290
291 argv++;
292
293 if (map_is_map_of_maps(info->type)) {
294 int argc = 2;
295
296 if (value_size != 4) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700297 p_err("value smaller than 4B for map in map?");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700298 return -1;
299 }
300 if (!argv[0] || !argv[1]) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700301 p_err("not enough value arguments for map in map");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700302 return -1;
303 }
304
305 fd = map_parse_fd(&argc, &argv);
306 if (fd < 0)
307 return -1;
308
309 *value_fd = value;
310 **value_fd = fd;
311 } else if (map_is_map_of_progs(info->type)) {
312 int argc = 2;
313
314 if (value_size != 4) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700315 p_err("value smaller than 4B for map of progs?");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700316 return -1;
317 }
318 if (!argv[0] || !argv[1]) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700319 p_err("not enough value arguments for map of progs");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700320 return -1;
321 }
322
323 fd = prog_parse_fd(&argc, &argv);
324 if (fd < 0)
325 return -1;
326
327 *value_fd = value;
328 **value_fd = fd;
329 } else {
330 argv = parse_bytes(argv, "value", value, value_size);
331 if (!argv)
332 return -1;
333 }
334
335 return parse_elem(argv, info, key, NULL, key_size, value_size,
336 flags, NULL);
337 } else if (is_prefix(*argv, "any") || is_prefix(*argv, "noexist") ||
338 is_prefix(*argv, "exist")) {
339 if (!flags) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700340 p_err("flags specified multiple times: %s", *argv);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700341 return -1;
342 }
343
344 if (is_prefix(*argv, "any"))
345 *flags = BPF_ANY;
346 else if (is_prefix(*argv, "noexist"))
347 *flags = BPF_NOEXIST;
348 else if (is_prefix(*argv, "exist"))
349 *flags = BPF_EXIST;
350
351 return parse_elem(argv + 1, info, key, value, key_size,
352 value_size, NULL, value_fd);
353 }
354
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700355 p_err("expected key or value, got: %s", *argv);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700356 return -1;
357}
358
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700359static int show_map_close_json(int fd, struct bpf_map_info *info)
360{
361 char *memlock;
362
363 memlock = get_fdinfo(fd, "memlock");
364 close(fd);
365
366 jsonw_start_object(json_wtr);
367
368 jsonw_uint_field(json_wtr, "id", info->id);
369 if (info->type < ARRAY_SIZE(map_type_name))
370 jsonw_string_field(json_wtr, "type",
371 map_type_name[info->type]);
372 else
373 jsonw_uint_field(json_wtr, "type", info->type);
374
375 if (*info->name)
376 jsonw_string_field(json_wtr, "name", info->name);
377
378 jsonw_name(json_wtr, "flags");
Jakub Kicinski4b6eca92018-03-23 19:45:12 -0700379 jsonw_printf(json_wtr, "%d", info->map_flags);
Jakub Kicinski064a07c2018-01-17 19:13:29 -0800380
381 print_dev_json(info->ifindex, info->netns_dev, info->netns_ino);
382
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700383 jsonw_uint_field(json_wtr, "bytes_key", info->key_size);
384 jsonw_uint_field(json_wtr, "bytes_value", info->value_size);
385 jsonw_uint_field(json_wtr, "max_entries", info->max_entries);
386
387 if (memlock)
388 jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock));
389 free(memlock);
390
Prashant Bhole4990f1f2017-11-08 13:55:48 +0900391 if (!hash_empty(map_table.table)) {
392 struct pinned_obj *obj;
393
394 jsonw_name(json_wtr, "pinned");
395 jsonw_start_array(json_wtr);
396 hash_for_each_possible(map_table.table, obj, hash, info->id) {
397 if (obj->id == info->id)
398 jsonw_string(json_wtr, obj->path);
399 }
400 jsonw_end_array(json_wtr);
401 }
402
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700403 jsonw_end_object(json_wtr);
404
405 return 0;
406}
407
408static int show_map_close_plain(int fd, struct bpf_map_info *info)
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700409{
410 char *memlock;
411
412 memlock = get_fdinfo(fd, "memlock");
413 close(fd);
414
415 printf("%u: ", info->id);
416 if (info->type < ARRAY_SIZE(map_type_name))
417 printf("%s ", map_type_name[info->type]);
418 else
419 printf("type %u ", info->type);
420
421 if (*info->name)
422 printf("name %s ", info->name);
423
Jakub Kicinski064a07c2018-01-17 19:13:29 -0800424 printf("flags 0x%x", info->map_flags);
425 print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino);
426 printf("\n");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700427 printf("\tkey %uB value %uB max_entries %u",
428 info->key_size, info->value_size, info->max_entries);
429
430 if (memlock)
431 printf(" memlock %sB", memlock);
432 free(memlock);
433
434 printf("\n");
Prashant Bhole4990f1f2017-11-08 13:55:48 +0900435 if (!hash_empty(map_table.table)) {
436 struct pinned_obj *obj;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700437
Prashant Bhole4990f1f2017-11-08 13:55:48 +0900438 hash_for_each_possible(map_table.table, obj, hash, info->id) {
439 if (obj->id == info->id)
440 printf("\tpinned %s\n", obj->path);
441 }
442 }
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700443 return 0;
444}
445
446static int do_show(int argc, char **argv)
447{
448 struct bpf_map_info info = {};
449 __u32 len = sizeof(info);
450 __u32 id = 0;
451 int err;
452 int fd;
453
Prashant Bholec541b732017-11-08 13:55:49 +0900454 if (show_pinned)
455 build_pinned_obj_table(&map_table, BPF_OBJ_MAP);
Prashant Bhole4990f1f2017-11-08 13:55:48 +0900456
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700457 if (argc == 2) {
458 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
459 if (fd < 0)
460 return -1;
461
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700462 if (json_output)
463 return show_map_close_json(fd, &info);
464 else
465 return show_map_close_plain(fd, &info);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700466 }
467
468 if (argc)
469 return BAD_ARG();
470
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700471 if (json_output)
472 jsonw_start_array(json_wtr);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700473 while (true) {
474 err = bpf_map_get_next_id(id, &id);
475 if (err) {
476 if (errno == ENOENT)
477 break;
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700478 p_err("can't get next map: %s%s", strerror(errno),
479 errno == EINVAL ? " -- kernel too old?" : "");
Jakub Kicinskib3b1b652017-12-22 11:36:05 -0800480 break;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700481 }
482
483 fd = bpf_map_get_fd_by_id(id);
484 if (fd < 0) {
Jakub Kicinski8207c6d2017-12-22 11:36:06 -0800485 if (errno == ENOENT)
486 continue;
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700487 p_err("can't get map by id (%u): %s",
488 id, strerror(errno));
Jakub Kicinskib3b1b652017-12-22 11:36:05 -0800489 break;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700490 }
491
492 err = bpf_obj_get_info_by_fd(fd, &info, &len);
493 if (err) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700494 p_err("can't get map info: %s", strerror(errno));
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700495 close(fd);
Jakub Kicinskib3b1b652017-12-22 11:36:05 -0800496 break;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700497 }
498
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700499 if (json_output)
500 show_map_close_json(fd, &info);
501 else
502 show_map_close_plain(fd, &info);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700503 }
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700504 if (json_output)
505 jsonw_end_array(json_wtr);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700506
507 return errno == ENOENT ? 0 : -1;
508}
509
510static int do_dump(int argc, char **argv)
511{
512 void *key, *value, *prev_key;
513 unsigned int num_elems = 0;
514 struct bpf_map_info info = {};
515 __u32 len = sizeof(info);
516 int err;
517 int fd;
518
519 if (argc != 2)
520 usage();
521
522 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
523 if (fd < 0)
524 return -1;
525
526 if (map_is_map_of_maps(info.type) || map_is_map_of_progs(info.type)) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700527 p_err("Dumping maps of maps and program maps not supported");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700528 close(fd);
529 return -1;
530 }
531
532 key = malloc(info.key_size);
533 value = alloc_value(&info);
534 if (!key || !value) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700535 p_err("mem alloc failed");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700536 err = -1;
537 goto exit_free;
538 }
539
540 prev_key = NULL;
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700541 if (json_output)
542 jsonw_start_array(json_wtr);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700543 while (true) {
544 err = bpf_map_get_next_key(fd, prev_key, key);
545 if (err) {
546 if (errno == ENOENT)
547 err = 0;
548 break;
549 }
550
551 if (!bpf_map_lookup_elem(fd, key, value)) {
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700552 if (json_output)
553 print_entry_json(&info, key, value);
554 else
555 print_entry_plain(&info, key, value);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700556 } else {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700557 if (json_output) {
558 jsonw_name(json_wtr, "key");
559 print_hex_data_json(key, info.key_size);
560 jsonw_name(json_wtr, "value");
561 jsonw_start_object(json_wtr);
562 jsonw_string_field(json_wtr, "error",
563 "can't lookup element");
564 jsonw_end_object(json_wtr);
565 } else {
566 p_info("can't lookup element with key: ");
567 fprint_hex(stderr, key, info.key_size, " ");
568 fprintf(stderr, "\n");
569 }
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700570 }
571
572 prev_key = key;
573 num_elems++;
574 }
575
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700576 if (json_output)
577 jsonw_end_array(json_wtr);
578 else
579 printf("Found %u element%s\n", num_elems,
580 num_elems != 1 ? "s" : "");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700581
582exit_free:
583 free(key);
584 free(value);
585 close(fd);
586
587 return err;
588}
589
590static int do_update(int argc, char **argv)
591{
592 struct bpf_map_info info = {};
593 __u32 len = sizeof(info);
594 __u32 *value_fd = NULL;
595 __u32 flags = BPF_ANY;
596 void *key, *value;
597 int fd, err;
598
599 if (argc < 2)
600 usage();
601
602 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
603 if (fd < 0)
604 return -1;
605
606 key = malloc(info.key_size);
607 value = alloc_value(&info);
608 if (!key || !value) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700609 p_err("mem alloc failed");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700610 err = -1;
611 goto exit_free;
612 }
613
614 err = parse_elem(argv, &info, key, value, info.key_size,
615 info.value_size, &flags, &value_fd);
616 if (err)
617 goto exit_free;
618
619 err = bpf_map_update_elem(fd, key, value, flags);
620 if (err) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700621 p_err("update failed: %s", strerror(errno));
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700622 goto exit_free;
623 }
624
625exit_free:
626 if (value_fd)
627 close(*value_fd);
628 free(key);
629 free(value);
630 close(fd);
631
Quentin Monnet004b45c2017-10-23 09:24:14 -0700632 if (!err && json_output)
633 jsonw_null(json_wtr);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700634 return err;
635}
636
637static int do_lookup(int argc, char **argv)
638{
639 struct bpf_map_info info = {};
640 __u32 len = sizeof(info);
641 void *key, *value;
642 int err;
643 int fd;
644
645 if (argc < 2)
646 usage();
647
648 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
649 if (fd < 0)
650 return -1;
651
652 key = malloc(info.key_size);
653 value = alloc_value(&info);
654 if (!key || !value) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700655 p_err("mem alloc failed");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700656 err = -1;
657 goto exit_free;
658 }
659
660 err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL);
661 if (err)
662 goto exit_free;
663
664 err = bpf_map_lookup_elem(fd, key, value);
665 if (!err) {
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700666 if (json_output)
667 print_entry_json(&info, key, value);
668 else
669 print_entry_plain(&info, key, value);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700670 } else if (errno == ENOENT) {
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700671 if (json_output) {
672 jsonw_null(json_wtr);
673 } else {
674 printf("key:\n");
675 fprint_hex(stdout, key, info.key_size, " ");
676 printf("\n\nNot found\n");
677 }
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700678 } else {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700679 p_err("lookup failed: %s", strerror(errno));
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700680 }
681
682exit_free:
683 free(key);
684 free(value);
685 close(fd);
686
687 return err;
688}
689
690static int do_getnext(int argc, char **argv)
691{
692 struct bpf_map_info info = {};
693 __u32 len = sizeof(info);
694 void *key, *nextkey;
695 int err;
696 int fd;
697
698 if (argc < 2)
699 usage();
700
701 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
702 if (fd < 0)
703 return -1;
704
705 key = malloc(info.key_size);
706 nextkey = malloc(info.key_size);
707 if (!key || !nextkey) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700708 p_err("mem alloc failed");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700709 err = -1;
710 goto exit_free;
711 }
712
713 if (argc) {
714 err = parse_elem(argv, &info, key, NULL, info.key_size, 0,
715 NULL, NULL);
716 if (err)
717 goto exit_free;
718 } else {
719 free(key);
720 key = NULL;
721 }
722
723 err = bpf_map_get_next_key(fd, key, nextkey);
724 if (err) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700725 p_err("can't get next key: %s", strerror(errno));
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700726 goto exit_free;
727 }
728
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700729 if (json_output) {
730 jsonw_start_object(json_wtr);
731 if (key) {
732 jsonw_name(json_wtr, "key");
733 print_hex_data_json(key, info.key_size);
734 } else {
735 jsonw_null_field(json_wtr, "key");
736 }
737 jsonw_name(json_wtr, "next_key");
738 print_hex_data_json(nextkey, info.key_size);
739 jsonw_end_object(json_wtr);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700740 } else {
Quentin Monnet831a0aa2017-10-23 09:24:11 -0700741 if (key) {
742 printf("key:\n");
743 fprint_hex(stdout, key, info.key_size, " ");
744 printf("\n");
745 } else {
746 printf("key: None\n");
747 }
748 printf("next key:\n");
749 fprint_hex(stdout, nextkey, info.key_size, " ");
750 printf("\n");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700751 }
752
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700753exit_free:
754 free(nextkey);
755 free(key);
756 close(fd);
757
758 return err;
759}
760
761static int do_delete(int argc, char **argv)
762{
763 struct bpf_map_info info = {};
764 __u32 len = sizeof(info);
765 void *key;
766 int err;
767 int fd;
768
769 if (argc < 2)
770 usage();
771
772 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
773 if (fd < 0)
774 return -1;
775
776 key = malloc(info.key_size);
777 if (!key) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700778 p_err("mem alloc failed");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700779 err = -1;
780 goto exit_free;
781 }
782
783 err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL);
784 if (err)
785 goto exit_free;
786
787 err = bpf_map_delete_elem(fd, key);
788 if (err)
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700789 p_err("delete failed: %s", strerror(errno));
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700790
791exit_free:
792 free(key);
793 close(fd);
794
Quentin Monnet004b45c2017-10-23 09:24:14 -0700795 if (!err && json_output)
796 jsonw_null(json_wtr);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700797 return err;
798}
799
800static int do_pin(int argc, char **argv)
801{
Quentin Monnet004b45c2017-10-23 09:24:14 -0700802 int err;
803
804 err = do_pin_any(argc, argv, bpf_map_get_fd_by_id);
805 if (!err && json_output)
806 jsonw_null(json_wtr);
807 return err;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700808}
809
810static int do_help(int argc, char **argv)
811{
Quentin Monnet004b45c2017-10-23 09:24:14 -0700812 if (json_output) {
813 jsonw_null(json_wtr);
814 return 0;
815 }
816
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700817 fprintf(stderr,
Jakub Kicinski6ebe6db2018-01-02 14:48:36 -0800818 "Usage: %s %s { show | list } [MAP]\n"
Jakub Kicinskif412eed2018-05-03 18:37:16 -0700819 " %s %s dump MAP\n"
820 " %s %s update MAP key DATA value VALUE [UPDATE_FLAGS]\n"
821 " %s %s lookup MAP key DATA\n"
822 " %s %s getnext MAP [key DATA]\n"
823 " %s %s delete MAP key DATA\n"
824 " %s %s pin MAP FILE\n"
825 " %s %s event_pipe MAP [cpu N index M]\n"
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700826 " %s %s help\n"
827 "\n"
828 " MAP := { id MAP_ID | pinned FILE }\n"
Jakub Kicinskic642ea22018-05-03 18:37:14 -0700829 " DATA := { [hex] BYTES }\n"
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700830 " " HELP_SPEC_PROGRAM "\n"
Jakub Kicinskic642ea22018-05-03 18:37:14 -0700831 " VALUE := { DATA | MAP | PROG }\n"
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700832 " UPDATE_FLAGS := { any | exist | noexist }\n"
Quentin Monnet0641c3c2017-10-23 09:24:16 -0700833 " " HELP_SPEC_OPTIONS "\n"
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700834 "",
835 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
836 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
Jakub Kicinskif412eed2018-05-03 18:37:16 -0700837 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700838
839 return 0;
840}
841
842static const struct cmd cmds[] = {
843 { "show", do_show },
Jakub Kicinski6ebe6db2018-01-02 14:48:36 -0800844 { "list", do_show },
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700845 { "help", do_help },
846 { "dump", do_dump },
847 { "update", do_update },
848 { "lookup", do_lookup },
849 { "getnext", do_getnext },
850 { "delete", do_delete },
851 { "pin", do_pin },
Jakub Kicinskif412eed2018-05-03 18:37:16 -0700852 { "event_pipe", do_event_pipe },
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700853 { 0 }
854};
855
856int do_map(int argc, char **argv)
857{
858 return cmd_select(cmds, argc, argv, do_help);
859}