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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.