root/tools/testing/selftests/bpf/progs/test_tcp_estats.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. inet_sk
  2. tcp_estats_ev_init
  3. unaligned_u32_set
  4. conn_id_ipv4_init
  5. conn_id_ipv6_init
  6. tcp_estats_conn_id_init
  7. tcp_estats_init
  8. send_basic_event
  9. SEC

   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         __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("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 */

/* [<][>][^][v][top][bottom][index][help] */