summaryrefslogtreecommitdiffstats
path: root/collectors/ebpf.plugin/ebpf_fd.c
diff options
context:
space:
mode:
Diffstat (limited to 'collectors/ebpf.plugin/ebpf_fd.c')
-rw-r--r--collectors/ebpf.plugin/ebpf_fd.c419
1 files changed, 371 insertions, 48 deletions
diff --git a/collectors/ebpf.plugin/ebpf_fd.c b/collectors/ebpf.plugin/ebpf_fd.c
index b4e577dad..30b7f22ce 100644
--- a/collectors/ebpf.plugin/ebpf_fd.c
+++ b/collectors/ebpf.plugin/ebpf_fd.c
@@ -29,15 +29,301 @@ struct config fd_config = { .first_section = NULL, .last_section = NULL, .mutex
.index = {.avl_tree = { .root = NULL, .compar = appconfig_section_compare },
.rwlock = AVL_LOCK_INITIALIZER } };
-struct netdata_static_thread fd_thread = {"FD KERNEL", NULL, NULL, 1, NULL,
- NULL, NULL};
-static enum ebpf_threads_status ebpf_fd_exited = NETDATA_THREAD_EBPF_RUNNING;
+struct netdata_static_thread fd_thread = {"FD KERNEL",
+ .config_section = NULL,
+ .config_name = NULL,
+ .env_name = NULL,
+ .enabled = 1,
+ .thread = NULL,
+ .init_routine = NULL,
+ .start_routine = NULL};
+
static netdata_idx_t fd_hash_values[NETDATA_FD_COUNTER];
static netdata_idx_t *fd_values = NULL;
netdata_fd_stat_t *fd_vector = NULL;
netdata_fd_stat_t **fd_pid = NULL;
+netdata_ebpf_targets_t fd_targets[] = { {.name = "open", .mode = EBPF_LOAD_TRAMPOLINE},
+ {.name = "close", .mode = EBPF_LOAD_TRAMPOLINE},
+ {.name = NULL, .mode = EBPF_LOAD_TRAMPOLINE}};
+
+#ifdef LIBBPF_MAJOR_VERSION
+#include "includes/fd.skel.h" // BTF code
+
+static struct fd_bpf *bpf_obj = NULL;
+
+/**
+ * Disable probe
+ *
+ * Disable all probes to use exclusively another method.
+ *
+ * @param obj is the main structure for bpf objects
+*/
+static inline void ebpf_fd_disable_probes(struct fd_bpf *obj)
+{
+ bpf_program__set_autoload(obj->progs.netdata_sys_open_kprobe, false);
+ bpf_program__set_autoload(obj->progs.netdata_sys_open_kretprobe, false);
+ bpf_program__set_autoload(obj->progs.netdata_release_task_fd_kprobe, false);
+ if (running_on_kernel >= NETDATA_EBPF_KERNEL_5_11) {
+ bpf_program__set_autoload(obj->progs.netdata___close_fd_kretprobe, false);
+ bpf_program__set_autoload(obj->progs.netdata___close_fd_kprobe, false);
+ bpf_program__set_autoload(obj->progs.netdata_close_fd_kprobe, false);
+ } else {
+ bpf_program__set_autoload(obj->progs.netdata___close_fd_kprobe, false);
+ bpf_program__set_autoload(obj->progs.netdata_close_fd_kretprobe, false);
+ bpf_program__set_autoload(obj->progs.netdata_close_fd_kprobe, false);
+ }
+}
+
+/*
+ * Disable specific probe
+ *
+ * Disable probes according the kernel version
+ *
+ * @param obj is the main structure for bpf objects
+ */
+static inline void ebpf_disable_specific_probes(struct fd_bpf *obj)
+{
+ if (running_on_kernel >= NETDATA_EBPF_KERNEL_5_11) {
+ bpf_program__set_autoload(obj->progs.netdata___close_fd_kretprobe, false);
+ bpf_program__set_autoload(obj->progs.netdata___close_fd_kprobe, false);
+ } else {
+ bpf_program__set_autoload(obj->progs.netdata_close_fd_kretprobe, false);
+ bpf_program__set_autoload(obj->progs.netdata_close_fd_kprobe, false);
+ }
+}
+
+/*
+ * Disable trampoline
+ *
+ * Disable all trampoline to use exclusively another method.
+ *
+ * @param obj is the main structure for bpf objects.
+ */
+static inline void ebpf_disable_trampoline(struct fd_bpf *obj)
+{
+ bpf_program__set_autoload(obj->progs.netdata_sys_open_fentry, false);
+ bpf_program__set_autoload(obj->progs.netdata_sys_open_fexit, false);
+ bpf_program__set_autoload(obj->progs.netdata_close_fd_fentry, false);
+ bpf_program__set_autoload(obj->progs.netdata_close_fd_fexit, false);
+ bpf_program__set_autoload(obj->progs.netdata___close_fd_fentry, false);
+ bpf_program__set_autoload(obj->progs.netdata___close_fd_fexit, false);
+ bpf_program__set_autoload(obj->progs.netdata_release_task_fd_fentry, false);
+}
+
+/*
+ * Disable specific trampoline
+ *
+ * Disable trampoline according to kernel version.
+ *
+ * @param obj is the main structure for bpf objects.
+ */
+static inline void ebpf_disable_specific_trampoline(struct fd_bpf *obj)
+{
+ if (running_on_kernel >= NETDATA_EBPF_KERNEL_5_11) {
+ bpf_program__set_autoload(obj->progs.netdata___close_fd_fentry, false);
+ bpf_program__set_autoload(obj->progs.netdata___close_fd_fexit, false);
+ } else {
+ bpf_program__set_autoload(obj->progs.netdata_close_fd_fentry, false);
+ bpf_program__set_autoload(obj->progs.netdata_close_fd_fexit, false);
+ }
+}
+
+/**
+ * Set trampoline target
+ *
+ * Set the targets we will monitor.
+ *
+ * @param obj is the main structure for bpf objects.
+ */
+static void ebpf_set_trampoline_target(struct fd_bpf *obj)
+{
+ bpf_program__set_attach_target(obj->progs.netdata_sys_open_fentry, 0, fd_targets[NETDATA_FD_SYSCALL_OPEN].name);
+ bpf_program__set_attach_target(obj->progs.netdata_sys_open_fexit, 0, fd_targets[NETDATA_FD_SYSCALL_OPEN].name);
+ bpf_program__set_attach_target(obj->progs.netdata_release_task_fd_fentry, 0, EBPF_COMMON_FNCT_CLEAN_UP);
+
+ if (running_on_kernel >= NETDATA_EBPF_KERNEL_5_11) {
+ bpf_program__set_attach_target(
+ obj->progs.netdata_close_fd_fentry, 0, fd_targets[NETDATA_FD_SYSCALL_CLOSE].name);
+ bpf_program__set_attach_target(obj->progs.netdata_close_fd_fexit, 0, fd_targets[NETDATA_FD_SYSCALL_CLOSE].name);
+ } else {
+ bpf_program__set_attach_target(
+ obj->progs.netdata___close_fd_fentry, 0, fd_targets[NETDATA_FD_SYSCALL_CLOSE].name);
+ bpf_program__set_attach_target(
+ obj->progs.netdata___close_fd_fexit, 0, fd_targets[NETDATA_FD_SYSCALL_CLOSE].name);
+ }
+}
+
+/**
+ * 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_fd_attach_probe(struct fd_bpf *obj)
+{
+ obj->links.netdata_sys_open_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_sys_open_kprobe, false,
+ fd_targets[NETDATA_FD_SYSCALL_OPEN].name);
+ int ret = libbpf_get_error(obj->links.netdata_sys_open_kprobe);
+ if (ret)
+ return -1;
+
+ obj->links.netdata_sys_open_kretprobe = bpf_program__attach_kprobe(obj->progs.netdata_sys_open_kretprobe, true,
+ fd_targets[NETDATA_FD_SYSCALL_OPEN].name);
+ ret = libbpf_get_error(obj->links.netdata_sys_open_kretprobe);
+ if (ret)
+ return -1;
+
+ obj->links.netdata_release_task_fd_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_release_task_fd_kprobe,
+ false,
+ EBPF_COMMON_FNCT_CLEAN_UP);
+ ret = libbpf_get_error(obj->links.netdata_release_task_fd_kprobe);
+ if (ret)
+ return -1;
+
+ if (running_on_kernel >= NETDATA_EBPF_KERNEL_5_11) {
+ obj->links.netdata_close_fd_kretprobe = bpf_program__attach_kprobe(obj->progs.netdata_close_fd_kretprobe, true,
+ fd_targets[NETDATA_FD_SYSCALL_CLOSE].name);
+ ret = libbpf_get_error(obj->links.netdata_close_fd_kretprobe);
+ if (ret)
+ return -1;
+
+ obj->links.netdata_close_fd_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_close_fd_kprobe, false,
+ fd_targets[NETDATA_FD_SYSCALL_CLOSE].name);
+ ret = libbpf_get_error(obj->links.netdata_close_fd_kprobe);
+ if (ret)
+ return -1;
+ } else {
+ obj->links.netdata___close_fd_kretprobe = bpf_program__attach_kprobe(obj->progs.netdata___close_fd_kretprobe,
+ true,
+ fd_targets[NETDATA_FD_SYSCALL_CLOSE].name);
+ ret = libbpf_get_error(obj->links.netdata___close_fd_kretprobe);
+ if (ret)
+ return -1;
+
+ obj->links.netdata___close_fd_kprobe = bpf_program__attach_kprobe(obj->progs.netdata___close_fd_kprobe,
+ false,
+ fd_targets[NETDATA_FD_SYSCALL_CLOSE].name);
+ ret = libbpf_get_error(obj->links.netdata___close_fd_kprobe);
+ if (ret)
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Set target values
+ *
+ * Set pointers used to laod data.
+ */
+static void ebpf_fd_set_target_values()
+{
+ static char *close_targets[] = {"close_fd", "__close_fd"};
+ static char *open_targets[] = {"do_sys_openat2", "do_sys_open"};
+ if (running_on_kernel >= NETDATA_EBPF_KERNEL_5_11) {
+ fd_targets[NETDATA_FD_SYSCALL_OPEN].name = open_targets[0];
+ fd_targets[NETDATA_FD_SYSCALL_CLOSE].name = close_targets[0];
+ } else {
+ fd_targets[NETDATA_FD_SYSCALL_OPEN].name = open_targets[1];
+ fd_targets[NETDATA_FD_SYSCALL_CLOSE].name = close_targets[1];
+ }
+}
+
+/**
+ * Set hash tables
+ *
+ * Set the values for maps according the value given by kernel.
+ *
+ * @param obj is the main structure for bpf objects.
+ */
+static void ebpf_fd_set_hash_tables(struct fd_bpf *obj)
+{
+ fd_maps[NETDATA_FD_GLOBAL_STATS].map_fd = bpf_map__fd(obj->maps.tbl_fd_global);
+ fd_maps[NETDATA_FD_PID_STATS].map_fd = bpf_map__fd(obj->maps.tbl_fd_pid);
+ fd_maps[NETDATA_FD_CONTROLLER].map_fd = bpf_map__fd(obj->maps.fd_ctrl);
+}
+
+/**
+ * Adjust Map Size
+ *
+ * Resize maps according input from users.
+ *
+ * @param obj is the main structure for bpf objects.
+ * @param em structure with configuration
+ */
+static void ebpf_fd_adjust_map_size(struct fd_bpf *obj, ebpf_module_t *em)
+{
+ ebpf_update_map_size(obj->maps.tbl_fd_pid, &fd_maps[NETDATA_FD_PID_STATS],
+ em, bpf_map__name(obj->maps.tbl_fd_pid));
+}
+
+/**
+ * Disable Release Task
+ *
+ * Disable release task when apps is not enabled.
+ *
+ * @param obj is the main structure for bpf objects.
+ */
+static void ebpf_fd_disable_release_task(struct fd_bpf *obj)
+{
+ bpf_program__set_autoload(obj->progs.netdata_release_task_fd_kprobe, false);
+ bpf_program__set_autoload(obj->progs.netdata_release_task_fd_fentry, false);
+}
+
+/**
+ * Load and attach
+ *
+ * Load and attach the eBPF code in kernel.
+ *
+ * @param obj is the main structure for bpf objects.
+ * @param em structure with configuration
+ *
+ * @return it returns 0 on succes and -1 otherwise
+ */
+static inline int ebpf_fd_load_and_attach(struct fd_bpf *obj, ebpf_module_t *em)
+{
+ netdata_ebpf_targets_t *mt = em->targets;
+ netdata_ebpf_program_loaded_t test = mt[NETDATA_FD_SYSCALL_OPEN].mode;
+
+ ebpf_fd_set_target_values();
+ if (test == EBPF_LOAD_TRAMPOLINE) {
+ ebpf_fd_disable_probes(obj);
+ ebpf_disable_specific_trampoline(obj);
+
+ ebpf_set_trampoline_target(obj);
+ // TODO: Remove this in next PR, because this specific trampoline has an error.
+ bpf_program__set_autoload(obj->progs.netdata_release_task_fd_fentry, false);
+ } else {
+ ebpf_disable_trampoline(obj);
+ ebpf_disable_specific_probes(obj);
+ }
+
+ ebpf_fd_adjust_map_size(obj, em);
+
+ if (!em->apps_charts && !em->cgroup_charts)
+ ebpf_fd_disable_release_task(obj);
+
+ int ret = fd_bpf__load(obj);
+ if (ret) {
+ return ret;
+ }
+
+ ret = (test == EBPF_LOAD_TRAMPOLINE) ? fd_bpf__attach(obj) : ebpf_fd_attach_probe(obj);
+ if (!ret) {
+ ebpf_fd_set_hash_tables(obj);
+
+ ebpf_update_controller(fd_maps[NETDATA_CACHESTAT_CTRL].map_fd, em);
+ }
+
+ return ret;
+}
+#endif
+
/*****************************************************************
*
* FUNCTIONS TO CLOSE THE THREAD
@@ -45,6 +331,38 @@ netdata_fd_stat_t **fd_pid = NULL;
*****************************************************************/
/**
+ * FD Free
+ *
+ * Cleanup variables after child threads to stop
+ *
+ * @param ptr thread data.
+ */
+static void ebpf_fd_free(ebpf_module_t *em)
+{
+ pthread_mutex_lock(&ebpf_exit_cleanup);
+ if (em->thread->enabled == NETDATA_THREAD_EBPF_RUNNING) {
+ em->thread->enabled = NETDATA_THREAD_EBPF_STOPPING;
+ pthread_mutex_unlock(&ebpf_exit_cleanup);
+ return;
+ }
+ pthread_mutex_unlock(&ebpf_exit_cleanup);
+
+ ebpf_cleanup_publish_syscall(fd_publish_aggregated);
+ freez(fd_thread.thread);
+ freez(fd_values);
+ freez(fd_vector);
+
+#ifdef LIBBPF_MAJOR_VERSION
+ if (bpf_obj)
+ fd_bpf__destroy(bpf_obj);
+#endif
+
+ pthread_mutex_lock(&ebpf_exit_cleanup);
+ em->thread->enabled = NETDATA_THREAD_EBPF_STOPPED;
+ pthread_mutex_unlock(&ebpf_exit_cleanup);
+}
+
+/**
* FD Exit
*
* Cancel child thread and exit.
@@ -54,12 +372,8 @@ netdata_fd_stat_t **fd_pid = NULL;
static void ebpf_fd_exit(void *ptr)
{
ebpf_module_t *em = (ebpf_module_t *)ptr;
- if (!em->enabled) {
- em->enabled = NETDATA_MAIN_THREAD_EXITED;
- return;
- }
-
- ebpf_fd_exited = NETDATA_THREAD_EBPF_STOPPING;
+ netdata_thread_cancel(*fd_thread.thread);
+ ebpf_fd_free(em);
}
/**
@@ -70,16 +384,7 @@ static void ebpf_fd_exit(void *ptr)
static void ebpf_fd_cleanup(void *ptr)
{
ebpf_module_t *em = (ebpf_module_t *)ptr;
- if (ebpf_fd_exited != NETDATA_THREAD_EBPF_STOPPED)
- return;
-
- ebpf_cleanup_publish_syscall(fd_publish_aggregated);
- freez(fd_thread.thread);
- freez(fd_values);
- freez(fd_vector);
-
- fd_thread.enabled = NETDATA_MAIN_THREAD_EXITED;
- em->enabled = NETDATA_MAIN_THREAD_EXITED;
+ ebpf_fd_free(em);
}
/*****************************************************************
@@ -153,17 +458,12 @@ void *ebpf_fd_read_hash(void *ptr)
ebpf_module_t *em = (ebpf_module_t *)ptr;
usec_t step = NETDATA_FD_SLEEP_MS * em->update_every;
- while (ebpf_fd_exited == NETDATA_THREAD_EBPF_RUNNING) {
- usec_t dt = heartbeat_next(&hb, step);
- (void)dt;
- if (ebpf_fd_exited == NETDATA_THREAD_EBPF_STOPPING)
- break;
+ while (!ebpf_exit_plugin) {
+ (void)heartbeat_next(&hb, step);
read_global_table();
}
- ebpf_fd_exited = NETDATA_THREAD_EBPF_STOPPED;
-
netdata_thread_cleanup_pop(1);
return NULL;
}
@@ -549,20 +849,15 @@ static void ebpf_create_systemd_fd_charts(ebpf_module_t *em)
* Send collected data to Netdata.
*
* @param em the main collector structure
- *
- * @return It returns the status for chart creation, if it is necessary to remove a specific dimension zero is returned
- * otherwise function returns 1 to avoid chart recreation
*/
-static int ebpf_send_systemd_fd_charts(ebpf_module_t *em)
+static void ebpf_send_systemd_fd_charts(ebpf_module_t *em)
{
- int ret = 1;
ebpf_cgroup_target_t *ect;
write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_SYSCALL_APPS_FILE_OPEN);
for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
if (unlikely(ect->systemd) && unlikely(ect->updated)) {
write_chart_dimension(ect->name, ect->publish_systemd_fd.open_call);
- } else if (unlikely(ect->systemd))
- ret = 0;
+ }
}
write_end_chart();
@@ -593,8 +888,6 @@ static int ebpf_send_systemd_fd_charts(ebpf_module_t *em)
}
write_end_chart();
}
-
- return ret;
}
/**
@@ -615,13 +908,11 @@ static void ebpf_fd_send_cgroup_data(ebpf_module_t *em)
int has_systemd = shm_ebpf_cgroup.header->systemd_enabled;
if (has_systemd) {
- static int systemd_charts = 0;
- if (!systemd_charts) {
+ if (send_cgroup_chart) {
ebpf_create_systemd_fd_charts(em);
- systemd_charts = 1;
}
- systemd_charts = ebpf_send_systemd_fd_charts(em);
+ ebpf_send_systemd_fd_charts(em);
}
for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
@@ -810,6 +1101,40 @@ static void ebpf_fd_allocate_global_vectors(int apps)
fd_values = callocz((size_t)ebpf_nprocs, sizeof(netdata_idx_t));
}
+/*
+ * Load BPF
+ *
+ * Load BPF files.
+ *
+ * @param em the structure with configuration
+ */
+static int ebpf_fd_load_bpf(ebpf_module_t *em)
+{
+ int ret = 0;
+ ebpf_adjust_apps_cgroup(em, em->targets[NETDATA_FD_SYSCALL_OPEN].mode);
+ if (em->load & EBPF_LOAD_LEGACY) {
+ em->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &em->objects);
+ if (!em->probe_links) {
+ em->enabled = CONFIG_BOOLEAN_NO;
+ ret = -1;
+ }
+ }
+#ifdef LIBBPF_MAJOR_VERSION
+ else {
+ bpf_obj = fd_bpf__open();
+ if (!bpf_obj)
+ ret = -1;
+ else
+ ret = ebpf_fd_load_and_attach(bpf_obj, em);
+ }
+#endif
+
+ if (ret)
+ error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->thread_name);
+
+ return ret;
+}
+
/**
* Directory Cache thread
*
@@ -826,17 +1151,16 @@ void *ebpf_fd_thread(void *ptr)
ebpf_module_t *em = (ebpf_module_t *)ptr;
em->maps = fd_maps;
- if (!em->enabled)
+#ifdef LIBBPF_MAJOR_VERSION
+ ebpf_adjust_thread_load(em, default_btf);
+#endif
+ if (ebpf_fd_load_bpf(em)) {
+ em->thread->enabled = NETDATA_THREAD_EBPF_STOPPED;
goto endfd;
+ }
ebpf_fd_allocate_global_vectors(em->apps_charts);
- em->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &em->objects);
- if (!em->probe_links) {
- em->enabled = CONFIG_BOOLEAN_NO;
- goto endfd;
- }
-
int algorithms[NETDATA_FD_SYSCALL_END] = {
NETDATA_EBPF_INCREMENTAL_IDX, NETDATA_EBPF_INCREMENTAL_IDX
};
@@ -852,8 +1176,7 @@ void *ebpf_fd_thread(void *ptr)
fd_collector(em);
endfd:
- if (!em->enabled)
- ebpf_update_disabled_plugin_stats(em);
+ ebpf_update_disabled_plugin_stats(em);
netdata_thread_cleanup_pop(1);
return NULL;