| // SPDX-License-Identifier: GPL-2.0 |
| // Copyright (c) 2020 Wenbo Zhang |
| #include <vmlinux.h> |
| #include <bpf/bpf_helpers.h> |
| #include <bpf/bpf_core_read.h> |
| #include <bpf/bpf_tracing.h> |
| #include "tcpconnlat.h" |
| |
| #define AF_INET 2 |
| #define AF_INET6 10 |
| |
| const volatile __u64 targ_min_us = 0; |
| const volatile pid_t targ_tgid = 0; |
| |
| struct piddata { |
| char comm[TASK_COMM_LEN]; |
| u64 ts; |
| u32 tgid; |
| }; |
| |
| struct { |
| __uint(type, BPF_MAP_TYPE_HASH); |
| __uint(max_entries, 4096); |
| __type(key, struct sock *); |
| __type(value, struct piddata); |
| } start SEC(".maps"); |
| |
| struct { |
| __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); |
| __uint(key_size, sizeof(u32)); |
| __uint(value_size, sizeof(u32)); |
| } events SEC(".maps"); |
| |
| static __always_inline int trace_connect(struct sock *sk) |
| { |
| u32 tgid = bpf_get_current_pid_tgid() >> 32; |
| struct piddata piddata = {}; |
| |
| if (targ_tgid && targ_tgid != tgid) |
| return 0; |
| |
| bpf_get_current_comm(&piddata.comm, sizeof(piddata.comm)); |
| piddata.ts = bpf_ktime_get_ns(); |
| piddata.tgid = tgid; |
| bpf_map_update_elem(&start, &sk, &piddata, 0); |
| return 0; |
| } |
| |
| SEC("fentry/tcp_v4_connect") |
| int BPF_PROG(tcp_v4_connect, struct sock *sk) |
| { |
| return trace_connect(sk); |
| } |
| |
| SEC("kprobe/tcp_v6_connect") |
| int BPF_KPROBE(tcp_v6_connect, struct sock *sk) |
| { |
| return trace_connect(sk); |
| } |
| |
| SEC("fentry/tcp_rcv_state_process") |
| int BPF_PROG(tcp_rcv_state_process, struct sock *sk) |
| { |
| struct piddata *piddatap; |
| struct event event = {}; |
| s64 delta; |
| u64 ts; |
| |
| if (sk->__sk_common.skc_state != TCP_SYN_SENT) |
| return 0; |
| |
| piddatap = bpf_map_lookup_elem(&start, &sk); |
| if (!piddatap) |
| return 0; |
| |
| ts = bpf_ktime_get_ns(); |
| delta = (s64)(ts - piddatap->ts); |
| if (delta < 0) |
| goto cleanup; |
| |
| event.delta_us = delta / 1000U; |
| if (targ_min_us && event.delta_us < targ_min_us) |
| goto cleanup; |
| __builtin_memcpy(&event.comm, piddatap->comm, |
| sizeof(event.comm)); |
| event.ts_us = ts / 1000; |
| event.tgid = piddatap->tgid; |
| event.lport = sk->__sk_common.skc_num; |
| event.dport = sk->__sk_common.skc_dport; |
| event.af = sk->__sk_common.skc_family; |
| if (event.af == AF_INET) { |
| event.saddr_v4 = sk->__sk_common.skc_rcv_saddr; |
| event.daddr_v4 = sk->__sk_common.skc_daddr; |
| } else { |
| BPF_CORE_READ_INTO(&event.saddr_v6, sk, |
| __sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32); |
| BPF_CORE_READ_INTO(&event.daddr_v6, sk, |
| __sk_common.skc_v6_daddr.in6_u.u6_addr32); |
| } |
| bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, |
| &event, sizeof(event)); |
| |
| cleanup: |
| bpf_map_delete_elem(&start, &sk); |
| return 0; |
| } |
| |
| char LICENSE[] SEC("license") = "GPL"; |