Skip to content

Commit a41fc45

Browse files
committed
libbpf-tools: Add tcplife
Signed-off-by: Hengqi Chen <[email protected]>
1 parent 5e3d41e commit a41fc45

File tree

5 files changed

+428
-0
lines changed

5 files changed

+428
-0
lines changed

libbpf-tools/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
/syscount
4545
/tcpconnect
4646
/tcpconnlat
47+
/tcplife
4748
/tcprtt
4849
/tcpsynbl
4950
/vfsstat

libbpf-tools/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ APPS = \
5757
syscount \
5858
tcpconnect \
5959
tcpconnlat \
60+
tcplife \
6061
tcprtt \
6162
tcpsynbl \
6263
vfsstat \

libbpf-tools/tcplife.bpf.c

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2022 Hengqi Chen */
3+
#include <vmlinux.h>
4+
#include <bpf/bpf_core_read.h>
5+
#include <bpf/bpf_helpers.h>
6+
#include <bpf/bpf_tracing.h>
7+
#include "tcplife.h"
8+
9+
#define MAX_ENTRIES 10240
10+
#define AF_INET 2
11+
#define AF_INET6 10
12+
13+
const volatile bool filter_sport = false;
14+
const volatile bool filter_dport = false;
15+
const volatile __u16 target_sports[MAX_PORTS] = {};
16+
const volatile __u16 target_dports[MAX_PORTS] = {};
17+
const volatile pid_t target_pid = 0;
18+
const volatile __u16 target_family = 0;
19+
20+
struct {
21+
__uint(type, BPF_MAP_TYPE_HASH);
22+
__uint(max_entries, MAX_ENTRIES);
23+
__type(key, struct sock *);
24+
__type(value, __u64);
25+
} birth SEC(".maps");
26+
27+
struct {
28+
__uint(type, BPF_MAP_TYPE_HASH);
29+
__uint(max_entries, MAX_ENTRIES);
30+
__type(key, struct sock *);
31+
__type(value, struct ident);
32+
} idents SEC(".maps");
33+
34+
struct {
35+
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
36+
__uint(key_size, sizeof(__u32));
37+
__uint(value_size, sizeof(__u32));
38+
} events SEC(".maps");
39+
40+
SEC("tracepoint/sock/inet_sock_set_state")
41+
int inet_sock_set_state(struct trace_event_raw_inet_sock_set_state *args)
42+
{
43+
__u64 ts, *start, delta_us, rx_b, tx_b;
44+
struct ident ident = {}, *identp;
45+
__u16 sport, dport, family;
46+
struct event event = {};
47+
struct tcp_sock *tp;
48+
struct sock *sk;
49+
bool found;
50+
__u32 pid;
51+
int i;
52+
53+
if (BPF_CORE_READ(args, protocol) != IPPROTO_TCP)
54+
return 0;
55+
56+
family = BPF_CORE_READ(args, family);
57+
if (target_family && family != target_family)
58+
return 0;
59+
60+
sport = BPF_CORE_READ(args, sport);
61+
if (filter_sport) {
62+
found = false;
63+
for (i = 0; i < MAX_PORTS; i++) {
64+
if (!target_sports[i])
65+
return 0;
66+
if (sport != target_sports[i])
67+
continue;
68+
found = true;
69+
break;
70+
}
71+
if (!found)
72+
return 0;
73+
}
74+
75+
dport = BPF_CORE_READ(args, dport);
76+
if (filter_dport) {
77+
found = false;
78+
for (i = 0; i < MAX_PORTS; i++) {
79+
if (!target_dports[i])
80+
return 0;
81+
if (dport != target_dports[i])
82+
continue;
83+
found = true;
84+
break;
85+
}
86+
if (!found)
87+
return 0;
88+
}
89+
90+
sk = (struct sock *)BPF_CORE_READ(args, skaddr);
91+
if (BPF_CORE_READ(args, newstate) < TCP_FIN_WAIT1) {
92+
ts = bpf_ktime_get_ns();
93+
bpf_map_update_elem(&birth, &sk, &ts, BPF_ANY);
94+
}
95+
96+
if (BPF_CORE_READ(args, newstate) == TCP_SYN_SENT || BPF_CORE_READ(args, newstate) == TCP_LAST_ACK) {
97+
pid = bpf_get_current_pid_tgid() >> 32;
98+
if (target_pid && pid != target_pid)
99+
return 0;
100+
ident.pid = pid;
101+
bpf_get_current_comm(ident.comm, sizeof(ident.comm));
102+
bpf_map_update_elem(&idents, &sk, &ident, BPF_ANY);
103+
}
104+
105+
if (BPF_CORE_READ(args, newstate) != TCP_CLOSE)
106+
return 0;
107+
108+
start = bpf_map_lookup_elem(&birth, &sk);
109+
if (!start) {
110+
bpf_map_delete_elem(&idents, &sk);
111+
return 0;
112+
}
113+
ts = bpf_ktime_get_ns();
114+
delta_us = (ts - *start) / 1000;
115+
116+
identp = bpf_map_lookup_elem(&idents, &sk);
117+
pid = identp ? identp->pid : bpf_get_current_pid_tgid() >> 32;
118+
if (target_pid && pid != target_pid)
119+
goto cleanup;
120+
121+
tp = (struct tcp_sock *)sk;
122+
rx_b = BPF_CORE_READ(tp, bytes_received);
123+
tx_b = BPF_CORE_READ(tp, bytes_acked);
124+
125+
event.ts_us = ts / 1000;
126+
event.span_us = delta_us;
127+
event.rx_b = rx_b;
128+
event.tx_b = tx_b;
129+
event.pid = pid;
130+
event.sport = sport;
131+
event.dport = dport;
132+
event.family = family;
133+
if (!identp)
134+
bpf_get_current_comm(event.comm, sizeof(event.comm));
135+
else
136+
bpf_probe_read_kernel(event.comm, sizeof(event.comm), (void *)identp->comm);
137+
if (family == AF_INET) {
138+
bpf_probe_read_kernel(&event.saddr, sizeof(args->saddr), BPF_CORE_READ(args, saddr));
139+
bpf_probe_read_kernel(&event.daddr, sizeof(args->daddr), BPF_CORE_READ(args, daddr));
140+
} else { /* AF_INET6 */
141+
bpf_probe_read_kernel(&event.saddr, sizeof(args->saddr_v6), BPF_CORE_READ(args, saddr_v6));
142+
bpf_probe_read_kernel(&event.daddr, sizeof(args->daddr_v6), BPF_CORE_READ(args, daddr_v6));
143+
}
144+
bpf_perf_event_output(args, &events, BPF_F_CURRENT_CPU, &event, sizeof(event));
145+
146+
cleanup:
147+
bpf_map_delete_elem(&birth, &sk);
148+
bpf_map_delete_elem(&idents, &sk);
149+
return 0;
150+
}
151+
152+
char LICENSE[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)