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_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 /* 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 __u32 type; 153 __u32 max_entries; 154 __u32 *key; 155 struct tcp_estats_basic_event *value; 156 } ev_record_map SEC(".maps") = { 157 .type = BPF_MAP_TYPE_HASH, 158 .max_entries = 1024, 159 }; 160 161 struct dummy_tracepoint_args { 162 unsigned long long pad; 163 struct sock *sock; 164 }; 165 166 static __always_inline void tcp_estats_ev_init(struct tcp_estats_event *event, 167 enum tcp_estats_event_type type) 168 { 169 event->magic = TCP_ESTATS_MAGIC; 170 event->ts = bpf_ktime_get_ns(); 171 event->event_type = type; 172 } 173 174 static __always_inline void unaligned_u32_set(unsigned char *to, __u8 *from) 175 { 176 to[0] = _(from[0]); 177 to[1] = _(from[1]); 178 to[2] = _(from[2]); 179 to[3] = _(from[3]); 180 } 181 182 static __always_inline void conn_id_ipv4_init(struct tcp_estats_conn_id *conn_id, 183 __be32 *saddr, __be32 *daddr) 184 { 185 conn_id->localaddressType = TCP_ESTATS_ADDRTYPE_IPV4; 186 187 unaligned_u32_set(conn_id->localaddress.data, (__u8 *)saddr); 188 unaligned_u32_set(conn_id->remaddress.data, (__u8 *)daddr); 189 } 190 191 static __always_inline void conn_id_ipv6_init(struct tcp_estats_conn_id *conn_id, 192 __be32 *saddr, __be32 *daddr) 193 { 194 conn_id->localaddressType = TCP_ESTATS_ADDRTYPE_IPV6; 195 196 unaligned_u32_set(conn_id->localaddress.data, (__u8 *)saddr); 197 unaligned_u32_set(conn_id->localaddress.data + sizeof(__u32), 198 (__u8 *)(saddr + 1)); 199 unaligned_u32_set(conn_id->localaddress.data + sizeof(__u32) * 2, 200 (__u8 *)(saddr + 2)); 201 unaligned_u32_set(conn_id->localaddress.data + sizeof(__u32) * 3, 202 (__u8 *)(saddr + 3)); 203 204 unaligned_u32_set(conn_id->remaddress.data, 205 (__u8 *)(daddr)); 206 unaligned_u32_set(conn_id->remaddress.data + sizeof(__u32), 207 (__u8 *)(daddr + 1)); 208 unaligned_u32_set(conn_id->remaddress.data + sizeof(__u32) * 2, 209 (__u8 *)(daddr + 2)); 210 unaligned_u32_set(conn_id->remaddress.data + sizeof(__u32) * 3, 211 (__u8 *)(daddr + 3)); 212 } 213 214 static __always_inline void tcp_estats_conn_id_init(struct tcp_estats_conn_id *conn_id, 215 struct sock *sk) 216 { 217 conn_id->localport = _(inet_sk(sk)->inet_sport); 218 conn_id->remport = _(inet_sk(sk)->inet_dport); 219 220 if (_(sk->sk_family) == AF_INET6) 221 conn_id_ipv6_init(conn_id, 222 sk->sk_v6_rcv_saddr.s6_addr32, 223 sk->sk_v6_daddr.s6_addr32); 224 else 225 conn_id_ipv4_init(conn_id, 226 &inet_sk(sk)->inet_saddr, 227 &inet_sk(sk)->inet_daddr); 228 } 229 230 static __always_inline void tcp_estats_init(struct sock *sk, 231 struct tcp_estats_event *event, 232 struct tcp_estats_conn_id *conn_id, 233 enum tcp_estats_event_type type) 234 { 235 tcp_estats_ev_init(event, type); 236 tcp_estats_conn_id_init(conn_id, sk); 237 } 238 239 static __always_inline void send_basic_event(struct sock *sk, 240 enum tcp_estats_event_type type) 241 { 242 struct tcp_estats_basic_event ev; 243 __u32 key = bpf_get_prandom_u32(); 244 245 memset(&ev, 0, sizeof(ev)); 246 tcp_estats_init(sk, &ev.event, &ev.conn_id, type); 247 bpf_map_update_elem(&ev_record_map, &key, &ev, BPF_ANY); 248 } 249 250 SEC("dummy_tracepoint") 251 int _dummy_tracepoint(struct dummy_tracepoint_args *arg) 252 { 253 if (!arg->sock) 254 return 0; 255 256 send_basic_event(arg->sock, TCP_ESTATS_TX_RESET); 257 return 0; 258 } 259 260 char _license[] SEC("license") = "GPL"; 261 __u32 _version SEC("version") = 1; /* ignored by tracepoints, required by libbpf.a */ 262