test_tcp_estats.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  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. /* This program shows clang/llvm is able to generate code pattern
  8. * like:
  9. * _tcp_send_active_reset:
  10. * 0: bf 16 00 00 00 00 00 00 r6 = r1
  11. * ......
  12. * 335: b7 01 00 00 0f 00 00 00 r1 = 15
  13. * 336: 05 00 48 00 00 00 00 00 goto 72
  14. *
  15. * LBB0_3:
  16. * 337: b7 01 00 00 01 00 00 00 r1 = 1
  17. * 338: 63 1a d0 ff 00 00 00 00 *(u32 *)(r10 - 48) = r1
  18. * 408: b7 01 00 00 03 00 00 00 r1 = 3
  19. *
  20. * LBB0_4:
  21. * 409: 71 a2 fe ff 00 00 00 00 r2 = *(u8 *)(r10 - 2)
  22. * 410: bf a7 00 00 00 00 00 00 r7 = r10
  23. * 411: 07 07 00 00 b8 ff ff ff r7 += -72
  24. * 412: bf 73 00 00 00 00 00 00 r3 = r7
  25. * 413: 0f 13 00 00 00 00 00 00 r3 += r1
  26. * 414: 73 23 2d 00 00 00 00 00 *(u8 *)(r3 + 45) = r2
  27. *
  28. * From the above code snippet, the code generated by the compiler
  29. * is reasonable. The "r1" is assigned to different values in basic
  30. * blocks "_tcp_send_active_reset" and "LBB0_3", and used in "LBB0_4".
  31. * The verifier should be able to handle such code patterns.
  32. */
  33. #include <string.h>
  34. #include <linux/bpf.h>
  35. #include <linux/ipv6.h>
  36. #include <linux/version.h>
  37. #include <sys/socket.h>
  38. #include "bpf_helpers.h"
  39. #define _(P) ({typeof(P) val = 0; bpf_probe_read(&val, sizeof(val), &P); val;})
  40. #define TCP_ESTATS_MAGIC 0xBAADBEEF
  41. /* This test case needs "sock" and "pt_regs" data structure.
  42. * Recursively, "sock" needs "sock_common" and "inet_sock".
  43. * However, this is a unit test case only for
  44. * verifier purpose without bpf program execution.
  45. * We can safely mock much simpler data structures, basically
  46. * only taking the necessary fields from kernel headers.
  47. */
  48. typedef __u32 __bitwise __portpair;
  49. typedef __u64 __bitwise __addrpair;
  50. struct sock_common {
  51. unsigned short skc_family;
  52. union {
  53. __addrpair skc_addrpair;
  54. struct {
  55. __be32 skc_daddr;
  56. __be32 skc_rcv_saddr;
  57. };
  58. };
  59. union {
  60. __portpair skc_portpair;
  61. struct {
  62. __be16 skc_dport;
  63. __u16 skc_num;
  64. };
  65. };
  66. struct in6_addr skc_v6_daddr;
  67. struct in6_addr skc_v6_rcv_saddr;
  68. };
  69. struct sock {
  70. struct sock_common __sk_common;
  71. #define sk_family __sk_common.skc_family
  72. #define sk_v6_daddr __sk_common.skc_v6_daddr
  73. #define sk_v6_rcv_saddr __sk_common.skc_v6_rcv_saddr
  74. };
  75. struct inet_sock {
  76. struct sock sk;
  77. #define inet_daddr sk.__sk_common.skc_daddr
  78. #define inet_dport sk.__sk_common.skc_dport
  79. __be32 inet_saddr;
  80. __be16 inet_sport;
  81. };
  82. struct pt_regs {
  83. long di;
  84. };
  85. static inline struct inet_sock *inet_sk(const struct sock *sk)
  86. {
  87. return (struct inet_sock *)sk;
  88. }
  89. /* Define various data structures for state recording.
  90. * Some fields are not used due to test simplification.
  91. */
  92. enum tcp_estats_addrtype {
  93. TCP_ESTATS_ADDRTYPE_IPV4 = 1,
  94. TCP_ESTATS_ADDRTYPE_IPV6 = 2
  95. };
  96. enum tcp_estats_event_type {
  97. TCP_ESTATS_ESTABLISH,
  98. TCP_ESTATS_PERIODIC,
  99. TCP_ESTATS_TIMEOUT,
  100. TCP_ESTATS_RETRANSMIT_TIMEOUT,
  101. TCP_ESTATS_RETRANSMIT_OTHER,
  102. TCP_ESTATS_SYN_RETRANSMIT,
  103. TCP_ESTATS_SYNACK_RETRANSMIT,
  104. TCP_ESTATS_TERM,
  105. TCP_ESTATS_TX_RESET,
  106. TCP_ESTATS_RX_RESET,
  107. TCP_ESTATS_WRITE_TIMEOUT,
  108. TCP_ESTATS_CONN_TIMEOUT,
  109. TCP_ESTATS_ACK_LATENCY,
  110. TCP_ESTATS_NEVENTS,
  111. };
  112. struct tcp_estats_event {
  113. int pid;
  114. int cpu;
  115. unsigned long ts;
  116. unsigned int magic;
  117. enum tcp_estats_event_type event_type;
  118. };
  119. /* The below data structure is packed in order for
  120. * llvm compiler to generate expected code.
  121. */
  122. struct tcp_estats_conn_id {
  123. unsigned int localaddressType;
  124. struct {
  125. unsigned char data[16];
  126. } localaddress;
  127. struct {
  128. unsigned char data[16];
  129. } remaddress;
  130. unsigned short localport;
  131. unsigned short remport;
  132. } __attribute__((__packed__));
  133. struct tcp_estats_basic_event {
  134. struct tcp_estats_event event;
  135. struct tcp_estats_conn_id conn_id;
  136. };
  137. struct bpf_map_def SEC("maps") ev_record_map = {
  138. .type = BPF_MAP_TYPE_HASH,
  139. .key_size = sizeof(__u32),
  140. .value_size = sizeof(struct tcp_estats_basic_event),
  141. .max_entries = 1024,
  142. };
  143. struct dummy_tracepoint_args {
  144. unsigned long long pad;
  145. struct sock *sock;
  146. };
  147. static __always_inline void tcp_estats_ev_init(struct tcp_estats_event *event,
  148. enum tcp_estats_event_type type)
  149. {
  150. event->magic = TCP_ESTATS_MAGIC;
  151. event->ts = bpf_ktime_get_ns();
  152. event->event_type = type;
  153. }
  154. static __always_inline void unaligned_u32_set(unsigned char *to, __u8 *from)
  155. {
  156. to[0] = _(from[0]);
  157. to[1] = _(from[1]);
  158. to[2] = _(from[2]);
  159. to[3] = _(from[3]);
  160. }
  161. static __always_inline void conn_id_ipv4_init(struct tcp_estats_conn_id *conn_id,
  162. __be32 *saddr, __be32 *daddr)
  163. {
  164. conn_id->localaddressType = TCP_ESTATS_ADDRTYPE_IPV4;
  165. unaligned_u32_set(conn_id->localaddress.data, (__u8 *)saddr);
  166. unaligned_u32_set(conn_id->remaddress.data, (__u8 *)daddr);
  167. }
  168. static __always_inline void conn_id_ipv6_init(struct tcp_estats_conn_id *conn_id,
  169. __be32 *saddr, __be32 *daddr)
  170. {
  171. conn_id->localaddressType = TCP_ESTATS_ADDRTYPE_IPV6;
  172. unaligned_u32_set(conn_id->localaddress.data, (__u8 *)saddr);
  173. unaligned_u32_set(conn_id->localaddress.data + sizeof(__u32),
  174. (__u8 *)(saddr + 1));
  175. unaligned_u32_set(conn_id->localaddress.data + sizeof(__u32) * 2,
  176. (__u8 *)(saddr + 2));
  177. unaligned_u32_set(conn_id->localaddress.data + sizeof(__u32) * 3,
  178. (__u8 *)(saddr + 3));
  179. unaligned_u32_set(conn_id->remaddress.data,
  180. (__u8 *)(daddr));
  181. unaligned_u32_set(conn_id->remaddress.data + sizeof(__u32),
  182. (__u8 *)(daddr + 1));
  183. unaligned_u32_set(conn_id->remaddress.data + sizeof(__u32) * 2,
  184. (__u8 *)(daddr + 2));
  185. unaligned_u32_set(conn_id->remaddress.data + sizeof(__u32) * 3,
  186. (__u8 *)(daddr + 3));
  187. }
  188. static __always_inline void tcp_estats_conn_id_init(struct tcp_estats_conn_id *conn_id,
  189. struct sock *sk)
  190. {
  191. conn_id->localport = _(inet_sk(sk)->inet_sport);
  192. conn_id->remport = _(inet_sk(sk)->inet_dport);
  193. if (_(sk->sk_family) == AF_INET6)
  194. conn_id_ipv6_init(conn_id,
  195. sk->sk_v6_rcv_saddr.s6_addr32,
  196. sk->sk_v6_daddr.s6_addr32);
  197. else
  198. conn_id_ipv4_init(conn_id,
  199. &inet_sk(sk)->inet_saddr,
  200. &inet_sk(sk)->inet_daddr);
  201. }
  202. static __always_inline void tcp_estats_init(struct sock *sk,
  203. struct tcp_estats_event *event,
  204. struct tcp_estats_conn_id *conn_id,
  205. enum tcp_estats_event_type type)
  206. {
  207. tcp_estats_ev_init(event, type);
  208. tcp_estats_conn_id_init(conn_id, sk);
  209. }
  210. static __always_inline void send_basic_event(struct sock *sk,
  211. enum tcp_estats_event_type type)
  212. {
  213. struct tcp_estats_basic_event ev;
  214. __u32 key = bpf_get_prandom_u32();
  215. memset(&ev, 0, sizeof(ev));
  216. tcp_estats_init(sk, &ev.event, &ev.conn_id, type);
  217. bpf_map_update_elem(&ev_record_map, &key, &ev, BPF_ANY);
  218. }
  219. SEC("dummy_tracepoint")
  220. int _dummy_tracepoint(struct dummy_tracepoint_args *arg)
  221. {
  222. if (!arg->sock)
  223. return 0;
  224. send_basic_event(arg->sock, TCP_ESTATS_TX_RESET);
  225. return 0;
  226. }
  227. char _license[] SEC("license") = "GPL";
  228. __u32 _version SEC("version") = 1; /* ignored by tracepoints, required by libbpf.a */