• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 };
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 
ptr_to_u64(const void * ptr)91 static inline uint64_t ptr_to_u64(const void *ptr)
92 {
93   return (uint64_t) (unsigned long) ptr;
94 }
95 
u64_to_ptr(uint64_t ptr)96 static inline void * u64_to_ptr(uint64_t ptr)
97 {
98   return (void *) (unsigned long ) ptr;
99 }
100 
handle_get_next_errno(int eno)101 static 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 
print_prog_hdr(void)119 static void print_prog_hdr(void)
120 {
121   printf("%9s %-15s %8s %6s %-12s %-15s\n",
122          "BID", "TYPE", "UID", "#MAPS", "LoadTime", "NAME");
123 }
124 
print_prog_info(const struct bpf_prog_info * prog_info)125 static 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 
print_map_hdr(void)167 static 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 
print_map_info(const struct bpf_map_info * map_info)174 static 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 
print_one_prog(uint32_t prog_id)194 static 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 = {};
257     info_len = sizeof(map_info);
258     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 
print_all_progs(void)287 int 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 
usage(void)324 void 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 
main(int argc,char ** argv)333 int 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 }
345