root/tools/testing/selftests/bpf/progs/sk_bypass_prot_mem.c
// SPDX-License-Identifier: GPL-2.0
/* Copyright 2025 Google LLC */

#include "bpf_tracing_net.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <errno.h>
#include "err.h"

extern int tcp_memory_per_cpu_fw_alloc __ksym;
extern int udp_memory_per_cpu_fw_alloc __ksym;

int nr_cpus;
bool tcp_activated, udp_activated;
long tcp_memory_allocated, udp_memory_allocated;

struct sk_prot {
        long *memory_allocated;
        int *memory_per_cpu_fw_alloc;
};

static int drain_memory_per_cpu_fw_alloc(__u32 i, struct sk_prot *sk_prot_ctx)
{
        int *memory_per_cpu_fw_alloc;

        memory_per_cpu_fw_alloc = bpf_per_cpu_ptr(sk_prot_ctx->memory_per_cpu_fw_alloc, i);
        if (memory_per_cpu_fw_alloc)
                *sk_prot_ctx->memory_allocated += *memory_per_cpu_fw_alloc;

        return 0;
}

static long get_memory_allocated(struct sock *_sk, int *memory_per_cpu_fw_alloc)
{
        struct sock *sk = bpf_core_cast(_sk, struct sock);
        struct sk_prot sk_prot_ctx;
        long memory_allocated;

        /* net_aligned_data.{tcp,udp}_memory_allocated was not available. */
        memory_allocated = sk->__sk_common.skc_prot->memory_allocated->counter;

        sk_prot_ctx.memory_allocated = &memory_allocated;
        sk_prot_ctx.memory_per_cpu_fw_alloc = memory_per_cpu_fw_alloc;

        bpf_loop(nr_cpus, drain_memory_per_cpu_fw_alloc, &sk_prot_ctx, 0);

        return memory_allocated;
}

static void fentry_init_sock(struct sock *sk, bool *activated,
                             long *memory_allocated, int *memory_per_cpu_fw_alloc)
{
        if (!*activated)
                return;

        *memory_allocated = get_memory_allocated(sk, memory_per_cpu_fw_alloc);
        *activated = false;
}

SEC("fentry/tcp_init_sock")
int BPF_PROG(fentry_tcp_init_sock, struct sock *sk)
{
        fentry_init_sock(sk, &tcp_activated,
                         &tcp_memory_allocated, &tcp_memory_per_cpu_fw_alloc);
        return 0;
}

SEC("fentry/udp_init_sock")
int BPF_PROG(fentry_udp_init_sock, struct sock *sk)
{
        fentry_init_sock(sk, &udp_activated,
                         &udp_memory_allocated, &udp_memory_per_cpu_fw_alloc);
        return 0;
}

SEC("cgroup/sock_create")
int sock_create(struct bpf_sock *ctx)
{
        int err, val = 1;

        err = bpf_setsockopt(ctx, SOL_SOCKET, SK_BPF_BYPASS_PROT_MEM,
                             &val, sizeof(val));
        if (err)
                goto err;

        val = 0;

        err = bpf_getsockopt(ctx, SOL_SOCKET, SK_BPF_BYPASS_PROT_MEM,
                             &val, sizeof(val));
        if (err)
                goto err;

        if (val != 1) {
                err = -EINVAL;
                goto err;
        }

        return 1;

err:
        set_if_not_errno_or_zero(err, -EFAULT);
        bpf_set_retval(err);
        return 0;
}

char LICENSE[] SEC("license") = "GPL";