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#include <string.h>
35#include <linux/bpf.h>
36#include <linux/ipv6.h>
37#include <linux/version.h>
38#include <sys/socket.h>
39#include "bpf_helpers.h"
40
41#define _(P) ({typeof(P) val = 0; bpf_probe_read(&val, sizeof(val), &P); val;})
42#define TCP_ESTATS_MAGIC 0xBAADBEEF
43
44
45
46
47
48
49
50
51typedef __u32 __bitwise __portpair;
52typedef __u64 __bitwise __addrpair;
53
54struct sock_common {
55 unsigned short skc_family;
56 union {
57 __addrpair skc_addrpair;
58 struct {
59 __be32 skc_daddr;
60 __be32 skc_rcv_saddr;
61 };
62 };
63 union {
64 __portpair skc_portpair;
65 struct {
66 __be16 skc_dport;
67 __u16 skc_num;
68 };
69 };
70 struct in6_addr skc_v6_daddr;
71 struct in6_addr skc_v6_rcv_saddr;
72};
73
74struct sock {
75 struct sock_common __sk_common;
76#define sk_family __sk_common.skc_family
77#define sk_v6_daddr __sk_common.skc_v6_daddr
78#define sk_v6_rcv_saddr __sk_common.skc_v6_rcv_saddr
79};
80
81struct inet_sock {
82 struct sock sk;
83#define inet_daddr sk.__sk_common.skc_daddr
84#define inet_dport sk.__sk_common.skc_dport
85 __be32 inet_saddr;
86 __be16 inet_sport;
87};
88
89struct pt_regs {
90 long di;
91};
92
93static inline struct inet_sock *inet_sk(const struct sock *sk)
94{
95 return (struct inet_sock *)sk;
96}
97
98
99
100
101enum tcp_estats_addrtype {
102 TCP_ESTATS_ADDRTYPE_IPV4 = 1,
103 TCP_ESTATS_ADDRTYPE_IPV6 = 2
104};
105
106enum tcp_estats_event_type {
107 TCP_ESTATS_ESTABLISH,
108 TCP_ESTATS_PERIODIC,
109 TCP_ESTATS_TIMEOUT,
110 TCP_ESTATS_RETRANSMIT_TIMEOUT,
111 TCP_ESTATS_RETRANSMIT_OTHER,
112 TCP_ESTATS_SYN_RETRANSMIT,
113 TCP_ESTATS_SYNACK_RETRANSMIT,
114 TCP_ESTATS_TERM,
115 TCP_ESTATS_TX_RESET,
116 TCP_ESTATS_RX_RESET,
117 TCP_ESTATS_WRITE_TIMEOUT,
118 TCP_ESTATS_CONN_TIMEOUT,
119 TCP_ESTATS_ACK_LATENCY,
120 TCP_ESTATS_NEVENTS,
121};
122
123struct tcp_estats_event {
124 int pid;
125 int cpu;
126 unsigned long ts;
127 unsigned int magic;
128 enum tcp_estats_event_type event_type;
129};
130
131
132
133
134struct tcp_estats_conn_id {
135 unsigned int localaddressType;
136 struct {
137 unsigned char data[16];
138 } localaddress;
139 struct {
140 unsigned char data[16];
141 } remaddress;
142 unsigned short localport;
143 unsigned short remport;
144} __attribute__((__packed__));
145
146struct tcp_estats_basic_event {
147 struct tcp_estats_event event;
148 struct tcp_estats_conn_id conn_id;
149};
150
151struct bpf_map_def SEC("maps") ev_record_map = {
152 .type = BPF_MAP_TYPE_HASH,
153 .key_size = sizeof(__u32),
154 .value_size = sizeof(struct tcp_estats_basic_event),
155 .max_entries = 1024,
156};
157
158struct dummy_tracepoint_args {
159 unsigned long long pad;
160 struct sock *sock;
161};
162
163static __always_inline void tcp_estats_ev_init(struct tcp_estats_event *event,
164 enum tcp_estats_event_type type)
165{
166 event->magic = TCP_ESTATS_MAGIC;
167 event->ts = bpf_ktime_get_ns();
168 event->event_type = type;
169}
170
171static __always_inline void unaligned_u32_set(unsigned char *to, __u8 *from)
172{
173 to[0] = _(from[0]);
174 to[1] = _(from[1]);
175 to[2] = _(from[2]);
176 to[3] = _(from[3]);
177}
178
179static __always_inline void conn_id_ipv4_init(struct tcp_estats_conn_id *conn_id,
180 __be32 *saddr, __be32 *daddr)
181{
182 conn_id->localaddressType = TCP_ESTATS_ADDRTYPE_IPV4;
183
184 unaligned_u32_set(conn_id->localaddress.data, (__u8 *)saddr);
185 unaligned_u32_set(conn_id->remaddress.data, (__u8 *)daddr);
186}
187
188static __always_inline void conn_id_ipv6_init(struct tcp_estats_conn_id *conn_id,
189 __be32 *saddr, __be32 *daddr)
190{
191 conn_id->localaddressType = TCP_ESTATS_ADDRTYPE_IPV6;
192
193 unaligned_u32_set(conn_id->localaddress.data, (__u8 *)saddr);
194 unaligned_u32_set(conn_id->localaddress.data + sizeof(__u32),
195 (__u8 *)(saddr + 1));
196 unaligned_u32_set(conn_id->localaddress.data + sizeof(__u32) * 2,
197 (__u8 *)(saddr + 2));
198 unaligned_u32_set(conn_id->localaddress.data + sizeof(__u32) * 3,
199 (__u8 *)(saddr + 3));
200
201 unaligned_u32_set(conn_id->remaddress.data,
202 (__u8 *)(daddr));
203 unaligned_u32_set(conn_id->remaddress.data + sizeof(__u32),
204 (__u8 *)(daddr + 1));
205 unaligned_u32_set(conn_id->remaddress.data + sizeof(__u32) * 2,
206 (__u8 *)(daddr + 2));
207 unaligned_u32_set(conn_id->remaddress.data + sizeof(__u32) * 3,
208 (__u8 *)(daddr + 3));
209}
210
211static __always_inline void tcp_estats_conn_id_init(struct tcp_estats_conn_id *conn_id,
212 struct sock *sk)
213{
214 conn_id->localport = _(inet_sk(sk)->inet_sport);
215 conn_id->remport = _(inet_sk(sk)->inet_dport);
216
217 if (_(sk->sk_family) == AF_INET6)
218 conn_id_ipv6_init(conn_id,
219 sk->sk_v6_rcv_saddr.s6_addr32,
220 sk->sk_v6_daddr.s6_addr32);
221 else
222 conn_id_ipv4_init(conn_id,
223 &inet_sk(sk)->inet_saddr,
224 &inet_sk(sk)->inet_daddr);
225}
226
227static __always_inline void tcp_estats_init(struct sock *sk,
228 struct tcp_estats_event *event,
229 struct tcp_estats_conn_id *conn_id,
230 enum tcp_estats_event_type type)
231{
232 tcp_estats_ev_init(event, type);
233 tcp_estats_conn_id_init(conn_id, sk);
234}
235
236static __always_inline void send_basic_event(struct sock *sk,
237 enum tcp_estats_event_type type)
238{
239 struct tcp_estats_basic_event ev;
240 __u32 key = bpf_get_prandom_u32();
241
242 memset(&ev, 0, sizeof(ev));
243 tcp_estats_init(sk, &ev.event, &ev.conn_id, type);
244 bpf_map_update_elem(&ev_record_map, &key, &ev, BPF_ANY);
245}
246
247SEC("dummy_tracepoint")
248int _dummy_tracepoint(struct dummy_tracepoint_args *arg)
249{
250 if (!arg->sock)
251 return 0;
252
253 send_basic_event(arg->sock, TCP_ESTATS_TX_RESET);
254 return 0;
255}
256
257char _license[] SEC("license") = "GPL";
258__u32 _version SEC("version") = 1;
259