// SPDX-License-Identifier: GPL-3.0-or-later
#include "ebpf.h"
#include "ebpf_swap.h"
static char *swap_dimension_name[NETDATA_SWAP_END] = { "read", "write" };
static netdata_syscall_stat_t swap_aggregated_data[NETDATA_SWAP_END];
static netdata_publish_syscall_t swap_publish_aggregated[NETDATA_SWAP_END];
netdata_publish_swap_t *swap_vector = NULL;
static netdata_idx_t swap_hash_values[NETDATA_SWAP_END];
static netdata_idx_t *swap_values = NULL;
netdata_publish_swap_t **swap_pid = NULL;
struct config swap_config = { .first_section = NULL,
.last_section = NULL,
.mutex = NETDATA_MUTEX_INITIALIZER,
.index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
.rwlock = AVL_LOCK_INITIALIZER } };
static ebpf_local_maps_t swap_maps[] = {{.name = "tbl_pid_swap", .internal_input = ND_EBPF_DEFAULT_PID_SIZE,
.user_input = 0,
.type = NETDATA_EBPF_MAP_RESIZABLE | NETDATA_EBPF_MAP_PID,
.map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
{.name = "swap_ctrl", .internal_input = NETDATA_CONTROLLER_END,
.user_input = 0,
.type = NETDATA_EBPF_MAP_CONTROLLER,
.map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
{.name = "tbl_swap", .internal_input = NETDATA_SWAP_END,
.user_input = 0,
.type = NETDATA_EBPF_MAP_STATIC,
.map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
{.name = NULL, .internal_input = 0, .user_input = 0}};
struct netdata_static_thread swap_threads = {"SWAP KERNEL", NULL, NULL, 1,
NULL, NULL, NULL};
static enum ebpf_threads_status ebpf_swap_exited = NETDATA_THREAD_EBPF_RUNNING;
netdata_ebpf_targets_t swap_targets[] = { {.name = "swap_readpage", .mode = EBPF_LOAD_TRAMPOLINE},
{.name = "swap_writepage", .mode = EBPF_LOAD_TRAMPOLINE},
{.name = NULL, .mode = EBPF_LOAD_TRAMPOLINE}};
#ifdef LIBBPF_MAJOR_VERSION
#include "includes/swap.skel.h" // BTF code
static struct swap_bpf *bpf_obj = NULL;
/**
* Disable probe
*
* Disable all probes to use exclusively another method.
*
* @param obj is the main structure for bpf objects
*/
static void ebpf_swap_disable_probe(struct swap_bpf *obj)
{
bpf_program__set_autoload(obj->progs.netdata_swap_readpage_probe, false);
bpf_program__set_autoload(obj->progs.netdata_swap_writepage_probe, false);
}
/*
* Disable trampoline
*
* Disable all trampoline to use exclusively another method.
*
* @param obj is the main structure for bpf objects.
*/
static void ebpf_swap_disable_trampoline(struct swap_bpf *obj)
{
bpf_program__set_autoload(obj->progs.netdata_swap_readpage_fentry, false);
bpf_program__set_autoload(obj->progs.netdata_swap_writepage_fentry, false);
bpf_program__set_autoload(obj->progs.netdata_release_task_fentry, false);
}
/**
* Set trampoline target
*
* Set the targets we will monitor.
*
* @param obj is the main structure for bpf objects.
*/
static void ebpf_swap_set_trampoline_target(struct swap_bpf *obj)
{
bpf_program__set_attach_target(obj->progs.netdata_swap_readpage_fentry, 0,
swap_targets[NETDATA_KEY_SWAP_READPAGE_CALL].name);
bpf_program__set_attach_target(obj->progs.netdata_swap_writepage_fentry, 0,
swap_targets[NETDATA_KEY_SWAP_WRITEPAGE_CALL].name);
bpf_program__set_attach_target(obj->progs.netdata_release_task_fentry, 0,
EBPF_COMMON_FNCT_CLEAN_UP);
}
/**
* Mount Attach Probe
*
* Attach probes to target
*
* @param obj is the main structure for bpf objects.
*
* @return It returns 0 on success and -1 otherwise.
*/
static int ebpf_swap_attach_kprobe(struct swap_bpf *obj)
{
obj->links.netdata_swap_readpage_probe = bpf_program__attach_kprobe(obj->progs.netdata_swap_readpage_probe,
false,
swap_targets[NETDATA_KEY_SWAP_READPAGE_CALL].name);
int ret = libbpf_get_error(obj->links.netdata_swap_readpage_probe);
if (ret)
return -1;
obj->links.netdata_swap_writepage_probe = bpf_program__attach_kprobe(obj->progs.netdata_swap_writepage_probe,
false,
swap_targets[NETDATA_KEY_SWAP_WRITEPAGE_CALL].name);
ret = libbpf_get_error(obj->links.netdata_swap_writepage_probe);
if (ret)
return -1;
obj->links.netdata_release_task_probe = bpf_program__attach_kprobe(obj->progs.netdata_release_task_probe,