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_kernel(&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 */