summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQuentin Monnet <quentin.monnet@netronome.com>2018-12-05 05:28:24 -0500
committerDaniel Borkmann <daniel@iogearbox.net>2018-12-05 10:41:52 -0500
commit30da46b5dc3a9a14db11706d841440e28b12bb53 (patch)
tree32ed4dde5cbce0f5ec6cdba14b33ef245de2579a
parent41888179b1b7d0524314758ce1ad7c2e3b602235 (diff)
tools: bpftool: add a command to dump the trace pipe
BPF programs can use the bpf_trace_printk() helper to print debug information into the trace pipe. Add a subcommand "bpftool prog tracelog" to simply dump this pipe to the console. This is for a good part copied from iproute2, where the feature is available with "tc exec bpf dbg". Changes include dumping pipe content to stdout instead of stderr and adding JSON support (content is dumped as an array of strings, one per line read from the pipe). This version is dual-licensed, with Daniel's permission. Cc: Daniel Borkmann <daniel@iogearbox.net> Suggested-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
-rw-r--r--tools/bpf/bpftool/Documentation/bpftool-prog.rst13
-rw-r--r--tools/bpf/bpftool/bash-completion/bpftool5
-rw-r--r--tools/bpf/bpftool/main.h1
-rw-r--r--tools/bpf/bpftool/prog.c4
-rw-r--r--tools/bpf/bpftool/tracelog.c157
5 files changed, 176 insertions, 4 deletions
diff --git a/tools/bpf/bpftool/Documentation/bpftool-prog.rst b/tools/bpf/bpftool/Documentation/bpftool-prog.rst
index ab36e920e552..5524b6dccd85 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-prog.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-prog.rst
@@ -26,8 +26,9 @@ MAP COMMANDS
26| **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}] 26| **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}]
27| **bpftool** **prog pin** *PROG* *FILE* 27| **bpftool** **prog pin** *PROG* *FILE*
28| **bpftool** **prog { load | loadall }** *OBJ* *PATH* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*] 28| **bpftool** **prog { load | loadall }** *OBJ* *PATH* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*]
29| **bpftool** **prog attach** *PROG* *ATTACH_TYPE* [*MAP*] 29| **bpftool** **prog attach** *PROG* *ATTACH_TYPE* [*MAP*]
30| **bpftool** **prog detach** *PROG* *ATTACH_TYPE* [*MAP*] 30| **bpftool** **prog detach** *PROG* *ATTACH_TYPE* [*MAP*]
31| **bpftool** **prog tracelog**
31| **bpftool** **prog help** 32| **bpftool** **prog help**
32| 33|
33| *MAP* := { **id** *MAP_ID* | **pinned** *FILE* } 34| *MAP* := { **id** *MAP_ID* | **pinned** *FILE* }
@@ -117,6 +118,14 @@ DESCRIPTION
117 parameter, with the exception of *flow_dissector* which is 118 parameter, with the exception of *flow_dissector* which is
118 detached from the current networking name space. 119 detached from the current networking name space.
119 120
121 **bpftool prog tracelog**
122 Dump the trace pipe of the system to the console (stdout).
123 Hit <Ctrl+C> to stop printing. BPF programs can write to this
124 trace pipe at runtime with the **bpf_trace_printk()** helper.
125 This should be used only for debugging purposes. For
126 streaming data from BPF programs to user space, one can use
127 perf events (see also **bpftool-map**\ (8)).
128
120 **bpftool prog help** 129 **bpftool prog help**
121 Print short help message. 130 Print short help message.
122 131
diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool
index 9a60080f085f..44c189ba072a 100644
--- a/tools/bpf/bpftool/bash-completion/bpftool
+++ b/tools/bpf/bpftool/bash-completion/bpftool
@@ -398,10 +398,13 @@ _bpftool()
398 ;; 398 ;;
399 esac 399 esac
400 ;; 400 ;;
401 tracelog)
402 return 0
403 ;;
401 *) 404 *)
402 [[ $prev == $object ]] && \ 405 [[ $prev == $object ]] && \
403 COMPREPLY=( $( compgen -W 'dump help pin attach detach load \ 406 COMPREPLY=( $( compgen -W 'dump help pin attach detach load \
404 show list' -- "$cur" ) ) 407 show list tracelog' -- "$cur" ) )
405 ;; 408 ;;
406 esac 409 esac
407 ;; 410 ;;
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index 2761981669c8..0be0dd8f467f 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -167,6 +167,7 @@ int do_event_pipe(int argc, char **argv);
167int do_cgroup(int argc, char **arg); 167int do_cgroup(int argc, char **arg);
168int do_perf(int argc, char **arg); 168int do_perf(int argc, char **arg);
169int do_net(int argc, char **arg); 169int do_net(int argc, char **arg);
170int do_tracelog(int argc, char **arg);
170 171
171int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what); 172int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what);
172int prog_parse_fd(int *argc, char ***argv); 173int prog_parse_fd(int *argc, char ***argv);
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
index 56db61c5a91f..54c8dbf05c9c 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c
@@ -1140,6 +1140,7 @@ static int do_help(int argc, char **argv)
1140 " [pinmaps MAP_DIR]\n" 1140 " [pinmaps MAP_DIR]\n"
1141 " %s %s attach PROG ATTACH_TYPE [MAP]\n" 1141 " %s %s attach PROG ATTACH_TYPE [MAP]\n"
1142 " %s %s detach PROG ATTACH_TYPE [MAP]\n" 1142 " %s %s detach PROG ATTACH_TYPE [MAP]\n"
1143 " %s %s tracelog\n"
1143 " %s %s help\n" 1144 " %s %s help\n"
1144 "\n" 1145 "\n"
1145 " " HELP_SPEC_MAP "\n" 1146 " " HELP_SPEC_MAP "\n"
@@ -1158,7 +1159,7 @@ static int do_help(int argc, char **argv)
1158 "", 1159 "",
1159 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1160 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
1160 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1161 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
1161 bin_name, argv[-2], bin_name, argv[-2]); 1162 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]);
1162 1163
1163 return 0; 1164 return 0;
1164} 1165}
@@ -1173,6 +1174,7 @@ static const struct cmd cmds[] = {
1173 { "loadall", do_loadall }, 1174 { "loadall", do_loadall },
1174 { "attach", do_attach }, 1175 { "attach", do_attach },
1175 { "detach", do_detach }, 1176 { "detach", do_detach },
1177 { "tracelog", do_tracelog },
1176 { 0 } 1178 { 0 }
1177}; 1179};
1178 1180
diff --git a/tools/bpf/bpftool/tracelog.c b/tools/bpf/bpftool/tracelog.c
new file mode 100644
index 000000000000..1fa8e513f590
--- /dev/null
+++ b/tools/bpf/bpftool/tracelog.c
@@ -0,0 +1,157 @@
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2/* Copyright (c) 2015-2017 Daniel Borkmann */
3/* Copyright (c) 2018 Netronome Systems, Inc. */
4
5#include <errno.h>
6#include <limits.h>
7#include <signal.h>
8#include <stdio.h>
9#include <string.h>
10#include <unistd.h>
11#include <linux/magic.h>
12#include <sys/fcntl.h>
13#include <sys/vfs.h>
14
15#include "main.h"
16
17#ifndef TRACEFS_MAGIC
18# define TRACEFS_MAGIC 0x74726163
19#endif
20
21#define _textify(x) #x
22#define textify(x) _textify(x)
23
24FILE *trace_pipe_fd;
25char *buff;
26
27static int validate_tracefs_mnt(const char *mnt, unsigned long magic)
28{
29 struct statfs st_fs;
30
31 if (statfs(mnt, &st_fs) < 0)
32 return -ENOENT;
33 if ((unsigned long)st_fs.f_type != magic)
34 return -ENOENT;
35
36 return 0;
37}
38
39static bool
40find_tracefs_mnt_single(unsigned long magic, char *mnt, const char *mntpt)
41{
42 size_t src_len;
43
44 if (validate_tracefs_mnt(mntpt, magic))
45 return false;
46
47 src_len = strlen(mntpt);
48 if (src_len + 1 >= PATH_MAX) {
49 p_err("tracefs mount point name too long");
50 return false;
51 }
52
53 strcpy(mnt, mntpt);
54 return true;
55}
56
57static bool find_tracefs_pipe(char *mnt)
58{
59 static const char * const known_mnts[] = {
60 "/sys/kernel/debug/tracing",
61 "/sys/kernel/tracing",
62 "/tracing",
63 "/trace",
64 };
65 const char *pipe_name = "/trace_pipe";
66 const char *fstype = "tracefs";
67 char type[100], format[32];
68 const char * const *ptr;
69 bool found = false;
70 FILE *fp;
71
72 for (ptr = known_mnts; ptr < known_mnts + ARRAY_SIZE(known_mnts); ptr++)
73 if (find_tracefs_mnt_single(TRACEFS_MAGIC, mnt, *ptr))
74 goto exit_found;
75
76 fp = fopen("/proc/mounts", "r");
77 if (!fp)
78 return false;
79
80 /* Allow room for NULL terminating byte and pipe file name */
81 snprintf(format, sizeof(format), "%%*s %%%zds %%99s %%*s %%*d %%*d\\n",
82 PATH_MAX - strlen(pipe_name) - 1);
83 while (fscanf(fp, format, mnt, type) == 2)
84 if (strcmp(type, fstype) == 0) {
85 found = true;
86 break;
87 }
88 fclose(fp);
89
90 /* The string from fscanf() might be truncated, check mnt is valid */
91 if (!found || validate_tracefs_mnt(mnt, TRACEFS_MAGIC))
92 return false;
93
94exit_found:
95 strcat(mnt, pipe_name);
96 return true;
97}
98
99static void exit_tracelog(int signum)
100{
101 fclose(trace_pipe_fd);
102 free(buff);
103
104 if (json_output) {
105 jsonw_end_array(json_wtr);
106 jsonw_destroy(&json_wtr);
107 }
108
109 exit(0);
110}
111
112int do_tracelog(int argc, char **argv)
113{
114 const struct sigaction act = {
115 .sa_handler = exit_tracelog
116 };
117 char trace_pipe[PATH_MAX];
118 bool found_trace_pipe;
119 size_t buff_len = 0;
120
121 if (json_output)
122 jsonw_start_array(json_wtr);
123
124 found_trace_pipe = find_tracefs_pipe(trace_pipe);
125 if (!found_trace_pipe) {
126 p_err("could not find trace pipe, tracefs not mounted?");
127 return -1;
128 }
129
130 trace_pipe_fd = fopen(trace_pipe, "r");
131 if (!trace_pipe_fd) {
132 p_err("could not open trace pipe: %s", strerror(errno));
133 return -1;
134 }
135
136 sigaction(SIGHUP, &act, NULL);
137 sigaction(SIGINT, &act, NULL);
138 sigaction(SIGTERM, &act, NULL);
139 while (1) {
140 ssize_t ret;
141
142 ret = getline(&buff, &buff_len, trace_pipe_fd);
143 if (ret <= 0) {
144 p_err("failed to read content from trace pipe: %s",
145 strerror(errno));
146 break;
147 }
148 if (json_output)
149 jsonw_string(json_wtr, buff);
150 else
151 printf("%s", buff);
152 }
153
154 fclose(trace_pipe_fd);
155 free(buff);
156 return -1;
157}