/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once

#include <syslog.h>

#if HAVE_LIBBPF

#include <bpf/bpf.h>    /* IWYU pragma: export */
#include <bpf/libbpf.h> /* IWYU pragma: export */

#include "dlfcn-util.h"
#include "shared-forward.h"

/* Always redeclare these so DLSYM_PROTOTYPE's typeof() resolves regardless of libbpf version;
 * suppress the warning when the libbpf headers already declare them.
 *  - bpf_map_create, bpf_object__next_map: available since libbpf 0.7
 *  - bpf_token_create:                     available since libbpf 1.5
 *  - bpf_create_map:                       removed in libbpf 1.0
 */
DISABLE_WARNING_REDUNDANT_DECLS;
/* NOLINTBEGIN(readability-redundant-declaration) */
struct bpf_map_create_opts;
struct bpf_token_create_opts;
extern int bpf_create_map(enum bpf_map_type, int key_size, int value_size, int max_entries, __u32 map_flags);
extern int bpf_map_create(enum bpf_map_type, const char *, __u32, __u32, __u32, const struct bpf_map_create_opts *);
extern struct bpf_map* bpf_object__next_map(const struct bpf_object *obj, const struct bpf_map *map);
extern int bpf_token_create(int bpffs_fd, struct bpf_token_create_opts *opts);
/* NOLINTEND(readability-redundant-declaration) */
REENABLE_WARNING;

extern DLSYM_PROTOTYPE(bpf_create_map);
extern DLSYM_PROTOTYPE(bpf_link__destroy);
extern DLSYM_PROTOTYPE(bpf_link__fd);
extern DLSYM_PROTOTYPE(bpf_link__open);
extern DLSYM_PROTOTYPE(bpf_link__pin);
extern DLSYM_PROTOTYPE(bpf_map__fd);
extern DLSYM_PROTOTYPE(bpf_map__name);
extern DLSYM_PROTOTYPE(bpf_map__set_inner_map_fd);
extern DLSYM_PROTOTYPE(bpf_map__set_max_entries);
extern DLSYM_PROTOTYPE(bpf_map__set_pin_path);
extern DLSYM_PROTOTYPE(bpf_map_create);
extern DLSYM_PROTOTYPE(bpf_map_delete_elem);
extern DLSYM_PROTOTYPE(bpf_map_get_fd_by_id);
extern DLSYM_PROTOTYPE(bpf_map_lookup_elem);
extern DLSYM_PROTOTYPE(bpf_map_update_elem);
extern DLSYM_PROTOTYPE(bpf_obj_get_info_by_fd);
/* The *_skeleton APIs are autogenerated by bpftool, the targets can be found
 * in ./build/src/core/bpf/socket-bind/socket-bind.skel.h */
extern DLSYM_PROTOTYPE(bpf_object__attach_skeleton);
extern DLSYM_PROTOTYPE(bpf_object__destroy_skeleton);
extern DLSYM_PROTOTYPE(bpf_object__detach_skeleton);
extern DLSYM_PROTOTYPE(bpf_object__load_skeleton);
extern DLSYM_PROTOTYPE(bpf_object__name);
extern DLSYM_PROTOTYPE(bpf_object__next_map);
extern DLSYM_PROTOTYPE(bpf_object__open_skeleton);
extern DLSYM_PROTOTYPE(bpf_object__pin_maps);
extern DLSYM_PROTOTYPE(bpf_program__attach);
extern DLSYM_PROTOTYPE(bpf_program__attach_cgroup);
extern DLSYM_PROTOTYPE(bpf_program__attach_lsm);
extern DLSYM_PROTOTYPE(bpf_program__name);
extern DLSYM_PROTOTYPE(bpf_program__set_autoload);
extern DLSYM_PROTOTYPE(bpf_token_create);
extern DLSYM_PROTOTYPE(libbpf_set_print);
extern DLSYM_PROTOTYPE(ring_buffer__epoll_fd);
extern DLSYM_PROTOTYPE(ring_buffer__free);
extern DLSYM_PROTOTYPE(ring_buffer__new);
extern DLSYM_PROTOTYPE(ring_buffer__poll);

/* Helper that uses the available variant behind the new API. */
static inline int compat_bpf_map_create(
                enum bpf_map_type map_type,
                const char *map_name,
                __u32 key_size,
                __u32 value_size,
                __u32 max_entries,
                const struct bpf_map_create_opts *opts) {

        if (sym_bpf_map_create)
                return sym_bpf_map_create(map_type, map_name, key_size,
                                          value_size, max_entries, opts);

        return sym_bpf_create_map(map_type, key_size, value_size, max_entries,
                                  0 /* opts->map_flags, but opts is always NULL for us so skip build dependency on the type */);
}

/* libbpf sometimes returns error codes that make sense only in the kernel, like 524 for EOPNOTSUPP. Use
 * this helper instead of libbpf_get_error() to ensure some of the known ones are translated into errnos
 * we understand. */
int bpf_get_error_translated(const void *ptr);

#endif

int dlopen_bpf(int log_level);
