Linux Audio

Check our new training course

Yocto / OpenEmbedded training

Mar 24-27, 2025, special US time zones
Register
Loading...
v5.9
  1/* Copyright (c) 2017 Facebook
  2 *
  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.
  6 */
  7
  8/* This program shows clang/llvm is able to generate code pattern
  9 * like:
 10 *   _tcp_send_active_reset:
 11 *      0:       bf 16 00 00 00 00 00 00         r6 = r1
 12 *    ......
 13 *    335:       b7 01 00 00 0f 00 00 00         r1 = 15
 14 *    336:       05 00 48 00 00 00 00 00         goto 72
 15 *
 16 *   LBB0_3:
 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
 20 *
 21 *   LBB0_4:
 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
 28 *
 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.
 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/bpf_helpers.h>
 40
 41#define _(P) ({typeof(P) val = 0; bpf_probe_read_kernel(&val, sizeof(val), &P); val;})
 42#define TCP_ESTATS_MAGIC 0xBAADBEEF
 43
 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.
 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/* Define various data structures for state recording.
 99 * Some fields are not used due to test simplification.
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/* The below data structure is packed in order for
132 * llvm compiler to generate expected code.
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 {
152	__uint(type, BPF_MAP_TYPE_HASH);
153	__uint(max_entries, 1024);
154	__type(key, __u32);
155	__type(value, struct tcp_estats_basic_event);
156} ev_record_map SEC(".maps");
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; /* ignored by tracepoints, required by libbpf.a */
v5.14.15
  1/* Copyright (c) 2017 Facebook
  2 *
  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.
  6 */
  7
  8/* This program shows clang/llvm is able to generate code pattern
  9 * like:
 10 *   _tcp_send_active_reset:
 11 *      0:       bf 16 00 00 00 00 00 00         r6 = r1
 12 *    ......
 13 *    335:       b7 01 00 00 0f 00 00 00         r1 = 15
 14 *    336:       05 00 48 00 00 00 00 00         goto 72
 15 *
 16 *   LBB0_3:
 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
 20 *
 21 *   LBB0_4:
 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
 28 *
 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.
 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/bpf_helpers.h>
 40
 41#define _(P) ({typeof(P) val = 0; bpf_probe_read_kernel(&val, sizeof(val), &P); val;})
 42#define TCP_ESTATS_MAGIC 0xBAADBEEF
 43
 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.
 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/* Define various data structures for state recording.
 99 * Some fields are not used due to test simplification.
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/* The below data structure is packed in order for
132 * llvm compiler to generate expected code.
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 {
152	__uint(type, BPF_MAP_TYPE_HASH);
153	__uint(max_entries, 1024);
154	__type(key, __u32);
155	__type(value, struct tcp_estats_basic_event);
156} ev_record_map SEC(".maps");
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; /* ignored by tracepoints, required by libbpf.a */