diff options
Diffstat (limited to 'libnetdata/ebpf/ebpf.c')
-rw-r--r-- | libnetdata/ebpf/ebpf.c | 268 |
1 files changed, 244 insertions, 24 deletions
diff --git a/libnetdata/ebpf/ebpf.c b/libnetdata/ebpf/ebpf.c index ca40492f1..dde6d57fc 100644 --- a/libnetdata/ebpf/ebpf.c +++ b/libnetdata/ebpf/ebpf.c @@ -279,7 +279,7 @@ 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_11, NETDATA_IDX_STR_V5_15, NETDATA_IDX_STR_V5_16 }; return kernel_names[selector]; @@ -301,7 +301,9 @@ static int ebpf_select_max_index(int is_rhf, uint32_t kver) if (kver >= NETDATA_EBPF_KERNEL_4_11) return NETDATA_IDX_V4_18; } else { // Kernels from kernel.org - if (kver >= NETDATA_EBPF_KERNEL_5_15) + if (kver >= NETDATA_EBPF_KERNEL_5_16) + return NETDATA_IDX_V5_16; + else if (kver >= NETDATA_EBPF_KERNEL_5_15) return NETDATA_IDX_V5_15; else if (kver >= NETDATA_EBPF_KERNEL_5_11) return NETDATA_IDX_V5_11; @@ -451,14 +453,53 @@ void ebpf_update_pid_table(ebpf_local_maps_t *pid, ebpf_module_t *em) pid->user_input = em->pid_map_size; } -void ebpf_update_map_sizes(struct bpf_object *program, ebpf_module_t *em) +/** + * Update map size + * + * Update map size with information read from configuration files. + * + * @param map the structure with file descriptor to update. + * @param lmap the structure with information from configuration files. + * @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) +{ + uint32_t apps_type = NETDATA_EBPF_MAP_PID | NETDATA_EBPF_MAP_RESIZABLE; + if (lmap->user_input && lmap->user_input != 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; +#ifdef LIBBPF_MAJOR_VERSION + bpf_map__set_max_entries(map, lmap->user_input); +#else + bpf_map__resize(map, lmap->user_input); +#endif + } +} + +/** + * Update Legacy map sizes + * + * Update map size for eBPF legacy code. + * + * @param program the structure with values read from binary. + * @param em the structure with information about how the module/thread is working. + */ +static void ebpf_update_legacy_map_sizes(struct bpf_object *program, ebpf_module_t *em) { struct bpf_map *map; ebpf_local_maps_t *maps = em->maps; if (!maps) return; - uint32_t apps_type = NETDATA_EBPF_MAP_PID | NETDATA_EBPF_MAP_RESIZABLE; bpf_map__for_each(map, program) { const char *map_name = bpf_map__name(map); @@ -467,15 +508,7 @@ void ebpf_update_map_sizes(struct bpf_object *program, ebpf_module_t *em) ebpf_local_maps_t *w = &maps[i]; if (w->type & NETDATA_EBPF_MAP_RESIZABLE) { if (!strcmp(w->name, map_name)) { - if (w->user_input && w->user_input != w->internal_input) { -#ifdef NETDATA_INTERNAL_CHECKS - info("Changing map %s from size %u to %u ", map_name, w->internal_input, w->user_input); -#endif - bpf_map__resize(map, w->user_input); - } else if (((w->type & apps_type) == apps_type) && (!em->apps_charts) && (!em->cgroup_charts)) { - w->user_input = ND_EBPF_DEFAULT_MIN_PID; - bpf_map__resize(map, w->user_input); - } + ebpf_update_map_size(map, w, em, map_name); } } @@ -564,7 +597,32 @@ static void ebpf_update_maps(ebpf_module_t *em, struct bpf_object *obj) } } -static void ebpf_update_controller(ebpf_module_t *em, struct bpf_object *obj) +/** + * Update Controller + * + * Update controller value with user input. + * + * @param fd the table file descriptor + * @param em structure with information about eBPF program we will load. + */ +void ebpf_update_controller(int fd, ebpf_module_t *em) +{ + uint32_t key = NETDATA_CONTROLLER_APPS_ENABLED; + uint32_t value = em->apps_charts | em->cgroup_charts; + int ret = bpf_map_update_elem(fd, &key, &value, 0); + if (ret) + error("Add key(%u) for controller table failed.", key); +} + +/** + * Update Legacy controller + * + * Update legacy controller table when eBPF program has it. + * + * @param em structure with information about eBPF program we will load. + * @param obj bpf object with tables. + */ +static void ebpf_update_legacy_controller(ebpf_module_t *em, struct bpf_object *obj) { ebpf_local_maps_t *maps = em->maps; if (!maps) @@ -580,11 +638,7 @@ static void ebpf_update_controller(ebpf_module_t *em, struct bpf_object *obj) w->type &= ~NETDATA_EBPF_MAP_CONTROLLER; w->type |= NETDATA_EBPF_MAP_CONTROLLER_UPDATED; - uint32_t key = NETDATA_CONTROLLER_APPS_ENABLED; - int value = em->apps_charts | em->cgroup_charts; - int ret = bpf_map_update_elem(w->map_fd, &key, &value, 0); - if (ret) - error("Add key(%u) for controller table failed.", key); + ebpf_update_controller(w->map_fd, em); } i++; } @@ -620,7 +674,7 @@ struct bpf_link **ebpf_load_program(char *plugins_dir, ebpf_module_t *em, int kv return NULL; } - ebpf_update_map_sizes(*obj, em); + ebpf_update_legacy_map_sizes(*obj, em); if (bpf_object__load(*obj)) { error("ERROR: loading BPF object file failed %s\n", lpath); @@ -629,7 +683,7 @@ struct bpf_link **ebpf_load_program(char *plugins_dir, ebpf_module_t *em, int kv } ebpf_update_maps(em, *obj); - ebpf_update_controller(em, *obj); + ebpf_update_legacy_controller(em, *obj); size_t count_programs = ebpf_count_programs(*obj); @@ -716,14 +770,131 @@ static void ebpf_select_mode_string(char *output, size_t len, netdata_run_mode_t } /** + * Convert string to load mode + * + * Convert the string given as argument to value present in enum. + * + * @param str value read from configuraion file. + * + * @return It returns the value to be used. + */ +netdata_ebpf_load_mode_t epbf_convert_string_to_load_mode(char *str) +{ + if (!strcasecmp(str, EBPF_CFG_CORE_PROGRAM)) + return EBPF_LOAD_CORE; + else if (!strcasecmp(str, EBPF_CFG_LEGACY_PROGRAM)) + return EBPF_LOAD_LEGACY; + + return EBPF_LOAD_PLAY_DICE; +} + +/** + * Convert load mode to string + * + * @param mode value that will select the string + * + * @return It returns the string associated to mode. + */ +static char *ebpf_convert_load_mode_to_string(netdata_ebpf_load_mode_t mode) +{ + if (mode == EBPF_LOAD_CORE) + return EBPF_CFG_CORE_PROGRAM; + else if (mode == EBPF_LOAD_LEGACY) + return EBPF_CFG_LEGACY_PROGRAM; + + return EBPF_CFG_DEFAULT_PROGRAM; +} + +/** + * CO-RE type + * + * Select the preferential type of CO-RE + * + * @param str value read from configuration file. + * @param lmode load mode used by collector. + */ +netdata_ebpf_program_loaded_t ebpf_convert_core_type(char *str, netdata_run_mode_t lmode) +{ + if (!strcasecmp(str, EBPF_CFG_ATTACH_TRACEPOINT)) + return EBPF_LOAD_TRACEPOINT; + else if (!strcasecmp(str, EBPF_CFG_ATTACH_PROBE)) { + return (lmode == MODE_ENTRY) ? EBPF_LOAD_PROBE : EBPF_LOAD_RETPROBE; + } + + return EBPF_LOAD_TRAMPOLINE; +} + +#ifdef LIBBPF_MAJOR_VERSION +/** + * Adjust Thread Load + * + * Adjust thread configuraton according specified load. + * + * @param mod the main structure that will be adjusted. + * @param file the btf file used with thread. + */ +void ebpf_adjust_thread_load(ebpf_module_t *mod, struct btf *file) +{ + if (!file) { + mod->load = EBPF_LOAD_LEGACY; + } else if (mod->load == EBPF_LOAD_PLAY_DICE && file) { + mod->load = EBPF_LOAD_CORE; + } +} + +/** + * + * @param filename + * @return + */ +struct btf *ebpf_parse_btf_file(const char *filename) +{ + struct btf *bf = btf__parse(filename, NULL); + if (libbpf_get_error(bf)) { + fprintf(stderr, "Cannot parse btf file"); + btf__free(bf); + return NULL; + } + + return bf; +} +#endif + +/** + * Update target with configuration + * + * Update target load mode with value. + * + * @param em the module structure + * @param value value used to update. + */ +static void ebpf_update_target_with_conf(ebpf_module_t *em, netdata_ebpf_program_loaded_t value) +{ + netdata_ebpf_targets_t *targets = em->targets; + if (!targets) { + return; + } + + int i = 0; + while (targets[i].name) { + targets[i].mode = value; + i++; + } +} + +/** + * Update Module using config + * + * Update configuration for a specific thread. + * * @param modules structure that will be updated */ void ebpf_update_module_using_config(ebpf_module_t *modules) { char default_value[EBPF_MAX_MODE_LENGTH + 1]; ebpf_select_mode_string(default_value, EBPF_MAX_MODE_LENGTH, modules->mode); - char *mode = appconfig_get(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_LOAD_MODE, default_value); - modules->mode = ebpf_select_mode(mode); + char *value = appconfig_get(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_LOAD_MODE, default_value); + modules->mode = ebpf_select_mode(value); modules->update_every = (int)appconfig_get_number(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_UPDATE_EVERY, modules->update_every); @@ -733,8 +904,15 @@ 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 = appconfig_get(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_TYPE_FORMAT, value); + modules->load = epbf_convert_string_to_load_mode(value); + + 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); +} /** * Update module @@ -991,3 +1169,45 @@ int ebpf_disable_tracing_values(char *subsys, char *eventname) { return ebpf_change_tracing_values(subsys, eventname, "0"); } + +/** + * Select PC prefix + * + * Identify the prefix to run on PC architecture. + * + * @return It returns 32 or 64 according to host arch. + */ +static uint32_t ebpf_select_pc_prefix() +{ + long counter = 1; + uint32_t i; + for (i = 0; i < 128; i++) { + counter <<= 1; + if (counter < 0) + break; + } + + return counter; +} + +/** + * Select Host Prefix + * + * Select prefix to syscall when host is running a kernel newer than 4.17.0 + * + * @param output the vector to store data. + * @param length length of output vector. + * @param syscall the syscall that prefix will be attached; + * @param kver the current kernel version in format MAJOR*65536 + MINOR*256 + PATCH + */ +void ebpf_select_host_prefix(char *output, size_t length, char *syscall, int kver) +{ + if (kver < NETDATA_EBPF_KERNEL_4_17) + snprintfz(output, length, "sys_%s", syscall); + else { + uint32_t arch = ebpf_select_pc_prefix(); + // Prefix selected according https://www.kernel.org/doc/html/latest/process/adding-syscalls.html + char *prefix = (arch == 32) ? "__ia32" : "__x64"; + snprintfz(output, length, "%s_sys_%s", prefix, syscall); + } +}
\ No newline at end of file |