brintos

brintos / linux-shallow public Read only

0
0
Text · 7.0 KiB · e2ae049 Raw
258 lines · c
1/* Copyright (c) 2017 Facebook2 *3 * This program is free software; you can redistribute it and/or4 * modify it under the terms of version 2 of the GNU General Public5 * License as published by the Free Software Foundation.6 */7 8/* This program shows clang/llvm is able to generate code pattern9 * like:10 *   _tcp_send_active_reset:11 *      0:       bf 16 00 00 00 00 00 00         r6 = r112 *    ......13 *    335:       b7 01 00 00 0f 00 00 00         r1 = 1514 *    336:       05 00 48 00 00 00 00 00         goto 7215 *16 *   LBB0_3:17 *    337:       b7 01 00 00 01 00 00 00         r1 = 118 *    338:       63 1a d0 ff 00 00 00 00         *(u32 *)(r10 - 48) = r119 *    408:       b7 01 00 00 03 00 00 00         r1 = 320 *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 = r1024 *    411:       07 07 00 00 b8 ff ff ff         r7 += -7225 *    412:       bf 73 00 00 00 00 00 00         r3 = r726 *    413:       0f 13 00 00 00 00 00 00         r3 += r127 *    414:       73 23 2d 00 00 00 00 00         *(u8 *)(r3 + 45) = r228 *29 * From the above code snippet, the code generated by the compiler30 * is reasonable. The "r1" is assigned to different values in basic31 * 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 0xBAADBEEF43 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 for47 * verifier purpose without bpf program execution.48 * We can safely mock much simpler data structures, basically49 * 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_family77#define sk_v6_daddr		__sk_common.skc_v6_daddr78#define sk_v6_rcv_saddr		__sk_common.skc_v6_rcv_saddr79};80 81struct inet_sock {82	struct sock		sk;83#define inet_daddr		sk.__sk_common.skc_daddr84#define inet_dport		sk.__sk_common.skc_dport85	__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 = 2104};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 for132 * 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	else222		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("tp/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