]> asedeno.scripts.mit.edu Git - linux.git/blob - tools/bpf/bpftool/prog.c
bpftool: implement prog load command
[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 "main.h"
51 #include "disasm.h"
52
53 static const char * const prog_type_name[] = {
54         [BPF_PROG_TYPE_UNSPEC]          = "unspec",
55         [BPF_PROG_TYPE_SOCKET_FILTER]   = "socket_filter",
56         [BPF_PROG_TYPE_KPROBE]          = "kprobe",
57         [BPF_PROG_TYPE_SCHED_CLS]       = "sched_cls",
58         [BPF_PROG_TYPE_SCHED_ACT]       = "sched_act",
59         [BPF_PROG_TYPE_TRACEPOINT]      = "tracepoint",
60         [BPF_PROG_TYPE_XDP]             = "xdp",
61         [BPF_PROG_TYPE_PERF_EVENT]      = "perf_event",
62         [BPF_PROG_TYPE_CGROUP_SKB]      = "cgroup_skb",
63         [BPF_PROG_TYPE_CGROUP_SOCK]     = "cgroup_sock",
64         [BPF_PROG_TYPE_LWT_IN]          = "lwt_in",
65         [BPF_PROG_TYPE_LWT_OUT]         = "lwt_out",
66         [BPF_PROG_TYPE_LWT_XMIT]        = "lwt_xmit",
67         [BPF_PROG_TYPE_SOCK_OPS]        = "sock_ops",
68         [BPF_PROG_TYPE_SK_SKB]          = "sk_skb",
69 };
70
71 static void print_boot_time(__u64 nsecs, char *buf, unsigned int size)
72 {
73         struct timespec real_time_ts, boot_time_ts;
74         time_t wallclock_secs;
75         struct tm load_tm;
76
77         buf[--size] = '\0';
78
79         if (clock_gettime(CLOCK_REALTIME, &real_time_ts) ||
80             clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) {
81                 perror("Can't read clocks");
82                 snprintf(buf, size, "%llu", nsecs / 1000000000);
83                 return;
84         }
85
86         wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) +
87                 nsecs / 1000000000;
88
89         if (!localtime_r(&wallclock_secs, &load_tm)) {
90                 snprintf(buf, size, "%llu", nsecs / 1000000000);
91                 return;
92         }
93
94         strftime(buf, size, "%b %d/%H:%M", &load_tm);
95 }
96
97 static int prog_fd_by_tag(unsigned char *tag)
98 {
99         struct bpf_prog_info info = {};
100         __u32 len = sizeof(info);
101         unsigned int id = 0;
102         int err;
103         int fd;
104
105         while (true) {
106                 err = bpf_prog_get_next_id(id, &id);
107                 if (err) {
108                         p_err("%s", strerror(errno));
109                         return -1;
110                 }
111
112                 fd = bpf_prog_get_fd_by_id(id);
113                 if (fd < 0) {
114                         p_err("can't get prog by id (%u): %s",
115                               id, strerror(errno));
116                         return -1;
117                 }
118
119                 err = bpf_obj_get_info_by_fd(fd, &info, &len);
120                 if (err) {
121                         p_err("can't get prog info (%u): %s",
122                               id, strerror(errno));
123                         close(fd);
124                         return -1;
125                 }
126
127                 if (!memcmp(tag, info.tag, BPF_TAG_SIZE))
128                         return fd;
129
130                 close(fd);
131         }
132 }
133
134 int prog_parse_fd(int *argc, char ***argv)
135 {
136         int fd;
137
138         if (is_prefix(**argv, "id")) {
139                 unsigned int id;
140                 char *endptr;
141
142                 NEXT_ARGP();
143
144                 id = strtoul(**argv, &endptr, 0);
145                 if (*endptr) {
146                         p_err("can't parse %s as ID", **argv);
147                         return -1;
148                 }
149                 NEXT_ARGP();
150
151                 fd = bpf_prog_get_fd_by_id(id);
152                 if (fd < 0)
153                         p_err("get by id (%u): %s", id, strerror(errno));
154                 return fd;
155         } else if (is_prefix(**argv, "tag")) {
156                 unsigned char tag[BPF_TAG_SIZE];
157
158                 NEXT_ARGP();
159
160                 if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2,
161                            tag + 3, tag + 4, tag + 5, tag + 6, tag + 7)
162                     != BPF_TAG_SIZE) {
163                         p_err("can't parse tag");
164                         return -1;
165                 }
166                 NEXT_ARGP();
167
168                 return prog_fd_by_tag(tag);
169         } else if (is_prefix(**argv, "pinned")) {
170                 char *path;
171
172                 NEXT_ARGP();
173
174                 path = **argv;
175                 NEXT_ARGP();
176
177                 return open_obj_pinned_any(path, BPF_OBJ_PROG);
178         }
179
180         p_err("expected 'id', 'tag' or 'pinned', got: '%s'?", **argv);
181         return -1;
182 }
183
184 static void show_prog_maps(int fd, u32 num_maps)
185 {
186         struct bpf_prog_info info = {};
187         __u32 len = sizeof(info);
188         __u32 map_ids[num_maps];
189         unsigned int i;
190         int err;
191
192         info.nr_map_ids = num_maps;
193         info.map_ids = ptr_to_u64(map_ids);
194
195         err = bpf_obj_get_info_by_fd(fd, &info, &len);
196         if (err || !info.nr_map_ids)
197                 return;
198
199         if (json_output) {
200                 jsonw_name(json_wtr, "map_ids");
201                 jsonw_start_array(json_wtr);
202                 for (i = 0; i < info.nr_map_ids; i++)
203                         jsonw_uint(json_wtr, map_ids[i]);
204                 jsonw_end_array(json_wtr);
205         } else {
206                 printf("  map_ids ");
207                 for (i = 0; i < info.nr_map_ids; i++)
208                         printf("%u%s", map_ids[i],
209                                i == info.nr_map_ids - 1 ? "" : ",");
210         }
211 }
212
213 static void print_prog_json(struct bpf_prog_info *info, int fd)
214 {
215         char *memlock;
216
217         jsonw_start_object(json_wtr);
218         jsonw_uint_field(json_wtr, "id", info->id);
219         if (info->type < ARRAY_SIZE(prog_type_name))
220                 jsonw_string_field(json_wtr, "type",
221                                    prog_type_name[info->type]);
222         else
223                 jsonw_uint_field(json_wtr, "type", info->type);
224
225         if (*info->name)
226                 jsonw_string_field(json_wtr, "name", info->name);
227
228         jsonw_name(json_wtr, "tag");
229         jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"",
230                      info->tag[0], info->tag[1], info->tag[2], info->tag[3],
231                      info->tag[4], info->tag[5], info->tag[6], info->tag[7]);
232
233         if (info->load_time) {
234                 char buf[32];
235
236                 print_boot_time(info->load_time, buf, sizeof(buf));
237
238                 /* Piggy back on load_time, since 0 uid is a valid one */
239                 jsonw_string_field(json_wtr, "loaded_at", buf);
240                 jsonw_uint_field(json_wtr, "uid", info->created_by_uid);
241         }
242
243         jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len);
244
245         if (info->jited_prog_len) {
246                 jsonw_bool_field(json_wtr, "jited", true);
247                 jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len);
248         } else {
249                 jsonw_bool_field(json_wtr, "jited", false);
250         }
251
252         memlock = get_fdinfo(fd, "memlock");
253         if (memlock)
254                 jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock));
255         free(memlock);
256
257         if (info->nr_map_ids)
258                 show_prog_maps(fd, info->nr_map_ids);
259
260         if (!hash_empty(prog_table.table)) {
261                 struct pinned_obj *obj;
262
263                 jsonw_name(json_wtr, "pinned");
264                 jsonw_start_array(json_wtr);
265                 hash_for_each_possible(prog_table.table, obj, hash, info->id) {
266                         if (obj->id == info->id)
267                                 jsonw_string(json_wtr, obj->path);
268                 }
269                 jsonw_end_array(json_wtr);
270         }
271
272         jsonw_end_object(json_wtr);
273 }
274
275 static void print_prog_plain(struct bpf_prog_info *info, int fd)
276 {
277         char *memlock;
278
279         printf("%u: ", info->id);
280         if (info->type < ARRAY_SIZE(prog_type_name))
281                 printf("%s  ", prog_type_name[info->type]);
282         else
283                 printf("type %u  ", info->type);
284
285         if (*info->name)
286                 printf("name %s  ", info->name);
287
288         printf("tag ");
289         fprint_hex(stdout, info->tag, BPF_TAG_SIZE, "");
290         printf("\n");
291
292         if (info->load_time) {
293                 char buf[32];
294
295                 print_boot_time(info->load_time, buf, sizeof(buf));
296
297                 /* Piggy back on load_time, since 0 uid is a valid one */
298                 printf("\tloaded_at %s  uid %u\n", buf, info->created_by_uid);
299         }
300
301         printf("\txlated %uB", info->xlated_prog_len);
302
303         if (info->jited_prog_len)
304                 printf("  jited %uB", info->jited_prog_len);
305         else
306                 printf("  not jited");
307
308         memlock = get_fdinfo(fd, "memlock");
309         if (memlock)
310                 printf("  memlock %sB", memlock);
311         free(memlock);
312
313         if (info->nr_map_ids)
314                 show_prog_maps(fd, info->nr_map_ids);
315
316         if (!hash_empty(prog_table.table)) {
317                 struct pinned_obj *obj;
318
319                 printf("\n");
320                 hash_for_each_possible(prog_table.table, obj, hash, info->id) {
321                         if (obj->id == info->id)
322                                 printf("\tpinned %s\n", obj->path);
323                 }
324         }
325
326         printf("\n");
327 }
328
329 static int show_prog(int fd)
330 {
331         struct bpf_prog_info info = {};
332         __u32 len = sizeof(info);
333         int err;
334
335         err = bpf_obj_get_info_by_fd(fd, &info, &len);
336         if (err) {
337                 p_err("can't get prog info: %s", strerror(errno));
338                 return -1;
339         }
340
341         if (json_output)
342                 print_prog_json(&info, fd);
343         else
344                 print_prog_plain(&info, fd);
345
346         return 0;
347 }
348
349 static int do_show(int argc, char **argv)
350 {
351         __u32 id = 0;
352         int err;
353         int fd;
354
355         if (show_pinned)
356                 build_pinned_obj_table(&prog_table, BPF_OBJ_PROG);
357
358         if (argc == 2) {
359                 fd = prog_parse_fd(&argc, &argv);
360                 if (fd < 0)
361                         return -1;
362
363                 return show_prog(fd);
364         }
365
366         if (argc)
367                 return BAD_ARG();
368
369         if (json_output)
370                 jsonw_start_array(json_wtr);
371         while (true) {
372                 err = bpf_prog_get_next_id(id, &id);
373                 if (err) {
374                         if (errno == ENOENT) {
375                                 err = 0;
376                                 break;
377                         }
378                         p_err("can't get next program: %s%s", strerror(errno),
379                               errno == EINVAL ? " -- kernel too old?" : "");
380                         err = -1;
381                         break;
382                 }
383
384                 fd = bpf_prog_get_fd_by_id(id);
385                 if (fd < 0) {
386                         p_err("can't get prog by id (%u): %s",
387                               id, strerror(errno));
388                         err = -1;
389                         break;
390                 }
391
392                 err = show_prog(fd);
393                 close(fd);
394                 if (err)
395                         break;
396         }
397
398         if (json_output)
399                 jsonw_end_array(json_wtr);
400
401         return err;
402 }
403
404 static void print_insn(struct bpf_verifier_env *env, const char *fmt, ...)
405 {
406         va_list args;
407
408         va_start(args, fmt);
409         vprintf(fmt, args);
410         va_end(args);
411 }
412
413 static void dump_xlated_plain(void *buf, unsigned int len, bool opcodes)
414 {
415         struct bpf_insn *insn = buf;
416         bool double_insn = false;
417         unsigned int i;
418
419         for (i = 0; i < len / sizeof(*insn); i++) {
420                 if (double_insn) {
421                         double_insn = false;
422                         continue;
423                 }
424
425                 double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW);
426
427                 printf("% 4d: ", i);
428                 print_bpf_insn(print_insn, NULL, insn + i, true);
429
430                 if (opcodes) {
431                         printf("       ");
432                         fprint_hex(stdout, insn + i, 8, " ");
433                         if (double_insn && i < len - 1) {
434                                 printf(" ");
435                                 fprint_hex(stdout, insn + i + 1, 8, " ");
436                         }
437                         printf("\n");
438                 }
439         }
440 }
441
442 static void print_insn_json(struct bpf_verifier_env *env, const char *fmt, ...)
443 {
444         unsigned int l = strlen(fmt);
445         char chomped_fmt[l];
446         va_list args;
447
448         va_start(args, fmt);
449         if (l > 0) {
450                 strncpy(chomped_fmt, fmt, l - 1);
451                 chomped_fmt[l - 1] = '\0';
452         }
453         jsonw_vprintf_enquote(json_wtr, chomped_fmt, args);
454         va_end(args);
455 }
456
457 static void dump_xlated_json(void *buf, unsigned int len, bool opcodes)
458 {
459         struct bpf_insn *insn = buf;
460         bool double_insn = false;
461         unsigned int i;
462
463         jsonw_start_array(json_wtr);
464         for (i = 0; i < len / sizeof(*insn); i++) {
465                 if (double_insn) {
466                         double_insn = false;
467                         continue;
468                 }
469                 double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW);
470
471                 jsonw_start_object(json_wtr);
472                 jsonw_name(json_wtr, "disasm");
473                 print_bpf_insn(print_insn_json, NULL, insn + i, true);
474
475                 if (opcodes) {
476                         jsonw_name(json_wtr, "opcodes");
477                         jsonw_start_object(json_wtr);
478
479                         jsonw_name(json_wtr, "code");
480                         jsonw_printf(json_wtr, "\"0x%02hhx\"", insn[i].code);
481
482                         jsonw_name(json_wtr, "src_reg");
483                         jsonw_printf(json_wtr, "\"0x%hhx\"", insn[i].src_reg);
484
485                         jsonw_name(json_wtr, "dst_reg");
486                         jsonw_printf(json_wtr, "\"0x%hhx\"", insn[i].dst_reg);
487
488                         jsonw_name(json_wtr, "off");
489                         print_hex_data_json((uint8_t *)(&insn[i].off), 2);
490
491                         jsonw_name(json_wtr, "imm");
492                         if (double_insn && i < len - 1)
493                                 print_hex_data_json((uint8_t *)(&insn[i].imm),
494                                                     12);
495                         else
496                                 print_hex_data_json((uint8_t *)(&insn[i].imm),
497                                                     4);
498                         jsonw_end_object(json_wtr);
499                 }
500                 jsonw_end_object(json_wtr);
501         }
502         jsonw_end_array(json_wtr);
503 }
504
505 static int do_dump(int argc, char **argv)
506 {
507         struct bpf_prog_info info = {};
508         __u32 len = sizeof(info);
509         unsigned int buf_size;
510         char *filepath = NULL;
511         bool opcodes = false;
512         unsigned char *buf;
513         __u32 *member_len;
514         __u64 *member_ptr;
515         ssize_t n;
516         int err;
517         int fd;
518
519         if (is_prefix(*argv, "jited")) {
520                 member_len = &info.jited_prog_len;
521                 member_ptr = &info.jited_prog_insns;
522         } else if (is_prefix(*argv, "xlated")) {
523                 member_len = &info.xlated_prog_len;
524                 member_ptr = &info.xlated_prog_insns;
525         } else {
526                 p_err("expected 'xlated' or 'jited', got: %s", *argv);
527                 return -1;
528         }
529         NEXT_ARG();
530
531         if (argc < 2)
532                 usage();
533
534         fd = prog_parse_fd(&argc, &argv);
535         if (fd < 0)
536                 return -1;
537
538         if (is_prefix(*argv, "file")) {
539                 NEXT_ARG();
540                 if (!argc) {
541                         p_err("expected file path");
542                         return -1;
543                 }
544
545                 filepath = *argv;
546                 NEXT_ARG();
547         } else if (is_prefix(*argv, "opcodes")) {
548                 opcodes = true;
549                 NEXT_ARG();
550         }
551
552         if (argc) {
553                 usage();
554                 return -1;
555         }
556
557         err = bpf_obj_get_info_by_fd(fd, &info, &len);
558         if (err) {
559                 p_err("can't get prog info: %s", strerror(errno));
560                 return -1;
561         }
562
563         if (!*member_len) {
564                 p_info("no instructions returned");
565                 close(fd);
566                 return 0;
567         }
568
569         buf_size = *member_len;
570
571         buf = malloc(buf_size);
572         if (!buf) {
573                 p_err("mem alloc failed");
574                 close(fd);
575                 return -1;
576         }
577
578         memset(&info, 0, sizeof(info));
579
580         *member_ptr = ptr_to_u64(buf);
581         *member_len = buf_size;
582
583         err = bpf_obj_get_info_by_fd(fd, &info, &len);
584         close(fd);
585         if (err) {
586                 p_err("can't get prog info: %s", strerror(errno));
587                 goto err_free;
588         }
589
590         if (*member_len > buf_size) {
591                 p_err("too many instructions returned");
592                 goto err_free;
593         }
594
595         if (filepath) {
596                 fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
597                 if (fd < 0) {
598                         p_err("can't open file %s: %s", filepath,
599                               strerror(errno));
600                         goto err_free;
601                 }
602
603                 n = write(fd, buf, *member_len);
604                 close(fd);
605                 if (n != *member_len) {
606                         p_err("error writing output file: %s",
607                               n < 0 ? strerror(errno) : "short write");
608                         goto err_free;
609                 }
610         } else {
611                 if (member_len == &info.jited_prog_len)
612                         disasm_print_insn(buf, *member_len, opcodes);
613                 else
614                         if (json_output)
615                                 dump_xlated_json(buf, *member_len, opcodes);
616                         else
617                                 dump_xlated_plain(buf, *member_len, opcodes);
618         }
619
620         free(buf);
621
622         return 0;
623
624 err_free:
625         free(buf);
626         return -1;
627 }
628
629 static int do_pin(int argc, char **argv)
630 {
631         int err;
632
633         err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id);
634         if (!err && json_output)
635                 jsonw_null(json_wtr);
636         return err;
637 }
638
639 static int do_load(int argc, char **argv)
640 {
641         struct bpf_object *obj;
642         int prog_fd;
643
644         if (argc != 2)
645                 usage();
646
647         if (bpf_prog_load(argv[0], BPF_PROG_TYPE_UNSPEC, &obj, &prog_fd)) {
648                 p_err("failed to load program\n");
649                 return -1;
650         }
651
652         if (do_pin_fd(prog_fd, argv[1])) {
653                 p_err("failed to pin program\n");
654                 return -1;
655         }
656
657         if (json_output)
658                 jsonw_null(json_wtr);
659
660         return 0;
661 }
662
663 static int do_help(int argc, char **argv)
664 {
665         if (json_output) {
666                 jsonw_null(json_wtr);
667                 return 0;
668         }
669
670         fprintf(stderr,
671                 "Usage: %s %s show [PROG]\n"
672                 "       %s %s dump xlated PROG [{ file FILE | opcodes }]\n"
673                 "       %s %s dump jited  PROG [{ file FILE | opcodes }]\n"
674                 "       %s %s pin   PROG FILE\n"
675                 "       %s %s load  OBJ  FILE\n"
676                 "       %s %s help\n"
677                 "\n"
678                 "       " HELP_SPEC_PROGRAM "\n"
679                 "       " HELP_SPEC_OPTIONS "\n"
680                 "",
681                 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
682                 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]);
683
684         return 0;
685 }
686
687 static const struct cmd cmds[] = {
688         { "show",       do_show },
689         { "help",       do_help },
690         { "dump",       do_dump },
691         { "pin",        do_pin },
692         { "load",       do_load },
693         { 0 }
694 };
695
696 int do_prog(int argc, char **argv)
697 {
698         return cmd_select(cmds, argc, argv, do_help);
699 }