Home | History | Annotate | Download | only in bpf
      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 bpf_map_def SEC("maps") ev_record_map = {
    152 	.type = BPF_MAP_TYPE_HASH,
    153 	.key_size = sizeof(__u32),
    154 	.value_size = sizeof(struct tcp_estats_basic_event),
    155 	.max_entries = 1024,
    156 };
    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("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 __u32 _version SEC("version") = 1; /* ignored by tracepoints, required by libbpf.a */
    259