int trace_inet_socket_accept_return()

in src/samplers/tcp/bpf.c [153:214]


int trace_inet_socket_accept_return(struct pt_regs *ctx)
{
    // inet_socket_accept returns sock* directly, so we get from PT_REGS_RC.
    struct sock *sk = (struct sock *)PT_REGS_RC(ctx);
    if (!sk)
        return 0;

    // check this is TCP
    u8 protocol = 0;
    // unfortunately, we need to have different handling for pre-4.10 and 4.10+
    // for pre-4.10, sk_wmem_queued is following sk_protocol field.
    // for 4.10+ to 5.5, sk_gso_max_segs is following sk_protocol field.
    // for 5.6+, sk_gso_max_segs is following sk_protocol field, but the sk_protocol becomes regular member
    // instead of bitfield.
    // in order to be compatible, we handle all cases.
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0)
    // 5.6+, we can read sk_protocol as a regular field.
    u16 p = 0;
    bpf_probe_read_kernel(&p, sizeof(p), ((const char*)sk) +
        offsetof(struct sock, sk_protocol));
    protocol = (u8) p;
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
    // from 4.10+ to 5.5, sk_protocol is a bit field
    // see https://elixir.bootlin.com/linux/v5.4/source/include/net/sock.h#L455.
    #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
        // get the sk_protocol bitfield
        protocol = *(u8 *)((u64)&sk->sk_gso_max_segs - 3);
    #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
        protocol = *(u8 *)((u64)&sk->sk_gso_max_segs - 1);
    #else
    #error "Fix your compiler's __BYTE_ORDER__?!"
    #endif
#else
    // for pre-4.10, sk_protocol is also a bit field
    #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
        protocol = *(u8 *)((u64)&sk->sk_wmem_queued - 3);
    #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
        protocol = *(u8 *)((u64)&sk->sk_wmem_queued - 1);
    #else
    #error "Fix your compiler's __BYTE_ORDER__?!"
    #endif
#endif

    // if the sock is not TCP, igonre.
    if (protocol != IPPROTO_TCP)
        return 0;

    // create the sock stats for the new accepted connection.
    struct sock_stats_t stats = {.pid = bpf_get_current_pid_tgid()};
    struct tcp_sock *ts = tcp_sk(sk);
    // we approximate the starting time to be current time minus the srtt.
    stats.ts = bpf_ktime_get_ns() - get_srtt_us(ts) * 1000;
    bpf_get_current_comm(&stats.task, sizeof(stats.task));
    // store the sock's stats.
    sock_stats_map.update(&sk, &stats);

    // increment counter;
    int loc = 0;
    add_value(conn_accepted.lookup(&loc), 1);

    return 0;
}