blob: 4621099a94d206953cdb43d060ea99061d596d43 [file] [log] [blame]
Martin KaFai Lauf89cb402017-10-19 23:52:54 -07001#include <time.h>
2#include <stdio.h>
3#include <errno.h>
4#include <string.h>
5#include <stdlib.h>
6#include <stdio.h>
7#include <stdint.h>
8#include <unistd.h>
9#include <ctype.h>
10#include <sysexits.h>
11
12#include "libbpf.h"
13
nikolay.samofatovc5308e92017-12-28 19:01:31 +030014// TODO: Remove this when CentOS 6 support is not needed anymore
15#ifndef CLOCK_BOOTTIME
16#define CLOCK_BOOTTIME 7
17#endif
18
Martin KaFai Lauf89cb402017-10-19 23:52:54 -070019static const char * const prog_type_strings[] = {
20 [BPF_PROG_TYPE_UNSPEC] = "unspec",
21 [BPF_PROG_TYPE_SOCKET_FILTER] = "socket filter",
22 [BPF_PROG_TYPE_KPROBE] = "kprobe",
23 [BPF_PROG_TYPE_SCHED_CLS] = "sched cls",
24 [BPF_PROG_TYPE_SCHED_ACT] = "sched act",
25 [BPF_PROG_TYPE_TRACEPOINT] = "tracepoint",
26 [BPF_PROG_TYPE_XDP] = "xdp",
27 [BPF_PROG_TYPE_PERF_EVENT] = "perf event",
28 [BPF_PROG_TYPE_CGROUP_SKB] = "cgroup skb",
29 [BPF_PROG_TYPE_CGROUP_SOCK] = "cgroup sock",
30 [BPF_PROG_TYPE_LWT_IN] = "lwt in",
31 [BPF_PROG_TYPE_LWT_OUT] = "lwt out",
32 [BPF_PROG_TYPE_LWT_XMIT] = "lwt xmit",
33 [BPF_PROG_TYPE_SOCK_OPS] = "sock ops",
34 [BPF_PROG_TYPE_SK_SKB] = "sk skb",
35};
36
37static const char * const map_type_strings[] = {
38 [BPF_MAP_TYPE_UNSPEC] = "unspec",
39 [BPF_MAP_TYPE_HASH] = "hash",
40 [BPF_MAP_TYPE_ARRAY] = "array",
41 [BPF_MAP_TYPE_PROG_ARRAY] = "prog array",
42 [BPF_MAP_TYPE_PERF_EVENT_ARRAY] = "perf-ev array",
43 [BPF_MAP_TYPE_PERCPU_HASH] = "percpu hash",
44 [BPF_MAP_TYPE_PERCPU_ARRAY] = "percpu array",
45 [BPF_MAP_TYPE_STACK_TRACE] = "stack trace",
46 [BPF_MAP_TYPE_CGROUP_ARRAY] = "cgroup array",
47 [BPF_MAP_TYPE_LRU_HASH] = "lru hash",
48 [BPF_MAP_TYPE_LRU_PERCPU_HASH] = "lru percpu hash",
49 [BPF_MAP_TYPE_LPM_TRIE] = "lpm trie",
50 [BPF_MAP_TYPE_ARRAY_OF_MAPS] = "array of maps",
51 [BPF_MAP_TYPE_HASH_OF_MAPS] = "hash of maps",
52 [BPF_MAP_TYPE_DEVMAP] = "devmap",
53 [BPF_MAP_TYPE_SOCKMAP] = "sockmap",
54};
55
56#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
57#define LAST_KNOWN_PROG_TYPE (ARRAY_SIZE(prog_type_strings) - 1)
58#define LAST_KNOWN_MAP_TYPE (ARRAY_SIZE(map_type_strings) - 1)
59#define min(x, y) ((x) < (y) ? (x) : (y))
60
61static inline uint64_t ptr_to_u64(const void *ptr)
62{
63 return (uint64_t) (unsigned long) ptr;
64}
65
66static inline void * u64_to_ptr(uint64_t ptr)
67{
68 return (void *) (unsigned long ) ptr;
69}
70
71static int handle_get_next_errno(int eno)
72{
73 switch (eno) {
74 case ENOENT:
75 return 0;
76 case EINVAL:
77 fprintf(stderr, "Kernel does not support BPF introspection\n");
78 return EX_UNAVAILABLE;
79 case EPERM:
80 fprintf(stderr,
81 "Require CAP_SYS_ADMIN capability. Please retry as root\n");
82 return EX_NOPERM;
83 default:
84 fprintf(stderr, "%s\n", strerror(errno));
85 return 1;
86 }
87}
88
89static void print_prog_hdr(void)
90{
91 printf("%9s %-15s %8s %6s %-12s %-15s\n",
92 "BID", "TYPE", "UID", "#MAPS", "LoadTime", "NAME");
93}
94
95static void print_prog_info(const struct bpf_prog_info *prog_info)
96{
97 struct timespec real_time_ts, boot_time_ts;
98 time_t wallclock_load_time = 0;
99 char unknown_prog_type[16];
100 const char *prog_type;
101 char load_time[16];
102 struct tm load_tm;
103
104 if (prog_info->type > LAST_KNOWN_PROG_TYPE) {
105 snprintf(unknown_prog_type, sizeof(unknown_prog_type), "<%u>",
106 prog_info->type);
107 unknown_prog_type[sizeof(unknown_prog_type) - 1] = '\0';
108 prog_type = unknown_prog_type;
109 } else {
110 prog_type = prog_type_strings[prog_info->type];
111 }
112
113 if (!clock_gettime(CLOCK_REALTIME, &real_time_ts) &&
114 !clock_gettime(CLOCK_BOOTTIME, &boot_time_ts) &&
115 real_time_ts.tv_sec >= boot_time_ts.tv_sec)
116 wallclock_load_time =
117 (real_time_ts.tv_sec - boot_time_ts.tv_sec) +
118 prog_info->load_time / 1000000000;
119
120 if (wallclock_load_time && localtime_r(&wallclock_load_time, &load_tm))
121 strftime(load_time, sizeof(load_time), "%b%d/%H:%M", &load_tm);
122 else
123 snprintf(load_time, sizeof(load_time), "<%llu>",
124 prog_info->load_time / 1000000000);
125 load_time[sizeof(load_time) - 1] = '\0';
126
127 if (prog_info->jited_prog_len)
128 printf("%9u %-15s %8u %6u %-12s %-15s\n",
129 prog_info->id, prog_type, prog_info->created_by_uid,
130 prog_info->nr_map_ids, load_time, prog_info->name);
131 else
132 printf("%8u- %-15s %8u %6u %-12s %-15s\n",
133 prog_info->id, prog_type, prog_info->created_by_uid,
134 prog_info->nr_map_ids, load_time, prog_info->name);
135}
136
137static void print_map_hdr(void)
138{
139 printf("%8s %-15s %-10s %8s %8s %8s %-15s\n",
140 "MID", "TYPE", "FLAGS", "KeySz", "ValueSz", "MaxEnts",
141 "NAME");
142}
143
144static void print_map_info(const struct bpf_map_info *map_info)
145{
146 char unknown_map_type[16];
147 const char *map_type;
148
149 if (map_info->type > LAST_KNOWN_MAP_TYPE) {
150 snprintf(unknown_map_type, sizeof(unknown_map_type),
151 "<%u>", map_info->type);
152 unknown_map_type[sizeof(unknown_map_type) - 1] = '\0';
153 map_type = unknown_map_type;
154 } else {
155 map_type = map_type_strings[map_info->type];
156 }
157
158 printf("%8u %-15s 0x%-8x %8u %8u %8u %-15s\n",
159 map_info->id, map_type, map_info->map_flags, map_info->key_size,
160 map_info->value_size, map_info->max_entries,
161 map_info->name);
162}
163
164static int print_one_prog(uint32_t prog_id)
165{
166 const uint32_t usual_nr_map_ids = 64;
167 uint32_t nr_map_ids = usual_nr_map_ids;
168 struct bpf_prog_info prog_info;
169 uint32_t *map_ids = NULL;
170 uint32_t info_len;
171 int ret = 0;
172 int prog_fd;
173 uint32_t i;
174
175 prog_fd = bpf_prog_get_fd_by_id(prog_id);
176 if (prog_fd == -1) {
177 if (errno == ENOENT) {
178 fprintf(stderr, "BID:%u not found\n", prog_id);
179 return EX_DATAERR;
180 } else {
181 return handle_get_next_errno(errno);
182 }
183 }
184
185 /* Retry at most one time for larger map_ids array */
186 for (i = 0; i < 2; i++) {
187 bzero(&prog_info, sizeof(prog_info));
188 prog_info.map_ids = ptr_to_u64(realloc(map_ids,
189 nr_map_ids * sizeof(*map_ids)));
190 if (!prog_info.map_ids) {
191 fprintf(stderr,
192 "Cannot allocate memory for %u map_ids for BID:%u\n",
193 nr_map_ids, prog_id);
194 close(prog_fd);
195 free(map_ids);
196 return 1;
197 }
198
199 map_ids = u64_to_ptr(prog_info.map_ids);
200 prog_info.nr_map_ids = nr_map_ids;
201 info_len = sizeof(prog_info);
202 ret = bpf_obj_get_info(prog_fd, &prog_info, &info_len);
203 if (ret) {
204 fprintf(stderr, "Cannot get info for BID:%u. %s(%d)\n",
205 prog_id, strerror(errno), errno);
206 close(prog_fd);
207 free(map_ids);
208 return ret;
209 }
210
211 if (prog_info.nr_map_ids <= nr_map_ids)
212 break;
213
214 nr_map_ids = prog_info.nr_map_ids;
215 }
216 close(prog_fd);
217
218 print_prog_hdr();
219 print_prog_info(&prog_info);
220 printf("\n");
221
222 /* Print all map_info used by the prog */
223 print_map_hdr();
224 nr_map_ids = min(prog_info.nr_map_ids, nr_map_ids);
225 for (i = 0; i < nr_map_ids; i++) {
226 struct bpf_map_info map_info = {};
Teng Qind77a41b2017-10-31 12:05:17 -0700227 info_len = sizeof(map_info);
Martin KaFai Lauf89cb402017-10-19 23:52:54 -0700228 int map_fd;
229
230 map_fd = bpf_map_get_fd_by_id(map_ids[i]);
231 if (map_fd == -1) {
232 if (errno == -ENOENT)
233 continue;
234
235 fprintf(stderr,
236 "Cannot get fd for map:%u. %s(%d)\n",
237 map_ids[i], strerror(errno), errno);
238 ret = map_fd;
239 break;
240 }
241
242 ret = bpf_obj_get_info(map_fd, &map_info, &info_len);
243 close(map_fd);
244 if (ret) {
245 fprintf(stderr, "Cannot get info for map:%u. %s(%d)\n",
246 map_ids[i], strerror(errno), errno);
247 break;
248 }
249
250 print_map_info(&map_info);
251 }
252
253 free(map_ids);
254 return ret;
255}
256
257int print_all_progs(void)
258{
259 uint32_t next_id = 0;
260
261 print_prog_hdr();
262
263 while (!bpf_prog_get_next_id(next_id, &next_id)) {
264 struct bpf_prog_info prog_info = {};
265 uint32_t prog_info_len = sizeof(prog_info);
266 int prog_fd;
267 int ret;
268
269 prog_fd = bpf_prog_get_fd_by_id(next_id);
270 if (prog_fd < 0) {
271 if (errno == ENOENT)
272 continue;
273 fprintf(stderr,
274 "Cannot get fd for BID:%u. %s(%d)\n",
275 next_id, strerror(errno), errno);
276 return 1;
277 }
278
279 ret = bpf_obj_get_info(prog_fd, &prog_info, &prog_info_len);
280 close(prog_fd);
281 if (ret) {
282 fprintf(stderr,
283 "Cannot get bpf_prog_info for BID:%u. %s(%d)\n",
284 next_id, strerror(errno), errno);
285 return ret;
286 }
287
288 print_prog_info(&prog_info);
289 }
290
291 return handle_get_next_errno(errno);
292}
293
294void usage(void)
295{
296 printf("BPF Program Snapshot (bps):\n"
297 "List of all BPF programs loaded into the system.\n\n");
298 printf("Usage: bps [bpf-prog-id]\n");
299 printf(" [bpf-prog-id] If specified, it shows the details info of the bpf-prog\n");
300 printf("\n");
301}
302
303int main(int argc, char **argv)
304{
305 if (argc > 1) {
306 if (!isdigit(*argv[1])) {
307 usage();
308 return EX_USAGE;
309 }
310 return print_one_prog((uint32_t)atoi(argv[1]));
311 }
312
313 return print_all_progs();
314}