#!/opt/sum/bin/bash

source ./kernel_config_utils.sh
source ./bpf_utils.sh

bpf_check() {
    is_error=false
    if ! kernel_config_check CONFIG_BPF_SYSCALL; then
        is_error=true
    fi
    if ! kernel_config_check CONFIG_CGROUPS; then
        is_error=true
    fi
    if ! kernel_config_check CONFIG_CGROUP_BPF; then
        is_error=true
    fi
    if ! kernel_config_check CONFIG_BPF_STREAM_PARSER; then
        is_error=true
    fi

    map_types=$(cat << EOF
    array
    hash
    lru_hash
    sockhash
    sockmap
EOF
)
    prog_types=$(cat << EOF
    perf_event
    sched_cls
    sock_ops
    socket_filter
    tracing
EOF
)
    helpers=$(cat << EOF
    bpf_map_lookup_elem
    bpf_map_update_elem
EOF
)
    declare -A progs_spec_helpers
    progs_spec_helpers=(
        ["sched_cls"]=$(cat << EOF
            bpf_clone_redirect
            bpf_l3_csum_replace
            bpf_l4_csum_replace
            bpf_redirect
            bpf_skb_store_bytes
EOF
)
        ["socket_filter"]=$(cat << EOF
            bpf_skb_load_bytes
EOF
)
        ["tracing"]=$(cat << EOF
            bpf_ktime_get_boot_ns
EOF
)
    )

    for map_type in $map_types; do
        if ! bpf_map_type_check $map_type; then
            is_error=true
        fi
    done
    for prog_type in $prog_types; do
        if bpf_prog_type_check $prog_type; then
            for helper in $helpers; do
                if ! bpf_prog_helper_check $prog_type $helper; then
                    is_error=true
                fi
            done

            local prog_spec_helpers="${progs_spec_helpers[$prog_type]}"

            for helper in $prog_spec_helpers; do
                if ! bpf_prog_helper_check $prog_type $helper; then
                    is_error=true
                fi
            done
        else
            is_error=true
        fi
    done

    if ! $BPFTOOL_CMD prog load /opt/sumports/lib/bpf_tc.o /sys/fs/bpf/dodo; then
        echo "prog load in /sys/fs/bpf/dodo failed"
        is_error="true"
    fi
    rm /sys/fs/bpf/dodo

    if [ "$is_error" == "true" ]; then
        return 1
    fi

    return 0
}

