Back to home page

OSCL-LXR

 
 

    


0001 /* Copyright (c) 2017 Facebook
0002  *
0003  * This program is free software; you can redistribute it and/or
0004  * modify it under the terms of version 2 of the GNU General Public
0005  * License as published by the Free Software Foundation.
0006  */
0007 
0008 /* This program shows clang/llvm is able to generate code pattern
0009  * like:
0010  *   _tcp_send_active_reset:
0011  *      0:       bf 16 00 00 00 00 00 00         r6 = r1
0012  *    ......
0013  *    335:       b7 01 00 00 0f 00 00 00         r1 = 15
0014  *    336:       05 00 48 00 00 00 00 00         goto 72
0015  *
0016  *   LBB0_3:
0017  *    337:       b7 01 00 00 01 00 00 00         r1 = 1
0018  *    338:       63 1a d0 ff 00 00 00 00         *(u32 *)(r10 - 48) = r1
0019  *    408:       b7 01 00 00 03 00 00 00         r1 = 3
0020  *
0021  *   LBB0_4:
0022  *    409:       71 a2 fe ff 00 00 00 00         r2 = *(u8 *)(r10 - 2)
0023  *    410:       bf a7 00 00 00 00 00 00         r7 = r10
0024  *    411:       07 07 00 00 b8 ff ff ff         r7 += -72
0025  *    412:       bf 73 00 00 00 00 00 00         r3 = r7
0026  *    413:       0f 13 00 00 00 00 00 00         r3 += r1
0027  *    414:       73 23 2d 00 00 00 00 00         *(u8 *)(r3 + 45) = r2
0028  *
0029  * From the above code snippet, the code generated by the compiler
0030  * is reasonable. The "r1" is assigned to different values in basic
0031  * blocks "_tcp_send_active_reset" and "LBB0_3", and used in "LBB0_4".
0032  * The verifier should be able to handle such code patterns.
0033  */
0034 #include <string.h>
0035 #include <linux/bpf.h>
0036 #include <linux/ipv6.h>
0037 #include <linux/version.h>
0038 #include <sys/socket.h>
0039 #include <bpf/bpf_helpers.h>
0040 
0041 #define _(P) ({typeof(P) val = 0; bpf_probe_read_kernel(&val, sizeof(val), &P); val;})
0042 #define TCP_ESTATS_MAGIC 0xBAADBEEF
0043 
0044 /* This test case needs "sock" and "pt_regs" data structure.
0045  * Recursively, "sock" needs "sock_common" and "inet_sock".
0046  * However, this is a unit test case only for
0047  * verifier purpose without bpf program execution.
0048  * We can safely mock much simpler data structures, basically
0049  * only taking the necessary fields from kernel headers.
0050  */
0051 typedef __u32 __bitwise __portpair;
0052 typedef __u64 __bitwise __addrpair;
0053 
0054 struct sock_common {
0055     unsigned short      skc_family;
0056     union {
0057         __addrpair  skc_addrpair;
0058         struct {
0059             __be32  skc_daddr;
0060             __be32  skc_rcv_saddr;
0061         };
0062     };
0063     union {
0064         __portpair  skc_portpair;
0065         struct {
0066             __be16  skc_dport;
0067             __u16   skc_num;
0068         };
0069     };
0070     struct in6_addr     skc_v6_daddr;
0071     struct in6_addr     skc_v6_rcv_saddr;
0072 };
0073 
0074 struct sock {
0075     struct sock_common  __sk_common;
0076 #define sk_family       __sk_common.skc_family
0077 #define sk_v6_daddr     __sk_common.skc_v6_daddr
0078 #define sk_v6_rcv_saddr     __sk_common.skc_v6_rcv_saddr
0079 };
0080 
0081 struct inet_sock {
0082     struct sock     sk;
0083 #define inet_daddr      sk.__sk_common.skc_daddr
0084 #define inet_dport      sk.__sk_common.skc_dport
0085     __be32          inet_saddr;
0086     __be16          inet_sport;
0087 };
0088 
0089 struct pt_regs {
0090     long di;
0091 };
0092 
0093 static inline struct inet_sock *inet_sk(const struct sock *sk)
0094 {
0095     return (struct inet_sock *)sk;
0096 }
0097 
0098 /* Define various data structures for state recording.
0099  * Some fields are not used due to test simplification.
0100  */
0101 enum tcp_estats_addrtype {
0102     TCP_ESTATS_ADDRTYPE_IPV4 = 1,
0103     TCP_ESTATS_ADDRTYPE_IPV6 = 2
0104 };
0105 
0106 enum tcp_estats_event_type {
0107     TCP_ESTATS_ESTABLISH,
0108     TCP_ESTATS_PERIODIC,
0109     TCP_ESTATS_TIMEOUT,
0110     TCP_ESTATS_RETRANSMIT_TIMEOUT,
0111     TCP_ESTATS_RETRANSMIT_OTHER,
0112     TCP_ESTATS_SYN_RETRANSMIT,
0113     TCP_ESTATS_SYNACK_RETRANSMIT,
0114     TCP_ESTATS_TERM,
0115     TCP_ESTATS_TX_RESET,
0116     TCP_ESTATS_RX_RESET,
0117     TCP_ESTATS_WRITE_TIMEOUT,
0118     TCP_ESTATS_CONN_TIMEOUT,
0119     TCP_ESTATS_ACK_LATENCY,
0120     TCP_ESTATS_NEVENTS,
0121 };
0122 
0123 struct tcp_estats_event {
0124     int pid;
0125     int cpu;
0126     unsigned long ts;
0127     unsigned int magic;
0128     enum tcp_estats_event_type event_type;
0129 };
0130 
0131 /* The below data structure is packed in order for
0132  * llvm compiler to generate expected code.
0133  */
0134 struct tcp_estats_conn_id {
0135     unsigned int localaddressType;
0136     struct {
0137         unsigned char data[16];
0138     } localaddress;
0139     struct {
0140         unsigned char data[16];
0141     } remaddress;
0142     unsigned short    localport;
0143     unsigned short    remport;
0144 } __attribute__((__packed__));
0145 
0146 struct tcp_estats_basic_event {
0147     struct tcp_estats_event event;
0148     struct tcp_estats_conn_id conn_id;
0149 };
0150 
0151 struct {
0152     __uint(type, BPF_MAP_TYPE_HASH);
0153     __uint(max_entries, 1024);
0154     __type(key, __u32);
0155     __type(value, struct tcp_estats_basic_event);
0156 } ev_record_map SEC(".maps");
0157 
0158 struct dummy_tracepoint_args {
0159     unsigned long long pad;
0160     struct sock *sock;
0161 };
0162 
0163 static __always_inline void tcp_estats_ev_init(struct tcp_estats_event *event,
0164                            enum tcp_estats_event_type type)
0165 {
0166     event->magic = TCP_ESTATS_MAGIC;
0167     event->ts = bpf_ktime_get_ns();
0168     event->event_type = type;
0169 }
0170 
0171 static __always_inline void unaligned_u32_set(unsigned char *to, __u8 *from)
0172 {
0173     to[0] = _(from[0]);
0174     to[1] = _(from[1]);
0175     to[2] = _(from[2]);
0176     to[3] = _(from[3]);
0177 }
0178 
0179 static __always_inline void conn_id_ipv4_init(struct tcp_estats_conn_id *conn_id,
0180                           __be32 *saddr, __be32 *daddr)
0181 {
0182     conn_id->localaddressType = TCP_ESTATS_ADDRTYPE_IPV4;
0183 
0184     unaligned_u32_set(conn_id->localaddress.data, (__u8 *)saddr);
0185     unaligned_u32_set(conn_id->remaddress.data, (__u8 *)daddr);
0186 }
0187 
0188 static __always_inline void conn_id_ipv6_init(struct tcp_estats_conn_id *conn_id,
0189                           __be32 *saddr, __be32 *daddr)
0190 {
0191     conn_id->localaddressType = TCP_ESTATS_ADDRTYPE_IPV6;
0192 
0193     unaligned_u32_set(conn_id->localaddress.data, (__u8 *)saddr);
0194     unaligned_u32_set(conn_id->localaddress.data + sizeof(__u32),
0195               (__u8 *)(saddr + 1));
0196     unaligned_u32_set(conn_id->localaddress.data + sizeof(__u32) * 2,
0197               (__u8 *)(saddr + 2));
0198     unaligned_u32_set(conn_id->localaddress.data + sizeof(__u32) * 3,
0199               (__u8 *)(saddr + 3));
0200 
0201     unaligned_u32_set(conn_id->remaddress.data,
0202               (__u8 *)(daddr));
0203     unaligned_u32_set(conn_id->remaddress.data + sizeof(__u32),
0204               (__u8 *)(daddr + 1));
0205     unaligned_u32_set(conn_id->remaddress.data + sizeof(__u32) * 2,
0206               (__u8 *)(daddr + 2));
0207     unaligned_u32_set(conn_id->remaddress.data + sizeof(__u32) * 3,
0208               (__u8 *)(daddr + 3));
0209 }
0210 
0211 static __always_inline void tcp_estats_conn_id_init(struct tcp_estats_conn_id *conn_id,
0212                             struct sock *sk)
0213 {
0214     conn_id->localport = _(inet_sk(sk)->inet_sport);
0215     conn_id->remport = _(inet_sk(sk)->inet_dport);
0216 
0217     if (_(sk->sk_family) == AF_INET6)
0218         conn_id_ipv6_init(conn_id,
0219                   sk->sk_v6_rcv_saddr.s6_addr32,
0220                   sk->sk_v6_daddr.s6_addr32);
0221     else
0222         conn_id_ipv4_init(conn_id,
0223                   &inet_sk(sk)->inet_saddr,
0224                   &inet_sk(sk)->inet_daddr);
0225 }
0226 
0227 static __always_inline void tcp_estats_init(struct sock *sk,
0228                         struct tcp_estats_event *event,
0229                         struct tcp_estats_conn_id *conn_id,
0230                         enum tcp_estats_event_type type)
0231 {
0232     tcp_estats_ev_init(event, type);
0233     tcp_estats_conn_id_init(conn_id, sk);
0234 }
0235 
0236 static __always_inline void send_basic_event(struct sock *sk,
0237                          enum tcp_estats_event_type type)
0238 {
0239     struct tcp_estats_basic_event ev;
0240     __u32 key = bpf_get_prandom_u32();
0241 
0242     memset(&ev, 0, sizeof(ev));
0243     tcp_estats_init(sk, &ev.event, &ev.conn_id, type);
0244     bpf_map_update_elem(&ev_record_map, &key, &ev, BPF_ANY);
0245 }
0246 
0247 SEC("tp/dummy/tracepoint")
0248 int _dummy_tracepoint(struct dummy_tracepoint_args *arg)
0249 {
0250     if (!arg->sock)
0251         return 0;
0252 
0253     send_basic_event(arg->sock, TCP_ESTATS_TX_RESET);
0254     return 0;
0255 }
0256 
0257 char _license[] SEC("license") = "GPL";