Skip to content

Commit 0e7b077

Browse files
committed
feat: rewrite tcpretrans plugin with native cilium/ebpf
- Replace inspektor-gadget TCP retransmission tracer with native eBPF kprobe - Add eBPF C program for tcp_retransmit_skb tracing - Add generated Go bindings for x86 and arm64 with empty .o stubs - Update plugin implementation and types Signed-off-by: Quang Nguyen <nguyenquang@microsoft.com>
1 parent 6b7cec7 commit 0e7b077

File tree

8 files changed

+668
-99
lines changed

8 files changed

+668
-99
lines changed

pkg/module/metrics/latency_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,20 +122,20 @@ func TestProcessFlow(t *testing.T) {
122122
*/
123123
// Node -> Api server.
124124
f1 := utils.ToFlow(l, t1, apiSeverIp, nodeIp, 80, 443, 6, 3, 0)
125-
metaf1 := &utils.RetinaMetadata{}
126-
utils.AddTCPID(metaf1, 1234)
125+
ext1 := utils.NewExtensions()
126+
utils.AddTCPID(ext1, 1234)
127127
utils.AddTCPFlags(f1, 1, 0, 0, 0, 0, 0, 0, 0, 0)
128-
utils.AddRetinaMetadata(f1, metaf1)
128+
utils.SetExtensions(f1, ext1)
129129
f1.Destination = &flow.Endpoint{
130130
PodName: "kubernetes-apiserver",
131131
}
132132

133133
// Api server -> Node.
134134
f2 := utils.ToFlow(l, t2, nodeIp, apiSeverIp, 443, 80, 6, 2, 0)
135-
metaf2 := &utils.RetinaMetadata{}
136-
utils.AddTCPID(metaf2, 1234)
135+
ext2 := utils.NewExtensions()
136+
utils.AddTCPID(ext2, 1234)
137137
utils.AddTCPFlags(f2, 1, 1, 0, 0, 0, 0, 0, 0, 0)
138-
utils.AddRetinaMetadata(f2, metaf2)
138+
utils.SetExtensions(f2, ext2)
139139
f2.Source = &flow.Endpoint{
140140
PodName: "kubernetes-apiserver",
141141
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
// go:build ignore
2+
3+
// Copyright (c) Microsoft Corporation.
4+
// Licensed under the MIT license.
5+
6+
// TCP retransmission tracer eBPF program
7+
// Hooks into tcp_retransmit_skb tracepoint/kprobe to capture TCP retransmission
8+
// events
9+
//
10+
// Based on tcpretrans from BCC (Apache 2.0 License)
11+
// https://github.com/iovisor/bcc
12+
// Copyright (c) 2016 Netflix, Inc.
13+
// Author: Brendan Gregg
14+
15+
#include "vmlinux.h"
16+
#include "bpf_helpers.h"
17+
#include "bpf_core_read.h"
18+
#include "bpf_tracing.h"
19+
#include "bpf_endian.h"
20+
21+
char __license[] SEC("license") = "Dual MIT/GPL";
22+
23+
// TCP retransmission event structure - sent to userspace
24+
struct tcpretrans_event {
25+
__u64 timestamp; // Boot time in nanoseconds
26+
__u32 src_ip; // Source IPv4 address (network byte order)
27+
__u32 dst_ip; // Destination IPv4 address (network byte order)
28+
__u16 src_port; // Source port (host byte order)
29+
__u16 dst_port; // Destination port (host byte order)
30+
__u32 state; // TCP state
31+
__u8 tcpflags; // TCP flags from the retransmitted packet
32+
__u8 af; // Address family (4 or 6)
33+
__u8 _pad[2];
34+
__u8 src_ip6[16]; // Source IPv6 address
35+
__u8 dst_ip6[16]; // Destination IPv6 address
36+
};
37+
38+
// Define const for bpf2go type generation
39+
const struct tcpretrans_event *unused_tcpretrans_event __attribute__((unused));
40+
41+
// Perf event array for streaming events to userspace
42+
struct {
43+
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
44+
__uint(key_size, sizeof(__u32));
45+
__uint(value_size, sizeof(__u32));
46+
} retina_tcpretrans_events SEC(".maps");
47+
48+
// TCP flag bit positions
49+
#define TCP_FLAG_FIN 0x01
50+
#define TCP_FLAG_SYN 0x02
51+
#define TCP_FLAG_RST 0x04
52+
#define TCP_FLAG_PSH 0x08
53+
#define TCP_FLAG_ACK 0x10
54+
#define TCP_FLAG_URG 0x20
55+
#define TCP_FLAG_ECE 0x40
56+
#define TCP_FLAG_CWR 0x80
57+
58+
static __always_inline void extract_tcp_info(struct sock *sk,
59+
struct tcpretrans_event *event) {
60+
// Read address family
61+
__u16 family = 0;
62+
BPF_CORE_READ_INTO(&family, sk, __sk_common.skc_family);
63+
64+
if (family == 2) { // AF_INET
65+
event->af = 4;
66+
BPF_CORE_READ_INTO(&event->src_ip, sk, __sk_common.skc_rcv_saddr);
67+
BPF_CORE_READ_INTO(&event->dst_ip, sk, __sk_common.skc_daddr);
68+
} else if (family == 10) { // AF_INET6
69+
event->af = 6;
70+
BPF_CORE_READ_INTO(&event->src_ip6, sk,
71+
__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr8);
72+
BPF_CORE_READ_INTO(&event->dst_ip6, sk,
73+
__sk_common.skc_v6_daddr.in6_u.u6_addr8);
74+
} else {
75+
return;
76+
}
77+
78+
// Read ports
79+
__u16 dport = 0;
80+
BPF_CORE_READ_INTO(&dport, sk, __sk_common.skc_dport);
81+
event->dst_port = bpf_ntohs(dport);
82+
83+
__u16 sport = 0;
84+
BPF_CORE_READ_INTO(&sport, sk, __sk_common.skc_num);
85+
event->src_port = sport; // already in host byte order
86+
87+
// Read TCP state
88+
BPF_CORE_READ_INTO(&event->state, sk, __sk_common.skc_state);
89+
}
90+
91+
SEC("kprobe/tcp_retransmit_skb")
92+
int BPF_KPROBE(retina_tcp_retransmit_skb, struct sock *sk,
93+
struct sk_buff *skb) {
94+
if (!sk || !skb)
95+
return 0;
96+
97+
struct tcpretrans_event event = {};
98+
event.timestamp = bpf_ktime_get_boot_ns();
99+
100+
extract_tcp_info(sk, &event);
101+
102+
// Skip if we couldn't determine the address family
103+
if (event.af == 0)
104+
return 0;
105+
106+
// Read TCP flags from the skb's transport header
107+
// TCP flags byte is at offset 13 in the TCP header
108+
// (byte 12 = data offset + reserved, byte 13 = flags)
109+
// Cannot use BPF_CORE_READ_INTO on bit-fields, so read the raw byte
110+
char *head = NULL;
111+
__u16 trans_header = 0;
112+
BPF_CORE_READ_INTO(&head, skb, head);
113+
BPF_CORE_READ_INTO(&trans_header, skb, transport_header);
114+
115+
if (head && trans_header) {
116+
// Read the flags byte (offset 13 in TCP header)
117+
__u8 flags_byte = 0;
118+
bpf_probe_read_kernel(&flags_byte, sizeof(flags_byte),
119+
head + trans_header + 13);
120+
event.tcpflags = flags_byte;
121+
}
122+
123+
bpf_perf_event_output(ctx, &retina_tcpretrans_events, BPF_F_CURRENT_CPU,
124+
&event, sizeof(event));
125+
126+
return 0;
127+
}

pkg/plugin/tcpretrans/tcpretrans_bpfel_arm64.go

Lines changed: 134 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/plugin/tcpretrans/tcpretrans_bpfel_arm64.o

Whitespace-only changes.

0 commit comments

Comments
 (0)