Skip to content

Commit 9dd85d2

Browse files
committed
libbpf-tools: add CO-RE tcpretrans
This commit adds tcpretrans port to CO-RE. This port aims to replicate the output of existing BCC/tools tcpretrans. Signed-off-by: Michael Gugino <[email protected]>
1 parent b21bd30 commit 9dd85d2

File tree

5 files changed

+549
-0
lines changed

5 files changed

+549
-0
lines changed

libbpf-tools/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
/syscount
3737
/tcpconnect
3838
/tcpconnlat
39+
/tcpretrans
3940
/vfsstat
4041
/xfsdist
4142
/xfsslower

libbpf-tools/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ APPS = \
4747
syscount \
4848
tcpconnect \
4949
tcpconnlat \
50+
tcpretrans \
5051
vfsstat \
5152
#
5253

libbpf-tools/tcpretrans.bpf.c

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
3+
/*
4+
* tcpretrans Trace IPv4 and IPv6 tcp retransmit events
5+
*
6+
* Copyright (c) 2020 Anton Protopopov
7+
* Copyright (c) 2021 Red Hat, Inc.
8+
*
9+
* Based on tcpconnect.c by Anton Protopopov and
10+
* tcpretrans(8) from BCC by Brendan Gregg
11+
* 15-Jul-2021 Michael Gugino Created this.
12+
*/
13+
#include <vmlinux.h>
14+
15+
#include <bpf/bpf_helpers.h>
16+
#include <bpf/bpf_core_read.h>
17+
#include <bpf/bpf_tracing.h>
18+
19+
#include "maps.bpf.h"
20+
#include "tcpretrans.h"
21+
22+
/* Define here, because there are conflicts with include files */
23+
#define AF_INET 2
24+
#define AF_INET6 10
25+
26+
const volatile bool do_count = 0;
27+
28+
struct {
29+
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
30+
__uint(key_size, sizeof(u32));
31+
__uint(value_size, sizeof(u32));
32+
} events SEC(".maps");
33+
34+
struct {
35+
__uint(type, BPF_MAP_TYPE_HASH);
36+
__uint(max_entries, MAX_ENTRIES);
37+
__type(key, struct ipv4_flow_key);
38+
__type(value, u64);
39+
__uint(map_flags, BPF_F_NO_PREALLOC);
40+
} ipv4_count SEC(".maps");
41+
42+
struct {
43+
__uint(type, BPF_MAP_TYPE_HASH);
44+
__uint(max_entries, MAX_ENTRIES);
45+
__type(key, struct ipv6_flow_key);
46+
__type(value, u64);
47+
__uint(map_flags, BPF_F_NO_PREALLOC);
48+
} ipv6_count SEC(".maps");
49+
50+
static void count_v4(const struct sock *skp)
51+
{
52+
struct ipv4_flow_key key = {};
53+
static __u64 zero;
54+
__u64 *val;
55+
56+
BPF_CORE_READ_INTO(&key.saddr, skp, __sk_common.skc_rcv_saddr);
57+
BPF_CORE_READ_INTO(&key.daddr, skp, __sk_common.skc_daddr);
58+
BPF_CORE_READ_INTO(&key.dport, skp, __sk_common.skc_dport);
59+
BPF_CORE_READ_INTO(&key.sport, skp, __sk_common.skc_num);
60+
val = bpf_map_lookup_or_try_init(&ipv4_count, &key, &zero);
61+
if (val)
62+
__atomic_add_fetch(val, 1, __ATOMIC_RELAXED);
63+
}
64+
65+
static void count_v6(const struct sock *skp)
66+
{
67+
struct ipv6_flow_key key = {};
68+
static const __u64 zero;
69+
__u64 *val;
70+
71+
BPF_CORE_READ_INTO(&key.saddr, skp,
72+
__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32);
73+
BPF_CORE_READ_INTO(&key.daddr, skp,
74+
__sk_common.skc_v6_daddr.in6_u.u6_addr32);
75+
BPF_CORE_READ_INTO(&key.dport, skp, __sk_common.skc_dport);
76+
BPF_CORE_READ_INTO(&key.sport, skp, __sk_common.skc_num);
77+
78+
val = bpf_map_lookup_or_try_init(&ipv6_count, &key, &zero);
79+
if (val)
80+
__atomic_add_fetch(val, 1, __ATOMIC_RELAXED);
81+
}
82+
83+
static int trace_event(void *ctx, const struct sock *skp, int type)
84+
{
85+
if (skp == NULL)
86+
return 0;
87+
88+
struct event e = {};
89+
__u32 family;
90+
__u64 pid_tgid;
91+
__u32 pid;
92+
int state;
93+
94+
family = BPF_CORE_READ(skp, __sk_common.skc_family);
95+
e.af = family;
96+
97+
if (do_count) {
98+
if (family == AF_INET)
99+
count_v4(skp);
100+
else
101+
count_v6(skp);
102+
return 0;
103+
}
104+
105+
e.type = type;
106+
pid_tgid = bpf_get_current_pid_tgid();
107+
pid = pid_tgid >> 32;
108+
e.pid = pid;
109+
110+
BPF_CORE_READ_INTO(&e.dport, skp, __sk_common.skc_dport);
111+
BPF_CORE_READ_INTO(&e.sport, skp, __sk_common.skc_num);
112+
state = BPF_CORE_READ(skp, __sk_common.skc_state);
113+
e.state = state;
114+
115+
if (family == AF_INET) {
116+
BPF_CORE_READ_INTO(&e.saddr, skp, __sk_common.skc_rcv_saddr);
117+
BPF_CORE_READ_INTO(&e.daddr, skp, __sk_common.skc_daddr);
118+
} else if (family == AF_INET6) {
119+
BPF_CORE_READ_INTO(e.saddr, skp,
120+
__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32);
121+
BPF_CORE_READ_INTO(e.daddr, skp,
122+
__sk_common.skc_v6_daddr.in6_u.u6_addr32);
123+
}
124+
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU,
125+
&e, sizeof(e));
126+
return 0;
127+
}
128+
129+
SEC("tp/tcp/tcp_retransmit_skb")
130+
int tracepoint__tcp__tcp_retransmit_skb(struct trace_event_raw_tcp_event_sk_skb* ctx)
131+
{
132+
const struct sock *skp;
133+
skp = BPF_CORE_READ(ctx, skaddr);
134+
return trace_event(ctx, skp, RETRANSMIT);
135+
}
136+
137+
SEC("kprobe/tcp_send_loss_probe")
138+
int BPF_KPROBE(tcp_send_loss_probe, struct sock *sk)
139+
{
140+
return trace_event(ctx, sk, TLP);
141+
}
142+
143+
SEC("kprobe/tcp_retransmit_skb")
144+
int BPF_KPROBE(tcp_retransmit_skb, struct sock *sk)
145+
{
146+
return trace_event(ctx, sk, RETRANSMIT);
147+
}
148+
149+
char LICENSE[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)