aboutsummaryrefslogtreecommitdiffstats
path: root/samples
diff options
context:
space:
mode:
Diffstat (limited to 'samples')
-rw-r--r--samples/bpf/Makefile4
-rw-r--r--samples/bpf/bpf_helpers.h6
-rw-r--r--samples/bpf/bpf_load.c125
-rw-r--r--samples/bpf/bpf_load.h3
-rw-r--r--samples/bpf/libbpf.c14
-rw-r--r--samples/bpf/libbpf.h5
-rw-r--r--samples/bpf/sock_example.c2
-rw-r--r--samples/bpf/test_verifier.c2
-rw-r--r--samples/bpf/tracex1_kern.c50
-rw-r--r--samples/bpf/tracex1_user.c25
10 files changed, 224 insertions, 12 deletions
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index b5b3600dcdf5..51f6f01e5a3a 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -6,23 +6,27 @@ hostprogs-y := test_verifier test_maps
6hostprogs-y += sock_example 6hostprogs-y += sock_example
7hostprogs-y += sockex1 7hostprogs-y += sockex1
8hostprogs-y += sockex2 8hostprogs-y += sockex2
9hostprogs-y += tracex1
9 10
10test_verifier-objs := test_verifier.o libbpf.o 11test_verifier-objs := test_verifier.o libbpf.o
11test_maps-objs := test_maps.o libbpf.o 12test_maps-objs := test_maps.o libbpf.o
12sock_example-objs := sock_example.o libbpf.o 13sock_example-objs := sock_example.o libbpf.o
13sockex1-objs := bpf_load.o libbpf.o sockex1_user.o 14sockex1-objs := bpf_load.o libbpf.o sockex1_user.o
14sockex2-objs := bpf_load.o libbpf.o sockex2_user.o 15sockex2-objs := bpf_load.o libbpf.o sockex2_user.o
16tracex1-objs := bpf_load.o libbpf.o tracex1_user.o
15 17
16# Tell kbuild to always build the programs 18# Tell kbuild to always build the programs
17always := $(hostprogs-y) 19always := $(hostprogs-y)
18always += sockex1_kern.o 20always += sockex1_kern.o
19always += sockex2_kern.o 21always += sockex2_kern.o
22always += tracex1_kern.o
20 23
21HOSTCFLAGS += -I$(objtree)/usr/include 24HOSTCFLAGS += -I$(objtree)/usr/include
22 25
23HOSTCFLAGS_bpf_load.o += -I$(objtree)/usr/include -Wno-unused-variable 26HOSTCFLAGS_bpf_load.o += -I$(objtree)/usr/include -Wno-unused-variable
24HOSTLOADLIBES_sockex1 += -lelf 27HOSTLOADLIBES_sockex1 += -lelf
25HOSTLOADLIBES_sockex2 += -lelf 28HOSTLOADLIBES_sockex2 += -lelf
29HOSTLOADLIBES_tracex1 += -lelf
26 30
27# point this to your LLVM backend with bpf support 31# point this to your LLVM backend with bpf support
28LLC=$(srctree)/tools/bpf/llvm/bld/Debug+Asserts/bin/llc 32LLC=$(srctree)/tools/bpf/llvm/bld/Debug+Asserts/bin/llc
diff --git a/samples/bpf/bpf_helpers.h b/samples/bpf/bpf_helpers.h
index ca0333146006..1c872bcf5a80 100644
--- a/samples/bpf/bpf_helpers.h
+++ b/samples/bpf/bpf_helpers.h
@@ -15,6 +15,12 @@ static int (*bpf_map_update_elem)(void *map, void *key, void *value,
15 (void *) BPF_FUNC_map_update_elem; 15 (void *) BPF_FUNC_map_update_elem;
16static int (*bpf_map_delete_elem)(void *map, void *key) = 16static int (*bpf_map_delete_elem)(void *map, void *key) =
17 (void *) BPF_FUNC_map_delete_elem; 17 (void *) BPF_FUNC_map_delete_elem;
18static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) =
19 (void *) BPF_FUNC_probe_read;
20static unsigned long long (*bpf_ktime_get_ns)(void) =
21 (void *) BPF_FUNC_ktime_get_ns;
22static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) =
23 (void *) BPF_FUNC_trace_printk;
18 24
19/* llvm builtin functions that eBPF C program may use to 25/* llvm builtin functions that eBPF C program may use to
20 * emit BPF_LD_ABS and BPF_LD_IND instructions 26 * emit BPF_LD_ABS and BPF_LD_IND instructions
diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c
index 1831d236382b..38dac5a53b51 100644
--- a/samples/bpf/bpf_load.c
+++ b/samples/bpf/bpf_load.c
@@ -8,29 +8,70 @@
8#include <unistd.h> 8#include <unistd.h>
9#include <string.h> 9#include <string.h>
10#include <stdbool.h> 10#include <stdbool.h>
11#include <stdlib.h>
11#include <linux/bpf.h> 12#include <linux/bpf.h>
12#include <linux/filter.h> 13#include <linux/filter.h>
14#include <linux/perf_event.h>
15#include <sys/syscall.h>
16#include <sys/ioctl.h>
17#include <sys/mman.h>
18#include <poll.h>
13#include "libbpf.h" 19#include "libbpf.h"
14#include "bpf_helpers.h" 20#include "bpf_helpers.h"
15#include "bpf_load.h" 21#include "bpf_load.h"
16 22
23#define DEBUGFS "/sys/kernel/debug/tracing/"
24
17static char license[128]; 25static char license[128];
26static int kern_version;
18static bool processed_sec[128]; 27static bool processed_sec[128];
19int map_fd[MAX_MAPS]; 28int map_fd[MAX_MAPS];
20int prog_fd[MAX_PROGS]; 29int prog_fd[MAX_PROGS];
30int event_fd[MAX_PROGS];
21int prog_cnt; 31int prog_cnt;
22 32
23static int load_and_attach(const char *event, struct bpf_insn *prog, int size) 33static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
24{ 34{
25 int fd;
26 bool is_socket = strncmp(event, "socket", 6) == 0; 35 bool is_socket = strncmp(event, "socket", 6) == 0;
27 36 bool is_kprobe = strncmp(event, "kprobe/", 7) == 0;
28 if (!is_socket) 37 bool is_kretprobe = strncmp(event, "kretprobe/", 10) == 0;
29 /* tracing events tbd */ 38 enum bpf_prog_type prog_type;
39 char buf[256];
40 int fd, efd, err, id;
41 struct perf_event_attr attr = {};
42
43 attr.type = PERF_TYPE_TRACEPOINT;
44 attr.sample_type = PERF_SAMPLE_RAW;
45 attr.sample_period = 1;
46 attr.wakeup_events = 1;
47
48 if (is_socket) {
49 prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
50 } else if (is_kprobe || is_kretprobe) {
51 prog_type = BPF_PROG_TYPE_KPROBE;
52 } else {
53 printf("Unknown event '%s'\n", event);
30 return -1; 54 return -1;
55 }
56
57 if (is_kprobe || is_kretprobe) {
58 if (is_kprobe)
59 event += 7;
60 else
61 event += 10;
62
63 snprintf(buf, sizeof(buf),
64 "echo '%c:%s %s' >> /sys/kernel/debug/tracing/kprobe_events",
65 is_kprobe ? 'p' : 'r', event, event);
66 err = system(buf);
67 if (err < 0) {
68 printf("failed to create kprobe '%s' error '%s'\n",
69 event, strerror(errno));
70 return -1;
71 }
72 }
31 73
32 fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, 74 fd = bpf_prog_load(prog_type, prog, size, license, kern_version);
33 prog, size, license);
34 75
35 if (fd < 0) { 76 if (fd < 0) {
36 printf("bpf_prog_load() err=%d\n%s", errno, bpf_log_buf); 77 printf("bpf_prog_load() err=%d\n%s", errno, bpf_log_buf);
@@ -39,6 +80,41 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
39 80
40 prog_fd[prog_cnt++] = fd; 81 prog_fd[prog_cnt++] = fd;
41 82
83 if (is_socket)
84 return 0;
85
86 strcpy(buf, DEBUGFS);
87 strcat(buf, "events/kprobes/");
88 strcat(buf, event);
89 strcat(buf, "/id");
90
91 efd = open(buf, O_RDONLY, 0);
92 if (efd < 0) {
93 printf("failed to open event %s\n", event);
94 return -1;
95 }
96
97 err = read(efd, buf, sizeof(buf));
98 if (err < 0 || err >= sizeof(buf)) {
99 printf("read from '%s' failed '%s'\n", event, strerror(errno));
100 return -1;
101 }
102
103 close(efd);
104
105 buf[err] = 0;
106 id = atoi(buf);
107 attr.config = id;
108
109 efd = perf_event_open(&attr, -1/*pid*/, 0/*cpu*/, -1/*group_fd*/, 0);
110 if (efd < 0) {
111 printf("event %d fd %d err %s\n", id, efd, strerror(errno));
112 return -1;
113 }
114 event_fd[prog_cnt - 1] = efd;
115 ioctl(efd, PERF_EVENT_IOC_ENABLE, 0);
116 ioctl(efd, PERF_EVENT_IOC_SET_BPF, fd);
117
42 return 0; 118 return 0;
43} 119}
44 120
@@ -135,6 +211,9 @@ int load_bpf_file(char *path)
135 if (gelf_getehdr(elf, &ehdr) != &ehdr) 211 if (gelf_getehdr(elf, &ehdr) != &ehdr)
136 return 1; 212 return 1;
137 213
214 /* clear all kprobes */
215 i = system("echo \"\" > /sys/kernel/debug/tracing/kprobe_events");
216
138 /* scan over all elf sections to get license and map info */ 217 /* scan over all elf sections to get license and map info */
139 for (i = 1; i < ehdr.e_shnum; i++) { 218 for (i = 1; i < ehdr.e_shnum; i++) {
140 219
@@ -149,6 +228,14 @@ int load_bpf_file(char *path)
149 if (strcmp(shname, "license") == 0) { 228 if (strcmp(shname, "license") == 0) {
150 processed_sec[i] = true; 229 processed_sec[i] = true;
151 memcpy(license, data->d_buf, data->d_size); 230 memcpy(license, data->d_buf, data->d_size);
231 } else if (strcmp(shname, "version") == 0) {
232 processed_sec[i] = true;
233 if (data->d_size != sizeof(int)) {
234 printf("invalid size of version section %zd\n",
235 data->d_size);
236 return 1;
237 }
238 memcpy(&kern_version, data->d_buf, sizeof(int));
152 } else if (strcmp(shname, "maps") == 0) { 239 } else if (strcmp(shname, "maps") == 0) {
153 processed_sec[i] = true; 240 processed_sec[i] = true;
154 if (load_maps(data->d_buf, data->d_size)) 241 if (load_maps(data->d_buf, data->d_size))
@@ -178,7 +265,8 @@ int load_bpf_file(char *path)
178 if (parse_relo_and_apply(data, symbols, &shdr, insns)) 265 if (parse_relo_and_apply(data, symbols, &shdr, insns))
179 continue; 266 continue;
180 267
181 if (memcmp(shname_prog, "events/", 7) == 0 || 268 if (memcmp(shname_prog, "kprobe/", 7) == 0 ||
269 memcmp(shname_prog, "kretprobe/", 10) == 0 ||
182 memcmp(shname_prog, "socket", 6) == 0) 270 memcmp(shname_prog, "socket", 6) == 0)
183 load_and_attach(shname_prog, insns, data_prog->d_size); 271 load_and_attach(shname_prog, insns, data_prog->d_size);
184 } 272 }
@@ -193,7 +281,8 @@ int load_bpf_file(char *path)
193 if (get_sec(elf, i, &ehdr, &shname, &shdr, &data)) 281 if (get_sec(elf, i, &ehdr, &shname, &shdr, &data))
194 continue; 282 continue;
195 283
196 if (memcmp(shname, "events/", 7) == 0 || 284 if (memcmp(shname, "kprobe/", 7) == 0 ||
285 memcmp(shname, "kretprobe/", 10) == 0 ||
197 memcmp(shname, "socket", 6) == 0) 286 memcmp(shname, "socket", 6) == 0)
198 load_and_attach(shname, data->d_buf, data->d_size); 287 load_and_attach(shname, data->d_buf, data->d_size);
199 } 288 }
@@ -201,3 +290,23 @@ int load_bpf_file(char *path)
201 close(fd); 290 close(fd);
202 return 0; 291 return 0;
203} 292}
293
294void read_trace_pipe(void)
295{
296 int trace_fd;
297
298 trace_fd = open(DEBUGFS "trace_pipe", O_RDONLY, 0);
299 if (trace_fd < 0)
300 return;
301
302 while (1) {
303 static char buf[4096];
304 ssize_t sz;
305
306 sz = read(trace_fd, buf, sizeof(buf));
307 if (sz > 0) {
308 buf[sz] = 0;
309 puts(buf);
310 }
311 }
312}
diff --git a/samples/bpf/bpf_load.h b/samples/bpf/bpf_load.h
index 27789a34f5e6..cbd7c2b532b9 100644
--- a/samples/bpf/bpf_load.h
+++ b/samples/bpf/bpf_load.h
@@ -6,6 +6,7 @@
6 6
7extern int map_fd[MAX_MAPS]; 7extern int map_fd[MAX_MAPS];
8extern int prog_fd[MAX_PROGS]; 8extern int prog_fd[MAX_PROGS];
9extern int event_fd[MAX_PROGS];
9 10
10/* parses elf file compiled by llvm .c->.o 11/* parses elf file compiled by llvm .c->.o
11 * . parses 'maps' section and creates maps via BPF syscall 12 * . parses 'maps' section and creates maps via BPF syscall
@@ -21,4 +22,6 @@ extern int prog_fd[MAX_PROGS];
21 */ 22 */
22int load_bpf_file(char *path); 23int load_bpf_file(char *path);
23 24
25void read_trace_pipe(void);
26
24#endif 27#endif
diff --git a/samples/bpf/libbpf.c b/samples/bpf/libbpf.c
index 46d50b7ddf79..7e1efa7e2ed7 100644
--- a/samples/bpf/libbpf.c
+++ b/samples/bpf/libbpf.c
@@ -81,7 +81,7 @@ char bpf_log_buf[LOG_BUF_SIZE];
81 81
82int bpf_prog_load(enum bpf_prog_type prog_type, 82int bpf_prog_load(enum bpf_prog_type prog_type,
83 const struct bpf_insn *insns, int prog_len, 83 const struct bpf_insn *insns, int prog_len,
84 const char *license) 84 const char *license, int kern_version)
85{ 85{
86 union bpf_attr attr = { 86 union bpf_attr attr = {
87 .prog_type = prog_type, 87 .prog_type = prog_type,
@@ -93,6 +93,11 @@ int bpf_prog_load(enum bpf_prog_type prog_type,
93 .log_level = 1, 93 .log_level = 1,
94 }; 94 };
95 95
96 /* assign one field outside of struct init to make sure any
97 * padding is zero initialized
98 */
99 attr.kern_version = kern_version;
100
96 bpf_log_buf[0] = 0; 101 bpf_log_buf[0] = 0;
97 102
98 return syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr)); 103 return syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
@@ -121,3 +126,10 @@ int open_raw_sock(const char *name)
121 126
122 return sock; 127 return sock;
123} 128}
129
130int perf_event_open(struct perf_event_attr *attr, int pid, int cpu,
131 int group_fd, unsigned long flags)
132{
133 return syscall(__NR_perf_event_open, attr, pid, cpu,
134 group_fd, flags);
135}
diff --git a/samples/bpf/libbpf.h b/samples/bpf/libbpf.h
index 58c5fe1bdba1..ac7b09672b46 100644
--- a/samples/bpf/libbpf.h
+++ b/samples/bpf/libbpf.h
@@ -13,7 +13,7 @@ int bpf_get_next_key(int fd, void *key, void *next_key);
13 13
14int bpf_prog_load(enum bpf_prog_type prog_type, 14int bpf_prog_load(enum bpf_prog_type prog_type,
15 const struct bpf_insn *insns, int insn_len, 15 const struct bpf_insn *insns, int insn_len,
16 const char *license); 16 const char *license, int kern_version);
17 17
18#define LOG_BUF_SIZE 65536 18#define LOG_BUF_SIZE 65536
19extern char bpf_log_buf[LOG_BUF_SIZE]; 19extern char bpf_log_buf[LOG_BUF_SIZE];
@@ -182,4 +182,7 @@ extern char bpf_log_buf[LOG_BUF_SIZE];
182/* create RAW socket and bind to interface 'name' */ 182/* create RAW socket and bind to interface 'name' */
183int open_raw_sock(const char *name); 183int open_raw_sock(const char *name);
184 184
185struct perf_event_attr;
186int perf_event_open(struct perf_event_attr *attr, int pid, int cpu,
187 int group_fd, unsigned long flags);
185#endif 188#endif
diff --git a/samples/bpf/sock_example.c b/samples/bpf/sock_example.c
index c8ad0404416f..a0ce251c5390 100644
--- a/samples/bpf/sock_example.c
+++ b/samples/bpf/sock_example.c
@@ -56,7 +56,7 @@ static int test_sock(void)
56 }; 56 };
57 57
58 prog_fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, prog, sizeof(prog), 58 prog_fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, prog, sizeof(prog),
59 "GPL"); 59 "GPL", 0);
60 if (prog_fd < 0) { 60 if (prog_fd < 0) {
61 printf("failed to load prog '%s'\n", strerror(errno)); 61 printf("failed to load prog '%s'\n", strerror(errno));
62 goto cleanup; 62 goto cleanup;
diff --git a/samples/bpf/test_verifier.c b/samples/bpf/test_verifier.c
index b96175e90363..740ce97cda5e 100644
--- a/samples/bpf/test_verifier.c
+++ b/samples/bpf/test_verifier.c
@@ -689,7 +689,7 @@ static int test(void)
689 689
690 prog_fd = bpf_prog_load(BPF_PROG_TYPE_UNSPEC, prog, 690 prog_fd = bpf_prog_load(BPF_PROG_TYPE_UNSPEC, prog,
691 prog_len * sizeof(struct bpf_insn), 691 prog_len * sizeof(struct bpf_insn),
692 "GPL"); 692 "GPL", 0);
693 693
694 if (tests[i].result == ACCEPT) { 694 if (tests[i].result == ACCEPT) {
695 if (prog_fd < 0) { 695 if (prog_fd < 0) {
diff --git a/samples/bpf/tracex1_kern.c b/samples/bpf/tracex1_kern.c
new file mode 100644
index 000000000000..31620463701a
--- /dev/null
+++ b/samples/bpf/tracex1_kern.c
@@ -0,0 +1,50 @@
1/* Copyright (c) 2013-2015 PLUMgrid, http://plumgrid.com
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of version 2 of the GNU General Public
5 * License as published by the Free Software Foundation.
6 */
7#include <linux/skbuff.h>
8#include <linux/netdevice.h>
9#include <uapi/linux/bpf.h>
10#include <linux/version.h>
11#include "bpf_helpers.h"
12
13#define _(P) ({typeof(P) val = 0; bpf_probe_read(&val, sizeof(val), &P); val;})
14
15/* kprobe is NOT a stable ABI
16 * kernel functions can be removed, renamed or completely change semantics.
17 * Number of arguments and their positions can change, etc.
18 * In such case this bpf+kprobe example will no longer be meaningful
19 */
20SEC("kprobe/__netif_receive_skb_core")
21int bpf_prog1(struct pt_regs *ctx)
22{
23 /* attaches to kprobe netif_receive_skb,
24 * looks for packets on loobpack device and prints them
25 */
26 char devname[IFNAMSIZ] = {};
27 struct net_device *dev;
28 struct sk_buff *skb;
29 int len;
30
31 /* non-portable! works for the given kernel only */
32 skb = (struct sk_buff *) ctx->di;
33
34 dev = _(skb->dev);
35
36 len = _(skb->len);
37
38 bpf_probe_read(devname, sizeof(devname), dev->name);
39
40 if (devname[0] == 'l' && devname[1] == 'o') {
41 char fmt[] = "skb %p len %d\n";
42 /* using bpf_trace_printk() for DEBUG ONLY */
43 bpf_trace_printk(fmt, sizeof(fmt), skb, len);
44 }
45
46 return 0;
47}
48
49char _license[] SEC("license") = "GPL";
50u32 _version SEC("version") = LINUX_VERSION_CODE;
diff --git a/samples/bpf/tracex1_user.c b/samples/bpf/tracex1_user.c
new file mode 100644
index 000000000000..31a48183beea
--- /dev/null
+++ b/samples/bpf/tracex1_user.c
@@ -0,0 +1,25 @@
1#include <stdio.h>
2#include <linux/bpf.h>
3#include <unistd.h>
4#include "libbpf.h"
5#include "bpf_load.h"
6
7int main(int ac, char **argv)
8{
9 FILE *f;
10 char filename[256];
11
12 snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
13
14 if (load_bpf_file(filename)) {
15 printf("%s", bpf_log_buf);
16 return 1;
17 }
18
19 f = popen("taskset 1 ping -c5 localhost", "r");
20 (void) f;
21
22 read_trace_pipe();
23
24 return 0;
25}