diff options
author | Alexei Starovoitov <ast@plumgrid.com> | 2015-03-25 15:49:24 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-04-02 07:25:50 -0400 |
commit | d822a192684912c80950d28a0b7adc96261e957c (patch) | |
tree | 5686f28d7d36ed9577af6e565f0cdd8c8fbedc65 /samples | |
parent | b896c4f95ab4052d6bad3acde95167d30242a84f (diff) |
samples/bpf: Add counting example for kfree_skb() function calls and the write() syscall
this example has two probes in one C file that attach to
different kprove events and use two different maps.
1st probe is x64 specific equivalent of dropmon. It attaches to
kfree_skb, retrevies 'ip' address of kfree_skb() caller and
counts number of packet drops at that 'ip' address. User space
prints 'location - count' map every second.
2nd probe attaches to kprobe:sys_write and computes a histogram
of different write sizes
Usage:
$ sudo tracex2
location 0xffffffff81695995 count 1
location 0xffffffff816d0da9 count 2
location 0xffffffff81695995 count 2
location 0xffffffff816d0da9 count 2
location 0xffffffff81695995 count 3
location 0xffffffff816d0da9 count 2
557145+0 records in
557145+0 records out
285258240 bytes (285 MB) copied, 1.02379 s, 279 MB/s
syscall write() stats
byte_size : count distribution
1 -> 1 : 3 | |
2 -> 3 : 0 | |
4 -> 7 : 0 | |
8 -> 15 : 0 | |
16 -> 31 : 2 | |
32 -> 63 : 3 | |
64 -> 127 : 1 | |
128 -> 255 : 1 | |
256 -> 511 : 0 | |
512 -> 1023 : 1118968 |************************************* |
Ctrl-C at any time. Kernel will auto cleanup maps and programs
$ addr2line -ape ./bld_x64/vmlinux 0xffffffff81695995
0xffffffff816d0da9 0xffffffff81695995:
./bld_x64/../net/ipv4/icmp.c:1038 0xffffffff816d0da9:
./bld_x64/../net/unix/af_unix.c:1231
Signed-off-by: Alexei Starovoitov <ast@plumgrid.com>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: David S. Miller <davem@davemloft.net>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Link: http://lkml.kernel.org/r/1427312966-8434-8-git-send-email-ast@plumgrid.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'samples')
-rw-r--r-- | samples/bpf/Makefile | 4 | ||||
-rw-r--r-- | samples/bpf/tracex2_kern.c | 86 | ||||
-rw-r--r-- | samples/bpf/tracex2_user.c | 95 |
3 files changed, 185 insertions, 0 deletions
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 51f6f01e5a3a..6dd272143733 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile | |||
@@ -7,6 +7,7 @@ hostprogs-y += sock_example | |||
7 | hostprogs-y += sockex1 | 7 | hostprogs-y += sockex1 |
8 | hostprogs-y += sockex2 | 8 | hostprogs-y += sockex2 |
9 | hostprogs-y += tracex1 | 9 | hostprogs-y += tracex1 |
10 | hostprogs-y += tracex2 | ||
10 | 11 | ||
11 | test_verifier-objs := test_verifier.o libbpf.o | 12 | test_verifier-objs := test_verifier.o libbpf.o |
12 | test_maps-objs := test_maps.o libbpf.o | 13 | test_maps-objs := test_maps.o libbpf.o |
@@ -14,12 +15,14 @@ sock_example-objs := sock_example.o libbpf.o | |||
14 | sockex1-objs := bpf_load.o libbpf.o sockex1_user.o | 15 | sockex1-objs := bpf_load.o libbpf.o sockex1_user.o |
15 | sockex2-objs := bpf_load.o libbpf.o sockex2_user.o | 16 | sockex2-objs := bpf_load.o libbpf.o sockex2_user.o |
16 | tracex1-objs := bpf_load.o libbpf.o tracex1_user.o | 17 | tracex1-objs := bpf_load.o libbpf.o tracex1_user.o |
18 | tracex2-objs := bpf_load.o libbpf.o tracex2_user.o | ||
17 | 19 | ||
18 | # Tell kbuild to always build the programs | 20 | # Tell kbuild to always build the programs |
19 | always := $(hostprogs-y) | 21 | always := $(hostprogs-y) |
20 | always += sockex1_kern.o | 22 | always += sockex1_kern.o |
21 | always += sockex2_kern.o | 23 | always += sockex2_kern.o |
22 | always += tracex1_kern.o | 24 | always += tracex1_kern.o |
25 | always += tracex2_kern.o | ||
23 | 26 | ||
24 | HOSTCFLAGS += -I$(objtree)/usr/include | 27 | HOSTCFLAGS += -I$(objtree)/usr/include |
25 | 28 | ||
@@ -27,6 +30,7 @@ HOSTCFLAGS_bpf_load.o += -I$(objtree)/usr/include -Wno-unused-variable | |||
27 | HOSTLOADLIBES_sockex1 += -lelf | 30 | HOSTLOADLIBES_sockex1 += -lelf |
28 | HOSTLOADLIBES_sockex2 += -lelf | 31 | HOSTLOADLIBES_sockex2 += -lelf |
29 | HOSTLOADLIBES_tracex1 += -lelf | 32 | HOSTLOADLIBES_tracex1 += -lelf |
33 | HOSTLOADLIBES_tracex2 += -lelf | ||
30 | 34 | ||
31 | # point this to your LLVM backend with bpf support | 35 | # point this to your LLVM backend with bpf support |
32 | LLC=$(srctree)/tools/bpf/llvm/bld/Debug+Asserts/bin/llc | 36 | LLC=$(srctree)/tools/bpf/llvm/bld/Debug+Asserts/bin/llc |
diff --git a/samples/bpf/tracex2_kern.c b/samples/bpf/tracex2_kern.c new file mode 100644 index 000000000000..19ec1cfc45db --- /dev/null +++ b/samples/bpf/tracex2_kern.c | |||
@@ -0,0 +1,86 @@ | |||
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 <linux/version.h> | ||
10 | #include <uapi/linux/bpf.h> | ||
11 | #include "bpf_helpers.h" | ||
12 | |||
13 | struct bpf_map_def SEC("maps") my_map = { | ||
14 | .type = BPF_MAP_TYPE_HASH, | ||
15 | .key_size = sizeof(long), | ||
16 | .value_size = sizeof(long), | ||
17 | .max_entries = 1024, | ||
18 | }; | ||
19 | |||
20 | /* kprobe is NOT a stable ABI. If kernel internals change this bpf+kprobe | ||
21 | * example will no longer be meaningful | ||
22 | */ | ||
23 | SEC("kprobe/kfree_skb") | ||
24 | int bpf_prog2(struct pt_regs *ctx) | ||
25 | { | ||
26 | long loc = 0; | ||
27 | long init_val = 1; | ||
28 | long *value; | ||
29 | |||
30 | /* x64 specific: read ip of kfree_skb caller. | ||
31 | * non-portable version of __builtin_return_address(0) | ||
32 | */ | ||
33 | bpf_probe_read(&loc, sizeof(loc), (void *)ctx->sp); | ||
34 | |||
35 | value = bpf_map_lookup_elem(&my_map, &loc); | ||
36 | if (value) | ||
37 | *value += 1; | ||
38 | else | ||
39 | bpf_map_update_elem(&my_map, &loc, &init_val, BPF_ANY); | ||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | static unsigned int log2(unsigned int v) | ||
44 | { | ||
45 | unsigned int r; | ||
46 | unsigned int shift; | ||
47 | |||
48 | r = (v > 0xFFFF) << 4; v >>= r; | ||
49 | shift = (v > 0xFF) << 3; v >>= shift; r |= shift; | ||
50 | shift = (v > 0xF) << 2; v >>= shift; r |= shift; | ||
51 | shift = (v > 0x3) << 1; v >>= shift; r |= shift; | ||
52 | r |= (v >> 1); | ||
53 | return r; | ||
54 | } | ||
55 | |||
56 | static unsigned int log2l(unsigned long v) | ||
57 | { | ||
58 | unsigned int hi = v >> 32; | ||
59 | if (hi) | ||
60 | return log2(hi) + 32; | ||
61 | else | ||
62 | return log2(v); | ||
63 | } | ||
64 | |||
65 | struct bpf_map_def SEC("maps") my_hist_map = { | ||
66 | .type = BPF_MAP_TYPE_ARRAY, | ||
67 | .key_size = sizeof(u32), | ||
68 | .value_size = sizeof(long), | ||
69 | .max_entries = 64, | ||
70 | }; | ||
71 | |||
72 | SEC("kprobe/sys_write") | ||
73 | int bpf_prog3(struct pt_regs *ctx) | ||
74 | { | ||
75 | long write_size = ctx->dx; /* arg3 */ | ||
76 | long init_val = 1; | ||
77 | long *value; | ||
78 | u32 index = log2l(write_size); | ||
79 | |||
80 | value = bpf_map_lookup_elem(&my_hist_map, &index); | ||
81 | if (value) | ||
82 | __sync_fetch_and_add(value, 1); | ||
83 | return 0; | ||
84 | } | ||
85 | char _license[] SEC("license") = "GPL"; | ||
86 | u32 _version SEC("version") = LINUX_VERSION_CODE; | ||
diff --git a/samples/bpf/tracex2_user.c b/samples/bpf/tracex2_user.c new file mode 100644 index 000000000000..91b8d0896fbb --- /dev/null +++ b/samples/bpf/tracex2_user.c | |||
@@ -0,0 +1,95 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <unistd.h> | ||
3 | #include <stdlib.h> | ||
4 | #include <signal.h> | ||
5 | #include <linux/bpf.h> | ||
6 | #include "libbpf.h" | ||
7 | #include "bpf_load.h" | ||
8 | |||
9 | #define MAX_INDEX 64 | ||
10 | #define MAX_STARS 38 | ||
11 | |||
12 | static void stars(char *str, long val, long max, int width) | ||
13 | { | ||
14 | int i; | ||
15 | |||
16 | for (i = 0; i < (width * val / max) - 1 && i < width - 1; i++) | ||
17 | str[i] = '*'; | ||
18 | if (val > max) | ||
19 | str[i - 1] = '+'; | ||
20 | str[i] = '\0'; | ||
21 | } | ||
22 | |||
23 | static void print_hist(int fd) | ||
24 | { | ||
25 | int key; | ||
26 | long value; | ||
27 | long data[MAX_INDEX] = {}; | ||
28 | char starstr[MAX_STARS]; | ||
29 | int i; | ||
30 | int max_ind = -1; | ||
31 | long max_value = 0; | ||
32 | |||
33 | for (key = 0; key < MAX_INDEX; key++) { | ||
34 | bpf_lookup_elem(fd, &key, &value); | ||
35 | data[key] = value; | ||
36 | if (value && key > max_ind) | ||
37 | max_ind = key; | ||
38 | if (value > max_value) | ||
39 | max_value = value; | ||
40 | } | ||
41 | |||
42 | printf(" syscall write() stats\n"); | ||
43 | printf(" byte_size : count distribution\n"); | ||
44 | for (i = 1; i <= max_ind + 1; i++) { | ||
45 | stars(starstr, data[i - 1], max_value, MAX_STARS); | ||
46 | printf("%8ld -> %-8ld : %-8ld |%-*s|\n", | ||
47 | (1l << i) >> 1, (1l << i) - 1, data[i - 1], | ||
48 | MAX_STARS, starstr); | ||
49 | } | ||
50 | } | ||
51 | static void int_exit(int sig) | ||
52 | { | ||
53 | print_hist(map_fd[1]); | ||
54 | exit(0); | ||
55 | } | ||
56 | |||
57 | int main(int ac, char **argv) | ||
58 | { | ||
59 | char filename[256]; | ||
60 | long key, next_key, value; | ||
61 | FILE *f; | ||
62 | int i; | ||
63 | |||
64 | snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); | ||
65 | |||
66 | signal(SIGINT, int_exit); | ||
67 | |||
68 | /* start 'ping' in the background to have some kfree_skb events */ | ||
69 | f = popen("ping -c5 localhost", "r"); | ||
70 | (void) f; | ||
71 | |||
72 | /* start 'dd' in the background to have plenty of 'write' syscalls */ | ||
73 | f = popen("dd if=/dev/zero of=/dev/null count=5000000", "r"); | ||
74 | (void) f; | ||
75 | |||
76 | if (load_bpf_file(filename)) { | ||
77 | printf("%s", bpf_log_buf); | ||
78 | return 1; | ||
79 | } | ||
80 | |||
81 | for (i = 0; i < 5; i++) { | ||
82 | key = 0; | ||
83 | while (bpf_get_next_key(map_fd[0], &key, &next_key) == 0) { | ||
84 | bpf_lookup_elem(map_fd[0], &next_key, &value); | ||
85 | printf("location 0x%lx count %ld\n", next_key, value); | ||
86 | key = next_key; | ||
87 | } | ||
88 | if (key) | ||
89 | printf("\n"); | ||
90 | sleep(1); | ||
91 | } | ||
92 | print_hist(map_fd[1]); | ||
93 | |||
94 | return 0; | ||
95 | } | ||