1 /* Copyright (c) 2017 Facebook
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of version 2 of the GNU General Public
5 * License as published by the Free Software Foundation.
8 /* This program shows clang/llvm is able to generate code pattern
10 * _tcp_send_active_reset:
11 * 0: bf 16 00 00 00 00 00 00 r6 = r1
13 * 335: b7 01 00 00 0f 00 00 00 r1 = 15
14 * 336: 05 00 48 00 00 00 00 00 goto 72
17 * 337: b7 01 00 00 01 00 00 00 r1 = 1
18 * 338: 63 1a d0 ff 00 00 00 00 *(u32 *)(r10 - 48) = r1
19 * 408: b7 01 00 00 03 00 00 00 r1 = 3
22 * 409: 71 a2 fe ff 00 00 00 00 r2 = *(u8 *)(r10 - 2)
23 * 410: bf a7 00 00 00 00 00 00 r7 = r10
24 * 411: 07 07 00 00 b8 ff ff ff r7 += -72
25 * 412: bf 73 00 00 00 00 00 00 r3 = r7
26 * 413: 0f 13 00 00 00 00 00 00 r3 += r1
27 * 414: 73 23 2d 00 00 00 00 00 *(u8 *)(r3 + 45) = r2
29 * From the above code snippet, the code generated by the compiler
30 * is reasonable. The "r1" is assigned to different values in basic
31 * blocks "_tcp_send_active_reset" and "LBB0_3", and used in "LBB0_4".
32 * The verifier should be able to handle such code patterns.
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"
41 #define _(P) ({typeof(P) val = 0; bpf_probe_read(&val, sizeof(val), &P); val;})
42 #define TCP_ESTATS_MAGIC 0xBAADBEEF
44 /* This test case needs "sock" and "pt_regs" data structure.
45 * Recursively, "sock" needs "sock_common" and "inet_sock".
46 * However, this is a unit test case only for
47 * verifier purpose without bpf program execution.
48 * We can safely mock much simpler data structures, basically
49 * only taking the necessary fields from kernel headers.
51 typedef __u32 __bitwise __portpair
;
52 typedef __u64 __bitwise __addrpair
;
55 unsigned short skc_family
;
57 __addrpair skc_addrpair
;
64 __portpair skc_portpair
;
70 struct in6_addr skc_v6_daddr
;
71 struct in6_addr skc_v6_rcv_saddr
;
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
83 #define inet_daddr sk.__sk_common.skc_daddr
84 #define inet_dport sk.__sk_common.skc_dport
93 static inline struct inet_sock
*inet_sk(const struct sock
*sk
)
95 return (struct inet_sock
*)sk
;
98 /* Define various data structures for state recording.
99 * Some fields are not used due to test simplification.
101 enum tcp_estats_addrtype
{
102 TCP_ESTATS_ADDRTYPE_IPV4
= 1,
103 TCP_ESTATS_ADDRTYPE_IPV6
= 2
106 enum tcp_estats_event_type
{
107 TCP_ESTATS_ESTABLISH
,
110 TCP_ESTATS_RETRANSMIT_TIMEOUT
,
111 TCP_ESTATS_RETRANSMIT_OTHER
,
112 TCP_ESTATS_SYN_RETRANSMIT
,
113 TCP_ESTATS_SYNACK_RETRANSMIT
,
117 TCP_ESTATS_WRITE_TIMEOUT
,
118 TCP_ESTATS_CONN_TIMEOUT
,
119 TCP_ESTATS_ACK_LATENCY
,
123 struct tcp_estats_event
{
128 enum tcp_estats_event_type event_type
;
131 /* The below data structure is packed in order for
132 * llvm compiler to generate expected code.
134 struct tcp_estats_conn_id
{
135 unsigned int localaddressType
;
137 unsigned char data
[16];
140 unsigned char data
[16];
142 unsigned short localport
;
143 unsigned short remport
;
144 } __attribute__((__packed__
));
146 struct tcp_estats_basic_event
{
147 struct tcp_estats_event event
;
148 struct tcp_estats_conn_id conn_id
;
152 __uint(type
, BPF_MAP_TYPE_HASH
);
153 __uint(max_entries
, 1024);
155 __type(value
, struct tcp_estats_basic_event
);
156 } ev_record_map
SEC(".maps");
158 struct dummy_tracepoint_args
{
159 unsigned long long pad
;
163 static __always_inline
void tcp_estats_ev_init(struct tcp_estats_event
*event
,
164 enum tcp_estats_event_type type
)
166 event
->magic
= TCP_ESTATS_MAGIC
;
167 event
->ts
= bpf_ktime_get_ns();
168 event
->event_type
= type
;
171 static __always_inline
void unaligned_u32_set(unsigned char *to
, __u8
*from
)
179 static __always_inline
void conn_id_ipv4_init(struct tcp_estats_conn_id
*conn_id
,
180 __be32
*saddr
, __be32
*daddr
)
182 conn_id
->localaddressType
= TCP_ESTATS_ADDRTYPE_IPV4
;
184 unaligned_u32_set(conn_id
->localaddress
.data
, (__u8
*)saddr
);
185 unaligned_u32_set(conn_id
->remaddress
.data
, (__u8
*)daddr
);
188 static __always_inline
void conn_id_ipv6_init(struct tcp_estats_conn_id
*conn_id
,
189 __be32
*saddr
, __be32
*daddr
)
191 conn_id
->localaddressType
= TCP_ESTATS_ADDRTYPE_IPV6
;
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));
201 unaligned_u32_set(conn_id
->remaddress
.data
,
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));
211 static __always_inline
void tcp_estats_conn_id_init(struct tcp_estats_conn_id
*conn_id
,
214 conn_id
->localport
= _(inet_sk(sk
)->inet_sport
);
215 conn_id
->remport
= _(inet_sk(sk
)->inet_dport
);
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
);
222 conn_id_ipv4_init(conn_id
,
223 &inet_sk(sk
)->inet_saddr
,
224 &inet_sk(sk
)->inet_daddr
);
227 static __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
)
232 tcp_estats_ev_init(event
, type
);
233 tcp_estats_conn_id_init(conn_id
, sk
);
236 static __always_inline
void send_basic_event(struct sock
*sk
,
237 enum tcp_estats_event_type type
)
239 struct tcp_estats_basic_event ev
;
240 __u32 key
= bpf_get_prandom_u32();
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
);
247 SEC("dummy_tracepoint")
248 int _dummy_tracepoint(struct dummy_tracepoint_args
*arg
)
253 send_basic_event(arg
->sock
, TCP_ESTATS_TX_RESET
);
257 char _license
[] SEC("license") = "GPL";
258 __u32 _version
SEC("version") = 1; /* ignored by tracepoints, required by libbpf.a */