1*387f9dfdSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0
2*387f9dfdSAndroid Build Coastguard Worker // Copyright (c) 2021 Wenbo Zhang
3*387f9dfdSAndroid Build Coastguard Worker #include <vmlinux.h>
4*387f9dfdSAndroid Build Coastguard Worker #include <bpf/bpf_helpers.h>
5*387f9dfdSAndroid Build Coastguard Worker #include <bpf/bpf_core_read.h>
6*387f9dfdSAndroid Build Coastguard Worker #include <bpf/bpf_tracing.h>
7*387f9dfdSAndroid Build Coastguard Worker #include <bpf/bpf_endian.h>
8*387f9dfdSAndroid Build Coastguard Worker #include "tcprtt.h"
9*387f9dfdSAndroid Build Coastguard Worker #include "bits.bpf.h"
10*387f9dfdSAndroid Build Coastguard Worker #include "maps.bpf.h"
11*387f9dfdSAndroid Build Coastguard Worker
12*387f9dfdSAndroid Build Coastguard Worker /* Taken from kernel include/linux/socket.h. */
13*387f9dfdSAndroid Build Coastguard Worker #define AF_INET 2 /* IP version 4 */
14*387f9dfdSAndroid Build Coastguard Worker #define AF_INET6 10 /* IP version 6 */
15*387f9dfdSAndroid Build Coastguard Worker
16*387f9dfdSAndroid Build Coastguard Worker
17*387f9dfdSAndroid Build Coastguard Worker const volatile bool targ_laddr_hist = false;
18*387f9dfdSAndroid Build Coastguard Worker const volatile bool targ_raddr_hist = false;
19*387f9dfdSAndroid Build Coastguard Worker const volatile bool targ_show_ext = false;
20*387f9dfdSAndroid Build Coastguard Worker const volatile __u16 targ_sport = 0;
21*387f9dfdSAndroid Build Coastguard Worker const volatile __u16 targ_dport = 0;
22*387f9dfdSAndroid Build Coastguard Worker const volatile __u32 targ_saddr = 0;
23*387f9dfdSAndroid Build Coastguard Worker const volatile __u32 targ_daddr = 0;
24*387f9dfdSAndroid Build Coastguard Worker const volatile __u8 targ_saddr_v6[IPV6_LEN] = {};
25*387f9dfdSAndroid Build Coastguard Worker const volatile __u8 targ_daddr_v6[IPV6_LEN] = {};
26*387f9dfdSAndroid Build Coastguard Worker const volatile bool targ_ms = false;
27*387f9dfdSAndroid Build Coastguard Worker
28*387f9dfdSAndroid Build Coastguard Worker #define MAX_ENTRIES 10240
29*387f9dfdSAndroid Build Coastguard Worker
30*387f9dfdSAndroid Build Coastguard Worker struct {
31*387f9dfdSAndroid Build Coastguard Worker __uint(type, BPF_MAP_TYPE_HASH);
32*387f9dfdSAndroid Build Coastguard Worker __uint(max_entries, MAX_ENTRIES);
33*387f9dfdSAndroid Build Coastguard Worker __type(key, struct hist_key);
34*387f9dfdSAndroid Build Coastguard Worker __type(value, struct hist);
35*387f9dfdSAndroid Build Coastguard Worker } hists SEC(".maps");
36*387f9dfdSAndroid Build Coastguard Worker
37*387f9dfdSAndroid Build Coastguard Worker static struct hist zero;
38*387f9dfdSAndroid Build Coastguard Worker
39*387f9dfdSAndroid Build Coastguard Worker /*
40*387f9dfdSAndroid Build Coastguard Worker * We cannot use the following:
41*387f9dfdSAndroid Build Coastguard Worker * __builtin_memcmp(targ_*addr_v6, *, sizeof(targ_*addr_v6));
42*387f9dfdSAndroid Build Coastguard Worker * Indeed, by using the builtin, we would discard the volatile qualifier of
43*387f9dfdSAndroid Build Coastguard Worker * targ_*addr_v6, so the compiler would optimize it and replaces the call
44*387f9dfdSAndroid Build Coastguard Worker * with 0.
45*387f9dfdSAndroid Build Coastguard Worker * So, using the volatile qualifier ensures this function is called at runtime.
46*387f9dfdSAndroid Build Coastguard Worker */
ipv6_is_not_zero(const volatile __u8 addr[IPV6_LEN])47*387f9dfdSAndroid Build Coastguard Worker static bool inline ipv6_is_not_zero(const volatile __u8 addr[IPV6_LEN])
48*387f9dfdSAndroid Build Coastguard Worker {
49*387f9dfdSAndroid Build Coastguard Worker for (int i = 0; i < IPV6_LEN; i++)
50*387f9dfdSAndroid Build Coastguard Worker if (addr[i])
51*387f9dfdSAndroid Build Coastguard Worker return true;
52*387f9dfdSAndroid Build Coastguard Worker return false;
53*387f9dfdSAndroid Build Coastguard Worker }
54*387f9dfdSAndroid Build Coastguard Worker
ipv6_are_different(const volatile __u8 a[IPV6_LEN],const __u8 b[IPV6_LEN])55*387f9dfdSAndroid Build Coastguard Worker static bool inline ipv6_are_different(const volatile __u8 a[IPV6_LEN], const __u8 b[IPV6_LEN])
56*387f9dfdSAndroid Build Coastguard Worker {
57*387f9dfdSAndroid Build Coastguard Worker for (int i = 0; i < IPV6_LEN; i++)
58*387f9dfdSAndroid Build Coastguard Worker if (a[i] != b[i])
59*387f9dfdSAndroid Build Coastguard Worker return true;
60*387f9dfdSAndroid Build Coastguard Worker return false;
61*387f9dfdSAndroid Build Coastguard Worker }
62*387f9dfdSAndroid Build Coastguard Worker
handle_tcp_rcv_established(struct sock * sk)63*387f9dfdSAndroid Build Coastguard Worker static int handle_tcp_rcv_established(struct sock *sk)
64*387f9dfdSAndroid Build Coastguard Worker {
65*387f9dfdSAndroid Build Coastguard Worker const struct inet_sock *inet = (struct inet_sock *)(sk);
66*387f9dfdSAndroid Build Coastguard Worker struct tcp_sock *ts;
67*387f9dfdSAndroid Build Coastguard Worker struct hist *histp;
68*387f9dfdSAndroid Build Coastguard Worker struct hist_key key = {};
69*387f9dfdSAndroid Build Coastguard Worker u64 slot;
70*387f9dfdSAndroid Build Coastguard Worker u32 srtt;
71*387f9dfdSAndroid Build Coastguard Worker
72*387f9dfdSAndroid Build Coastguard Worker if (targ_sport && targ_sport != BPF_CORE_READ(inet, inet_sport))
73*387f9dfdSAndroid Build Coastguard Worker return 0;
74*387f9dfdSAndroid Build Coastguard Worker if (targ_dport && targ_dport != BPF_CORE_READ(sk, __sk_common.skc_dport))
75*387f9dfdSAndroid Build Coastguard Worker return 0;
76*387f9dfdSAndroid Build Coastguard Worker
77*387f9dfdSAndroid Build Coastguard Worker key.family = BPF_CORE_READ(sk, __sk_common.skc_family);
78*387f9dfdSAndroid Build Coastguard Worker switch (key.family) {
79*387f9dfdSAndroid Build Coastguard Worker case AF_INET:
80*387f9dfdSAndroid Build Coastguard Worker /* If we set any of IPv6 address, we do not care about IPv4 ones. */
81*387f9dfdSAndroid Build Coastguard Worker if (ipv6_is_not_zero(targ_saddr_v6) || ipv6_is_not_zero(targ_daddr_v6))
82*387f9dfdSAndroid Build Coastguard Worker return 0;
83*387f9dfdSAndroid Build Coastguard Worker
84*387f9dfdSAndroid Build Coastguard Worker if (targ_saddr && targ_saddr != BPF_CORE_READ(inet, inet_saddr))
85*387f9dfdSAndroid Build Coastguard Worker return 0;
86*387f9dfdSAndroid Build Coastguard Worker
87*387f9dfdSAndroid Build Coastguard Worker if (targ_daddr && targ_daddr != BPF_CORE_READ(sk, __sk_common.skc_daddr))
88*387f9dfdSAndroid Build Coastguard Worker return 0;
89*387f9dfdSAndroid Build Coastguard Worker
90*387f9dfdSAndroid Build Coastguard Worker break;
91*387f9dfdSAndroid Build Coastguard Worker case AF_INET6:
92*387f9dfdSAndroid Build Coastguard Worker /*
93*387f9dfdSAndroid Build Coastguard Worker * Reciprocal of the above: if we set any of IPv4 address, we do not care
94*387f9dfdSAndroid Build Coastguard Worker * about IPv6 ones.
95*387f9dfdSAndroid Build Coastguard Worker */
96*387f9dfdSAndroid Build Coastguard Worker if (targ_saddr || targ_daddr)
97*387f9dfdSAndroid Build Coastguard Worker return 0;
98*387f9dfdSAndroid Build Coastguard Worker
99*387f9dfdSAndroid Build Coastguard Worker if (ipv6_is_not_zero(targ_saddr_v6)
100*387f9dfdSAndroid Build Coastguard Worker && ipv6_are_different(targ_saddr_v6, BPF_CORE_READ(inet, pinet6, saddr.in6_u.u6_addr8)))
101*387f9dfdSAndroid Build Coastguard Worker return 0;
102*387f9dfdSAndroid Build Coastguard Worker
103*387f9dfdSAndroid Build Coastguard Worker if (ipv6_is_not_zero(targ_daddr_v6)
104*387f9dfdSAndroid Build Coastguard Worker && ipv6_are_different(targ_daddr_v6, BPF_CORE_READ(sk, __sk_common.skc_v6_daddr.in6_u.u6_addr8)))
105*387f9dfdSAndroid Build Coastguard Worker return 0;
106*387f9dfdSAndroid Build Coastguard Worker
107*387f9dfdSAndroid Build Coastguard Worker break;
108*387f9dfdSAndroid Build Coastguard Worker default:
109*387f9dfdSAndroid Build Coastguard Worker return 0;
110*387f9dfdSAndroid Build Coastguard Worker }
111*387f9dfdSAndroid Build Coastguard Worker
112*387f9dfdSAndroid Build Coastguard Worker if (targ_laddr_hist) {
113*387f9dfdSAndroid Build Coastguard Worker if (key.family == AF_INET6)
114*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(key.addr, sizeof(key.addr), BPF_CORE_READ(inet, pinet6, saddr.in6_u.u6_addr8));
115*387f9dfdSAndroid Build Coastguard Worker else
116*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(key.addr, sizeof(inet->inet_saddr), &inet->inet_saddr);
117*387f9dfdSAndroid Build Coastguard Worker } else if (targ_raddr_hist) {
118*387f9dfdSAndroid Build Coastguard Worker if (key.family == AF_INET6)
119*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&key.addr, sizeof(key.addr), BPF_CORE_READ(sk, __sk_common.skc_v6_daddr.in6_u.u6_addr8));
120*387f9dfdSAndroid Build Coastguard Worker else
121*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&key.addr, sizeof(inet->sk.__sk_common.skc_daddr), &inet->sk.__sk_common.skc_daddr);
122*387f9dfdSAndroid Build Coastguard Worker } else {
123*387f9dfdSAndroid Build Coastguard Worker key.family = 0;
124*387f9dfdSAndroid Build Coastguard Worker }
125*387f9dfdSAndroid Build Coastguard Worker
126*387f9dfdSAndroid Build Coastguard Worker histp = bpf_map_lookup_or_try_init(&hists, &key, &zero);
127*387f9dfdSAndroid Build Coastguard Worker if (!histp)
128*387f9dfdSAndroid Build Coastguard Worker return 0;
129*387f9dfdSAndroid Build Coastguard Worker ts = (struct tcp_sock *)(sk);
130*387f9dfdSAndroid Build Coastguard Worker srtt = BPF_CORE_READ(ts, srtt_us) >> 3;
131*387f9dfdSAndroid Build Coastguard Worker if (targ_ms)
132*387f9dfdSAndroid Build Coastguard Worker srtt /= 1000U;
133*387f9dfdSAndroid Build Coastguard Worker slot = log2l(srtt);
134*387f9dfdSAndroid Build Coastguard Worker if (slot >= MAX_SLOTS)
135*387f9dfdSAndroid Build Coastguard Worker slot = MAX_SLOTS - 1;
136*387f9dfdSAndroid Build Coastguard Worker __sync_fetch_and_add(&histp->slots[slot], 1);
137*387f9dfdSAndroid Build Coastguard Worker if (targ_show_ext) {
138*387f9dfdSAndroid Build Coastguard Worker __sync_fetch_and_add(&histp->latency, srtt);
139*387f9dfdSAndroid Build Coastguard Worker __sync_fetch_and_add(&histp->cnt, 1);
140*387f9dfdSAndroid Build Coastguard Worker }
141*387f9dfdSAndroid Build Coastguard Worker return 0;
142*387f9dfdSAndroid Build Coastguard Worker }
143*387f9dfdSAndroid Build Coastguard Worker
144*387f9dfdSAndroid Build Coastguard Worker SEC("fentry/tcp_rcv_established")
BPF_PROG(tcp_rcv,struct sock * sk)145*387f9dfdSAndroid Build Coastguard Worker int BPF_PROG(tcp_rcv, struct sock *sk)
146*387f9dfdSAndroid Build Coastguard Worker {
147*387f9dfdSAndroid Build Coastguard Worker return handle_tcp_rcv_established(sk);
148*387f9dfdSAndroid Build Coastguard Worker }
149*387f9dfdSAndroid Build Coastguard Worker
150*387f9dfdSAndroid Build Coastguard Worker SEC("kprobe/tcp_rcv_established")
BPF_KPROBE(tcp_rcv_kprobe,struct sock * sk)151*387f9dfdSAndroid Build Coastguard Worker int BPF_KPROBE(tcp_rcv_kprobe, struct sock *sk)
152*387f9dfdSAndroid Build Coastguard Worker {
153*387f9dfdSAndroid Build Coastguard Worker return handle_tcp_rcv_established(sk);
154*387f9dfdSAndroid Build Coastguard Worker }
155*387f9dfdSAndroid Build Coastguard Worker
156*387f9dfdSAndroid Build Coastguard Worker char LICENSE[] SEC("license") = "Dual BSD/GPL";
157