diff options
Diffstat (limited to '')
-rw-r--r-- | libnetdata/ebpf/ebpf.c | 161 | ||||
-rw-r--r-- | libnetdata/ebpf/ebpf.h | 23 |
2 files changed, 165 insertions, 19 deletions
diff --git a/libnetdata/ebpf/ebpf.c b/libnetdata/ebpf/ebpf.c index 8619ae26..1f71f6a2 100644 --- a/libnetdata/ebpf/ebpf.c +++ b/libnetdata/ebpf/ebpf.c @@ -295,25 +295,112 @@ static int select_file(char *name, const char *program, size_t length, int mode, return ret; } -struct bpf_link **ebpf_load_program(char *plugins_dir, ebpf_module_t *em, char *kernel_string, struct bpf_object **obj, int *map_fd) +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) +{ + struct bpf_map *map; + ebpf_local_maps_t *maps = em->maps; + if (!maps) + return; + + bpf_map__for_each(map, program) + { + const char *map_name = bpf_map__name(map); + int i = 0; ; + while (maps[i].name) { + ebpf_local_maps_t *w = &maps[i]; + if (w->user_input != w->internal_input && !strcmp(w->name, map_name)) { +#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); + } + i++; + } + } +} + +size_t ebpf_count_programs(struct bpf_object *obj) +{ + size_t tot = 0; + struct bpf_program *prog; + bpf_object__for_each_program(prog, obj) + { + tot++; + } + + return tot; +} + +static ebpf_specify_name_t *ebpf_find_names(ebpf_specify_name_t *names, const char *prog_name) +{ + size_t i = 0; + while (names[i].program_name) { + if (!strcmp(prog_name, names[i].program_name)) + return &names[i]; + + i++; + } + + return NULL; +} + +static struct bpf_link **ebpf_attach_programs(struct bpf_object *obj, size_t length, ebpf_specify_name_t *names) +{ + struct bpf_link **links = callocz(length , sizeof(struct bpf_link *)); + size_t i = 0; + struct bpf_program *prog; + bpf_object__for_each_program(prog, obj) + { + links[i] = bpf_program__attach(prog); + if (libbpf_get_error(links[i]) && names) { + const char *name = bpf_program__name(prog); + ebpf_specify_name_t *w = ebpf_find_names(names, name); + if (w) { + enum bpf_prog_type type = bpf_program__get_type(prog); + if (type == BPF_PROG_TYPE_KPROBE) + links[i] = bpf_program__attach_kprobe(prog, w->retprobe, w->optional); + } + } + + if (libbpf_get_error(links[i])) { + links[i] = NULL; + } + + i++; + } + + return links; +} + +struct bpf_link **ebpf_load_program(char *plugins_dir, ebpf_module_t *em, char *kernel_string, + struct bpf_object **obj, int *map_fd) { char lpath[4096]; char lname[128]; - int prog_fd; int test = select_file(lname, em->thread_name, (size_t)127, em->mode, kernel_string); if (test < 0 || test > 127) return NULL; snprintf(lpath, 4096, "%s/ebpf.d/%s", plugins_dir, lname); - // We are using BPF_PROG_TYPE_UNSPEC instead a specific type for bpf_prog_load to define the type - // according the eBPF program loaded - if (bpf_prog_load(lpath, BPF_PROG_TYPE_UNSPEC, obj, &prog_fd)) { - em->enabled = CONFIG_BOOLEAN_NO; - info("Cannot load program: %s", lpath); + *obj = bpf_object__open_file(lpath, NULL); + if (libbpf_get_error(obj)) { + error("Cannot open BPF object %s", lpath); + bpf_object__close(*obj); + return NULL; + } + + ebpf_update_map_sizes(*obj, em); + + if (bpf_object__load(*obj)) { + error("ERROR: loading BPF object file failed %s\n", lpath); + bpf_object__close(*obj); return NULL; - } else { - info("The eBPF program %s was loaded with success.", em->thread_name); } struct bpf_map *map; @@ -324,16 +411,53 @@ struct bpf_link **ebpf_load_program(char *plugins_dir, ebpf_module_t *em, char * i++; } - struct bpf_program *prog; - struct bpf_link **links = callocz(NETDATA_MAX_PROBES , sizeof(struct bpf_link *)); - i = 0; - bpf_object__for_each_program(prog, *obj) - { - links[i] = bpf_program__attach(prog); - i++; + size_t count_programs = ebpf_count_programs(*obj); + + return ebpf_attach_programs(*obj, count_programs, em->names); +} + +static char *ebpf_update_name(char *search) +{ + char filename[FILENAME_MAX + 1]; + char *ret = NULL; + snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, NETDATA_KALLSYMS); + procfile *ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT); + if(unlikely(!ff)) { + error("Cannot open %s%s", netdata_configured_host_prefix, NETDATA_KALLSYMS); + return ret; } - return links; + ff = procfile_readall(ff); + if(unlikely(!ff)) + return ret; + + unsigned long i, lines = procfile_lines(ff); + size_t length = strlen(search); + for(i = 0; i < lines ; i++) { + char *cmp = procfile_lineword(ff, i,2);; + if (!strncmp(search, cmp, length)) { + ret = strdupz(cmp); + break; + } + } + + procfile_close(ff); + + return ret; +} + +void ebpf_update_names(ebpf_specify_name_t *opt, ebpf_module_t *em) +{ + int mode = em->mode; + em->names = opt; + + size_t i = 0; + while (opt[i].program_name) { + opt[i].retprobe = (mode == MODE_RETURN); + opt[i].optional = ebpf_update_name(opt[i].function_to_attach); + + i++; + } } //---------------------------------------------------------------------------------------------------------------------- @@ -368,6 +492,9 @@ void ebpf_update_module_using_config(ebpf_module_t *modules, struct config *cfg) modules->apps_charts = appconfig_get_boolean(cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_APPLICATION, CONFIG_BOOLEAN_YES); + + modules->pid_map_size = (uint32_t)appconfig_get_number(cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_PID_SIZE, + modules->pid_map_size); } diff --git a/libnetdata/ebpf/ebpf.h b/libnetdata/ebpf/ebpf.h index ac3a1a2f..bc55d959 100644 --- a/libnetdata/ebpf/ebpf.h +++ b/libnetdata/ebpf/ebpf.h @@ -7,6 +7,7 @@ #include <bpf/libbpf.h> #define NETDATA_DEBUGFS "/sys/kernel/debug/tracing/" +#define NETDATA_KALLSYMS "/proc/kallsyms" // Config files #define EBPF_GLOBAL_SECTION "global" @@ -15,6 +16,7 @@ #define EBPF_CFG_LOAD_MODE_RETURN "return" #define EBPF_CFG_UPDATE_EVERY "update every" +#define EBPF_CFG_PID_SIZE "pid table size" #define EBPF_CFG_APPLICATION "apps" /** @@ -95,6 +97,21 @@ typedef enum { MODE_ENTRY // This attaches kprobe when the function is called } netdata_run_mode_t; +#define ND_EBPF_DEFAULT_PID_SIZE 32768U + +typedef struct ebpf_local_maps { + char *name; + uint32_t internal_input; + uint32_t user_input; +} ebpf_local_maps_t; + +typedef struct ebpf_specify_name { + char *program_name; + char *function_to_attach; + char *optional; + bool retprobe; +} ebpf_specify_name_t; + typedef struct ebpf_module { const char *thread_name; const char *config_name; @@ -107,10 +124,11 @@ typedef struct ebpf_module { uint32_t thread_id; int optional; void (*apps_routine)(struct ebpf_module *em, void *ptr); + ebpf_local_maps_t *maps; + ebpf_specify_name_t *names; + uint32_t pid_map_size; } ebpf_module_t; -#define NETDATA_MAX_PROBES 64 - extern int get_kernel_version(char *out, int size); extern int get_redhat_release(); extern int has_condition_to_run(int version); @@ -126,5 +144,6 @@ extern void ebpf_mount_config_name(char *filename, size_t length, char *path, ch extern int ebpf_load_config(struct config *config, char *filename); extern void ebpf_update_module_using_config(ebpf_module_t *modules, struct config *cfg); extern void ebpf_update_module(ebpf_module_t *em, struct config *cfg, char *cfg_file); +extern void ebpf_update_names(ebpf_specify_name_t *opt, ebpf_module_t *em); #endif /* NETDATA_EBPF_H */ |