0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
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
0045
0046
0047
0048
0049
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
0099
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
0132
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";