~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/bpf/progs/test_tcp_estats.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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  */
 51 typedef __u32 __bitwise __portpair;
 52 typedef __u64 __bitwise __addrpair;
 53 
 54 struct 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 
 74 struct 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 
 81 struct 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 
 89 struct pt_regs {
 90         long di;
 91 };
 92 
 93 static 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  */
101 enum tcp_estats_addrtype {
102         TCP_ESTATS_ADDRTYPE_IPV4 = 1,
103         TCP_ESTATS_ADDRTYPE_IPV6 = 2
104 };
105 
106 enum 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 
123 struct 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  */
134 struct 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 
146 struct tcp_estats_basic_event {
147         struct tcp_estats_event event;
148         struct tcp_estats_conn_id conn_id;
149 };
150 
151 struct {
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 
158 struct dummy_tracepoint_args {
159         unsigned long long pad;
160         struct sock *sock;
161 };
162 
163 static __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 
171 static __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 
179 static __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 
188 static __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 
211 static __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 
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)
231 {
232         tcp_estats_ev_init(event, type);
233         tcp_estats_conn_id_init(conn_id, sk);
234 }
235 
236 static __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 
247 SEC("tp/dummy/tracepoint")
248 int _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 
257 char _license[] SEC("license") = "GPL";
258 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php