blob: a3521deca86943aa93e24560b5aa7a47d1fb983d [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 Kicinski3ff5a4d2018-07-10 14:43:07 -07004#define _GNU_SOURCE
Jakub Kicinski71bb4282017-10-04 20:10:04 -07005#include <errno.h>
6#include <fcntl.h>
Jakub Kicinskic9c35992017-10-09 10:30:13 -07007#include <stdarg.h>
Jakub Kicinski71bb4282017-10-04 20:10:04 -07008#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <time.h>
12#include <unistd.h>
Jakub Kicinskiba6dd672018-07-10 14:42:58 -070013#include <net/if.h>
Jakub Kicinski71bb4282017-10-04 20:10:04 -070014#include <sys/types.h>
15#include <sys/stat.h>
16
Jakub Kicinskic8406842018-07-10 14:43:03 -070017#include <linux/err.h>
Quentin Monnetba95c742019-07-05 18:54:33 +010018#include <linux/sizes.h>
Jakub Kicinskic8406842018-07-10 14:43:03 -070019
Toke Høiland-Jørgensen229c3b42020-01-20 14:06:46 +010020#include <bpf/bpf.h>
21#include <bpf/btf.h>
22#include <bpf/libbpf.h>
Jakub Kicinski71bb4282017-10-04 20:10:04 -070023
Jiong Wangb6c1ced2018-03-01 18:01:22 -080024#include "cfg.h"
Jakub Kicinski71bb4282017-10-04 20:10:04 -070025#include "main.h"
Jiong Wang73bb5b42018-03-01 18:01:17 -080026#include "xlated_dumper.h"
Jakub Kicinski71bb4282017-10-04 20:10:04 -070027
Paul Chaignonec202502019-12-13 20:10:04 +010028enum dump_mode {
29 DUMP_JITED,
30 DUMP_XLATED,
31};
32
John Fastabendb7d38262018-10-15 11:19:50 -070033static const char * const attach_type_strings[] = {
34 [BPF_SK_SKB_STREAM_PARSER] = "stream_parser",
35 [BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict",
36 [BPF_SK_MSG_VERDICT] = "msg_verdict",
Stanislav Fomichev092f0892018-11-09 08:21:46 -080037 [BPF_FLOW_DISSECTOR] = "flow_dissector",
John Fastabendb7d38262018-10-15 11:19:50 -070038 [__MAX_BPF_ATTACH_TYPE] = NULL,
39};
40
Quentin Monnetc1011892018-12-14 13:56:01 +000041static enum bpf_attach_type parse_attach_type(const char *str)
John Fastabendb7d38262018-10-15 11:19:50 -070042{
43 enum bpf_attach_type type;
44
45 for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) {
46 if (attach_type_strings[type] &&
47 is_prefix(str, attach_type_strings[type]))
48 return type;
49 }
50
51 return __MAX_BPF_ATTACH_TYPE;
52}
53
Jakub Kicinski71bb4282017-10-04 20:10:04 -070054static void print_boot_time(__u64 nsecs, char *buf, unsigned int size)
55{
56 struct timespec real_time_ts, boot_time_ts;
57 time_t wallclock_secs;
58 struct tm load_tm;
59
60 buf[--size] = '\0';
61
62 if (clock_gettime(CLOCK_REALTIME, &real_time_ts) ||
63 clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) {
64 perror("Can't read clocks");
65 snprintf(buf, size, "%llu", nsecs / 1000000000);
66 return;
67 }
68
69 wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) +
Jakub Kicinski07480cb2018-06-14 11:06:55 -070070 (real_time_ts.tv_nsec - boot_time_ts.tv_nsec + nsecs) /
71 1000000000;
72
Jakub Kicinski71bb4282017-10-04 20:10:04 -070073
74 if (!localtime_r(&wallclock_secs, &load_tm)) {
75 snprintf(buf, size, "%llu", nsecs / 1000000000);
76 return;
77 }
78
Quentin Monneta3fe1f62018-05-01 21:18:38 +010079 if (json_output)
80 strftime(buf, size, "%s", &load_tm);
81 else
82 strftime(buf, size, "%FT%T%z", &load_tm);
Jakub Kicinski71bb4282017-10-04 20:10:04 -070083}
84
Paul Chaignona7d22ca2019-12-13 20:10:17 +010085static int prog_fd_by_nametag(void *nametag, int **fds, bool tag)
Jakub Kicinski71bb4282017-10-04 20:10:04 -070086{
Jakub Kicinski71bb4282017-10-04 20:10:04 -070087 unsigned int id = 0;
Paul Chaignonec202502019-12-13 20:10:04 +010088 int fd, nb_fds = 0;
89 void *tmp;
Jakub Kicinski71bb4282017-10-04 20:10:04 -070090 int err;
Jakub Kicinski71bb4282017-10-04 20:10:04 -070091
92 while (true) {
Jiri Olsa752bcf82019-01-18 13:58:17 +010093 struct bpf_prog_info info = {};
94 __u32 len = sizeof(info);
95
Jakub Kicinski71bb4282017-10-04 20:10:04 -070096 err = bpf_prog_get_next_id(id, &id);
97 if (err) {
Paul Chaignonec202502019-12-13 20:10:04 +010098 if (errno != ENOENT) {
99 p_err("%s", strerror(errno));
100 goto err_close_fds;
101 }
102 return nb_fds;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700103 }
104
105 fd = bpf_prog_get_fd_by_id(id);
106 if (fd < 0) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700107 p_err("can't get prog by id (%u): %s",
108 id, strerror(errno));
Paul Chaignonec202502019-12-13 20:10:04 +0100109 goto err_close_fds;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700110 }
111
112 err = bpf_obj_get_info_by_fd(fd, &info, &len);
113 if (err) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700114 p_err("can't get prog info (%u): %s",
115 id, strerror(errno));
Paul Chaignonec202502019-12-13 20:10:04 +0100116 goto err_close_fd;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700117 }
118
Paul Chaignona7d22ca2019-12-13 20:10:17 +0100119 if ((tag && memcmp(nametag, info.tag, BPF_TAG_SIZE)) ||
120 (!tag && strncmp(nametag, info.name, BPF_OBJ_NAME_LEN))) {
Paul Chaignonec202502019-12-13 20:10:04 +0100121 close(fd);
122 continue;
123 }
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700124
Paul Chaignonec202502019-12-13 20:10:04 +0100125 if (nb_fds > 0) {
126 tmp = realloc(*fds, (nb_fds + 1) * sizeof(int));
127 if (!tmp) {
128 p_err("failed to realloc");
129 goto err_close_fd;
130 }
131 *fds = tmp;
132 }
133 (*fds)[nb_fds++] = fd;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700134 }
Paul Chaignonec202502019-12-13 20:10:04 +0100135
136err_close_fd:
137 close(fd);
138err_close_fds:
139 while (--nb_fds >= 0)
140 close((*fds)[nb_fds]);
141 return -1;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700142}
143
Paul Chaignonec202502019-12-13 20:10:04 +0100144static int prog_parse_fds(int *argc, char ***argv, int **fds)
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700145{
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700146 if (is_prefix(**argv, "id")) {
147 unsigned int id;
148 char *endptr;
149
150 NEXT_ARGP();
151
152 id = strtoul(**argv, &endptr, 0);
153 if (*endptr) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700154 p_err("can't parse %s as ID", **argv);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700155 return -1;
156 }
157 NEXT_ARGP();
158
Paul Chaignonec202502019-12-13 20:10:04 +0100159 (*fds)[0] = bpf_prog_get_fd_by_id(id);
160 if ((*fds)[0] < 0) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700161 p_err("get by id (%u): %s", id, strerror(errno));
Paul Chaignonec202502019-12-13 20:10:04 +0100162 return -1;
163 }
164 return 1;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700165 } else if (is_prefix(**argv, "tag")) {
166 unsigned char tag[BPF_TAG_SIZE];
167
168 NEXT_ARGP();
169
170 if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2,
171 tag + 3, tag + 4, tag + 5, tag + 6, tag + 7)
172 != BPF_TAG_SIZE) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700173 p_err("can't parse tag");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700174 return -1;
175 }
176 NEXT_ARGP();
177
Paul Chaignona7d22ca2019-12-13 20:10:17 +0100178 return prog_fd_by_nametag(tag, fds, true);
179 } else if (is_prefix(**argv, "name")) {
180 char *name;
181
182 NEXT_ARGP();
183
184 name = **argv;
185 if (strlen(name) > BPF_OBJ_NAME_LEN - 1) {
186 p_err("can't parse name");
187 return -1;
188 }
189 NEXT_ARGP();
190
191 return prog_fd_by_nametag(name, fds, false);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700192 } else if (is_prefix(**argv, "pinned")) {
193 char *path;
194
195 NEXT_ARGP();
196
197 path = **argv;
198 NEXT_ARGP();
199
Paul Chaignonec202502019-12-13 20:10:04 +0100200 (*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_PROG);
201 if ((*fds)[0] < 0)
202 return -1;
203 return 1;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700204 }
205
Paul Chaignona7d22ca2019-12-13 20:10:17 +0100206 p_err("expected 'id', 'tag', 'name' or 'pinned', got: '%s'?", **argv);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700207 return -1;
208}
209
Paul Chaignonec202502019-12-13 20:10:04 +0100210int prog_parse_fd(int *argc, char ***argv)
211{
212 int *fds = NULL;
213 int nb_fds, fd;
214
215 fds = malloc(sizeof(int));
216 if (!fds) {
217 p_err("mem alloc failed");
218 return -1;
219 }
220 nb_fds = prog_parse_fds(argc, argv, &fds);
221 if (nb_fds != 1) {
222 if (nb_fds > 1) {
223 p_err("several programs match this handle");
224 while (nb_fds--)
225 close(fds[nb_fds]);
226 }
227 fd = -1;
228 goto exit_free;
229 }
230
231 fd = fds[0];
232exit_free:
233 free(fds);
234 return fd;
235}
236
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700237static void show_prog_maps(int fd, u32 num_maps)
238{
239 struct bpf_prog_info info = {};
240 __u32 len = sizeof(info);
241 __u32 map_ids[num_maps];
242 unsigned int i;
243 int err;
244
245 info.nr_map_ids = num_maps;
246 info.map_ids = ptr_to_u64(map_ids);
247
248 err = bpf_obj_get_info_by_fd(fd, &info, &len);
249 if (err || !info.nr_map_ids)
250 return;
251
Quentin Monnet743cc662017-10-23 09:24:08 -0700252 if (json_output) {
253 jsonw_name(json_wtr, "map_ids");
254 jsonw_start_array(json_wtr);
255 for (i = 0; i < info.nr_map_ids; i++)
256 jsonw_uint(json_wtr, map_ids[i]);
257 jsonw_end_array(json_wtr);
258 } else {
259 printf(" map_ids ");
260 for (i = 0; i < info.nr_map_ids; i++)
261 printf("%u%s", map_ids[i],
262 i == info.nr_map_ids - 1 ? "" : ",");
263 }
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700264}
265
Paul Chaignonec202502019-12-13 20:10:04 +0100266static void print_prog_header_json(struct bpf_prog_info *info)
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700267{
Quentin Monnet743cc662017-10-23 09:24:08 -0700268 jsonw_uint_field(json_wtr, "id", info->id);
269 if (info->type < ARRAY_SIZE(prog_type_name))
270 jsonw_string_field(json_wtr, "type",
271 prog_type_name[info->type]);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700272 else
Quentin Monnet743cc662017-10-23 09:24:08 -0700273 jsonw_uint_field(json_wtr, "type", info->type);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700274
Quentin Monnet743cc662017-10-23 09:24:08 -0700275 if (*info->name)
276 jsonw_string_field(json_wtr, "name", info->name);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700277
Quentin Monnet743cc662017-10-23 09:24:08 -0700278 jsonw_name(json_wtr, "tag");
279 jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"",
280 info->tag[0], info->tag[1], info->tag[2], info->tag[3],
281 info->tag[4], info->tag[5], info->tag[6], info->tag[7]);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700282
Jiri Olsa9b984a22018-04-26 10:18:01 +0200283 jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible);
Alexei Starovoitov88ad4722019-02-25 14:28:42 -0800284 if (info->run_time_ns) {
285 jsonw_uint_field(json_wtr, "run_time_ns", info->run_time_ns);
286 jsonw_uint_field(json_wtr, "run_cnt", info->run_cnt);
287 }
Paul Chaignonec202502019-12-13 20:10:04 +0100288}
Jiri Olsa9b984a22018-04-26 10:18:01 +0200289
Paul Chaignonec202502019-12-13 20:10:04 +0100290static void print_prog_json(struct bpf_prog_info *info, int fd)
291{
292 char *memlock;
293
294 jsonw_start_object(json_wtr);
295 print_prog_header_json(info);
Jakub Kicinski52262212017-12-27 18:39:10 -0800296 print_dev_json(info->ifindex, info->netns_dev, info->netns_ino);
297
Quentin Monnet743cc662017-10-23 09:24:08 -0700298 if (info->load_time) {
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700299 char buf[32];
300
Quentin Monnet743cc662017-10-23 09:24:08 -0700301 print_boot_time(info->load_time, buf, sizeof(buf));
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700302
303 /* Piggy back on load_time, since 0 uid is a valid one */
Quentin Monneta3fe1f62018-05-01 21:18:38 +0100304 jsonw_name(json_wtr, "loaded_at");
305 jsonw_printf(json_wtr, "%s", buf);
Quentin Monnet743cc662017-10-23 09:24:08 -0700306 jsonw_uint_field(json_wtr, "uid", info->created_by_uid);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700307 }
308
Quentin Monnet743cc662017-10-23 09:24:08 -0700309 jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700310
Quentin Monnet743cc662017-10-23 09:24:08 -0700311 if (info->jited_prog_len) {
312 jsonw_bool_field(json_wtr, "jited", true);
313 jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len);
314 } else {
315 jsonw_bool_field(json_wtr, "jited", false);
316 }
317
318 memlock = get_fdinfo(fd, "memlock");
319 if (memlock)
320 jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock));
321 free(memlock);
322
323 if (info->nr_map_ids)
324 show_prog_maps(fd, info->nr_map_ids);
325
Prashant Bhole569b0c72019-04-10 13:56:42 +0900326 if (info->btf_id)
327 jsonw_int_field(json_wtr, "btf_id", info->btf_id);
328
Prashant Bhole4990f1f2017-11-08 13:55:48 +0900329 if (!hash_empty(prog_table.table)) {
330 struct pinned_obj *obj;
331
332 jsonw_name(json_wtr, "pinned");
333 jsonw_start_array(json_wtr);
334 hash_for_each_possible(prog_table.table, obj, hash, info->id) {
335 if (obj->id == info->id)
336 jsonw_string(json_wtr, obj->path);
337 }
338 jsonw_end_array(json_wtr);
339 }
340
Quentin Monnet743cc662017-10-23 09:24:08 -0700341 jsonw_end_object(json_wtr);
342}
343
Paul Chaignonec202502019-12-13 20:10:04 +0100344static void print_prog_header_plain(struct bpf_prog_info *info)
Quentin Monnet743cc662017-10-23 09:24:08 -0700345{
Quentin Monnet743cc662017-10-23 09:24:08 -0700346 printf("%u: ", info->id);
347 if (info->type < ARRAY_SIZE(prog_type_name))
348 printf("%s ", prog_type_name[info->type]);
349 else
350 printf("type %u ", info->type);
351
352 if (*info->name)
353 printf("name %s ", info->name);
354
355 printf("tag ");
356 fprint_hex(stdout, info->tag, BPF_TAG_SIZE, "");
Jakub Kicinski52262212017-12-27 18:39:10 -0800357 print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino);
Jiri Olsa9b984a22018-04-26 10:18:01 +0200358 printf("%s", info->gpl_compatible ? " gpl" : "");
Alexei Starovoitov88ad4722019-02-25 14:28:42 -0800359 if (info->run_time_ns)
360 printf(" run_time_ns %lld run_cnt %lld",
361 info->run_time_ns, info->run_cnt);
Quentin Monnet743cc662017-10-23 09:24:08 -0700362 printf("\n");
Paul Chaignonec202502019-12-13 20:10:04 +0100363}
364
365static void print_prog_plain(struct bpf_prog_info *info, int fd)
366{
367 char *memlock;
368
369 print_prog_header_plain(info);
Quentin Monnet743cc662017-10-23 09:24:08 -0700370
371 if (info->load_time) {
372 char buf[32];
373
374 print_boot_time(info->load_time, buf, sizeof(buf));
375
376 /* Piggy back on load_time, since 0 uid is a valid one */
377 printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid);
378 }
379
380 printf("\txlated %uB", info->xlated_prog_len);
381
382 if (info->jited_prog_len)
383 printf(" jited %uB", info->jited_prog_len);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700384 else
385 printf(" not jited");
386
387 memlock = get_fdinfo(fd, "memlock");
388 if (memlock)
389 printf(" memlock %sB", memlock);
390 free(memlock);
391
Quentin Monnet743cc662017-10-23 09:24:08 -0700392 if (info->nr_map_ids)
393 show_prog_maps(fd, info->nr_map_ids);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700394
Prashant Bhole4990f1f2017-11-08 13:55:48 +0900395 if (!hash_empty(prog_table.table)) {
396 struct pinned_obj *obj;
397
Prashant Bhole4990f1f2017-11-08 13:55:48 +0900398 hash_for_each_possible(prog_table.table, obj, hash, info->id) {
399 if (obj->id == info->id)
Quentin Monneta8bfd2b2018-11-08 11:52:26 +0000400 printf("\n\tpinned %s", obj->path);
Prashant Bhole4990f1f2017-11-08 13:55:48 +0900401 }
402 }
403
Prashant Bhole569b0c72019-04-10 13:56:42 +0900404 if (info->btf_id)
Quentin Monnet031ebc12019-04-12 14:29:34 +0100405 printf("\n\tbtf_id %d", info->btf_id);
Prashant Bhole569b0c72019-04-10 13:56:42 +0900406
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700407 printf("\n");
Quentin Monnet743cc662017-10-23 09:24:08 -0700408}
409
410static int show_prog(int fd)
411{
412 struct bpf_prog_info info = {};
413 __u32 len = sizeof(info);
414 int err;
415
416 err = bpf_obj_get_info_by_fd(fd, &info, &len);
417 if (err) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700418 p_err("can't get prog info: %s", strerror(errno));
Quentin Monnet743cc662017-10-23 09:24:08 -0700419 return -1;
420 }
421
422 if (json_output)
423 print_prog_json(&info, fd);
424 else
425 print_prog_plain(&info, fd);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700426
427 return 0;
428}
429
Paul Chaignonec202502019-12-13 20:10:04 +0100430static int do_show_subset(int argc, char **argv)
431{
432 int *fds = NULL;
433 int nb_fds, i;
434 int err = -1;
435
436 fds = malloc(sizeof(int));
437 if (!fds) {
438 p_err("mem alloc failed");
439 return -1;
440 }
441 nb_fds = prog_parse_fds(&argc, &argv, &fds);
442 if (nb_fds < 1)
443 goto exit_free;
444
445 if (json_output && nb_fds > 1)
446 jsonw_start_array(json_wtr); /* root array */
447 for (i = 0; i < nb_fds; i++) {
448 err = show_prog(fds[i]);
449 if (err) {
450 for (; i < nb_fds; i++)
451 close(fds[i]);
452 break;
453 }
454 close(fds[i]);
455 }
456 if (json_output && nb_fds > 1)
457 jsonw_end_array(json_wtr); /* root array */
458
459exit_free:
460 free(fds);
461 return err;
462}
463
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700464static int do_show(int argc, char **argv)
Quentin Monnet743cc662017-10-23 09:24:08 -0700465{
466 __u32 id = 0;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700467 int err;
468 int fd;
469
Prashant Bholec541b732017-11-08 13:55:49 +0900470 if (show_pinned)
471 build_pinned_obj_table(&prog_table, BPF_OBJ_PROG);
Prashant Bhole4990f1f2017-11-08 13:55:48 +0900472
Paul Chaignonec202502019-12-13 20:10:04 +0100473 if (argc == 2)
474 return do_show_subset(argc, argv);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700475
476 if (argc)
477 return BAD_ARG();
478
Quentin Monnet743cc662017-10-23 09:24:08 -0700479 if (json_output)
480 jsonw_start_array(json_wtr);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700481 while (true) {
482 err = bpf_prog_get_next_id(id, &id);
483 if (err) {
Quentin Monnet1739c262017-10-19 15:46:20 -0700484 if (errno == ENOENT) {
485 err = 0;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700486 break;
Quentin Monnet1739c262017-10-19 15:46:20 -0700487 }
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700488 p_err("can't get next program: %s%s", strerror(errno),
489 errno == EINVAL ? " -- kernel too old?" : "");
Quentin Monnet743cc662017-10-23 09:24:08 -0700490 err = -1;
491 break;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700492 }
493
494 fd = bpf_prog_get_fd_by_id(id);
495 if (fd < 0) {
Jakub Kicinski8207c6d2017-12-22 11:36:06 -0800496 if (errno == ENOENT)
497 continue;
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700498 p_err("can't get prog by id (%u): %s",
499 id, strerror(errno));
Quentin Monnet743cc662017-10-23 09:24:08 -0700500 err = -1;
501 break;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700502 }
503
504 err = show_prog(fd);
505 close(fd);
506 if (err)
Quentin Monnet743cc662017-10-23 09:24:08 -0700507 break;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700508 }
509
Quentin Monnet743cc662017-10-23 09:24:08 -0700510 if (json_output)
511 jsonw_end_array(json_wtr);
512
513 return err;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700514}
515
Paul Chaignonec202502019-12-13 20:10:04 +0100516static int
517prog_dump(struct bpf_prog_info *info, enum dump_mode mode,
518 char *filepath, bool opcodes, bool visual, bool linum)
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700519{
Martin KaFai Laub053b432018-12-07 16:42:32 -0800520 struct bpf_prog_linfo *prog_linfo = NULL;
Jakub Kicinski3ddeac62018-10-18 11:34:55 -0700521 const char *disasm_opt = NULL;
Daniel Borkmann7105e822017-12-20 13:42:57 +0100522 struct dump_data dd = {};
Song Liucae73f22019-03-11 22:30:39 -0700523 void *func_info = NULL;
Yonghong Song254471e2018-11-19 15:29:21 -0800524 struct btf *btf = NULL;
Yonghong Song254471e2018-11-19 15:29:21 -0800525 char func_sig[1024];
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700526 unsigned char *buf;
Song Liucae73f22019-03-11 22:30:39 -0700527 __u32 member_len;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700528 ssize_t n;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700529 int fd;
530
Song Liucae73f22019-03-11 22:30:39 -0700531 if (mode == DUMP_JITED) {
Toke Høiland-Jørgensen5b79bcd2019-12-10 19:14:12 +0100532 if (info->jited_prog_len == 0 || !info->jited_prog_insns) {
Song Liucae73f22019-03-11 22:30:39 -0700533 p_info("no instructions returned");
Paul Chaignonec202502019-12-13 20:10:04 +0100534 return -1;
Song Liucae73f22019-03-11 22:30:39 -0700535 }
536 buf = (unsigned char *)(info->jited_prog_insns);
537 member_len = info->jited_prog_len;
538 } else { /* DUMP_XLATED */
539 if (info->xlated_prog_len == 0) {
540 p_err("error retrieving insn dump: kernel.kptr_restrict set?");
Paul Chaignonec202502019-12-13 20:10:04 +0100541 return -1;
Song Liucae73f22019-03-11 22:30:39 -0700542 }
543 buf = (unsigned char *)info->xlated_prog_insns;
544 member_len = info->xlated_prog_len;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700545 }
546
Song Liucae73f22019-03-11 22:30:39 -0700547 if (info->btf_id && btf__get_from_id(info->btf_id, &btf)) {
Yonghong Song254471e2018-11-19 15:29:21 -0800548 p_err("failed to get btf");
Paul Chaignonec202502019-12-13 20:10:04 +0100549 return -1;
Yonghong Song254471e2018-11-19 15:29:21 -0800550 }
551
Song Liucae73f22019-03-11 22:30:39 -0700552 func_info = (void *)info->func_info;
553
554 if (info->nr_line_info) {
555 prog_linfo = bpf_prog_linfo__new(info);
Martin KaFai Laub053b432018-12-07 16:42:32 -0800556 if (!prog_linfo)
Martin KaFai Lau10a5ce92018-12-10 10:53:24 -0800557 p_info("error in processing bpf_line_info. continue without it.");
Martin KaFai Laub053b432018-12-07 16:42:32 -0800558 }
559
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700560 if (filepath) {
561 fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
562 if (fd < 0) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700563 p_err("can't open file %s: %s", filepath,
564 strerror(errno));
Paul Chaignonec202502019-12-13 20:10:04 +0100565 return -1;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700566 }
567
Song Liucae73f22019-03-11 22:30:39 -0700568 n = write(fd, buf, member_len);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700569 close(fd);
Song Liucae73f22019-03-11 22:30:39 -0700570 if (n != member_len) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700571 p_err("error writing output file: %s",
572 n < 0 ? strerror(errno) : "short write");
Paul Chaignonec202502019-12-13 20:10:04 +0100573 return -1;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700574 }
Quentin Monnet52c84d32018-02-14 22:42:54 -0800575
576 if (json_output)
577 jsonw_null(json_wtr);
Song Liucae73f22019-03-11 22:30:39 -0700578 } else if (mode == DUMP_JITED) {
Jiong Wang31972392018-03-01 18:01:16 -0800579 const char *name = NULL;
Jiong Wange6593592018-01-16 16:05:21 -0800580
Song Liucae73f22019-03-11 22:30:39 -0700581 if (info->ifindex) {
582 name = ifindex_to_bfd_params(info->ifindex,
583 info->netns_dev,
584 info->netns_ino,
Jakub Kicinski3ddeac62018-10-18 11:34:55 -0700585 &disasm_opt);
Jiong Wang31972392018-03-01 18:01:16 -0800586 if (!name)
Paul Chaignonec202502019-12-13 20:10:04 +0100587 return -1;
Daniel Borkmann7105e822017-12-20 13:42:57 +0100588 }
Jiong Wang31972392018-03-01 18:01:16 -0800589
Song Liucae73f22019-03-11 22:30:39 -0700590 if (info->nr_jited_func_lens && info->jited_func_lens) {
Sandipan Dasf7f62c72018-05-24 12:26:54 +0530591 struct kernel_sym *sym = NULL;
Yonghong Song254471e2018-11-19 15:29:21 -0800592 struct bpf_func_info *record;
Sandipan Dasf7f62c72018-05-24 12:26:54 +0530593 char sym_name[SYM_MAX_NAME];
594 unsigned char *img = buf;
595 __u64 *ksyms = NULL;
596 __u32 *lens;
597 __u32 i;
Song Liucae73f22019-03-11 22:30:39 -0700598 if (info->nr_jited_ksyms) {
Sandipan Dasf7f62c72018-05-24 12:26:54 +0530599 kernel_syms_load(&dd);
Song Liucae73f22019-03-11 22:30:39 -0700600 ksyms = (__u64 *) info->jited_ksyms;
Sandipan Dasf7f62c72018-05-24 12:26:54 +0530601 }
602
603 if (json_output)
604 jsonw_start_array(json_wtr);
605
Song Liucae73f22019-03-11 22:30:39 -0700606 lens = (__u32 *) info->jited_func_lens;
607 for (i = 0; i < info->nr_jited_func_lens; i++) {
Sandipan Dasf7f62c72018-05-24 12:26:54 +0530608 if (ksyms) {
609 sym = kernel_syms_search(&dd, ksyms[i]);
610 if (sym)
611 sprintf(sym_name, "%s", sym->name);
612 else
613 sprintf(sym_name, "0x%016llx", ksyms[i]);
614 } else {
615 strcpy(sym_name, "unknown");
616 }
617
Yonghong Song254471e2018-11-19 15:29:21 -0800618 if (func_info) {
Song Liucae73f22019-03-11 22:30:39 -0700619 record = func_info + i * info->func_info_rec_size;
Yonghong Song254471e2018-11-19 15:29:21 -0800620 btf_dumper_type_only(btf, record->type_id,
621 func_sig,
622 sizeof(func_sig));
623 }
624
Sandipan Dasf7f62c72018-05-24 12:26:54 +0530625 if (json_output) {
626 jsonw_start_object(json_wtr);
Yonghong Song254471e2018-11-19 15:29:21 -0800627 if (func_info && func_sig[0] != '\0') {
628 jsonw_name(json_wtr, "proto");
629 jsonw_string(json_wtr, func_sig);
630 }
Sandipan Dasf7f62c72018-05-24 12:26:54 +0530631 jsonw_name(json_wtr, "name");
632 jsonw_string(json_wtr, sym_name);
633 jsonw_name(json_wtr, "insns");
634 } else {
Yonghong Song254471e2018-11-19 15:29:21 -0800635 if (func_info && func_sig[0] != '\0')
636 printf("%s:\n", func_sig);
Sandipan Dasf7f62c72018-05-24 12:26:54 +0530637 printf("%s:\n", sym_name);
638 }
639
Martin KaFai Laub053b432018-12-07 16:42:32 -0800640 disasm_print_insn(img, lens[i], opcodes,
641 name, disasm_opt, btf,
642 prog_linfo, ksyms[i], i,
643 linum);
644
Sandipan Dasf7f62c72018-05-24 12:26:54 +0530645 img += lens[i];
646
647 if (json_output)
648 jsonw_end_object(json_wtr);
649 else
650 printf("\n");
651 }
652
653 if (json_output)
654 jsonw_end_array(json_wtr);
655 } else {
Song Liucae73f22019-03-11 22:30:39 -0700656 disasm_print_insn(buf, member_len, opcodes, name,
Martin KaFai Laub053b432018-12-07 16:42:32 -0800657 disasm_opt, btf, NULL, 0, 0, false);
Sandipan Dasf7f62c72018-05-24 12:26:54 +0530658 }
Jiong Wangb6c1ced2018-03-01 18:01:22 -0800659 } else if (visual) {
660 if (json_output)
661 jsonw_null(json_wtr);
662 else
Song Liucae73f22019-03-11 22:30:39 -0700663 dump_xlated_cfg(buf, member_len);
Jiong Wang31972392018-03-01 18:01:16 -0800664 } else {
665 kernel_syms_load(&dd);
Song Liucae73f22019-03-11 22:30:39 -0700666 dd.nr_jited_ksyms = info->nr_jited_ksyms;
667 dd.jited_ksyms = (__u64 *) info->jited_ksyms;
Yonghong Song254471e2018-11-19 15:29:21 -0800668 dd.btf = btf;
669 dd.func_info = func_info;
Song Liucae73f22019-03-11 22:30:39 -0700670 dd.finfo_rec_size = info->func_info_rec_size;
Martin KaFai Laub053b432018-12-07 16:42:32 -0800671 dd.prog_linfo = prog_linfo;
Sandipan Dasf84192e2018-05-24 12:26:50 +0530672
Jiong Wang31972392018-03-01 18:01:16 -0800673 if (json_output)
Song Liucae73f22019-03-11 22:30:39 -0700674 dump_xlated_json(&dd, buf, member_len, opcodes,
Martin KaFai Laub053b432018-12-07 16:42:32 -0800675 linum);
Jiong Wang31972392018-03-01 18:01:16 -0800676 else
Song Liucae73f22019-03-11 22:30:39 -0700677 dump_xlated_plain(&dd, buf, member_len, opcodes,
Martin KaFai Laub053b432018-12-07 16:42:32 -0800678 linum);
Jiong Wang31972392018-03-01 18:01:16 -0800679 kernel_syms_destroy(&dd);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700680 }
681
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700682 return 0;
Paul Chaignonec202502019-12-13 20:10:04 +0100683}
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700684
Paul Chaignonec202502019-12-13 20:10:04 +0100685static int do_dump(int argc, char **argv)
686{
687 struct bpf_prog_info_linear *info_linear;
688 char *filepath = NULL;
689 bool opcodes = false;
690 bool visual = false;
691 enum dump_mode mode;
692 bool linum = false;
693 int *fds = NULL;
694 int nb_fds, i = 0;
695 int err = -1;
696 __u64 arrays;
697
698 if (is_prefix(*argv, "jited")) {
699 if (disasm_init())
700 return -1;
701 mode = DUMP_JITED;
702 } else if (is_prefix(*argv, "xlated")) {
703 mode = DUMP_XLATED;
704 } else {
705 p_err("expected 'xlated' or 'jited', got: %s", *argv);
706 return -1;
707 }
708 NEXT_ARG();
709
710 if (argc < 2)
711 usage();
712
713 fds = malloc(sizeof(int));
714 if (!fds) {
715 p_err("mem alloc failed");
716 return -1;
717 }
718 nb_fds = prog_parse_fds(&argc, &argv, &fds);
719 if (nb_fds < 1)
720 goto exit_free;
721
722 if (is_prefix(*argv, "file")) {
723 NEXT_ARG();
724 if (!argc) {
725 p_err("expected file path");
726 goto exit_close;
727 }
728 if (nb_fds > 1) {
729 p_err("several programs matched");
730 goto exit_close;
731 }
732
733 filepath = *argv;
734 NEXT_ARG();
735 } else if (is_prefix(*argv, "opcodes")) {
736 opcodes = true;
737 NEXT_ARG();
738 } else if (is_prefix(*argv, "visual")) {
739 if (nb_fds > 1) {
740 p_err("several programs matched");
741 goto exit_close;
742 }
743
744 visual = true;
745 NEXT_ARG();
746 } else if (is_prefix(*argv, "linum")) {
747 linum = true;
748 NEXT_ARG();
749 }
750
751 if (argc) {
752 usage();
753 goto exit_close;
754 }
755
756 if (mode == DUMP_JITED)
757 arrays = 1UL << BPF_PROG_INFO_JITED_INSNS;
758 else
759 arrays = 1UL << BPF_PROG_INFO_XLATED_INSNS;
760
761 arrays |= 1UL << BPF_PROG_INFO_JITED_KSYMS;
762 arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS;
763 arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO;
764 arrays |= 1UL << BPF_PROG_INFO_LINE_INFO;
765 arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO;
766
767 if (json_output && nb_fds > 1)
768 jsonw_start_array(json_wtr); /* root array */
769 for (i = 0; i < nb_fds; i++) {
770 info_linear = bpf_program__get_prog_info_linear(fds[i], arrays);
771 if (IS_ERR_OR_NULL(info_linear)) {
772 p_err("can't get prog info: %s", strerror(errno));
773 break;
774 }
775
776 if (json_output && nb_fds > 1) {
777 jsonw_start_object(json_wtr); /* prog object */
778 print_prog_header_json(&info_linear->info);
779 jsonw_name(json_wtr, "insns");
780 } else if (nb_fds > 1) {
781 print_prog_header_plain(&info_linear->info);
782 }
783
784 err = prog_dump(&info_linear->info, mode, filepath, opcodes,
785 visual, linum);
786
787 if (json_output && nb_fds > 1)
788 jsonw_end_object(json_wtr); /* prog object */
789 else if (i != nb_fds - 1 && nb_fds > 1)
790 printf("\n");
791
792 free(info_linear);
793 if (err)
794 break;
795 close(fds[i]);
796 }
797 if (json_output && nb_fds > 1)
798 jsonw_end_array(json_wtr); /* root array */
799
800exit_close:
801 for (; i < nb_fds; i++)
802 close(fds[i]);
803exit_free:
804 free(fds);
805 return err;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700806}
807
808static int do_pin(int argc, char **argv)
809{
Quentin Monnet004b45c2017-10-23 09:24:14 -0700810 int err;
811
812 err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id);
813 if (!err && json_output)
814 jsonw_null(json_wtr);
815 return err;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700816}
817
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -0700818struct map_replace {
819 int idx;
820 int fd;
821 char *name;
822};
823
Quentin Monnetc1011892018-12-14 13:56:01 +0000824static int map_replace_compar(const void *p1, const void *p2)
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -0700825{
826 const struct map_replace *a = p1, *b = p2;
827
828 return a->idx - b->idx;
829}
830
Stanislav Fomichev092f0892018-11-09 08:21:46 -0800831static int parse_attach_detach_args(int argc, char **argv, int *progfd,
832 enum bpf_attach_type *attach_type,
833 int *mapfd)
834{
835 if (!REQ_ARGS(3))
836 return -EINVAL;
837
838 *progfd = prog_parse_fd(&argc, &argv);
839 if (*progfd < 0)
840 return *progfd;
841
842 *attach_type = parse_attach_type(*argv);
843 if (*attach_type == __MAX_BPF_ATTACH_TYPE) {
844 p_err("invalid attach/detach type");
845 return -EINVAL;
846 }
847
848 if (*attach_type == BPF_FLOW_DISSECTOR) {
849 *mapfd = -1;
850 return 0;
851 }
852
853 NEXT_ARG();
854 if (!REQ_ARGS(2))
855 return -EINVAL;
856
857 *mapfd = map_parse_fd(&argc, &argv);
858 if (*mapfd < 0)
859 return *mapfd;
860
861 return 0;
862}
863
John Fastabendb7d38262018-10-15 11:19:50 -0700864static int do_attach(int argc, char **argv)
865{
866 enum bpf_attach_type attach_type;
Stanislav Fomichev092f0892018-11-09 08:21:46 -0800867 int err, progfd;
868 int mapfd;
John Fastabendb7d38262018-10-15 11:19:50 -0700869
Stanislav Fomichev092f0892018-11-09 08:21:46 -0800870 err = parse_attach_detach_args(argc, argv,
871 &progfd, &attach_type, &mapfd);
872 if (err)
873 return err;
John Fastabendb7d38262018-10-15 11:19:50 -0700874
875 err = bpf_prog_attach(progfd, mapfd, attach_type, 0);
876 if (err) {
877 p_err("failed prog attach to map");
878 return -EINVAL;
879 }
880
881 if (json_output)
882 jsonw_null(json_wtr);
883 return 0;
884}
885
886static int do_detach(int argc, char **argv)
887{
888 enum bpf_attach_type attach_type;
Stanislav Fomichev092f0892018-11-09 08:21:46 -0800889 int err, progfd;
890 int mapfd;
John Fastabendb7d38262018-10-15 11:19:50 -0700891
Stanislav Fomichev092f0892018-11-09 08:21:46 -0800892 err = parse_attach_detach_args(argc, argv,
893 &progfd, &attach_type, &mapfd);
894 if (err)
895 return err;
John Fastabendb7d38262018-10-15 11:19:50 -0700896
897 err = bpf_prog_detach2(progfd, mapfd, attach_type);
898 if (err) {
899 p_err("failed prog detach from map");
900 return -EINVAL;
901 }
902
903 if (json_output)
904 jsonw_null(json_wtr);
905 return 0;
906}
Stanislav Fomichev77380992018-11-09 08:21:44 -0800907
Quentin Monnetba95c742019-07-05 18:54:33 +0100908static int check_single_stdin(char *file_data_in, char *file_ctx_in)
909{
910 if (file_data_in && file_ctx_in &&
911 !strcmp(file_data_in, "-") && !strcmp(file_ctx_in, "-")) {
912 p_err("cannot use standard input for both data_in and ctx_in");
913 return -1;
914 }
915
916 return 0;
917}
918
919static int get_run_data(const char *fname, void **data_ptr, unsigned int *size)
920{
921 size_t block_size = 256;
922 size_t buf_size = block_size;
923 size_t nb_read = 0;
924 void *tmp;
925 FILE *f;
926
927 if (!fname) {
928 *data_ptr = NULL;
929 *size = 0;
930 return 0;
931 }
932
933 if (!strcmp(fname, "-"))
934 f = stdin;
935 else
936 f = fopen(fname, "r");
937 if (!f) {
938 p_err("failed to open %s: %s", fname, strerror(errno));
939 return -1;
940 }
941
942 *data_ptr = malloc(block_size);
943 if (!*data_ptr) {
944 p_err("failed to allocate memory for data_in/ctx_in: %s",
945 strerror(errno));
946 goto err_fclose;
947 }
948
949 while ((nb_read += fread(*data_ptr + nb_read, 1, block_size, f))) {
950 if (feof(f))
951 break;
952 if (ferror(f)) {
953 p_err("failed to read data_in/ctx_in from %s: %s",
954 fname, strerror(errno));
955 goto err_free;
956 }
957 if (nb_read > buf_size - block_size) {
958 if (buf_size == UINT32_MAX) {
959 p_err("data_in/ctx_in is too long (max: %d)",
960 UINT32_MAX);
961 goto err_free;
962 }
963 /* No space for fread()-ing next chunk; realloc() */
964 buf_size *= 2;
965 tmp = realloc(*data_ptr, buf_size);
966 if (!tmp) {
967 p_err("failed to reallocate data_in/ctx_in: %s",
968 strerror(errno));
969 goto err_free;
970 }
971 *data_ptr = tmp;
972 }
973 }
974 if (f != stdin)
975 fclose(f);
976
977 *size = nb_read;
978 return 0;
979
980err_free:
981 free(*data_ptr);
982 *data_ptr = NULL;
983err_fclose:
984 if (f != stdin)
985 fclose(f);
986 return -1;
987}
988
989static void hex_print(void *data, unsigned int size, FILE *f)
990{
991 size_t i, j;
992 char c;
993
994 for (i = 0; i < size; i += 16) {
995 /* Row offset */
996 fprintf(f, "%07zx\t", i);
997
998 /* Hexadecimal values */
999 for (j = i; j < i + 16 && j < size; j++)
1000 fprintf(f, "%02x%s", *(uint8_t *)(data + j),
1001 j % 2 ? " " : "");
1002 for (; j < i + 16; j++)
1003 fprintf(f, " %s", j % 2 ? " " : "");
1004
1005 /* ASCII values (if relevant), '.' otherwise */
1006 fprintf(f, "| ");
1007 for (j = i; j < i + 16 && j < size; j++) {
1008 c = *(char *)(data + j);
1009 if (c < ' ' || c > '~')
1010 c = '.';
1011 fprintf(f, "%c%s", c, j == i + 7 ? " " : "");
1012 }
1013
1014 fprintf(f, "\n");
1015 }
1016}
1017
1018static int
1019print_run_output(void *data, unsigned int size, const char *fname,
1020 const char *json_key)
1021{
1022 size_t nb_written;
1023 FILE *f;
1024
1025 if (!fname)
1026 return 0;
1027
1028 if (!strcmp(fname, "-")) {
1029 f = stdout;
1030 if (json_output) {
1031 jsonw_name(json_wtr, json_key);
1032 print_data_json(data, size);
1033 } else {
1034 hex_print(data, size, f);
1035 }
1036 return 0;
1037 }
1038
1039 f = fopen(fname, "w");
1040 if (!f) {
1041 p_err("failed to open %s: %s", fname, strerror(errno));
1042 return -1;
1043 }
1044
1045 nb_written = fwrite(data, 1, size, f);
1046 fclose(f);
1047 if (nb_written != size) {
1048 p_err("failed to write output data/ctx: %s", strerror(errno));
1049 return -1;
1050 }
1051
1052 return 0;
1053}
1054
1055static int alloc_run_data(void **data_ptr, unsigned int size_out)
1056{
1057 *data_ptr = calloc(size_out, 1);
1058 if (!*data_ptr) {
1059 p_err("failed to allocate memory for output data/ctx: %s",
1060 strerror(errno));
1061 return -1;
1062 }
1063
1064 return 0;
1065}
1066
1067static int do_run(int argc, char **argv)
1068{
1069 char *data_fname_in = NULL, *data_fname_out = NULL;
1070 char *ctx_fname_in = NULL, *ctx_fname_out = NULL;
1071 struct bpf_prog_test_run_attr test_attr = {0};
1072 const unsigned int default_size = SZ_32K;
1073 void *data_in = NULL, *data_out = NULL;
1074 void *ctx_in = NULL, *ctx_out = NULL;
1075 unsigned int repeat = 1;
1076 int fd, err;
1077
1078 if (!REQ_ARGS(4))
1079 return -1;
1080
1081 fd = prog_parse_fd(&argc, &argv);
1082 if (fd < 0)
1083 return -1;
1084
1085 while (argc) {
1086 if (detect_common_prefix(*argv, "data_in", "data_out",
1087 "data_size_out", NULL))
1088 return -1;
1089 if (detect_common_prefix(*argv, "ctx_in", "ctx_out",
1090 "ctx_size_out", NULL))
1091 return -1;
1092
1093 if (is_prefix(*argv, "data_in")) {
1094 NEXT_ARG();
1095 if (!REQ_ARGS(1))
1096 return -1;
1097
1098 data_fname_in = GET_ARG();
1099 if (check_single_stdin(data_fname_in, ctx_fname_in))
1100 return -1;
1101 } else if (is_prefix(*argv, "data_out")) {
1102 NEXT_ARG();
1103 if (!REQ_ARGS(1))
1104 return -1;
1105
1106 data_fname_out = GET_ARG();
1107 } else if (is_prefix(*argv, "data_size_out")) {
1108 char *endptr;
1109
1110 NEXT_ARG();
1111 if (!REQ_ARGS(1))
1112 return -1;
1113
1114 test_attr.data_size_out = strtoul(*argv, &endptr, 0);
1115 if (*endptr) {
1116 p_err("can't parse %s as output data size",
1117 *argv);
1118 return -1;
1119 }
1120 NEXT_ARG();
1121 } else if (is_prefix(*argv, "ctx_in")) {
1122 NEXT_ARG();
1123 if (!REQ_ARGS(1))
1124 return -1;
1125
1126 ctx_fname_in = GET_ARG();
1127 if (check_single_stdin(data_fname_in, ctx_fname_in))
1128 return -1;
1129 } else if (is_prefix(*argv, "ctx_out")) {
1130 NEXT_ARG();
1131 if (!REQ_ARGS(1))
1132 return -1;
1133
1134 ctx_fname_out = GET_ARG();
1135 } else if (is_prefix(*argv, "ctx_size_out")) {
1136 char *endptr;
1137
1138 NEXT_ARG();
1139 if (!REQ_ARGS(1))
1140 return -1;
1141
1142 test_attr.ctx_size_out = strtoul(*argv, &endptr, 0);
1143 if (*endptr) {
1144 p_err("can't parse %s as output context size",
1145 *argv);
1146 return -1;
1147 }
1148 NEXT_ARG();
1149 } else if (is_prefix(*argv, "repeat")) {
1150 char *endptr;
1151
1152 NEXT_ARG();
1153 if (!REQ_ARGS(1))
1154 return -1;
1155
1156 repeat = strtoul(*argv, &endptr, 0);
1157 if (*endptr) {
1158 p_err("can't parse %s as repeat number",
1159 *argv);
1160 return -1;
1161 }
1162 NEXT_ARG();
1163 } else {
1164 p_err("expected no more arguments, 'data_in', 'data_out', 'data_size_out', 'ctx_in', 'ctx_out', 'ctx_size_out' or 'repeat', got: '%s'?",
1165 *argv);
1166 return -1;
1167 }
1168 }
1169
1170 err = get_run_data(data_fname_in, &data_in, &test_attr.data_size_in);
1171 if (err)
1172 return -1;
1173
1174 if (data_in) {
1175 if (!test_attr.data_size_out)
1176 test_attr.data_size_out = default_size;
1177 err = alloc_run_data(&data_out, test_attr.data_size_out);
1178 if (err)
1179 goto free_data_in;
1180 }
1181
1182 err = get_run_data(ctx_fname_in, &ctx_in, &test_attr.ctx_size_in);
1183 if (err)
1184 goto free_data_out;
1185
1186 if (ctx_in) {
1187 if (!test_attr.ctx_size_out)
1188 test_attr.ctx_size_out = default_size;
1189 err = alloc_run_data(&ctx_out, test_attr.ctx_size_out);
1190 if (err)
1191 goto free_ctx_in;
1192 }
1193
1194 test_attr.prog_fd = fd;
1195 test_attr.repeat = repeat;
1196 test_attr.data_in = data_in;
1197 test_attr.data_out = data_out;
1198 test_attr.ctx_in = ctx_in;
1199 test_attr.ctx_out = ctx_out;
1200
1201 err = bpf_prog_test_run_xattr(&test_attr);
1202 if (err) {
1203 p_err("failed to run program: %s", strerror(errno));
1204 goto free_ctx_out;
1205 }
1206
1207 err = 0;
1208
1209 if (json_output)
1210 jsonw_start_object(json_wtr); /* root */
1211
1212 /* Do not exit on errors occurring when printing output data/context,
1213 * we still want to print return value and duration for program run.
1214 */
1215 if (test_attr.data_size_out)
1216 err += print_run_output(test_attr.data_out,
1217 test_attr.data_size_out,
1218 data_fname_out, "data_out");
1219 if (test_attr.ctx_size_out)
1220 err += print_run_output(test_attr.ctx_out,
1221 test_attr.ctx_size_out,
1222 ctx_fname_out, "ctx_out");
1223
1224 if (json_output) {
1225 jsonw_uint_field(json_wtr, "retval", test_attr.retval);
1226 jsonw_uint_field(json_wtr, "duration", test_attr.duration);
1227 jsonw_end_object(json_wtr); /* root */
1228 } else {
1229 fprintf(stdout, "Return value: %u, duration%s: %uns\n",
1230 test_attr.retval,
1231 repeat > 1 ? " (average)" : "", test_attr.duration);
1232 }
1233
1234free_ctx_out:
1235 free(ctx_out);
1236free_ctx_in:
1237 free(ctx_in);
1238free_data_out:
1239 free(data_out);
1240free_data_in:
1241 free(data_in);
1242
1243 return err;
1244}
1245
Stanislav Fomichev77380992018-11-09 08:21:44 -08001246static int load_with_options(int argc, char **argv, bool first_prog_only)
Roman Gushchin49a086c2017-12-13 15:18:53 +00001247{
Andrii Nakryiko32e3e582019-10-07 15:56:04 -07001248 enum bpf_prog_type common_prog_type = BPF_PROG_TYPE_UNSPEC;
Andrii Nakryikoe00aca62019-10-22 10:21:00 -07001249 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts,
1250 .relaxed_maps = relaxed_maps,
1251 );
1252 struct bpf_object_load_attr load_attr = { 0 };
Quentin Monnet55d77802019-05-24 11:36:48 +01001253 enum bpf_attach_type expected_attach_type;
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -07001254 struct map_replace *map_replace = NULL;
Stanislav Fomichev77380992018-11-09 08:21:44 -08001255 struct bpf_program *prog = NULL, *pos;
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -07001256 unsigned int old_map_fds = 0;
Stanislav Fomichev3767a942018-11-09 08:21:45 -08001257 const char *pinmaps = NULL;
Roman Gushchin49a086c2017-12-13 15:18:53 +00001258 struct bpf_object *obj;
Jakub Kicinskic8406842018-07-10 14:43:03 -07001259 struct bpf_map *map;
1260 const char *pinfile;
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -07001261 unsigned int i, j;
Jakub Kicinskic8406842018-07-10 14:43:03 -07001262 __u32 ifindex = 0;
Andrii Nakryiko32e3e582019-10-07 15:56:04 -07001263 const char *file;
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -07001264 int idx, err;
Roman Gushchin49a086c2017-12-13 15:18:53 +00001265
Andrii Nakryiko32e3e582019-10-07 15:56:04 -07001266
Jakub Kicinski8d1fc3d2018-07-10 14:42:57 -07001267 if (!REQ_ARGS(2))
1268 return -1;
Andrii Nakryiko32e3e582019-10-07 15:56:04 -07001269 file = GET_ARG();
Jakub Kicinski8d1fc3d2018-07-10 14:42:57 -07001270 pinfile = GET_ARG();
Roman Gushchin49a086c2017-12-13 15:18:53 +00001271
Jakub Kicinskiba6dd672018-07-10 14:42:58 -07001272 while (argc) {
Jakub Kicinski49f2cba2018-07-10 14:43:00 -07001273 if (is_prefix(*argv, "type")) {
1274 char *type;
1275
1276 NEXT_ARG();
1277
Andrii Nakryiko32e3e582019-10-07 15:56:04 -07001278 if (common_prog_type != BPF_PROG_TYPE_UNSPEC) {
Jakub Kicinski49f2cba2018-07-10 14:43:00 -07001279 p_err("program type already specified");
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -07001280 goto err_free_reuse_maps;
Jakub Kicinski49f2cba2018-07-10 14:43:00 -07001281 }
1282 if (!REQ_ARGS(1))
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -07001283 goto err_free_reuse_maps;
Jakub Kicinski49f2cba2018-07-10 14:43:00 -07001284
1285 /* Put a '/' at the end of type to appease libbpf */
1286 type = malloc(strlen(*argv) + 2);
1287 if (!type) {
1288 p_err("mem alloc failed");
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -07001289 goto err_free_reuse_maps;
Jakub Kicinski49f2cba2018-07-10 14:43:00 -07001290 }
1291 *type = 0;
1292 strcat(type, *argv);
1293 strcat(type, "/");
1294
Andrii Nakryiko32e3e582019-10-07 15:56:04 -07001295 err = libbpf_prog_type_by_name(type, &common_prog_type,
Jakub Kicinskic8406842018-07-10 14:43:03 -07001296 &expected_attach_type);
Jakub Kicinski49f2cba2018-07-10 14:43:00 -07001297 free(type);
Taeung Songc76e4c22019-01-21 22:06:38 +09001298 if (err < 0)
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -07001299 goto err_free_reuse_maps;
Taeung Songc76e4c22019-01-21 22:06:38 +09001300
Jakub Kicinski49f2cba2018-07-10 14:43:00 -07001301 NEXT_ARG();
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -07001302 } else if (is_prefix(*argv, "map")) {
Jakub Kicinskidde70112018-11-21 13:53:17 -08001303 void *new_map_replace;
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -07001304 char *endptr, *name;
1305 int fd;
1306
1307 NEXT_ARG();
1308
1309 if (!REQ_ARGS(4))
1310 goto err_free_reuse_maps;
1311
1312 if (is_prefix(*argv, "idx")) {
1313 NEXT_ARG();
1314
1315 idx = strtoul(*argv, &endptr, 0);
1316 if (*endptr) {
1317 p_err("can't parse %s as IDX", *argv);
1318 goto err_free_reuse_maps;
1319 }
1320 name = NULL;
1321 } else if (is_prefix(*argv, "name")) {
1322 NEXT_ARG();
1323
1324 name = *argv;
1325 idx = -1;
1326 } else {
1327 p_err("expected 'idx' or 'name', got: '%s'?",
1328 *argv);
1329 goto err_free_reuse_maps;
1330 }
1331 NEXT_ARG();
1332
1333 fd = map_parse_fd(&argc, &argv);
1334 if (fd < 0)
1335 goto err_free_reuse_maps;
1336
Jakub Kicinskidde70112018-11-21 13:53:17 -08001337 new_map_replace = reallocarray(map_replace,
1338 old_map_fds + 1,
1339 sizeof(*map_replace));
1340 if (!new_map_replace) {
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -07001341 p_err("mem alloc failed");
1342 goto err_free_reuse_maps;
1343 }
Jakub Kicinskidde70112018-11-21 13:53:17 -08001344 map_replace = new_map_replace;
1345
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -07001346 map_replace[old_map_fds].idx = idx;
1347 map_replace[old_map_fds].name = name;
1348 map_replace[old_map_fds].fd = fd;
1349 old_map_fds++;
Jakub Kicinski49f2cba2018-07-10 14:43:00 -07001350 } else if (is_prefix(*argv, "dev")) {
Jakub Kicinskiba6dd672018-07-10 14:42:58 -07001351 NEXT_ARG();
1352
Jakub Kicinskic8406842018-07-10 14:43:03 -07001353 if (ifindex) {
Jakub Kicinskiba6dd672018-07-10 14:42:58 -07001354 p_err("offload device already specified");
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -07001355 goto err_free_reuse_maps;
Jakub Kicinskiba6dd672018-07-10 14:42:58 -07001356 }
1357 if (!REQ_ARGS(1))
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -07001358 goto err_free_reuse_maps;
Jakub Kicinskiba6dd672018-07-10 14:42:58 -07001359
Jakub Kicinskic8406842018-07-10 14:43:03 -07001360 ifindex = if_nametoindex(*argv);
1361 if (!ifindex) {
Jakub Kicinskiba6dd672018-07-10 14:42:58 -07001362 p_err("unrecognized netdevice '%s': %s",
1363 *argv, strerror(errno));
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -07001364 goto err_free_reuse_maps;
Jakub Kicinskiba6dd672018-07-10 14:42:58 -07001365 }
1366 NEXT_ARG();
Stanislav Fomichev3767a942018-11-09 08:21:45 -08001367 } else if (is_prefix(*argv, "pinmaps")) {
1368 NEXT_ARG();
1369
1370 if (!REQ_ARGS(1))
1371 goto err_free_reuse_maps;
1372
1373 pinmaps = GET_ARG();
Jakub Kicinskiba6dd672018-07-10 14:42:58 -07001374 } else {
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -07001375 p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?",
Jakub Kicinskiba6dd672018-07-10 14:42:58 -07001376 *argv);
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -07001377 goto err_free_reuse_maps;
Jakub Kicinskiba6dd672018-07-10 14:42:58 -07001378 }
1379 }
1380
Yonghong Songac4e0e02019-05-16 10:17:31 -07001381 set_max_rlimit();
1382
Andrii Nakryiko32e3e582019-10-07 15:56:04 -07001383 obj = bpf_object__open_file(file, &open_opts);
Jakub Kicinskic8406842018-07-10 14:43:03 -07001384 if (IS_ERR_OR_NULL(obj)) {
1385 p_err("failed to open object file");
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -07001386 goto err_free_reuse_maps;
Roman Gushchin49a086c2017-12-13 15:18:53 +00001387 }
1388
Stanislav Fomichev77380992018-11-09 08:21:44 -08001389 bpf_object__for_each_program(pos, obj) {
Andrii Nakryiko32e3e582019-10-07 15:56:04 -07001390 enum bpf_prog_type prog_type = common_prog_type;
Jakub Kicinskic8406842018-07-10 14:43:03 -07001391
Andrii Nakryiko32e3e582019-10-07 15:56:04 -07001392 if (prog_type == BPF_PROG_TYPE_UNSPEC) {
Stanislav Fomichev77380992018-11-09 08:21:44 -08001393 const char *sec_name = bpf_program__title(pos, false);
Jakub Kicinskic8406842018-07-10 14:43:03 -07001394
Stanislav Fomichev77380992018-11-09 08:21:44 -08001395 err = libbpf_prog_type_by_name(sec_name, &prog_type,
1396 &expected_attach_type);
Taeung Songc76e4c22019-01-21 22:06:38 +09001397 if (err < 0)
Stanislav Fomichev77380992018-11-09 08:21:44 -08001398 goto err_close_obj;
Jakub Kicinskic8406842018-07-10 14:43:03 -07001399 }
Stanislav Fomichev77380992018-11-09 08:21:44 -08001400
1401 bpf_program__set_ifindex(pos, ifindex);
1402 bpf_program__set_type(pos, prog_type);
1403 bpf_program__set_expected_attach_type(pos, expected_attach_type);
Jakub Kicinskic8406842018-07-10 14:43:03 -07001404 }
Jakub Kicinskic8406842018-07-10 14:43:03 -07001405
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -07001406 qsort(map_replace, old_map_fds, sizeof(*map_replace),
1407 map_replace_compar);
1408
1409 /* After the sort maps by name will be first on the list, because they
1410 * have idx == -1. Resolve them.
1411 */
1412 j = 0;
1413 while (j < old_map_fds && map_replace[j].name) {
1414 i = 0;
Jakub Kicinskif74a53d92019-02-27 19:04:12 -08001415 bpf_object__for_each_map(map, obj) {
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -07001416 if (!strcmp(bpf_map__name(map), map_replace[j].name)) {
1417 map_replace[j].idx = i;
1418 break;
1419 }
1420 i++;
1421 }
1422 if (map_replace[j].idx == -1) {
1423 p_err("unable to find map '%s'", map_replace[j].name);
1424 goto err_close_obj;
1425 }
1426 j++;
1427 }
1428 /* Resort if any names were resolved */
1429 if (j)
1430 qsort(map_replace, old_map_fds, sizeof(*map_replace),
1431 map_replace_compar);
1432
1433 /* Set ifindex and name reuse */
1434 j = 0;
1435 idx = 0;
Jakub Kicinskif74a53d92019-02-27 19:04:12 -08001436 bpf_object__for_each_map(map, obj) {
Jakub Kicinskic8406842018-07-10 14:43:03 -07001437 if (!bpf_map__is_offload_neutral(map))
1438 bpf_map__set_ifindex(map, ifindex);
1439
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -07001440 if (j < old_map_fds && idx == map_replace[j].idx) {
1441 err = bpf_map__reuse_fd(map, map_replace[j++].fd);
1442 if (err) {
1443 p_err("unable to set up map reuse: %d", err);
1444 goto err_close_obj;
1445 }
1446
1447 /* Next reuse wants to apply to the same map */
1448 if (j < old_map_fds && map_replace[j].idx == idx) {
1449 p_err("replacement for map idx %d specified more than once",
1450 idx);
1451 goto err_close_obj;
1452 }
1453 }
1454
1455 idx++;
1456 }
1457 if (j < old_map_fds) {
1458 p_err("map idx '%d' not used", map_replace[j].idx);
1459 goto err_close_obj;
1460 }
1461
Quentin Monnet55d77802019-05-24 11:36:48 +01001462 load_attr.obj = obj;
1463 if (verifier_logs)
1464 /* log_level1 + log_level2 + stats, but not stable UAPI */
1465 load_attr.log_level = 1 + 2 + 4;
1466
1467 err = bpf_object__load_xattr(&load_attr);
Jakub Kicinskic8406842018-07-10 14:43:03 -07001468 if (err) {
1469 p_err("failed to load object file");
1470 goto err_close_obj;
1471 }
1472
Stanislav Fomichev77380992018-11-09 08:21:44 -08001473 err = mount_bpffs_for_pin(pinfile);
1474 if (err)
Jakub Kicinskibfee71f2018-06-20 11:42:46 -07001475 goto err_close_obj;
Roman Gushchin49a086c2017-12-13 15:18:53 +00001476
Stanislav Fomichev77380992018-11-09 08:21:44 -08001477 if (first_prog_only) {
1478 prog = bpf_program__next(NULL, obj);
1479 if (!prog) {
1480 p_err("object file doesn't contain any bpf program");
1481 goto err_close_obj;
1482 }
1483
1484 err = bpf_obj_pin(bpf_program__fd(prog), pinfile);
1485 if (err) {
1486 p_err("failed to pin program %s",
1487 bpf_program__title(prog, false));
1488 goto err_close_obj;
1489 }
1490 } else {
1491 err = bpf_object__pin_programs(obj, pinfile);
1492 if (err) {
1493 p_err("failed to pin all programs");
1494 goto err_close_obj;
1495 }
1496 }
1497
Stanislav Fomichev3767a942018-11-09 08:21:45 -08001498 if (pinmaps) {
1499 err = bpf_object__pin_maps(obj, pinmaps);
1500 if (err) {
1501 p_err("failed to pin all maps");
1502 goto err_unpin;
1503 }
1504 }
1505
Roman Gushchin49a086c2017-12-13 15:18:53 +00001506 if (json_output)
1507 jsonw_null(json_wtr);
1508
Jakub Kicinskibfee71f2018-06-20 11:42:46 -07001509 bpf_object__close(obj);
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -07001510 for (i = 0; i < old_map_fds; i++)
1511 close(map_replace[i].fd);
1512 free(map_replace);
Jakub Kicinskibfee71f2018-06-20 11:42:46 -07001513
Roman Gushchin49a086c2017-12-13 15:18:53 +00001514 return 0;
Jakub Kicinskibfee71f2018-06-20 11:42:46 -07001515
Stanislav Fomichev3767a942018-11-09 08:21:45 -08001516err_unpin:
1517 if (first_prog_only)
1518 unlink(pinfile);
1519 else
1520 bpf_object__unpin_programs(obj, pinfile);
Jakub Kicinskibfee71f2018-06-20 11:42:46 -07001521err_close_obj:
1522 bpf_object__close(obj);
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -07001523err_free_reuse_maps:
1524 for (i = 0; i < old_map_fds; i++)
1525 close(map_replace[i].fd);
1526 free(map_replace);
Jakub Kicinskibfee71f2018-06-20 11:42:46 -07001527 return -1;
Roman Gushchin49a086c2017-12-13 15:18:53 +00001528}
1529
Stanislav Fomichev77380992018-11-09 08:21:44 -08001530static int do_load(int argc, char **argv)
1531{
1532 return load_with_options(argc, argv, true);
1533}
1534
1535static int do_loadall(int argc, char **argv)
1536{
1537 return load_with_options(argc, argv, false);
1538}
1539
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001540static int do_help(int argc, char **argv)
1541{
Quentin Monnet004b45c2017-10-23 09:24:14 -07001542 if (json_output) {
1543 jsonw_null(json_wtr);
1544 return 0;
1545 }
1546
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001547 fprintf(stderr,
Jakub Kicinski6ebe6db2018-01-02 14:48:36 -08001548 "Usage: %s %s { show | list } [PROG]\n"
Martin KaFai Laub053b432018-12-07 16:42:32 -08001549 " %s %s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n"
1550 " %s %s dump jited PROG [{ file FILE | opcodes | linum }]\n"
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001551 " %s %s pin PROG FILE\n"
Stanislav Fomichev77380992018-11-09 08:21:44 -08001552 " %s %s { load | loadall } OBJ PATH \\\n"
1553 " [type TYPE] [dev NAME] \\\n"
Stanislav Fomichev3767a942018-11-09 08:21:45 -08001554 " [map { idx IDX | name NAME } MAP]\\\n"
1555 " [pinmaps MAP_DIR]\n"
Stanislav Fomichev092f0892018-11-09 08:21:46 -08001556 " %s %s attach PROG ATTACH_TYPE [MAP]\n"
1557 " %s %s detach PROG ATTACH_TYPE [MAP]\n"
Quentin Monnetba95c742019-07-05 18:54:33 +01001558 " %s %s run PROG \\\n"
1559 " data_in FILE \\\n"
1560 " [data_out FILE [data_size_out L]] \\\n"
1561 " [ctx_in FILE [ctx_out FILE [ctx_size_out M]]] \\\n"
1562 " [repeat N]\n"
Quentin Monnet30da46b2018-12-05 10:28:24 +00001563 " %s %s tracelog\n"
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001564 " %s %s help\n"
1565 "\n"
Jakub Kicinski3ff5a4d2018-07-10 14:43:07 -07001566 " " HELP_SPEC_MAP "\n"
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001567 " " HELP_SPEC_PROGRAM "\n"
Jakub Kicinski49f2cba2018-07-10 14:43:00 -07001568 " TYPE := { socket | kprobe | kretprobe | classifier | action |\n"
1569 " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n"
1570 " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n"
1571 " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n"
Andrey Ignatovf25377e2019-04-16 13:13:47 -07001572 " sk_reuseport | flow_dissector | cgroup/sysctl |\n"
Jakub Kicinski49f2cba2018-07-10 14:43:00 -07001573 " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n"
1574 " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n"
Daniel Borkmann000aa122019-06-07 01:49:00 +02001575 " cgroup/sendmsg4 | cgroup/sendmsg6 | cgroup/recvmsg4 |\n"
Stanislav Fomichevf6d08d92019-06-27 13:38:55 -07001576 " cgroup/recvmsg6 | cgroup/getsockopt |\n"
1577 " cgroup/setsockopt }\n"
Alban Crequya5d92652019-02-19 15:13:32 +01001578 " ATTACH_TYPE := { msg_verdict | stream_verdict | stream_parser |\n"
Stanislav Fomichev092f0892018-11-09 08:21:46 -08001579 " flow_dissector }\n"
Quentin Monnet0641c3c2017-10-23 09:24:16 -07001580 " " HELP_SPEC_OPTIONS "\n"
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001581 "",
1582 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
John Fastabendb7d38262018-10-15 11:19:50 -07001583 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
Quentin Monnetba95c742019-07-05 18:54:33 +01001584 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
1585 bin_name, argv[-2]);
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001586
1587 return 0;
1588}
1589
1590static const struct cmd cmds[] = {
1591 { "show", do_show },
Jakub Kicinski6ebe6db2018-01-02 14:48:36 -08001592 { "list", do_show },
Quentin Monnet9f606172017-10-19 15:46:22 -07001593 { "help", do_help },
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001594 { "dump", do_dump },
1595 { "pin", do_pin },
Roman Gushchin49a086c2017-12-13 15:18:53 +00001596 { "load", do_load },
Stanislav Fomichev77380992018-11-09 08:21:44 -08001597 { "loadall", do_loadall },
John Fastabendb7d38262018-10-15 11:19:50 -07001598 { "attach", do_attach },
1599 { "detach", do_detach },
Quentin Monnet30da46b2018-12-05 10:28:24 +00001600 { "tracelog", do_tracelog },
Quentin Monnetba95c742019-07-05 18:54:33 +01001601 { "run", do_run },
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001602 { 0 }
1603};
1604
1605int do_prog(int argc, char **argv)
1606{
1607 return cmd_select(cmds, argc, argv, do_help);
1608}