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 "vmlinux.h" |
8 | #include <linux/version.h> |
9 | #include <bpf/bpf_helpers.h> |
10 | #include <bpf/bpf_tracing.h> |
11 | #include <bpf/bpf_core_read.h> |
12 | |
13 | struct { |
14 | __uint(type, BPF_MAP_TYPE_HASH); |
15 | __type(key, long); |
16 | __type(value, long); |
17 | __uint(max_entries, 1024); |
18 | } my_map SEC(".maps" ); |
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_reason" ) |
24 | int bpf_prog2(struct pt_regs *ctx) |
25 | { |
26 | long loc = 0; |
27 | long init_val = 1; |
28 | long *value; |
29 | |
30 | /* read ip of kfree_skb_reason caller. |
31 | * non-portable version of __builtin_return_address(0) |
32 | */ |
33 | BPF_KPROBE_READ_RET_IP(loc, ctx); |
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(v: hi) + 32; |
61 | else |
62 | return log2(v); |
63 | } |
64 | |
65 | struct hist_key { |
66 | char comm[16]; |
67 | u64 pid_tgid; |
68 | u64 uid_gid; |
69 | u64 index; |
70 | }; |
71 | |
72 | struct { |
73 | __uint(type, BPF_MAP_TYPE_PERCPU_HASH); |
74 | __uint(key_size, sizeof(struct hist_key)); |
75 | __uint(value_size, sizeof(long)); |
76 | __uint(max_entries, 1024); |
77 | } my_hist_map SEC(".maps" ); |
78 | |
79 | SEC("ksyscall/write" ) |
80 | int BPF_KSYSCALL(bpf_prog3, unsigned int fd, const char *buf, size_t count) |
81 | { |
82 | long init_val = 1; |
83 | long *value; |
84 | struct hist_key key; |
85 | |
86 | key.index = log2l(v: count); |
87 | key.pid_tgid = bpf_get_current_pid_tgid(); |
88 | key.uid_gid = bpf_get_current_uid_gid(); |
89 | bpf_get_current_comm(&key.comm, sizeof(key.comm)); |
90 | |
91 | value = bpf_map_lookup_elem(&my_hist_map, &key); |
92 | if (value) |
93 | __sync_fetch_and_add(value, 1); |
94 | else |
95 | bpf_map_update_elem(&my_hist_map, &key, &init_val, BPF_ANY); |
96 | return 0; |
97 | } |
98 | char _license[] SEC("license" ) = "GPL" ; |
99 | u32 _version SEC("version" ) = LINUX_VERSION_CODE; |
100 | |