1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2 /* Copyright (c) 2022 Hengqi Chen */
3
4 #include "compat.h"
5 #include "trace_helpers.h"
6 #include <stdlib.h>
7 #include <errno.h>
8 #include <bpf/libbpf.h>
9
10 #define PERF_BUFFER_PAGES 64
11
12 struct bpf_buffer {
13 struct bpf_map *events;
14 void *inner;
15 bpf_buffer_sample_fn fn;
16 void *ctx;
17 int type;
18 };
19
perfbuf_sample_fn(void * ctx,int cpu,void * data,__u32 size)20 static void perfbuf_sample_fn(void *ctx, int cpu, void *data, __u32 size)
21 {
22 struct bpf_buffer *buffer = ctx;
23 bpf_buffer_sample_fn fn;
24
25 fn = buffer->fn;
26 if (!fn)
27 return;
28
29 (void)fn(buffer->ctx, data, size);
30 }
31
bpf_buffer__new(struct bpf_map * events,struct bpf_map * heap)32 struct bpf_buffer *bpf_buffer__new(struct bpf_map *events, struct bpf_map *heap)
33 {
34 struct bpf_buffer *buffer;
35 bool use_ringbuf;
36 int type;
37
38 use_ringbuf = probe_ringbuf();
39 if (use_ringbuf) {
40 bpf_map__set_autocreate(heap, false);
41 type = BPF_MAP_TYPE_RINGBUF;
42 } else {
43 bpf_map__set_type(events, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
44 bpf_map__set_key_size(events, sizeof(int));
45 bpf_map__set_value_size(events, sizeof(int));
46 type = BPF_MAP_TYPE_PERF_EVENT_ARRAY;
47 }
48
49 buffer = calloc(1, sizeof(*buffer));
50 if (!buffer) {
51 errno = ENOMEM;
52 return NULL;
53 }
54
55 buffer->events = events;
56 buffer->type = type;
57 return buffer;
58 }
59
bpf_buffer__open(struct bpf_buffer * buffer,bpf_buffer_sample_fn sample_cb,bpf_buffer_lost_fn lost_cb,void * ctx)60 int bpf_buffer__open(struct bpf_buffer *buffer, bpf_buffer_sample_fn sample_cb,
61 bpf_buffer_lost_fn lost_cb, void *ctx)
62 {
63 int fd, type;
64 void *inner;
65
66 fd = bpf_map__fd(buffer->events);
67 type = buffer->type;
68
69 switch (type) {
70 case BPF_MAP_TYPE_PERF_EVENT_ARRAY:
71 buffer->fn = sample_cb;
72 buffer->ctx = ctx;
73 inner = perf_buffer__new(fd, PERF_BUFFER_PAGES, perfbuf_sample_fn, lost_cb, buffer, NULL);
74 break;
75 case BPF_MAP_TYPE_RINGBUF:
76 inner = ring_buffer__new(fd, sample_cb, ctx, NULL);
77 break;
78 default:
79 return 0;
80 }
81
82 if (!inner)
83 return -errno;
84
85 buffer->inner = inner;
86 return 0;
87 }
88
bpf_buffer__poll(struct bpf_buffer * buffer,int timeout_ms)89 int bpf_buffer__poll(struct bpf_buffer *buffer, int timeout_ms)
90 {
91 switch (buffer->type) {
92 case BPF_MAP_TYPE_PERF_EVENT_ARRAY:
93 return perf_buffer__poll(buffer->inner, timeout_ms);
94 case BPF_MAP_TYPE_RINGBUF:
95 return ring_buffer__poll(buffer->inner, timeout_ms);
96 default:
97 return -EINVAL;
98 }
99 }
100
bpf_buffer__free(struct bpf_buffer * buffer)101 void bpf_buffer__free(struct bpf_buffer *buffer)
102 {
103 if (!buffer)
104 return;
105
106 switch (buffer->type) {
107 case BPF_MAP_TYPE_PERF_EVENT_ARRAY:
108 perf_buffer__free(buffer->inner);
109 break;
110 case BPF_MAP_TYPE_RINGBUF:
111 ring_buffer__free(buffer->inner);
112 break;
113 }
114 free(buffer);
115 }
116