1 #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
14 // TODO: Remove this when CentOS 6 support is not needed anymore
15 #ifndef CLOCK_BOOTTIME
16 #define CLOCK_BOOTTIME 7
17 #endif
18
19 static 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 [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",
40 [BPF_PROG_TYPE_SK_REUSEPORT] = "sk_reuseport",
41 [BPF_PROG_TYPE_FLOW_DISSECTOR] = "flow_dissector",
42 [BPF_PROG_TYPE_CGROUP_SYSCTL] = "cgroup_sysctl",
43 [BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE] = "raw_tracepoint_writable",
44 [BPF_PROG_TYPE_CGROUP_SOCKOPT] = "cgroup_sockopt",
45 [BPF_PROG_TYPE_TRACING] = "tracing",
46 [BPF_PROG_TYPE_STRUCT_OPS] = "struct_ops",
47 [BPF_PROG_TYPE_EXT] = "ext",
48 [BPF_PROG_TYPE_LSM] = "lsm",
49 [BPF_PROG_TYPE_SK_LOOKUP] = "sk_lookup",
50 [BPF_PROG_TYPE_SYSCALL] = "syscall",
51 };
52
53 static 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",
70 [BPF_MAP_TYPE_CPUMAP] = "cpumap",
71 [BPF_MAP_TYPE_SOCKHASH] = "sockhash",
72 [BPF_MAP_TYPE_CGROUP_STORAGE] = "cgroup_storage",
73 [BPF_MAP_TYPE_REUSEPORT_SOCKARRAY] = "reuseport_sockarray",
74 [BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE] = "precpu_cgroup_storage",
75 [BPF_MAP_TYPE_QUEUE] = "queue",
76 [BPF_MAP_TYPE_STACK] = "stack",
77 [BPF_MAP_TYPE_SK_STORAGE] = "sk_storage",
78 [BPF_MAP_TYPE_DEVMAP_HASH] = "devmap_hash",
79 [BPF_MAP_TYPE_STRUCT_OPS] = "struct_ops",
80 [BPF_MAP_TYPE_RINGBUF] = "ringbuf",
81 [BPF_MAP_TYPE_INODE_STORAGE] = "inode_storage",
82 [BPF_MAP_TYPE_TASK_STORAGE] = "task_storage",
83 [BPF_MAP_TYPE_BLOOM_FILTER] = "bloom_filter",
84 [BPF_MAP_TYPE_USER_RINGBUF] = "user_ringbuf",
85 [BPF_MAP_TYPE_CGRP_STORAGE] = "cgrp_storage",
86 };
87
88 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
89 #define LAST_KNOWN_PROG_TYPE (ARRAY_SIZE(prog_type_strings) - 1)
90 #define LAST_KNOWN_MAP_TYPE (ARRAY_SIZE(map_type_strings) - 1)
91 #define min(x, y) ((x) < (y) ? (x) : (y))
92
ptr_to_u64(const void * ptr)93 static inline uint64_t ptr_to_u64(const void *ptr)
94 {
95 return (uint64_t) (unsigned long) ptr;
96 }
97
u64_to_ptr(uint64_t ptr)98 static inline void * u64_to_ptr(uint64_t ptr)
99 {
100 return (void *) (unsigned long ) ptr;
101 }
102
handle_get_next_errno(int eno)103 static int handle_get_next_errno(int eno)
104 {
105 switch (eno) {
106 case ENOENT:
107 return 0;
108 case EINVAL:
109 fprintf(stderr, "Kernel does not support BPF introspection\n");
110 return EX_UNAVAILABLE;
111 case EPERM:
112 fprintf(stderr,
113 "Require CAP_SYS_ADMIN capability. Please retry as root\n");
114 return EX_NOPERM;
115 default:
116 fprintf(stderr, "%s\n", strerror(errno));
117 return 1;
118 }
119 }
120
print_prog_hdr(void)121 static void print_prog_hdr(void)
122 {
123 printf("%9s %-15s %8s %6s %-12s %-15s\n",
124 "BID", "TYPE", "UID", "#MAPS", "LoadTime", "NAME");
125 }
126
print_prog_info(const struct bpf_prog_info * prog_info)127 static void print_prog_info(const struct bpf_prog_info *prog_info)
128 {
129 struct timespec real_time_ts, boot_time_ts;
130 time_t wallclock_load_time = 0;
131 char unknown_prog_type[16];
132 const char *prog_type;
133 char load_time[16];
134 struct tm load_tm;
135
136 if (prog_info->type > LAST_KNOWN_PROG_TYPE) {
137 snprintf(unknown_prog_type, sizeof(unknown_prog_type), "<%u>",
138 prog_info->type);
139 unknown_prog_type[sizeof(unknown_prog_type) - 1] = '\0';
140 prog_type = unknown_prog_type;
141 } else {
142 prog_type = prog_type_strings[prog_info->type];
143 }
144
145 if (!clock_gettime(CLOCK_REALTIME, &real_time_ts) &&
146 !clock_gettime(CLOCK_BOOTTIME, &boot_time_ts) &&
147 real_time_ts.tv_sec >= boot_time_ts.tv_sec)
148 wallclock_load_time =
149 (real_time_ts.tv_sec - boot_time_ts.tv_sec) +
150 prog_info->load_time / 1000000000;
151
152 if (wallclock_load_time && localtime_r(&wallclock_load_time, &load_tm))
153 strftime(load_time, sizeof(load_time), "%b%d/%H:%M", &load_tm);
154 else
155 snprintf(load_time, sizeof(load_time), "<%llu>",
156 prog_info->load_time / 1000000000);
157 load_time[sizeof(load_time) - 1] = '\0';
158
159 if (prog_info->jited_prog_len)
160 printf("%9u %-15s %8u %6u %-12s %-15s\n",
161 prog_info->id, prog_type, prog_info->created_by_uid,
162 prog_info->nr_map_ids, load_time, prog_info->name);
163 else
164 printf("%8u- %-15s %8u %6u %-12s %-15s\n",
165 prog_info->id, prog_type, prog_info->created_by_uid,
166 prog_info->nr_map_ids, load_time, prog_info->name);
167 }
168
print_map_hdr(void)169 static void print_map_hdr(void)
170 {
171 printf("%8s %-15s %-10s %8s %8s %8s %-15s\n",
172 "MID", "TYPE", "FLAGS", "KeySz", "ValueSz", "MaxEnts",
173 "NAME");
174 }
175
print_map_info(const struct bpf_map_info * map_info)176 static void print_map_info(const struct bpf_map_info *map_info)
177 {
178 char unknown_map_type[16];
179 const char *map_type;
180
181 if (map_info->type > LAST_KNOWN_MAP_TYPE) {
182 snprintf(unknown_map_type, sizeof(unknown_map_type),
183 "<%u>", map_info->type);
184 unknown_map_type[sizeof(unknown_map_type) - 1] = '\0';
185 map_type = unknown_map_type;
186 } else {
187 map_type = map_type_strings[map_info->type];
188 }
189
190 printf("%8u %-15s 0x%-8x %8u %8u %8u %-15s\n",
191 map_info->id, map_type, map_info->map_flags, map_info->key_size,
192 map_info->value_size, map_info->max_entries,
193 map_info->name);
194 }
195
print_one_prog(uint32_t prog_id)196 static int print_one_prog(uint32_t prog_id)
197 {
198 const uint32_t usual_nr_map_ids = 64;
199 uint32_t nr_map_ids = usual_nr_map_ids;
200 struct bpf_prog_info prog_info;
201 uint32_t *map_ids = NULL;
202 uint32_t info_len;
203 int ret = 0;
204 int prog_fd;
205 uint32_t i;
206
207 prog_fd = bpf_prog_get_fd_by_id(prog_id);
208 if (prog_fd == -1) {
209 if (errno == ENOENT) {
210 fprintf(stderr, "BID:%u not found\n", prog_id);
211 return EX_DATAERR;
212 } else {
213 return handle_get_next_errno(errno);
214 }
215 }
216
217 /* Retry at most one time for larger map_ids array */
218 for (i = 0; i < 2; i++) {
219 bzero(&prog_info, sizeof(prog_info));
220 prog_info.map_ids = ptr_to_u64(realloc(map_ids,
221 nr_map_ids * sizeof(*map_ids)));
222 if (!prog_info.map_ids) {
223 fprintf(stderr,
224 "Cannot allocate memory for %u map_ids for BID:%u\n",
225 nr_map_ids, prog_id);
226 close(prog_fd);
227 free(map_ids);
228 return 1;
229 }
230
231 map_ids = u64_to_ptr(prog_info.map_ids);
232 prog_info.nr_map_ids = nr_map_ids;
233 info_len = sizeof(prog_info);
234 ret = bpf_obj_get_info(prog_fd, &prog_info, &info_len);
235 if (ret) {
236 fprintf(stderr, "Cannot get info for BID:%u. %s(%d)\n",
237 prog_id, strerror(errno), errno);
238 close(prog_fd);
239 free(map_ids);
240 return ret;
241 }
242
243 if (prog_info.nr_map_ids <= nr_map_ids)
244 break;
245
246 nr_map_ids = prog_info.nr_map_ids;
247 }
248 close(prog_fd);
249
250 print_prog_hdr();
251 print_prog_info(&prog_info);
252 printf("\n");
253
254 /* Print all map_info used by the prog */
255 print_map_hdr();
256 nr_map_ids = min(prog_info.nr_map_ids, nr_map_ids);
257 for (i = 0; i < nr_map_ids; i++) {
258 struct bpf_map_info map_info = {};
259 info_len = sizeof(map_info);
260 int map_fd;
261
262 map_fd = bpf_map_get_fd_by_id(map_ids[i]);
263 if (map_fd == -1) {
264 if (errno == -ENOENT)
265 continue;
266
267 fprintf(stderr,
268 "Cannot get fd for map:%u. %s(%d)\n",
269 map_ids[i], strerror(errno), errno);
270 ret = map_fd;
271 break;
272 }
273
274 ret = bpf_obj_get_info(map_fd, &map_info, &info_len);
275 close(map_fd);
276 if (ret) {
277 fprintf(stderr, "Cannot get info for map:%u. %s(%d)\n",
278 map_ids[i], strerror(errno), errno);
279 break;
280 }
281
282 print_map_info(&map_info);
283 }
284
285 free(map_ids);
286 return ret;
287 }
288
print_all_progs(void)289 int print_all_progs(void)
290 {
291 uint32_t next_id = 0;
292
293 print_prog_hdr();
294
295 while (!bpf_prog_get_next_id(next_id, &next_id)) {
296 struct bpf_prog_info prog_info = {};
297 uint32_t prog_info_len = sizeof(prog_info);
298 int prog_fd;
299 int ret;
300
301 prog_fd = bpf_prog_get_fd_by_id(next_id);
302 if (prog_fd < 0) {
303 if (errno == ENOENT)
304 continue;
305 fprintf(stderr,
306 "Cannot get fd for BID:%u. %s(%d)\n",
307 next_id, strerror(errno), errno);
308 return 1;
309 }
310
311 ret = bpf_obj_get_info(prog_fd, &prog_info, &prog_info_len);
312 close(prog_fd);
313 if (ret) {
314 fprintf(stderr,
315 "Cannot get bpf_prog_info for BID:%u. %s(%d)\n",
316 next_id, strerror(errno), errno);
317 return ret;
318 }
319
320 print_prog_info(&prog_info);
321 }
322
323 return handle_get_next_errno(errno);
324 }
325
usage(void)326 void usage(void)
327 {
328 printf("BPF Program Snapshot (bps):\n"
329 "List of all BPF programs loaded into the system.\n\n");
330 printf("Usage: bps [bpf-prog-id]\n");
331 printf(" [bpf-prog-id] If specified, it shows the details info of the bpf-prog\n");
332 printf("\n");
333 }
334
main(int argc,char ** argv)335 int main(int argc, char **argv)
336 {
337 if (argc > 1) {
338 if (!isdigit(*argv[1])) {
339 usage();
340 return EX_USAGE;
341 }
342 return print_one_prog((uint32_t)atoi(argv[1]));
343 }
344
345 return print_all_progs();
346 }
347