summaryrefslogtreecommitdiffstats
path: root/libnetdata/ebpf
diff options
context:
space:
mode:
Diffstat (limited to 'libnetdata/ebpf')
-rw-r--r--libnetdata/ebpf/README.md4
-rw-r--r--libnetdata/ebpf/ebpf.c99
-rw-r--r--libnetdata/ebpf/ebpf.h32
3 files changed, 126 insertions, 9 deletions
diff --git a/libnetdata/ebpf/README.md b/libnetdata/ebpf/README.md
index c2dabe102..bf2c6ff35 100644
--- a/libnetdata/ebpf/README.md
+++ b/libnetdata/ebpf/README.md
@@ -1,10 +1,10 @@
<!--
-title "eBPF"
+title: "eBPF"
custom_edit_url: https://github.com/netdata/netdata/edit/master/libnetdata/ebpf/README.md
sidebar_label: "eBPF"
learn_status: "Published"
learn_topic_type: "Tasks"
-learn_rel_path: "Developers/libnetdata libraries"
+learn_rel_path: "Developers/libnetdata"
-->
# eBPF library
diff --git a/libnetdata/ebpf/ebpf.c b/libnetdata/ebpf/ebpf.c
index 7cad59785..61833dd73 100644
--- a/libnetdata/ebpf/ebpf.c
+++ b/libnetdata/ebpf/ebpf.c
@@ -366,20 +366,22 @@ static uint32_t ebpf_select_index(uint32_t kernels, int is_rhf, uint32_t kver)
* V - The kernel version in string format.
*
* @param out the vector where the name will be stored
- * @param path
* @param len the size of the out vector.
+ * @param path where the binaries are stored
* @param kver the kernel version
* @param name the eBPF program name.
* @param is_return is return or entry ?
*/
-static void ebpf_mount_name(char *out, size_t len, char *path, uint32_t kver, const char *name, int is_return)
+static void ebpf_mount_name(char *out, size_t len, char *path, uint32_t kver, const char *name,
+ int is_return, int is_rhf)
{
char *version = ebpf_select_kernel_name(kver);
- snprintfz(out, len, "%s/ebpf.d/%cnetdata_ebpf_%s.%s.o",
+ snprintfz(out, len, "%s/ebpf.d/%cnetdata_ebpf_%s.%s%s.o",
path,
(is_return) ? 'r' : 'p',
name,
- version);
+ version,
+ (is_rhf != -1) ? ".rhf" : "");
}
//----------------------------------------------------------------------------------------------------------------------
@@ -439,7 +441,7 @@ void ebpf_update_stats(ebpf_plugin_stats_t *report, ebpf_module_t *em)
report->threads++;
// It is not necessary to report more information.
- if (!em->enabled)
+ if (em->enabled != NETDATA_THREAD_EBPF_RUNNING)
return;
report->running++;
@@ -454,6 +456,91 @@ void ebpf_update_stats(ebpf_plugin_stats_t *report, ebpf_module_t *em)
ebpf_stats_targets(report, em->targets);
}
+/**
+ * Update Kernel memory with memory
+ *
+ * This algorithm is an adaptation of https://elixir.bootlin.com/linux/v6.1.14/source/tools/bpf/bpftool/common.c#L402
+ * to get 'memlock' data and update report.
+ *
+ * @param report the output structure
+ * @param map pointer to a map.
+ * @param action What action will be done with this map.
+ */
+void ebpf_update_kernel_memory(ebpf_plugin_stats_t *report, ebpf_local_maps_t *map, ebpf_stats_action_t action)
+{
+ char filename[FILENAME_MAX+1];
+ snprintfz(filename, FILENAME_MAX, "/proc/self/fdinfo/%d", map->map_fd);
+ procfile *ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
+ if(unlikely(!ff)) {
+ error("Cannot open %s", filename);
+ return;
+ }
+
+ ff = procfile_readall(ff);
+ if(unlikely(!ff))
+ return;
+
+ unsigned long j, lines = procfile_lines(ff);
+ char *memlock = { "memlock" };
+ for (j = 0; j < lines ; j++) {
+ char *cmp = procfile_lineword(ff, j,0);
+ if (!strncmp(memlock, cmp, 7)) {
+ uint64_t memsize = (uint64_t) str2l(procfile_lineword(ff, j,1));
+ switch (action) {
+ case EBPF_ACTION_STAT_ADD: {
+ report->memlock_kern += memsize;
+ report->hash_tables += 1;
+#ifdef NETDATA_DEV_MODE
+ info("Hash table %u: %s (FD = %d) is consuming %lu bytes totalizing %lu bytes",
+ report->hash_tables, map->name, map->map_fd, memsize, report->memlock_kern);
+#endif
+ break;
+ }
+ case EBPF_ACTION_STAT_REMOVE: {
+ report->memlock_kern -= memsize;
+ report->hash_tables -= 1;
+#ifdef NETDATA_DEV_MODE
+ info("Hash table %s (FD = %d) was removed releasing %lu bytes, now we have %u tables loaded totalizing %lu bytes.",
+ map->name, map->map_fd, memsize, report->hash_tables, report->memlock_kern);
+#endif
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ procfile_close(ff);
+}
+
+/**
+ * Update Kernel memory with memory
+ *
+ * This algorithm is an adaptation of https://elixir.bootlin.com/linux/v6.1.14/source/tools/bpf/bpftool/common.c#L402
+ * to get 'memlock' data and update report.
+ *
+ * @param report the output structure
+ * @param map pointer to a map. Last map must fish with name = NULL
+ */
+void ebpf_update_kernel_memory_with_vector(ebpf_plugin_stats_t *report, ebpf_local_maps_t *maps)
+{
+ if (!maps)
+ return;
+
+ ebpf_local_maps_t *map;
+ int i = 0;
+ for (map = &maps[i]; maps[i].name; i++, map = &maps[i]) {
+ int fd = map->map_fd;
+ if (fd == ND_EBPF_MAP_FD_NOT_INITIALIZED)
+ continue;
+
+ ebpf_update_kernel_memory(report, map, EBPF_ACTION_STAT_ADD);
+ }
+}
+
//----------------------------------------------------------------------------------------------------------------------
void ebpf_update_pid_table(ebpf_local_maps_t *pid, ebpf_module_t *em)
@@ -696,7 +783,7 @@ struct bpf_link **ebpf_load_program(char *plugins_dir, ebpf_module_t *em, int kv
uint32_t idx = ebpf_select_index(em->kernels, is_rhf, kver);
- ebpf_mount_name(lpath, 4095, plugins_dir, idx, em->thread_name, em->mode);
+ ebpf_mount_name(lpath, 4095, plugins_dir, idx, em->thread_name, em->mode, is_rhf);
// When this function is called ebpf.plugin is using legacy code, so we should reset the variable
em->load &= ~ NETDATA_EBPF_LOAD_METHODS;
diff --git a/libnetdata/ebpf/ebpf.h b/libnetdata/ebpf/ebpf.h
index cf3fa7ccd..bf5fdc33d 100644
--- a/libnetdata/ebpf/ebpf.h
+++ b/libnetdata/ebpf/ebpf.h
@@ -10,6 +10,7 @@
#include <linux/btf.h>
#endif
#include <stdlib.h> // Necessary for stdtoul
+#include "libnetdata/aral/aral.h"
#define NETDATA_DEBUGFS "/sys/kernel/debug/tracing/"
#define NETDATA_KALLSYMS "/proc/kallsyms"
@@ -238,18 +239,38 @@ typedef struct ebpf_plugin_stats {
uint32_t retprobes; // Number of kretprobes loaded
uint32_t tracepoints; // Number of tracepoints used
uint32_t trampolines; // Number of trampolines used
+
+ uint64_t memlock_kern; // The same information reported by bpftool, but it is not accurated
+ // https://lore.kernel.org/linux-mm/20230112155326.26902-5-laoar.shao@gmail.com/T/
+ uint32_t hash_tables; // Number of hash tables used on the system.
} ebpf_plugin_stats_t;
+typedef enum ebpf_stats_action {
+ EBPF_ACTION_STAT_ADD,
+ EBPF_ACTION_STAT_REMOVE,
+} ebpf_stats_action_t;
+
typedef enum netdata_apps_integration_flags {
NETDATA_EBPF_APPS_FLAG_NO,
NETDATA_EBPF_APPS_FLAG_YES,
NETDATA_EBPF_APPS_FLAG_CHART_CREATED
} netdata_apps_integration_flags_t;
+#define NETDATA_EBPF_CHART_MEM_LENGTH 48
+#define NETDATA_EBPF_STAT_DIMENSION_MEMORY "memory"
+#define NETDATA_EBPF_STAT_DIMENSION_ARAL "aral"
+
+enum ebpf_threads_status {
+ NETDATA_THREAD_EBPF_RUNNING,
+ NETDATA_THREAD_EBPF_STOPPING,
+ NETDATA_THREAD_EBPF_STOPPED,
+ NETDATA_THREAD_EBPF_NOT_RUNNING
+};
+
typedef struct ebpf_module {
const char *thread_name;
const char *config_name;
- int enabled;
+ enum ebpf_threads_status enabled;
void *(*start_routine)(void *);
int update_every;
int global_charts;
@@ -271,6 +292,10 @@ typedef struct ebpf_module {
struct bpf_link **probe_links;
struct bpf_object *objects;
struct netdata_static_thread *thread;
+
+ // charts
+ char memory_usage[NETDATA_EBPF_CHART_MEM_LENGTH];
+ char memory_allocations[NETDATA_EBPF_CHART_MEM_LENGTH];
} ebpf_module_t;
int ebpf_get_kernel_version();
@@ -368,4 +393,9 @@ struct btf *ebpf_load_btf_file(char *path, char *filename);
int ebpf_is_function_inside_btf(struct btf *file, char *function);
#endif
+void ebpf_update_kernel_memory_with_vector(ebpf_plugin_stats_t *report, ebpf_local_maps_t *maps);
+void ebpf_update_kernel_memory(ebpf_plugin_stats_t *report, ebpf_local_maps_t *map, ebpf_stats_action_t action);
+void ebpf_statistic_create_aral_chart(char *name, ebpf_module_t *em);
+void ebpf_send_data_aral_chart(ARAL *memory, ebpf_module_t *em);
+
#endif /* NETDATA_EBPF_H */