-
Notifications
You must be signed in to change notification settings - Fork 0
/
prober.c
188 lines (149 loc) · 4.57 KB
/
prober.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
// Adopted from - https://github.com/iovisor/bcc/blob/master/tools/tcptop.py
#include <uapi/linux/ptrace.h>
#include <net/sock.h>
#include <bcc/proto.h>
struct ipv4_key_t {
u32 pid;
char name[TASK_COMM_LEN];
u32 saddr;
u32 daddr;
u16 lport;
u16 dport;
};
BPF_HASH(ipv4_send_bytes, struct ipv4_key_t);
BPF_HASH(sock_store, u32, struct sock *);
struct ipv4_data_t {
u32 saddr;
u32 daddr;
u16 lport;
u16 dport;
u64 rx_b;
u64 tx_b;
u64 span_us;
u32 state;
};
BPF_PERF_OUTPUT(ipv4_events);
BPF_HASH(birth, struct sock *, u64);
static int tcp_send_entry(struct sock *sk)
{
if (container_should_be_filtered()) {
return 0;
}
u32 pid = bpf_get_current_pid_tgid() >> 32;
u32 tid = bpf_get_current_pid_tgid();
u16 family = sk->__sk_common.skc_family;
sock_store.update(&tid, &sk);
// Recoard the birth of the sequence
u64 ts = bpf_ktime_get_ns();
birth.update(&sk, &ts);
return 0;
}
// Track in new send events
// It could be either tcp_sendmsg or tcp_sendpage
// http://vger.kernel.org/~davem/tcp_output.html
int kprobe__tcp_sendmsg(struct pt_regs *ctx, struct sock *sk, struct msghdr *msg, size_t size)
{
return tcp_send_entry(sk);
}
int kprobe__tcp_sendpage(struct pt_regs *ctx, struct sock *sk, struct page *page, int offset, size_t size)
{
return tcp_send_entry(sk);
}
// Collect data about the send event at the end of function execution
static int tcp_sendstat(int size)
{
if (container_should_be_filtered()) {
return 0;
}
u32 pid = bpf_get_current_pid_tgid() >> 32;
u32 tid = bpf_get_current_pid_tgid();
struct sock **sockpp;
sockpp = sock_store.lookup(&tid);
if (sockpp == 0) {
return 0; //miss the entry
}
struct sock *sk = *sockpp;
u16 dport = 0, family;
bpf_probe_read_kernel(&family, sizeof(family),
&sk->__sk_common.skc_family);
struct ipv4_key_t ipv4_key = {.pid = pid};
bpf_get_current_comm(&ipv4_key.name, sizeof(ipv4_key.name));
bpf_probe_read_kernel(&ipv4_key.saddr, sizeof(ipv4_key.saddr),
&sk->__sk_common.skc_rcv_saddr);
bpf_probe_read_kernel(&ipv4_key.daddr, sizeof(ipv4_key.daddr),
&sk->__sk_common.skc_daddr);
bpf_probe_read_kernel(&ipv4_key.lport, sizeof(ipv4_key.lport),
&sk->__sk_common.skc_num);
bpf_probe_read_kernel(&dport, sizeof(dport),
&sk->__sk_common.skc_dport);
ipv4_key.dport = ntohs(dport);
ipv4_send_bytes.increment(ipv4_key, size);
sock_store.delete(&tid);
// else drop
return 0;
}
int kretprobe__tcp_sendmsg(struct pt_regs *ctx)
{
int size = PT_REGS_RC(ctx);
if (size > 0)
return tcp_sendstat(size);
else
return 0;
}
int kretprobe__tcp_sendpage(struct pt_regs *ctx)
{
int size = PT_REGS_RC(ctx);
if (size > 0)
return tcp_sendstat(size);
else
return 0;
}
/*
* tcp_recvmsg() would be obvious to trace, but is less suitable because:
* - we'd need to trace both entry and return, to have both sock and size
* - misses tcp_read_sock() traffic
* we'd much prefer tracepoints once they are available.
*/
int kprobe__tcp_cleanup_rbuf(struct pt_regs *ctx, struct sock *sk, int copied)
{
if (container_should_be_filtered()) {
return 0;
}
u32 pid = bpf_get_current_pid_tgid() >> 32;
u16 dport = 0, family = sk->__sk_common.skc_family;
u64 *val, zero = 0;
if (copied <= 0)
return 0;
// Calculate lifespan
u64 *tsp, delta_us;
tsp = birth.lookup(&sk);
if (tsp == 0) {
// whoami.delete(&sk); // may not exist
return 0; // missed create
}
delta_us = (bpf_ktime_get_ns() - *tsp) / 1000;
birth.delete(&sk);
struct ipv4_key_t ipv4_key = {.pid = pid};
bpf_get_current_comm(&ipv4_key.name, sizeof(ipv4_key.name));
ipv4_key.saddr = sk->__sk_common.skc_rcv_saddr;
ipv4_key.daddr = sk->__sk_common.skc_daddr;
ipv4_key.lport = sk->__sk_common.skc_num;
dport = sk->__sk_common.skc_dport;
ipv4_key.dport = ntohs(dport);
u64 *tx_b = ipv4_send_bytes.lookup(&ipv4_key);
if (tx_b == 0) {
// whoami.delete(&sk); // may not exist
return 0; // missed create
}
ipv4_send_bytes.delete(&ipv4_key);
struct ipv4_data_t data4 = {};
data4.span_us = delta_us;
data4.rx_b = copied;
data4.tx_b = *tx_b;
data4.saddr = sk->__sk_common.skc_rcv_saddr;
data4.lport = sk->__sk_common.skc_num;
data4.daddr = sk->__sk_common.skc_daddr;
data4.dport = ntohs(dport);
ipv4_events.perf_submit(ctx, &data4, sizeof(data4));
return 0;
}