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
|
/*
* TCPSendStack Summarize tcp_sendmsg() calling stack traces.
* For Linux, uses BCC, eBPF. Embedded C.
*
* Basic example of BCC in-kernel stack trace dedup.
*
* USAGE: TCPSendStack [duration]
*
* Copyright (c) Facebook, Inc.
* Licensed under the Apache License, Version 2.0 (the "License")
*/
#include <unistd.h>
#include <algorithm>
#include <iostream>
#include "BPF.h"
const std::string BPF_PROGRAM = R"(
#include <linux/sched.h>
#include <uapi/linux/ptrace.h>
struct stack_key_t {
int pid;
char name[16];
int user_stack;
int kernel_stack;
};
BPF_STACK_TRACE(stack_traces, 10240)
BPF_HASH(counts, struct stack_key_t, uint64_t);
int on_tcp_send(struct pt_regs *ctx) {
struct stack_key_t key = {};
key.pid = bpf_get_current_pid_tgid() >> 32;
bpf_get_current_comm(&key.name, sizeof(key.name));
key.kernel_stack = stack_traces.get_stackid(ctx, BPF_F_REUSE_STACKID);
key.user_stack = stack_traces.get_stackid(
ctx, BPF_F_REUSE_STACKID | BPF_F_USER_STACK
);
u64 zero = 0, *val;
val = counts.lookup_or_init(&key, &zero);
(*val)++;
return 0;
}
)";
// Define the same struct to use in user space.
struct stack_key_t {
int pid;
char name[16];
int user_stack;
int kernel_stack;
};
int main(int argc, char** argv) {
ebpf::BPF bpf;
auto init_res = bpf.init(BPF_PROGRAM);
if (init_res.code() != 0) {
std::cerr << init_res.msg() << std::endl;
return 1;
}
auto attach_res = bpf.attach_kprobe("tcp_sendmsg", "on_tcp_send");
if (attach_res.code() != 0) {
std::cerr << attach_res.msg() << std::endl;
return 1;
}
int probe_time = 10;
if (argc == 2) {
probe_time = atoi(argv[1]);
}
std::cout << "Probing for " << probe_time << " seconds" << std::endl;
sleep(probe_time);
auto table =
bpf.get_hash_table<stack_key_t, uint64_t>("counts").get_table_offline();
std::sort(table.begin(), table.end(), [](std::pair<stack_key_t, uint64_t> a,
std::pair<stack_key_t, uint64_t> b) {
return a.second < b.second;
});
auto stacks = bpf.get_stack_table("stack_traces");
for (auto it : table) {
std::cout << "PID: " << it.first.pid << " (" << it.first.name << ") "
<< "made " << it.second
<< " TCP sends on following stack: " << std::endl;
std::cout << " Kernel Stack:" << std::endl;
if (it.first.kernel_stack >= 0) {
auto syms = stacks.get_stack_symbol(it.first.kernel_stack, -1);
for (auto sym : syms)
std::cout << " " << sym << std::endl;
} else
std::cout << " " << it.first.kernel_stack << std::endl;
std::cout << " User Stack:" << std::endl;
if (it.first.user_stack >= 0) {
auto syms = stacks.get_stack_symbol(it.first.user_stack, it.first.pid);
for (auto sym : syms)
std::cout << " " << sym << std::endl;
} else
std::cout << " " << it.first.user_stack << std::endl;
}
auto detach_res = bpf.detach_kprobe("tcp_sendmsg");
if (detach_res.code() != 0) {
std::cerr << detach_res.msg() << std::endl;
return 1;
}
return 0;
}
|