aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakub Kicinski <jakub.kicinski@netronome.com>2018-05-10 13:24:40 -0400
committerDaniel Borkmann <daniel@iogearbox.net>2018-05-10 19:40:52 -0400
commitd0cabbb021bee5c4b831a0235af9534ad07f8d3d (patch)
tree7843337206d80588110d9112d49836624b09be64
parent5f9380572b4bb24f60cd492b17331db6ee34a516 (diff)
tools: bpf: move the event reading loop to libbpf
There are two copies of event reading loop - in bpftool and trace_helpers "library". Consolidate them and move the code to libbpf. Return codes from trace_helpers are kept, but renamed to include LIBBPF prefix. Suggested-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
-rw-r--r--samples/bpf/Makefile8
-rw-r--r--samples/bpf/trace_output_user.c6
-rw-r--r--tools/bpf/bpftool/map_perf_ring.c66
-rw-r--r--tools/lib/bpf/Makefile2
-rw-r--r--tools/lib/bpf/libbpf.c61
-rw-r--r--tools/lib/bpf/libbpf.h13
-rw-r--r--tools/testing/selftests/bpf/Makefile2
-rw-r--r--tools/testing/selftests/bpf/test_progs.c6
-rw-r--r--tools/testing/selftests/bpf/trace_helpers.c87
-rw-r--r--tools/testing/selftests/bpf/trace_helpers.h11
10 files changed, 139 insertions, 123 deletions
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index 79cdb66a5ea7..8ce72d211c3e 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -165,6 +165,14 @@ HOSTCFLAGS += -I$(srctree)/tools/lib/ -I$(srctree)/tools/include
165HOSTCFLAGS += -I$(srctree)/tools/perf 165HOSTCFLAGS += -I$(srctree)/tools/perf
166 166
167HOSTCFLAGS_bpf_load.o += -I$(objtree)/usr/include -Wno-unused-variable 167HOSTCFLAGS_bpf_load.o += -I$(objtree)/usr/include -Wno-unused-variable
168HOSTCFLAGS_trace_helpers.o += -I$(srctree)/tools/lib/bpf/
169
170HOSTCFLAGS_trace_output_user.o += -I$(srctree)/tools/lib/bpf/
171HOSTCFLAGS_offwaketime_user.o += -I$(srctree)/tools/lib/bpf/
172HOSTCFLAGS_spintest_user.o += -I$(srctree)/tools/lib/bpf/
173HOSTCFLAGS_trace_event_user.o += -I$(srctree)/tools/lib/bpf/
174HOSTCFLAGS_sampleip_user.o += -I$(srctree)/tools/lib/bpf/
175
168HOSTLOADLIBES_test_lru_dist += -lelf 176HOSTLOADLIBES_test_lru_dist += -lelf
169HOSTLOADLIBES_sock_example += -lelf 177HOSTLOADLIBES_sock_example += -lelf
170HOSTLOADLIBES_fds_example += -lelf 178HOSTLOADLIBES_fds_example += -lelf
diff --git a/samples/bpf/trace_output_user.c b/samples/bpf/trace_output_user.c
index 5e78c2ecd08d..da98be721001 100644
--- a/samples/bpf/trace_output_user.c
+++ b/samples/bpf/trace_output_user.c
@@ -48,7 +48,7 @@ static int print_bpf_output(void *data, int size)
48 if (e->cookie != 0x12345678) { 48 if (e->cookie != 0x12345678) {
49 printf("BUG pid %llx cookie %llx sized %d\n", 49 printf("BUG pid %llx cookie %llx sized %d\n",
50 e->pid, e->cookie, size); 50 e->pid, e->cookie, size);
51 return PERF_EVENT_ERROR; 51 return LIBBPF_PERF_EVENT_ERROR;
52 } 52 }
53 53
54 cnt++; 54 cnt++;
@@ -56,10 +56,10 @@ static int print_bpf_output(void *data, int size)
56 if (cnt == MAX_CNT) { 56 if (cnt == MAX_CNT) {
57 printf("recv %lld events per sec\n", 57 printf("recv %lld events per sec\n",
58 MAX_CNT * 1000000000ll / (time_get_ns() - start_time)); 58 MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
59 return PERF_EVENT_DONE; 59 return LIBBPF_PERF_EVENT_DONE;
60 } 60 }
61 61
62 return PERF_EVENT_CONT; 62 return LIBBPF_PERF_EVENT_CONT;
63} 63}
64 64
65static void test_bpf_perf_event(void) 65static void test_bpf_perf_event(void)
diff --git a/tools/bpf/bpftool/map_perf_ring.c b/tools/bpf/bpftool/map_perf_ring.c
index 9ae4bb8a2cad..1832100d1b27 100644
--- a/tools/bpf/bpftool/map_perf_ring.c
+++ b/tools/bpf/bpftool/map_perf_ring.c
@@ -50,14 +50,15 @@ static void int_exit(int signo)
50 stop = true; 50 stop = true;
51} 51}
52 52
53static void 53static enum bpf_perf_event_ret print_bpf_output(void *event, void *priv)
54print_bpf_output(struct event_ring_info *ring, struct perf_event_sample *e)
55{ 54{
55 struct event_ring_info *ring = priv;
56 struct perf_event_sample *e = event;
56 struct { 57 struct {
57 struct perf_event_header header; 58 struct perf_event_header header;
58 __u64 id; 59 __u64 id;
59 __u64 lost; 60 __u64 lost;
60 } *lost = (void *)e; 61 } *lost = event;
61 62
62 if (json_output) { 63 if (json_output) {
63 jsonw_start_object(json_wtr); 64 jsonw_start_object(json_wtr);
@@ -96,60 +97,23 @@ print_bpf_output(struct event_ring_info *ring, struct perf_event_sample *e)
96 e->header.type, e->header.size); 97 e->header.type, e->header.size);
97 } 98 }
98 } 99 }
100
101 return LIBBPF_PERF_EVENT_CONT;
99} 102}
100 103
101static void 104static void
102perf_event_read(struct event_ring_info *ring, void **buf, size_t *buf_len) 105perf_event_read(struct event_ring_info *ring, void **buf, size_t *buf_len)
103{ 106{
104 volatile struct perf_event_mmap_page *header = ring->mem; 107 enum bpf_perf_event_ret ret;
105 __u64 buffer_size = MMAP_PAGE_CNT * get_page_size(); 108
106 __u64 data_tail = header->data_tail; 109 ret = bpf_perf_event_read_simple(ring->mem,
107 __u64 data_head = header->data_head; 110 MMAP_PAGE_CNT * get_page_size(),
108 void *base, *begin, *end; 111 get_page_size(), buf, buf_len,
109 112 print_bpf_output, ring);
110 asm volatile("" ::: "memory"); /* in real code it should be smp_rmb() */ 113 if (ret != LIBBPF_PERF_EVENT_CONT) {
111 if (data_head == data_tail) 114 fprintf(stderr, "perf read loop failed with %d\n", ret);
112 return; 115 stop = true;
113
114 base = ((char *)header) + get_page_size();
115
116 begin = base + data_tail % buffer_size;
117 end = base + data_head % buffer_size;
118
119 while (begin != end) {
120 struct perf_event_sample *e;
121
122 e = begin;
123 if (begin + e->header.size > base + buffer_size) {
124 long len = base + buffer_size - begin;
125
126 if (*buf_len < e->header.size) {
127 free(*buf);
128 *buf = malloc(e->header.size);
129 if (!*buf) {
130 fprintf(stderr,
131 "can't allocate memory");
132 stop = true;
133 return;
134 }
135 *buf_len = e->header.size;
136 }
137
138 memcpy(*buf, begin, len);
139 memcpy(*buf + len, base, e->header.size - len);
140 e = (void *)*buf;
141 begin = base + e->header.size - len;
142 } else if (begin + e->header.size == base + buffer_size) {
143 begin = base;
144 } else {
145 begin += e->header.size;
146 }
147
148 print_bpf_output(ring, e);
149 } 116 }
150
151 __sync_synchronize(); /* smp_mb() */
152 header->data_tail = data_head;
153} 117}
154 118
155static int perf_mmap_size(void) 119static int perf_mmap_size(void)
diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile
index e6d5f8d1477f..f3fab4af4260 100644
--- a/tools/lib/bpf/Makefile
+++ b/tools/lib/bpf/Makefile
@@ -69,7 +69,7 @@ FEATURE_USER = .libbpf
69FEATURE_TESTS = libelf libelf-getphdrnum libelf-mmap bpf 69FEATURE_TESTS = libelf libelf-getphdrnum libelf-mmap bpf
70FEATURE_DISPLAY = libelf bpf 70FEATURE_DISPLAY = libelf bpf
71 71
72INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi 72INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi -I$(srctree)/tools/perf
73FEATURE_CHECK_CFLAGS-bpf = $(INCLUDES) 73FEATURE_CHECK_CFLAGS-bpf = $(INCLUDES)
74 74
75check_feat := 1 75check_feat := 1
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 7bcdca13083a..ce96f1fe3f37 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -31,6 +31,7 @@
31#include <unistd.h> 31#include <unistd.h>
32#include <fcntl.h> 32#include <fcntl.h>
33#include <errno.h> 33#include <errno.h>
34#include <perf-sys.h>
34#include <asm/unistd.h> 35#include <asm/unistd.h>
35#include <linux/err.h> 36#include <linux/err.h>
36#include <linux/kernel.h> 37#include <linux/kernel.h>
@@ -2210,3 +2211,63 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
2210 *prog_fd = bpf_program__fd(first_prog); 2211 *prog_fd = bpf_program__fd(first_prog);
2211 return 0; 2212 return 0;
2212} 2213}
2214
2215enum bpf_perf_event_ret
2216bpf_perf_event_read_simple(void *mem, unsigned long size,
2217 unsigned long page_size, void **buf, size_t *buf_len,
2218 bpf_perf_event_print_t fn, void *priv)
2219{
2220 volatile struct perf_event_mmap_page *header = mem;
2221 __u64 data_tail = header->data_tail;
2222 __u64 data_head = header->data_head;
2223 void *base, *begin, *end;
2224 int ret;
2225
2226 asm volatile("" ::: "memory"); /* in real code it should be smp_rmb() */
2227 if (data_head == data_tail)
2228 return LIBBPF_PERF_EVENT_CONT;
2229
2230 base = ((char *)header) + page_size;
2231
2232 begin = base + data_tail % size;
2233 end = base + data_head % size;
2234
2235 while (begin != end) {
2236 struct perf_event_header *ehdr;
2237
2238 ehdr = begin;
2239 if (begin + ehdr->size > base + size) {
2240 long len = base + size - begin;
2241
2242 if (*buf_len < ehdr->size) {
2243 free(*buf);
2244 *buf = malloc(ehdr->size);
2245 if (!*buf) {
2246 ret = LIBBPF_PERF_EVENT_ERROR;
2247 break;
2248 }
2249 *buf_len = ehdr->size;
2250 }
2251
2252 memcpy(*buf, begin, len);
2253 memcpy(*buf + len, base, ehdr->size - len);
2254 ehdr = (void *)*buf;
2255 begin = base + ehdr->size - len;
2256 } else if (begin + ehdr->size == base + size) {
2257 begin = base;
2258 } else {
2259 begin += ehdr->size;
2260 }
2261
2262 ret = fn(ehdr, priv);
2263 if (ret != LIBBPF_PERF_EVENT_CONT)
2264 break;
2265
2266 data_tail += ehdr->size;
2267 }
2268
2269 __sync_synchronize(); /* smp_mb() */
2270 header->data_tail = data_tail;
2271
2272 return ret;
2273}
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 197f9ce2248c..ce681097584e 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -267,4 +267,17 @@ int bpf_prog_load(const char *file, enum bpf_prog_type type,
267 struct bpf_object **pobj, int *prog_fd); 267 struct bpf_object **pobj, int *prog_fd);
268 268
269int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags); 269int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags);
270
271enum bpf_perf_event_ret {
272 LIBBPF_PERF_EVENT_DONE = 0,
273 LIBBPF_PERF_EVENT_ERROR = -1,
274 LIBBPF_PERF_EVENT_CONT = -2,
275};
276
277typedef enum bpf_perf_event_ret (*bpf_perf_event_print_t)(void *event,
278 void *priv);
279int bpf_perf_event_read_simple(void *mem, unsigned long size,
280 unsigned long page_size,
281 void **buf, size_t *buf_len,
282 bpf_perf_event_print_t fn, void *priv);
270#endif 283#endif
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 79d29d6cc719..438d4f93875b 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -10,7 +10,7 @@ ifneq ($(wildcard $(GENHDR)),)
10 GENFLAGS := -DHAVE_GENHDR 10 GENFLAGS := -DHAVE_GENHDR
11endif 11endif
12 12
13CFLAGS += -Wall -O2 -I$(APIDIR) -I$(LIBDIR) -I$(GENDIR) $(GENFLAGS) -I../../../include 13CFLAGS += -Wall -O2 -I$(APIDIR) -I$(LIBDIR) -I$(BPFDIR) -I$(GENDIR) $(GENFLAGS) -I../../../include
14LDLIBS += -lcap -lelf -lrt -lpthread 14LDLIBS += -lcap -lelf -lrt -lpthread
15 15
16TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read 16TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read
diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c
index ed197eef1cfc..f7731973ec68 100644
--- a/tools/testing/selftests/bpf/test_progs.c
+++ b/tools/testing/selftests/bpf/test_progs.c
@@ -1337,12 +1337,12 @@ static int get_stack_print_output(void *data, int size)
1337 good_user_stack = true; 1337 good_user_stack = true;
1338 } 1338 }
1339 if (!good_kern_stack || !good_user_stack) 1339 if (!good_kern_stack || !good_user_stack)
1340 return PERF_EVENT_ERROR; 1340 return LIBBPF_PERF_EVENT_ERROR;
1341 1341
1342 if (cnt == MAX_CNT_RAWTP) 1342 if (cnt == MAX_CNT_RAWTP)
1343 return PERF_EVENT_DONE; 1343 return LIBBPF_PERF_EVENT_DONE;
1344 1344
1345 return PERF_EVENT_CONT; 1345 return LIBBPF_PERF_EVENT_CONT;
1346} 1346}
1347 1347
1348static void test_get_stack_raw_tp(void) 1348static void test_get_stack_raw_tp(void)
diff --git a/tools/testing/selftests/bpf/trace_helpers.c b/tools/testing/selftests/bpf/trace_helpers.c
index ad025bd75f1c..8fb4fe8686e4 100644
--- a/tools/testing/selftests/bpf/trace_helpers.c
+++ b/tools/testing/selftests/bpf/trace_helpers.c
@@ -74,7 +74,7 @@ struct ksym *ksym_search(long key)
74 74
75static int page_size; 75static int page_size;
76static int page_cnt = 8; 76static int page_cnt = 8;
77static volatile struct perf_event_mmap_page *header; 77static struct perf_event_mmap_page *header;
78 78
79int perf_event_mmap(int fd) 79int perf_event_mmap(int fd)
80{ 80{
@@ -107,74 +107,47 @@ struct perf_event_sample {
107 char data[]; 107 char data[];
108}; 108};
109 109
110static int perf_event_read(perf_event_print_fn fn) 110static enum bpf_perf_event_ret bpf_perf_event_print(void *event, void *priv)
111{ 111{
112 __u64 data_tail = header->data_tail; 112 struct perf_event_sample *e = event;
113 __u64 data_head = header->data_head; 113 perf_event_print_fn fn = priv;
114 __u64 buffer_size = page_cnt * page_size;
115 void *base, *begin, *end;
116 char buf[256];
117 int ret; 114 int ret;
118 115
119 asm volatile("" ::: "memory"); /* in real code it should be smp_rmb() */ 116 if (e->header.type == PERF_RECORD_SAMPLE) {
120 if (data_head == data_tail) 117 ret = fn(e->data, e->size);
121 return PERF_EVENT_CONT; 118 if (ret != LIBBPF_PERF_EVENT_CONT)
122 119 return ret;
123 base = ((char *)header) + page_size; 120 } else if (e->header.type == PERF_RECORD_LOST) {
124 121 struct {
125 begin = base + data_tail % buffer_size; 122 struct perf_event_header header;
126 end = base + data_head % buffer_size; 123 __u64 id;
127 124 __u64 lost;
128 while (begin != end) { 125 } *lost = (void *) e;
129 struct perf_event_sample *e; 126 printf("lost %lld events\n", lost->lost);
130 127 } else {
131 e = begin; 128 printf("unknown event type=%d size=%d\n",
132 if (begin + e->header.size > base + buffer_size) { 129 e->header.type, e->header.size);
133 long len = base + buffer_size - begin;
134
135 assert(len < e->header.size);
136 memcpy(buf, begin, len);
137 memcpy(buf + len, base, e->header.size - len);
138 e = (void *) buf;
139 begin = base + e->header.size - len;
140 } else if (begin + e->header.size == base + buffer_size) {
141 begin = base;
142 } else {
143 begin += e->header.size;
144 }
145
146 if (e->header.type == PERF_RECORD_SAMPLE) {
147 ret = fn(e->data, e->size);
148 if (ret != PERF_EVENT_CONT)
149 return ret;
150 } else if (e->header.type == PERF_RECORD_LOST) {
151 struct {
152 struct perf_event_header header;
153 __u64 id;
154 __u64 lost;
155 } *lost = (void *) e;
156 printf("lost %lld events\n", lost->lost);
157 } else {
158 printf("unknown event type=%d size=%d\n",
159 e->header.type, e->header.size);
160 }
161 } 130 }
162 131
163 __sync_synchronize(); /* smp_mb() */ 132 return LIBBPF_PERF_EVENT_CONT;
164 header->data_tail = data_head;
165 return PERF_EVENT_CONT;
166} 133}
167 134
168int perf_event_poller(int fd, perf_event_print_fn output_fn) 135int perf_event_poller(int fd, perf_event_print_fn output_fn)
169{ 136{
170 int ret; 137 enum bpf_perf_event_ret ret;
138 void *buf = NULL;
139 size_t len = 0;
171 140
172 for (;;) { 141 for (;;) {
173 perf_event_poll(fd); 142 perf_event_poll(fd);
174 ret = perf_event_read(output_fn); 143 ret = bpf_perf_event_read_simple(header, page_cnt * page_size,
175 if (ret != PERF_EVENT_CONT) 144 page_size, &buf, &len,
176 return ret; 145 bpf_perf_event_print,
146 output_fn);
147 if (ret != LIBBPF_PERF_EVENT_CONT)
148 break;
177 } 149 }
150 free(buf);
178 151
179 return PERF_EVENT_DONE; 152 return ret;
180} 153}
diff --git a/tools/testing/selftests/bpf/trace_helpers.h b/tools/testing/selftests/bpf/trace_helpers.h
index fe3eefd21e86..36d90e3b1ea9 100644
--- a/tools/testing/selftests/bpf/trace_helpers.h
+++ b/tools/testing/selftests/bpf/trace_helpers.h
@@ -2,6 +2,8 @@
2#ifndef __TRACE_HELPER_H 2#ifndef __TRACE_HELPER_H
3#define __TRACE_HELPER_H 3#define __TRACE_HELPER_H
4 4
5#include <libbpf.h>
6
5struct ksym { 7struct ksym {
6 long addr; 8 long addr;
7 char *name; 9 char *name;
@@ -10,14 +12,9 @@ struct ksym {
10int load_kallsyms(void); 12int load_kallsyms(void);
11struct ksym *ksym_search(long key); 13struct ksym *ksym_search(long key);
12 14
13typedef int (*perf_event_print_fn)(void *data, int size); 15typedef enum bpf_perf_event_ret (*perf_event_print_fn)(void *data, int size);
14
15/* return code for perf_event_print_fn */
16#define PERF_EVENT_DONE 0
17#define PERF_EVENT_ERROR -1
18#define PERF_EVENT_CONT -2
19 16
20int perf_event_mmap(int fd); 17int perf_event_mmap(int fd);
21/* return PERF_EVENT_DONE or PERF_EVENT_ERROR */ 18/* return LIBBPF_PERF_EVENT_DONE or LIBBPF_PERF_EVENT_ERROR */
22int perf_event_poller(int fd, perf_event_print_fn output_fn); 19int perf_event_poller(int fd, perf_event_print_fn output_fn);
23#endif 20#endif