blob: 232b23d414f8d026cafc7c42042536f006eda3d0 [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",
Yonghong Song6f3c8252018-06-10 18:04:11 -070035 [BPF_PROG_TYPE_CGROUP_DEVICE] = "cgroup_device",
36 [BPF_PROG_TYPE_SK_MSG] = "sk_msg",
37 [BPF_PROG_TYPE_RAW_TRACEPOINT] = "raw_tracepoint",
38 [BPF_PROG_TYPE_CGROUP_SOCK_ADDR] = "cgroup_sock_addr",
39 [BPF_PROG_TYPE_LIRC_MODE2] = "lirc_mode2",
yonghong-song3835b2d2018-08-16 18:49:06 -070040 [BPF_PROG_TYPE_SK_REUSEPORT] = "sk_reuseport",
yonghong-songd4b23872018-10-10 16:48:15 -070041 [BPF_PROG_TYPE_FLOW_DISSECTOR] = "flow_dissector",
Yonghong Song912d3572019-04-29 11:43:22 -070042 [BPF_PROG_TYPE_CGROUP_SYSCTL] = "cgroup_sysctl",
Yonghong Song3bdeff32019-05-17 10:26:44 -070043 [BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE] = "raw_tracepoint_writable",
Yonghong Song06e30cc2019-07-09 22:54:31 -070044 [BPF_PROG_TYPE_CGROUP_SOCKOPT] = "cgroup_sockopt",
yonghong-song992e4822019-11-13 13:37:58 -080045 [BPF_PROG_TYPE_TRACING] = "tracing",
Yonghong Song071eef62020-01-10 12:52:44 -080046 [BPF_PROG_TYPE_STRUCT_OPS] = "struct_ops",
Yonghong Song83b67c22020-01-27 14:35:21 -080047 [BPF_PROG_TYPE_EXT] = "ext",
Yonghong Songdf3e7d62020-04-20 09:25:57 -070048 [BPF_PROG_TYPE_LSM] = "lsm",
Yonghong Song8a164f92020-07-30 11:32:49 -070049 [BPF_PROG_TYPE_SK_LOOKUP] = "sk_lookup",
yonghong-song949a4e52021-07-18 15:05:34 -070050 [BPF_PROG_TYPE_SYSCALL] = "syscall",
Martin KaFai Lauf89cb402017-10-19 23:52:54 -070051};
52
53static const char * const map_type_strings[] = {
54 [BPF_MAP_TYPE_UNSPEC] = "unspec",
55 [BPF_MAP_TYPE_HASH] = "hash",
56 [BPF_MAP_TYPE_ARRAY] = "array",
57 [BPF_MAP_TYPE_PROG_ARRAY] = "prog array",
58 [BPF_MAP_TYPE_PERF_EVENT_ARRAY] = "perf-ev array",
59 [BPF_MAP_TYPE_PERCPU_HASH] = "percpu hash",
60 [BPF_MAP_TYPE_PERCPU_ARRAY] = "percpu array",
61 [BPF_MAP_TYPE_STACK_TRACE] = "stack trace",
62 [BPF_MAP_TYPE_CGROUP_ARRAY] = "cgroup array",
63 [BPF_MAP_TYPE_LRU_HASH] = "lru hash",
64 [BPF_MAP_TYPE_LRU_PERCPU_HASH] = "lru percpu hash",
65 [BPF_MAP_TYPE_LPM_TRIE] = "lpm trie",
66 [BPF_MAP_TYPE_ARRAY_OF_MAPS] = "array of maps",
67 [BPF_MAP_TYPE_HASH_OF_MAPS] = "hash of maps",
68 [BPF_MAP_TYPE_DEVMAP] = "devmap",
69 [BPF_MAP_TYPE_SOCKMAP] = "sockmap",
Yonghong Song6f3c8252018-06-10 18:04:11 -070070 [BPF_MAP_TYPE_CPUMAP] = "cpumap",
71 [BPF_MAP_TYPE_SOCKHASH] = "sockhash",
yonghong-song3835b2d2018-08-16 18:49:06 -070072 [BPF_MAP_TYPE_CGROUP_STORAGE] = "cgroup_storage",
73 [BPF_MAP_TYPE_REUSEPORT_SOCKARRAY] = "reuseport_sockarray",
Yonghong Song2a68bd82018-10-27 23:14:52 -070074 [BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE] = "precpu_cgroup_storage",
75 [BPF_MAP_TYPE_QUEUE] = "queue",
76 [BPF_MAP_TYPE_STACK] = "stack",
Yonghong Song3bdeff32019-05-17 10:26:44 -070077 [BPF_MAP_TYPE_SK_STORAGE] = "sk_storage",
yonghong-songeb018cf2019-10-02 16:34:38 -070078 [BPF_MAP_TYPE_DEVMAP_HASH] = "devmap_hash",
Yonghong Song071eef62020-01-10 12:52:44 -080079 [BPF_MAP_TYPE_STRUCT_OPS] = "struct_ops",
Yonghong Song99fa3122020-06-16 00:03:11 -070080 [BPF_MAP_TYPE_RINGBUF] = "ringbuf",
Yonghong Songd0e1c932020-10-01 17:32:16 -070081 [BPF_MAP_TYPE_INODE_STORAGE] = "inode_storage",
Yonghong Song1f4b9072021-01-04 20:11:54 -080082 [BPF_MAP_TYPE_TASK_STORAGE] = "task_storage",
Yonghong Song9d6776b2021-11-17 15:57:02 -080083 [BPF_MAP_TYPE_BLOOM_FILTER] = "bloom_filter",
Martin KaFai Lauf89cb402017-10-19 23:52:54 -070084};
85
86#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
87#define LAST_KNOWN_PROG_TYPE (ARRAY_SIZE(prog_type_strings) - 1)
88#define LAST_KNOWN_MAP_TYPE (ARRAY_SIZE(map_type_strings) - 1)
89#define min(x, y) ((x) < (y) ? (x) : (y))
90
91static inline uint64_t ptr_to_u64(const void *ptr)
92{
93 return (uint64_t) (unsigned long) ptr;
94}
95
96static inline void * u64_to_ptr(uint64_t ptr)
97{
98 return (void *) (unsigned long ) ptr;
99}
100
101static int handle_get_next_errno(int eno)
102{
103 switch (eno) {
104 case ENOENT:
105 return 0;
106 case EINVAL:
107 fprintf(stderr, "Kernel does not support BPF introspection\n");
108 return EX_UNAVAILABLE;
109 case EPERM:
110 fprintf(stderr,
111 "Require CAP_SYS_ADMIN capability. Please retry as root\n");
112 return EX_NOPERM;
113 default:
114 fprintf(stderr, "%s\n", strerror(errno));
115 return 1;
116 }
117}
118
119static void print_prog_hdr(void)
120{
121 printf("%9s %-15s %8s %6s %-12s %-15s\n",
122 "BID", "TYPE", "UID", "#MAPS", "LoadTime", "NAME");
123}
124
125static void print_prog_info(const struct bpf_prog_info *prog_info)
126{
127 struct timespec real_time_ts, boot_time_ts;
128 time_t wallclock_load_time = 0;
129 char unknown_prog_type[16];
130 const char *prog_type;
131 char load_time[16];
132 struct tm load_tm;
133
134 if (prog_info->type > LAST_KNOWN_PROG_TYPE) {
135 snprintf(unknown_prog_type, sizeof(unknown_prog_type), "<%u>",
136 prog_info->type);
137 unknown_prog_type[sizeof(unknown_prog_type) - 1] = '\0';
138 prog_type = unknown_prog_type;
139 } else {
140 prog_type = prog_type_strings[prog_info->type];
141 }
142
143 if (!clock_gettime(CLOCK_REALTIME, &real_time_ts) &&
144 !clock_gettime(CLOCK_BOOTTIME, &boot_time_ts) &&
145 real_time_ts.tv_sec >= boot_time_ts.tv_sec)
146 wallclock_load_time =
147 (real_time_ts.tv_sec - boot_time_ts.tv_sec) +
148 prog_info->load_time / 1000000000;
149
150 if (wallclock_load_time && localtime_r(&wallclock_load_time, &load_tm))
151 strftime(load_time, sizeof(load_time), "%b%d/%H:%M", &load_tm);
152 else
153 snprintf(load_time, sizeof(load_time), "<%llu>",
154 prog_info->load_time / 1000000000);
155 load_time[sizeof(load_time) - 1] = '\0';
156
157 if (prog_info->jited_prog_len)
158 printf("%9u %-15s %8u %6u %-12s %-15s\n",
159 prog_info->id, prog_type, prog_info->created_by_uid,
160 prog_info->nr_map_ids, load_time, prog_info->name);
161 else
162 printf("%8u- %-15s %8u %6u %-12s %-15s\n",
163 prog_info->id, prog_type, prog_info->created_by_uid,
164 prog_info->nr_map_ids, load_time, prog_info->name);
165}
166
167static void print_map_hdr(void)
168{
169 printf("%8s %-15s %-10s %8s %8s %8s %-15s\n",
170 "MID", "TYPE", "FLAGS", "KeySz", "ValueSz", "MaxEnts",
171 "NAME");
172}
173
174static void print_map_info(const struct bpf_map_info *map_info)
175{
176 char unknown_map_type[16];
177 const char *map_type;
178
179 if (map_info->type > LAST_KNOWN_MAP_TYPE) {
180 snprintf(unknown_map_type, sizeof(unknown_map_type),
181 "<%u>", map_info->type);
182 unknown_map_type[sizeof(unknown_map_type) - 1] = '\0';
183 map_type = unknown_map_type;
184 } else {
185 map_type = map_type_strings[map_info->type];
186 }
187
188 printf("%8u %-15s 0x%-8x %8u %8u %8u %-15s\n",
189 map_info->id, map_type, map_info->map_flags, map_info->key_size,
190 map_info->value_size, map_info->max_entries,
191 map_info->name);
192}
193
194static int print_one_prog(uint32_t prog_id)
195{
196 const uint32_t usual_nr_map_ids = 64;
197 uint32_t nr_map_ids = usual_nr_map_ids;
198 struct bpf_prog_info prog_info;
199 uint32_t *map_ids = NULL;
200 uint32_t info_len;
201 int ret = 0;
202 int prog_fd;
203 uint32_t i;
204
205 prog_fd = bpf_prog_get_fd_by_id(prog_id);
206 if (prog_fd == -1) {
207 if (errno == ENOENT) {
208 fprintf(stderr, "BID:%u not found\n", prog_id);
209 return EX_DATAERR;
210 } else {
211 return handle_get_next_errno(errno);
212 }
213 }
214
215 /* Retry at most one time for larger map_ids array */
216 for (i = 0; i < 2; i++) {
217 bzero(&prog_info, sizeof(prog_info));
218 prog_info.map_ids = ptr_to_u64(realloc(map_ids,
219 nr_map_ids * sizeof(*map_ids)));
220 if (!prog_info.map_ids) {
221 fprintf(stderr,
222 "Cannot allocate memory for %u map_ids for BID:%u\n",
223 nr_map_ids, prog_id);
224 close(prog_fd);
225 free(map_ids);
226 return 1;
227 }
228
229 map_ids = u64_to_ptr(prog_info.map_ids);
230 prog_info.nr_map_ids = nr_map_ids;
231 info_len = sizeof(prog_info);
232 ret = bpf_obj_get_info(prog_fd, &prog_info, &info_len);
233 if (ret) {
234 fprintf(stderr, "Cannot get info for BID:%u. %s(%d)\n",
235 prog_id, strerror(errno), errno);
236 close(prog_fd);
237 free(map_ids);
238 return ret;
239 }
240
241 if (prog_info.nr_map_ids <= nr_map_ids)
242 break;
243
244 nr_map_ids = prog_info.nr_map_ids;
245 }
246 close(prog_fd);
247
248 print_prog_hdr();
249 print_prog_info(&prog_info);
250 printf("\n");
251
252 /* Print all map_info used by the prog */
253 print_map_hdr();
254 nr_map_ids = min(prog_info.nr_map_ids, nr_map_ids);
255 for (i = 0; i < nr_map_ids; i++) {
256 struct bpf_map_info map_info = {};
Teng Qind77a41b2017-10-31 12:05:17 -0700257 info_len = sizeof(map_info);
Martin KaFai Lauf89cb402017-10-19 23:52:54 -0700258 int map_fd;
259
260 map_fd = bpf_map_get_fd_by_id(map_ids[i]);
261 if (map_fd == -1) {
262 if (errno == -ENOENT)
263 continue;
264
265 fprintf(stderr,
266 "Cannot get fd for map:%u. %s(%d)\n",
267 map_ids[i], strerror(errno), errno);
268 ret = map_fd;
269 break;
270 }
271
272 ret = bpf_obj_get_info(map_fd, &map_info, &info_len);
273 close(map_fd);
274 if (ret) {
275 fprintf(stderr, "Cannot get info for map:%u. %s(%d)\n",
276 map_ids[i], strerror(errno), errno);
277 break;
278 }
279
280 print_map_info(&map_info);
281 }
282
283 free(map_ids);
284 return ret;
285}
286
287int print_all_progs(void)
288{
289 uint32_t next_id = 0;
290
291 print_prog_hdr();
292
293 while (!bpf_prog_get_next_id(next_id, &next_id)) {
294 struct bpf_prog_info prog_info = {};
295 uint32_t prog_info_len = sizeof(prog_info);
296 int prog_fd;
297 int ret;
298
299 prog_fd = bpf_prog_get_fd_by_id(next_id);
300 if (prog_fd < 0) {
301 if (errno == ENOENT)
302 continue;
303 fprintf(stderr,
304 "Cannot get fd for BID:%u. %s(%d)\n",
305 next_id, strerror(errno), errno);
306 return 1;
307 }
308
309 ret = bpf_obj_get_info(prog_fd, &prog_info, &prog_info_len);
310 close(prog_fd);
311 if (ret) {
312 fprintf(stderr,
313 "Cannot get bpf_prog_info for BID:%u. %s(%d)\n",
314 next_id, strerror(errno), errno);
315 return ret;
316 }
317
318 print_prog_info(&prog_info);
319 }
320
321 return handle_get_next_errno(errno);
322}
323
324void usage(void)
325{
326 printf("BPF Program Snapshot (bps):\n"
327 "List of all BPF programs loaded into the system.\n\n");
328 printf("Usage: bps [bpf-prog-id]\n");
329 printf(" [bpf-prog-id] If specified, it shows the details info of the bpf-prog\n");
330 printf("\n");
331}
332
333int main(int argc, char **argv)
334{
335 if (argc > 1) {
336 if (!isdigit(*argv[1])) {
337 usage();
338 return EX_USAGE;
339 }
340 return print_one_prog((uint32_t)atoi(argv[1]));
341 }
342
343 return print_all_progs();
344}