summaryrefslogtreecommitdiffstats
path: root/libnetdata/ebpf/ebpf.c
diff options
context:
space:
mode:
Diffstat (limited to 'libnetdata/ebpf/ebpf.c')
-rw-r--r--libnetdata/ebpf/ebpf.c202
1 files changed, 172 insertions, 30 deletions
diff --git a/libnetdata/ebpf/ebpf.c b/libnetdata/ebpf/ebpf.c
index c48f2f24e..382485e5f 100644
--- a/libnetdata/ebpf/ebpf.c
+++ b/libnetdata/ebpf/ebpf.c
@@ -239,7 +239,7 @@ static int kernel_is_rejected()
}
fclose(kernel_reject_list);
- freez(reject_string);
+ free(reject_string);
return 0;
}
@@ -279,7 +279,8 @@ static char *ebpf_select_kernel_name(uint32_t selector)
{
static char *kernel_names[] = { NETDATA_IDX_STR_V3_10, NETDATA_IDX_STR_V4_14, NETDATA_IDX_STR_V4_16,
NETDATA_IDX_STR_V4_18, NETDATA_IDX_STR_V5_4, NETDATA_IDX_STR_V5_10,
- NETDATA_IDX_STR_V5_11, NETDATA_IDX_STR_V5_15, NETDATA_IDX_STR_V5_16
+ NETDATA_IDX_STR_V5_11, NETDATA_IDX_STR_V5_14, NETDATA_IDX_STR_V5_15,
+ NETDATA_IDX_STR_V5_16
};
return kernel_names[selector];
@@ -298,7 +299,11 @@ static char *ebpf_select_kernel_name(uint32_t selector)
static int ebpf_select_max_index(int is_rhf, uint32_t kver)
{
if (is_rhf > 0) { // Is Red Hat family
- if (kver >= NETDATA_EBPF_KERNEL_4_11)
+ if (kver >= NETDATA_EBPF_KERNEL_5_14)
+ return NETDATA_IDX_V5_14;
+ else if (kver >= NETDATA_EBPF_KERNEL_5_4 && kver < NETDATA_EBPF_KERNEL_5_5) // For Oracle Linux
+ return NETDATA_IDX_V5_4;
+ else if (kver >= NETDATA_EBPF_KERNEL_4_11)
return NETDATA_IDX_V4_18;
} else { // Kernels from kernel.org
if (kver >= NETDATA_EBPF_KERNEL_5_16)
@@ -334,6 +339,9 @@ static uint32_t ebpf_select_index(uint32_t kernels, int is_rhf, uint32_t kver)
uint32_t start = ebpf_select_max_index(is_rhf, kver);
uint32_t idx;
+ if (is_rhf == -1)
+ kernels &= ~NETDATA_V5_14;
+
for (idx = start; idx; idx--) {
if (kernels & 1 << idx)
break;
@@ -438,9 +446,9 @@ void ebpf_update_stats(ebpf_plugin_stats_t *report, ebpf_module_t *em)
// In theory the `else if` is useless, because when this function is called, the module should not stay in
// EBPF_LOAD_PLAY_DICE. We have this additional condition to detect errors from developers.
- if (em->load == EBPF_LOAD_LEGACY)
+ if (em->load & EBPF_LOAD_LEGACY)
report->legacy++;
- else if (em->load == EBPF_LOAD_CORE)
+ else if (em->load & EBPF_LOAD_CORE)
report->core++;
ebpf_stats_targets(report, em->targets);
@@ -463,26 +471,42 @@ void ebpf_update_pid_table(ebpf_local_maps_t *pid, ebpf_module_t *em)
* @param em the structure with information about how the module/thread is working.
* @param map_name the name of the file used to log.
*/
-void ebpf_update_map_size(struct bpf_map *map, ebpf_local_maps_t *lmap, ebpf_module_t *em, const char *map_name)
+void ebpf_update_map_size(struct bpf_map *map, ebpf_local_maps_t *lmap, ebpf_module_t *em, const char *map_name __maybe_unused)
{
+ uint32_t define_size = 0;
uint32_t apps_type = NETDATA_EBPF_MAP_PID | NETDATA_EBPF_MAP_RESIZABLE;
if (lmap->user_input && lmap->user_input != lmap->internal_input) {
+ define_size = lmap->internal_input;
#ifdef NETDATA_INTERNAL_CHECKS
info("Changing map %s from size %u to %u ", map_name, lmap->internal_input, lmap->user_input);
#endif
-#ifdef LIBBPF_MAJOR_VERSION
- bpf_map__set_max_entries(map, lmap->user_input);
-#else
- bpf_map__resize(map, lmap->user_input);
-#endif
} else if (((lmap->type & apps_type) == apps_type) && (!em->apps_charts) && (!em->cgroup_charts)) {
lmap->user_input = ND_EBPF_DEFAULT_MIN_PID;
+ } else if (((em->apps_charts) || (em->cgroup_charts)) && (em->apps_level != NETDATA_APPS_NOT_SET)) {
+ switch (em->apps_level) {
+ case NETDATA_APPS_LEVEL_ALL: {
+ define_size = lmap->user_input;
+ break;
+ }
+ case NETDATA_APPS_LEVEL_PARENT: {
+ define_size = ND_EBPF_DEFAULT_PID_SIZE / 2;
+ break;
+ }
+ case NETDATA_APPS_LEVEL_REAL_PARENT:
+ default: {
+ define_size = ND_EBPF_DEFAULT_PID_SIZE / 3;
+ }
+ }
+ }
+
+ if (!define_size)
+ return;
+
#ifdef LIBBPF_MAJOR_VERSION
- bpf_map__set_max_entries(map, lmap->user_input);
+ bpf_map__set_max_entries(map, define_size);
#else
- bpf_map__resize(map, lmap->user_input);
+ bpf_map__resize(map, define_size);
#endif
- }
}
/**
@@ -607,11 +631,18 @@ static void ebpf_update_maps(ebpf_module_t *em, struct bpf_object *obj)
*/
void ebpf_update_controller(int fd, ebpf_module_t *em)
{
- uint32_t key = NETDATA_CONTROLLER_APPS_ENABLED;
- uint32_t value = (em->apps_charts & NETDATA_EBPF_APPS_FLAG_YES) | em->cgroup_charts;
- int ret = bpf_map_update_elem(fd, &key, &value, 0);
- if (ret)
- error("Add key(%u) for controller table failed.", key);
+ uint32_t values[NETDATA_CONTROLLER_END] = {
+ (em->apps_charts & NETDATA_EBPF_APPS_FLAG_YES) | em->cgroup_charts,
+ em->apps_level
+ };
+ uint32_t key;
+ uint32_t end = (em->apps_level != NETDATA_APPS_NOT_SET) ? NETDATA_CONTROLLER_END : NETDATA_CONTROLLER_APPS_LEVEL;
+
+ for (key = NETDATA_CONTROLLER_APPS_ENABLED; key < end; key++) {
+ int ret = bpf_map_update_elem(fd, &key, &values[key], 0);
+ if (ret)
+ error("Add key(%u) for controller table failed.", key);
+ }
}
/**
@@ -667,6 +698,10 @@ struct bpf_link **ebpf_load_program(char *plugins_dir, ebpf_module_t *em, int kv
ebpf_mount_name(lpath, 4095, plugins_dir, idx, em->thread_name, em->mode);
+ // When this function is called ebpf.plugin is using legacy code, so we should reset the variable
+ em->load &= ~ NETDATA_EBPF_LOAD_METHODS;
+ em->load |= EBPF_LOAD_LEGACY;
+
*obj = bpf_object__open_file(lpath, NULL);
if (libbpf_get_error(obj)) {
error("Cannot open BPF object %s", lpath);
@@ -797,15 +832,53 @@ netdata_ebpf_load_mode_t epbf_convert_string_to_load_mode(char *str)
*/
static char *ebpf_convert_load_mode_to_string(netdata_ebpf_load_mode_t mode)
{
- if (mode == EBPF_LOAD_CORE)
+ if (mode & EBPF_LOAD_CORE)
return EBPF_CFG_CORE_PROGRAM;
- else if (mode == EBPF_LOAD_LEGACY)
+ else if (mode & EBPF_LOAD_LEGACY)
return EBPF_CFG_LEGACY_PROGRAM;
return EBPF_CFG_DEFAULT_PROGRAM;
}
/**
+ * Convert collect pid to string
+ *
+ * @param level value that will select the string
+ *
+ * @return It returns the string associated to level.
+ */
+static char *ebpf_convert_collect_pid_to_string(netdata_apps_level_t level)
+{
+ if (level == NETDATA_APPS_LEVEL_REAL_PARENT)
+ return EBPF_CFG_PID_REAL_PARENT;
+ else if (level == NETDATA_APPS_LEVEL_PARENT)
+ return EBPF_CFG_PID_PARENT;
+ else if (level == NETDATA_APPS_LEVEL_ALL)
+ return EBPF_CFG_PID_ALL;
+
+ return EBPF_CFG_PID_INTERNAL_USAGE;
+}
+
+/**
+ * Convert string to apps level
+ *
+ * @param str the argument read from config files
+ *
+ * @return it returns the level associated to the string or default when it is a wrong value
+ */
+netdata_apps_level_t ebpf_convert_string_to_apps_level(char *str)
+{
+ if (!strcasecmp(str, EBPF_CFG_PID_REAL_PARENT))
+ return NETDATA_APPS_LEVEL_REAL_PARENT;
+ else if (!strcasecmp(str, EBPF_CFG_PID_PARENT))
+ return NETDATA_APPS_LEVEL_PARENT;
+ else if (!strcasecmp(str, EBPF_CFG_PID_ALL))
+ return NETDATA_APPS_LEVEL_ALL;
+
+ return NETDATA_APPS_NOT_SET;
+}
+
+/**
* CO-RE type
*
* Select the preferential type of CO-RE
@@ -836,9 +909,11 @@ netdata_ebpf_program_loaded_t ebpf_convert_core_type(char *str, netdata_run_mode
void ebpf_adjust_thread_load(ebpf_module_t *mod, struct btf *file)
{
if (!file) {
- mod->load = EBPF_LOAD_LEGACY;
+ mod->load &= ~EBPF_LOAD_CORE;
+ mod->load |= EBPF_LOAD_LEGACY;
} else if (mod->load == EBPF_LOAD_PLAY_DICE && file) {
- mod->load = EBPF_LOAD_CORE;
+ mod->load &= ~EBPF_LOAD_LEGACY;
+ mod->load |= EBPF_LOAD_CORE;
}
}
@@ -952,13 +1027,45 @@ static void ebpf_update_target_with_conf(ebpf_module_t *em, netdata_ebpf_program
}
/**
+ * Select Load Mode
+ *
+ * Select the load mode according the given inputs.
+ *
+ * @param btf_file a pointer to the loaded btf file.
+ * @parma load current value.
+ * @param btf_file a pointer to the loaded btf file.
+ * @param is_rhf is Red Hat family?
+ *
+ * @return it returns the new load mode.
+ */
+static netdata_ebpf_load_mode_t ebpf_select_load_mode(struct btf *btf_file, netdata_ebpf_load_mode_t load,
+ int kver, int is_rh)
+{
+#ifdef LIBBPF_MAJOR_VERSION
+ if ((load & EBPF_LOAD_CORE) || (load & EBPF_LOAD_PLAY_DICE)) {
+ // Quick fix for Oracle linux 8.x
+ load = (!btf_file || (is_rh && (kver >= NETDATA_EBPF_KERNEL_5_4 && kver < NETDATA_EBPF_KERNEL_5_5))) ?
+ EBPF_LOAD_LEGACY : EBPF_LOAD_CORE;
+ }
+#else
+ load = EBPF_LOAD_LEGACY;
+#endif
+
+ return load;
+}
+
+/**
* Update Module using config
*
* Update configuration for a specific thread.
*
* @param modules structure that will be updated
+ * @oaram origin specify the configuration file loaded
+ * @param btf_file a pointer to the loaded btf file.
+ * @param is_rhf is Red Hat family?
*/
-void ebpf_update_module_using_config(ebpf_module_t *modules)
+void ebpf_update_module_using_config(ebpf_module_t *modules, netdata_ebpf_load_mode_t origin, struct btf *btf_file,
+ int kver, int is_rh)
{
char default_value[EBPF_MAX_MODE_LENGTH + 1];
ebpf_select_mode_string(default_value, EBPF_MAX_MODE_LENGTH, modules->mode);
@@ -977,13 +1084,19 @@ void ebpf_update_module_using_config(ebpf_module_t *modules)
modules->pid_map_size = (uint32_t)appconfig_get_number(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_PID_SIZE,
modules->pid_map_size);
- value = ebpf_convert_load_mode_to_string(modules->load);
+ value = ebpf_convert_load_mode_to_string(modules->load & NETDATA_EBPF_LOAD_METHODS);
value = appconfig_get(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_TYPE_FORMAT, value);
- modules->load = epbf_convert_string_to_load_mode(value);
+ netdata_ebpf_load_mode_t load = epbf_convert_string_to_load_mode(value);
+ load = ebpf_select_load_mode(btf_file, load, kver, is_rh);
+ modules->load = origin | load;
value = appconfig_get(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_CORE_ATTACH, EBPF_CFG_ATTACH_TRAMPOLINE);
netdata_ebpf_program_loaded_t fill_lm = ebpf_convert_core_type(value, modules->mode);
ebpf_update_target_with_conf(modules, fill_lm);
+
+ value = ebpf_convert_collect_pid_to_string(modules->apps_level);
+ value = appconfig_get(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_COLLECT_PID, value);
+ modules->apps_level = ebpf_convert_string_to_apps_level(value);
}
/**
@@ -995,10 +1108,15 @@ void ebpf_update_module_using_config(ebpf_module_t *modules)
* update the variables.
*
* @param em the module structure
+ * @param btf_file a pointer to the loaded btf file.
+ * @param is_rhf is Red Hat family?
+ * @param kver the kernel version
*/
-void ebpf_update_module(ebpf_module_t *em)
+void ebpf_update_module(ebpf_module_t *em, struct btf *btf_file, int kver, int is_rh)
{
char filename[FILENAME_MAX+1];
+ netdata_ebpf_load_mode_t origin;
+
ebpf_mount_config_name(filename, FILENAME_MAX, ebpf_user_config_dir, em->config_file);
if (!ebpf_load_config(em->cfg, filename)) {
ebpf_mount_config_name(filename, FILENAME_MAX, ebpf_stock_config_dir, em->config_file);
@@ -1006,9 +1124,32 @@ void ebpf_update_module(ebpf_module_t *em)
error("Cannot load the ebpf configuration file %s", em->config_file);
return;
}
- }
+ // If user defined data globaly, we will have here EBPF_LOADED_FROM_USER, we need to consider this, to avoid
+ // forcing users to configure thread by thread.
+ origin = (!(em->load & NETDATA_EBPF_LOAD_SOURCE)) ? EBPF_LOADED_FROM_STOCK : em->load & NETDATA_EBPF_LOAD_SOURCE;
+ } else
+ origin = EBPF_LOADED_FROM_USER;
- ebpf_update_module_using_config(em);
+ ebpf_update_module_using_config(em, origin, btf_file, kver, is_rh);
+}
+
+/**
+ * Adjust Apps Cgroup
+ *
+ * Apps and cgroup has internal cleanup that needs attaching tracers to release_task, to avoid overload the function
+ * we will enable this integration by default, if and only if, we are running with trampolines.
+ *
+ * @param em a poiter to the main thread structure.
+ * @param mode is the mode used with different
+ */
+void ebpf_adjust_apps_cgroup(ebpf_module_t *em, netdata_ebpf_program_loaded_t mode)
+{
+ if ((em->load & EBPF_LOADED_FROM_STOCK) &&
+ (em->apps_charts || em->cgroup_charts) &&
+ mode != EBPF_LOAD_TRAMPOLINE) {
+ em->apps_charts = NETDATA_EBPF_APPS_FLAG_NO;
+ em->cgroup_charts = 0;
+ }
}
//----------------------------------------------------------------------------------------------------------------------
@@ -1282,4 +1423,5 @@ void ebpf_select_host_prefix(char *output, size_t length, char *syscall, int kve
char *prefix = (arch == 32) ? "__ia32" : "__x64";
snprintfz(output, length, "%s_sys_%s", prefix, syscall);
}
-} \ No newline at end of file
+}
+