bpftool: Support new prog types and attach types
[muen/linux.git] / tools / bpf / bpftool / prog.c
1 /*
2  * Copyright (C) 2017 Netronome Systems, Inc.
3  *
4  * This software is dual licensed under the GNU General License Version 2,
5  * June 1991 as shown in the file COPYING in the top-level directory of this
6  * source tree or the BSD 2-Clause License provided below.  You have the
7  * option to license this software under the complete terms of either license.
8  *
9  * The BSD 2-Clause License:
10  *
11  *     Redistribution and use in source and binary forms, with or
12  *     without modification, are permitted provided that the following
13  *     conditions are met:
14  *
15  *      1. Redistributions of source code must retain the above
16  *         copyright notice, this list of conditions and the following
17  *         disclaimer.
18  *
19  *      2. Redistributions in binary form must reproduce the above
20  *         copyright notice, this list of conditions and the following
21  *         disclaimer in the documentation and/or other materials
22  *         provided with the distribution.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31  * SOFTWARE.
32  */
33
34 /* Author: Jakub Kicinski <kubakici@wp.pl> */
35
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <stdarg.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <time.h>
43 #include <unistd.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46
47 #include <bpf.h>
48 #include <libbpf.h>
49
50 #include "cfg.h"
51 #include "main.h"
52 #include "xlated_dumper.h"
53
54 static const char * const prog_type_name[] = {
55         [BPF_PROG_TYPE_UNSPEC]          = "unspec",
56         [BPF_PROG_TYPE_SOCKET_FILTER]   = "socket_filter",
57         [BPF_PROG_TYPE_KPROBE]          = "kprobe",
58         [BPF_PROG_TYPE_SCHED_CLS]       = "sched_cls",
59         [BPF_PROG_TYPE_SCHED_ACT]       = "sched_act",
60         [BPF_PROG_TYPE_TRACEPOINT]      = "tracepoint",
61         [BPF_PROG_TYPE_XDP]             = "xdp",
62         [BPF_PROG_TYPE_PERF_EVENT]      = "perf_event",
63         [BPF_PROG_TYPE_CGROUP_SKB]      = "cgroup_skb",
64         [BPF_PROG_TYPE_CGROUP_SOCK]     = "cgroup_sock",
65         [BPF_PROG_TYPE_LWT_IN]          = "lwt_in",
66         [BPF_PROG_TYPE_LWT_OUT]         = "lwt_out",
67         [BPF_PROG_TYPE_LWT_XMIT]        = "lwt_xmit",
68         [BPF_PROG_TYPE_SOCK_OPS]        = "sock_ops",
69         [BPF_PROG_TYPE_SK_SKB]          = "sk_skb",
70         [BPF_PROG_TYPE_CGROUP_DEVICE]   = "cgroup_device",
71         [BPF_PROG_TYPE_SK_MSG]          = "sk_msg",
72         [BPF_PROG_TYPE_RAW_TRACEPOINT]  = "raw_tracepoint",
73         [BPF_PROG_TYPE_CGROUP_SOCK_ADDR] = "cgroup_sock_addr",
74 };
75
76 static void print_boot_time(__u64 nsecs, char *buf, unsigned int size)
77 {
78         struct timespec real_time_ts, boot_time_ts;
79         time_t wallclock_secs;
80         struct tm load_tm;
81
82         buf[--size] = '\0';
83
84         if (clock_gettime(CLOCK_REALTIME, &real_time_ts) ||
85             clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) {
86                 perror("Can't read clocks");
87                 snprintf(buf, size, "%llu", nsecs / 1000000000);
88                 return;
89         }
90
91         wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) +
92                 nsecs / 1000000000;
93
94         if (!localtime_r(&wallclock_secs, &load_tm)) {
95                 snprintf(buf, size, "%llu", nsecs / 1000000000);
96                 return;
97         }
98
99         strftime(buf, size, "%b %d/%H:%M", &load_tm);
100 }
101
102 static int prog_fd_by_tag(unsigned char *tag)
103 {
104         struct bpf_prog_info info = {};
105         __u32 len = sizeof(info);
106         unsigned int id = 0;
107         int err;
108         int fd;
109
110         while (true) {
111                 err = bpf_prog_get_next_id(id, &id);
112                 if (err) {
113                         p_err("%s", strerror(errno));
114                         return -1;
115                 }
116
117                 fd = bpf_prog_get_fd_by_id(id);
118                 if (fd < 0) {
119                         p_err("can't get prog by id (%u): %s",
120                               id, strerror(errno));
121                         return -1;
122                 }
123
124                 err = bpf_obj_get_info_by_fd(fd, &info, &len);
125                 if (err) {
126                         p_err("can't get prog info (%u): %s",
127                               id, strerror(errno));
128                         close(fd);
129                         return -1;
130                 }
131
132                 if (!memcmp(tag, info.tag, BPF_TAG_SIZE))
133                         return fd;
134
135                 close(fd);
136         }
137 }
138
139 int prog_parse_fd(int *argc, char ***argv)
140 {
141         int fd;
142
143         if (is_prefix(**argv, "id")) {
144                 unsigned int id;
145                 char *endptr;
146
147                 NEXT_ARGP();
148
149                 id = strtoul(**argv, &endptr, 0);
150                 if (*endptr) {
151                         p_err("can't parse %s as ID", **argv);
152                         return -1;
153                 }
154                 NEXT_ARGP();
155
156                 fd = bpf_prog_get_fd_by_id(id);
157                 if (fd < 0)
158                         p_err("get by id (%u): %s", id, strerror(errno));
159                 return fd;
160         } else if (is_prefix(**argv, "tag")) {
161                 unsigned char tag[BPF_TAG_SIZE];
162
163                 NEXT_ARGP();
164
165                 if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2,
166                            tag + 3, tag + 4, tag + 5, tag + 6, tag + 7)
167                     != BPF_TAG_SIZE) {
168                         p_err("can't parse tag");
169                         return -1;
170                 }
171                 NEXT_ARGP();
172
173                 return prog_fd_by_tag(tag);
174         } else if (is_prefix(**argv, "pinned")) {
175                 char *path;
176
177                 NEXT_ARGP();
178
179                 path = **argv;
180                 NEXT_ARGP();
181
182                 return open_obj_pinned_any(path, BPF_OBJ_PROG);
183         }
184
185         p_err("expected 'id', 'tag' or 'pinned', got: '%s'?", **argv);
186         return -1;
187 }
188
189 static void show_prog_maps(int fd, u32 num_maps)
190 {
191         struct bpf_prog_info info = {};
192         __u32 len = sizeof(info);
193         __u32 map_ids[num_maps];
194         unsigned int i;
195         int err;
196
197         info.nr_map_ids = num_maps;
198         info.map_ids = ptr_to_u64(map_ids);
199
200         err = bpf_obj_get_info_by_fd(fd, &info, &len);
201         if (err || !info.nr_map_ids)
202                 return;
203
204         if (json_output) {
205                 jsonw_name(json_wtr, "map_ids");
206                 jsonw_start_array(json_wtr);
207                 for (i = 0; i < info.nr_map_ids; i++)
208                         jsonw_uint(json_wtr, map_ids[i]);
209                 jsonw_end_array(json_wtr);
210         } else {
211                 printf("  map_ids ");
212                 for (i = 0; i < info.nr_map_ids; i++)
213                         printf("%u%s", map_ids[i],
214                                i == info.nr_map_ids - 1 ? "" : ",");
215         }
216 }
217
218 static void print_prog_json(struct bpf_prog_info *info, int fd)
219 {
220         char *memlock;
221
222         jsonw_start_object(json_wtr);
223         jsonw_uint_field(json_wtr, "id", info->id);
224         if (info->type < ARRAY_SIZE(prog_type_name))
225                 jsonw_string_field(json_wtr, "type",
226                                    prog_type_name[info->type]);
227         else
228                 jsonw_uint_field(json_wtr, "type", info->type);
229
230         if (*info->name)
231                 jsonw_string_field(json_wtr, "name", info->name);
232
233         jsonw_name(json_wtr, "tag");
234         jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"",
235                      info->tag[0], info->tag[1], info->tag[2], info->tag[3],
236                      info->tag[4], info->tag[5], info->tag[6], info->tag[7]);
237
238         print_dev_json(info->ifindex, info->netns_dev, info->netns_ino);
239
240         if (info->load_time) {
241                 char buf[32];
242
243                 print_boot_time(info->load_time, buf, sizeof(buf));
244
245                 /* Piggy back on load_time, since 0 uid is a valid one */
246                 jsonw_string_field(json_wtr, "loaded_at", buf);
247                 jsonw_uint_field(json_wtr, "uid", info->created_by_uid);
248         }
249
250         jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len);
251
252         if (info->jited_prog_len) {
253                 jsonw_bool_field(json_wtr, "jited", true);
254                 jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len);
255         } else {
256                 jsonw_bool_field(json_wtr, "jited", false);
257         }
258
259         memlock = get_fdinfo(fd, "memlock");
260         if (memlock)
261                 jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock));
262         free(memlock);
263
264         if (info->nr_map_ids)
265                 show_prog_maps(fd, info->nr_map_ids);
266
267         if (!hash_empty(prog_table.table)) {
268                 struct pinned_obj *obj;
269
270                 jsonw_name(json_wtr, "pinned");
271                 jsonw_start_array(json_wtr);
272                 hash_for_each_possible(prog_table.table, obj, hash, info->id) {
273                         if (obj->id == info->id)
274                                 jsonw_string(json_wtr, obj->path);
275                 }
276                 jsonw_end_array(json_wtr);
277         }
278
279         jsonw_end_object(json_wtr);
280 }
281
282 static void print_prog_plain(struct bpf_prog_info *info, int fd)
283 {
284         char *memlock;
285
286         printf("%u: ", info->id);
287         if (info->type < ARRAY_SIZE(prog_type_name))
288                 printf("%s  ", prog_type_name[info->type]);
289         else
290                 printf("type %u  ", info->type);
291
292         if (*info->name)
293                 printf("name %s  ", info->name);
294
295         printf("tag ");
296         fprint_hex(stdout, info->tag, BPF_TAG_SIZE, "");
297         print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino);
298         printf("\n");
299
300         if (info->load_time) {
301                 char buf[32];
302
303                 print_boot_time(info->load_time, buf, sizeof(buf));
304
305                 /* Piggy back on load_time, since 0 uid is a valid one */
306                 printf("\tloaded_at %s  uid %u\n", buf, info->created_by_uid);
307         }
308
309         printf("\txlated %uB", info->xlated_prog_len);
310
311         if (info->jited_prog_len)
312                 printf("  jited %uB", info->jited_prog_len);
313         else
314                 printf("  not jited");
315
316         memlock = get_fdinfo(fd, "memlock");
317         if (memlock)
318                 printf("  memlock %sB", memlock);
319         free(memlock);
320
321         if (info->nr_map_ids)
322                 show_prog_maps(fd, info->nr_map_ids);
323
324         if (!hash_empty(prog_table.table)) {
325                 struct pinned_obj *obj;
326
327                 printf("\n");
328                 hash_for_each_possible(prog_table.table, obj, hash, info->id) {
329                         if (obj->id == info->id)
330                                 printf("\tpinned %s\n", obj->path);
331                 }
332         }
333
334         printf("\n");
335 }
336
337 static int show_prog(int fd)
338 {
339         struct bpf_prog_info info = {};
340         __u32 len = sizeof(info);
341         int err;
342
343         err = bpf_obj_get_info_by_fd(fd, &info, &len);
344         if (err) {
345                 p_err("can't get prog info: %s", strerror(errno));
346                 return -1;
347         }
348
349         if (json_output)
350                 print_prog_json(&info, fd);
351         else
352                 print_prog_plain(&info, fd);
353
354         return 0;
355 }
356
357 static int do_show(int argc, char **argv)
358 {
359         __u32 id = 0;
360         int err;
361         int fd;
362
363         if (show_pinned)
364                 build_pinned_obj_table(&prog_table, BPF_OBJ_PROG);
365
366         if (argc == 2) {
367                 fd = prog_parse_fd(&argc, &argv);
368                 if (fd < 0)
369                         return -1;
370
371                 return show_prog(fd);
372         }
373
374         if (argc)
375                 return BAD_ARG();
376
377         if (json_output)
378                 jsonw_start_array(json_wtr);
379         while (true) {
380                 err = bpf_prog_get_next_id(id, &id);
381                 if (err) {
382                         if (errno == ENOENT) {
383                                 err = 0;
384                                 break;
385                         }
386                         p_err("can't get next program: %s%s", strerror(errno),
387                               errno == EINVAL ? " -- kernel too old?" : "");
388                         err = -1;
389                         break;
390                 }
391
392                 fd = bpf_prog_get_fd_by_id(id);
393                 if (fd < 0) {
394                         if (errno == ENOENT)
395                                 continue;
396                         p_err("can't get prog by id (%u): %s",
397                               id, strerror(errno));
398                         err = -1;
399                         break;
400                 }
401
402                 err = show_prog(fd);
403                 close(fd);
404                 if (err)
405                         break;
406         }
407
408         if (json_output)
409                 jsonw_end_array(json_wtr);
410
411         return err;
412 }
413
414 static int do_dump(int argc, char **argv)
415 {
416         struct bpf_prog_info info = {};
417         struct dump_data dd = {};
418         __u32 len = sizeof(info);
419         unsigned int buf_size;
420         char *filepath = NULL;
421         bool opcodes = false;
422         bool visual = false;
423         unsigned char *buf;
424         __u32 *member_len;
425         __u64 *member_ptr;
426         ssize_t n;
427         int err;
428         int fd;
429
430         if (is_prefix(*argv, "jited")) {
431                 member_len = &info.jited_prog_len;
432                 member_ptr = &info.jited_prog_insns;
433         } else if (is_prefix(*argv, "xlated")) {
434                 member_len = &info.xlated_prog_len;
435                 member_ptr = &info.xlated_prog_insns;
436         } else {
437                 p_err("expected 'xlated' or 'jited', got: %s", *argv);
438                 return -1;
439         }
440         NEXT_ARG();
441
442         if (argc < 2)
443                 usage();
444
445         fd = prog_parse_fd(&argc, &argv);
446         if (fd < 0)
447                 return -1;
448
449         if (is_prefix(*argv, "file")) {
450                 NEXT_ARG();
451                 if (!argc) {
452                         p_err("expected file path");
453                         return -1;
454                 }
455
456                 filepath = *argv;
457                 NEXT_ARG();
458         } else if (is_prefix(*argv, "opcodes")) {
459                 opcodes = true;
460                 NEXT_ARG();
461         } else if (is_prefix(*argv, "visual")) {
462                 visual = true;
463                 NEXT_ARG();
464         }
465
466         if (argc) {
467                 usage();
468                 return -1;
469         }
470
471         err = bpf_obj_get_info_by_fd(fd, &info, &len);
472         if (err) {
473                 p_err("can't get prog info: %s", strerror(errno));
474                 return -1;
475         }
476
477         if (!*member_len) {
478                 p_info("no instructions returned");
479                 close(fd);
480                 return 0;
481         }
482
483         buf_size = *member_len;
484
485         buf = malloc(buf_size);
486         if (!buf) {
487                 p_err("mem alloc failed");
488                 close(fd);
489                 return -1;
490         }
491
492         memset(&info, 0, sizeof(info));
493
494         *member_ptr = ptr_to_u64(buf);
495         *member_len = buf_size;
496
497         err = bpf_obj_get_info_by_fd(fd, &info, &len);
498         close(fd);
499         if (err) {
500                 p_err("can't get prog info: %s", strerror(errno));
501                 goto err_free;
502         }
503
504         if (*member_len > buf_size) {
505                 p_err("too many instructions returned");
506                 goto err_free;
507         }
508
509         if ((member_len == &info.jited_prog_len &&
510              info.jited_prog_insns == 0) ||
511             (member_len == &info.xlated_prog_len &&
512              info.xlated_prog_insns == 0)) {
513                 p_err("error retrieving insn dump: kernel.kptr_restrict set?");
514                 goto err_free;
515         }
516
517         if (filepath) {
518                 fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
519                 if (fd < 0) {
520                         p_err("can't open file %s: %s", filepath,
521                               strerror(errno));
522                         goto err_free;
523                 }
524
525                 n = write(fd, buf, *member_len);
526                 close(fd);
527                 if (n != *member_len) {
528                         p_err("error writing output file: %s",
529                               n < 0 ? strerror(errno) : "short write");
530                         goto err_free;
531                 }
532
533                 if (json_output)
534                         jsonw_null(json_wtr);
535         } else if (member_len == &info.jited_prog_len) {
536                 const char *name = NULL;
537
538                 if (info.ifindex) {
539                         name = ifindex_to_bfd_name_ns(info.ifindex,
540                                                       info.netns_dev,
541                                                       info.netns_ino);
542                         if (!name)
543                                 goto err_free;
544                 }
545
546                 disasm_print_insn(buf, *member_len, opcodes, name);
547         } else if (visual) {
548                 if (json_output)
549                         jsonw_null(json_wtr);
550                 else
551                         dump_xlated_cfg(buf, *member_len);
552         } else {
553                 kernel_syms_load(&dd);
554                 if (json_output)
555                         dump_xlated_json(&dd, buf, *member_len, opcodes);
556                 else
557                         dump_xlated_plain(&dd, buf, *member_len, opcodes);
558                 kernel_syms_destroy(&dd);
559         }
560
561         free(buf);
562         return 0;
563
564 err_free:
565         free(buf);
566         return -1;
567 }
568
569 static int do_pin(int argc, char **argv)
570 {
571         int err;
572
573         err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id);
574         if (!err && json_output)
575                 jsonw_null(json_wtr);
576         return err;
577 }
578
579 static int do_load(int argc, char **argv)
580 {
581         struct bpf_object *obj;
582         int prog_fd;
583
584         if (argc != 2)
585                 usage();
586
587         if (bpf_prog_load(argv[0], BPF_PROG_TYPE_UNSPEC, &obj, &prog_fd)) {
588                 p_err("failed to load program");
589                 return -1;
590         }
591
592         if (do_pin_fd(prog_fd, argv[1])) {
593                 p_err("failed to pin program");
594                 return -1;
595         }
596
597         if (json_output)
598                 jsonw_null(json_wtr);
599
600         return 0;
601 }
602
603 static int do_help(int argc, char **argv)
604 {
605         if (json_output) {
606                 jsonw_null(json_wtr);
607                 return 0;
608         }
609
610         fprintf(stderr,
611                 "Usage: %s %s { show | list } [PROG]\n"
612                 "       %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n"
613                 "       %s %s dump jited  PROG [{ file FILE | opcodes }]\n"
614                 "       %s %s pin   PROG FILE\n"
615                 "       %s %s load  OBJ  FILE\n"
616                 "       %s %s help\n"
617                 "\n"
618                 "       " HELP_SPEC_PROGRAM "\n"
619                 "       " HELP_SPEC_OPTIONS "\n"
620                 "",
621                 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
622                 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]);
623
624         return 0;
625 }
626
627 static const struct cmd cmds[] = {
628         { "show",       do_show },
629         { "list",       do_show },
630         { "help",       do_help },
631         { "dump",       do_dump },
632         { "pin",        do_pin },
633         { "load",       do_load },
634         { 0 }
635 };
636
637 int do_prog(int argc, char **argv)
638 {
639         return cmd_select(cmds, argc, argv, do_help);
640 }