diff options
Diffstat (limited to 'collectors/ebpf.plugin/ebpf.c')
-rw-r--r-- | collectors/ebpf.plugin/ebpf.c | 1306 |
1 files changed, 448 insertions, 858 deletions
diff --git a/collectors/ebpf.plugin/ebpf.c b/collectors/ebpf.plugin/ebpf.c index 3648ad54c2..8ef20b03fc 100644 --- a/collectors/ebpf.plugin/ebpf.c +++ b/collectors/ebpf.plugin/ebpf.c @@ -35,409 +35,154 @@ void netdata_cleanup_and_exit(int ret) { } // ---------------------------------------------------------------------- -//Netdata eBPF library -void *libnetdata = NULL; -int (*load_bpf_file)(char *, int) = NULL; -int (*set_bpf_perf_event)(int, int); -int (*perf_event_unmap)(struct perf_event_mmap_page *, size_t); -int (*perf_event_mmap_header)(int, struct perf_event_mmap_page **, int); -void (*netdata_perf_loop_multi)(int *, struct perf_event_mmap_page **, int, int *, int (*nsb)(void *, int), int); -int *map_fd = NULL; - -//Perf event variables -static int pmu_fd[NETDATA_MAX_PROCESSOR]; -static struct perf_event_mmap_page *headers[NETDATA_MAX_PROCESSOR]; -int page_cnt = 8; - -//Libbpf (It is necessary to have at least kernel 4.10) -int (*bpf_map_lookup_elem)(int, const void *, void *); - -static char *plugin_dir = PLUGINS_DIR; -static char *user_config_dir = CONFIG_DIR; -static char *stock_config_dir = LIBCONFIG_DIR; -static char *netdata_configured_log_dir = LOG_DIR; - -FILE *developer_log = NULL; - -//Global vectors -netdata_syscall_stat_t *aggregated_data = NULL; -netdata_publish_syscall_t *publish_aggregated = NULL; +char *ebpf_plugin_dir = PLUGINS_DIR; +static char *ebpf_user_config_dir = CONFIG_DIR; +static char *ebpf_stock_config_dir = LIBCONFIG_DIR; +static char *ebpf_configured_log_dir = LOG_DIR; static int update_every = 1; static int thread_finished = 0; -static int close_plugin = 0; -static netdata_run_mode_t mode = MODE_ENTRY; -static int debug_log = 0; -static int use_stdout = 0; -struct config collector_config; -static int mykernel = 0; -static char kernel_string[64]; -static int nprocs; +int close_ebpf_plugin = 0; +struct config collector_config = { .first_section = NULL, .last_section = NULL, .mutex = NETDATA_MUTEX_INITIALIZER, + .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare }, + .rwlock = AVL_LOCK_INITIALIZER } }; + +int running_on_kernel = 0; +char kernel_string[64]; +int ebpf_nprocs; static int isrh; netdata_idx_t *hash_values; pthread_mutex_t lock; -static struct ebpf_module { - const char *thread_name; - int enabled; - void (*start_routine) (void *); - int update_time; - int global_charts; - int apps_charts; - netdata_run_mode_t mode; -} ebpf_modules[] = { - { .thread_name = "process", .enabled = 0, .start_routine = NULL, .update_time = 1, .global_charts = 1, .apps_charts = 1, .mode = MODE_ENTRY }, - { .thread_name = "network_viewer", .enabled = 0, .start_routine = NULL, .update_time = 1, .global_charts = 1, .apps_charts = 1, .mode = MODE_ENTRY }, - { .thread_name = NULL, .enabled = 0, .start_routine = NULL, .update_time = 1, .global_charts = 0, .apps_charts = 1, .mode = MODE_ENTRY }, +netdata_ebpf_events_t process_probes[] = { + { .type = 'r', .name = "vfs_write" }, + { .type = 'r', .name = "vfs_writev" }, + { .type = 'r', .name = "vfs_read" }, + { .type = 'r', .name = "vfs_readv" }, + { .type = 'r', .name = "do_sys_open" }, + { .type = 'r', .name = "vfs_unlink" }, + { .type = 'p', .name = "do_exit" }, + { .type = 'p', .name = "release_task" }, + { .type = 'r', .name = "_do_fork" }, + { .type = 'r', .name = "__close_fd" }, + { .type = 'r', .name = "__x64_sys_clone" }, + { .type = 0, .name = NULL } }; -static char *dimension_names[NETDATA_MAX_MONITOR_VECTOR] = { "open", "close", "delete", "read", "write", "process", "task", "process", "thread" }; -static char *id_names[NETDATA_MAX_MONITOR_VECTOR] = { "do_sys_open", "__close_fd", "vfs_unlink", "vfs_read", "vfs_write", "do_exit", "release_task", "_do_fork", "sys_clone" }; -static char *status[] = { "process", "zombie" }; - -int event_pid = 0; -netdata_ebpf_events_t collector_events[] = { - { .type = 'r', .name = "vfs_write" }, - { .type = 'r', .name = "vfs_writev" }, - { .type = 'r', .name = "vfs_read" }, - { .type = 'r', .name = "vfs_readv" }, - { .type = 'r', .name = "do_sys_open" }, - { .type = 'r', .name = "vfs_unlink" }, - { .type = 'p', .name = "do_exit" }, - { .type = 'p', .name = "release_task" }, - { .type = 'r', .name = "_do_fork" }, - { .type = 'r', .name = "__close_fd" }, - { .type = 'r', .name = "__x64_sys_clone" }, - { .type = 0, .name = NULL } +netdata_ebpf_events_t socket_probes[] = { + { .type = 'r', .name = "tcp_sendmsg" }, + { .type = 'p', .name = "tcp_cleanup_rbuf" }, + { .type = 'p', .name = "tcp_close" }, + { .type = 'p', .name = "udp_recvmsg" }, + { .type = 'r', .name = "udp_recvmsg" }, + { .type = 'r', .name = "udp_sendmsg" }, + { .type = 'p', .name = "do_exit" }, + { .type = 0, .name = NULL } }; -void open_developer_log() { - char filename[FILENAME_MAX+1]; - int tot = sprintf(filename, "%s/%s", netdata_configured_log_dir, NETDATA_DEVELOPER_LOG_FILE); - - if(tot > 0) - developer_log = fopen(filename, "a"); -} - -static int unmap_memory() { - int i; - int size = (int)sysconf(_SC_PAGESIZE)*(page_cnt + 1); - for ( i = 0 ; i < nprocs ; i++ ) { - if (perf_event_unmap(headers[i], size) < 0) { - fprintf(stderr,"[EBPF PROCESS] CANNOT unmap headers.\n"); - return -1; - } - - close(pmu_fd[i]); - } - - return 0; -} +ebpf_module_t ebpf_modules[] = { + { .thread_name = "process", .config_name = "process", .enabled = 0, .start_routine = ebpf_process_thread, + .update_time = 1, .global_charts = 1, .apps_charts = 1, .mode = MODE_ENTRY, .probes = process_probes }, + { .thread_name = "socket", .config_name = "network viewer", .enabled = 0, .start_routine = ebpf_socket_thread, + .update_time = 1, .global_charts = 1, .apps_charts = 1, .mode = MODE_ENTRY, .probes = socket_probes }, + { .thread_name = NULL, .enabled = 0, .start_routine = NULL, .update_time = 1, + .global_charts = 0, .apps_charts = 1, .mode = MODE_ENTRY, .probes = NULL }, +}; -static void int_exit(int sig) +/** + * Close the collector gracefully + * + * @param sig is the signal number used to close the collector + */ +static void ebpf_exit(int sig) { - close_plugin = 1; + int event_pid; + close_ebpf_plugin = 1; //When both threads were not finished case I try to go in front this address, the collector will crash if (!thread_finished) { return; } - if (aggregated_data) { - free(aggregated_data); - aggregated_data = NULL; - } - - if (publish_aggregated) { - free(publish_aggregated); - publish_aggregated = NULL; - } - - if(mode == MODE_DEVMODE && debug_log) { - unmap_memory(); - } - - if (libnetdata) { - dlclose(libnetdata); - libnetdata = NULL; - } - - if (developer_log) { - fclose(developer_log); - developer_log = NULL; - } - - if (hash_values) { - freez(hash_values); - } - - if (event_pid) { - int ret = fork(); - if (ret < 0) //error - error("[EBPF PROCESS] Cannot fork(), so I won't be able to clean %skprobe_events", NETDATA_DEBUGFS); - else if (!ret) { //child - int i; - for ( i=getdtablesize(); i>=0; --i) - close(i); - - int fd = open("/dev/null",O_RDWR, 0); - if (fd != -1) { - dup2 (fd, STDIN_FILENO); - dup2 (fd, STDOUT_FILENO); - dup2 (fd, STDERR_FILENO); - } - - if (fd > 2) - close (fd); - - int sid = setsid(); - if(sid >= 0) { - sleep(1); - if(debug_log) { - open_developer_log(); - } - debug(D_EXIT, "Wait for father %d die", event_pid); - clean_kprobe_events(developer_log, event_pid, collector_events); - } else { - error("Cannot become session id leader, so I won't try to clean kprobe_events.\n"); - } - } else { //parent - exit(0); - } - - if (developer_log) { - fclose(developer_log); - developer_log = NULL; + event_pid = getpid(); + int ret = fork(); + if (ret < 0) //error + error("Cannot fork(), so I won't be able to clean %skprobe_events", NETDATA_DEBUGFS); + else if (!ret) { //child + int i; + for ( i=getdtablesize(); i>=0; --i) + close(i); + + int fd = open("/dev/null",O_RDWR, 0); + if (fd != -1) { + dup2 (fd, STDIN_FILENO); + dup2 (fd, STDOUT_FILENO); + dup2 (fd, STDERR_FILENO); } - } - - exit(sig); -} - -static inline void netdata_write_chart_cmd(char *type - , char *id - , char *axis - , char *web - , int order) -{ - printf("CHART %s.%s '' '' '%s' '%s' '' line %d 1 ''\n" - , type - , id - , axis - , web - , order); -} - -static void netdata_write_global_dimension(char *d, char *n) -{ - printf("DIMENSION %s %s absolute 1 1\n", d, n); -} - -static void netdata_create_global_dimension(void *ptr, int end) -{ - netdata_publish_syscall_t *move = ptr; - - int i = 0; - while (move && i < end) { - netdata_write_global_dimension(move->name, move->dimension); - - move = move->next; - i++; - } -} -static inline void netdata_create_chart(char *family - , char *name - , char *axis - , char *web - , int order - , void (*ncd)(void *, int) - , void *move - , int end) -{ - netdata_write_chart_cmd(family, name, axis, web, order); - ncd(move, end); -} - -static void netdata_create_io_chart(char *family, char *name, char *axis, char *web, int order) { - printf("CHART %s.%s '' '' '%s' '%s' '' line %d 1 ''\n" - , family - , name - , axis - , web - , order); - - printf("DIMENSION %s %s absolute 1 1\n", id_names[3], NETDATA_VFS_DIM_OUT_FILE_BYTES); - printf("DIMENSION %s %s absolute 1 1\n", id_names[4], NETDATA_VFS_DIM_IN_FILE_BYTES); -} - -static void netdata_process_status_chart(char *family, char *name, char *axis, char *web, int order) { - printf("CHART %s.%s '' '' '%s' '%s' '' line %d 1 ''\n" - , family - , name - , axis - , web - , order); - - printf("DIMENSION %s '' absolute 1 1\n", status[0]); - printf("DIMENSION %s '' absolute 1 1\n", status[1]); -} - -static void netdata_global_charts_create() { - netdata_create_chart(NETDATA_EBPF_FAMILY - , NETDATA_FILE_OPEN_CLOSE_COUNT - , "Calls" - , NETDATA_FILE_GROUP - , 970 - , netdata_create_global_dimension - , publish_aggregated - , 2); - - if(mode < MODE_ENTRY) { - netdata_create_chart(NETDATA_EBPF_FAMILY - , NETDATA_FILE_OPEN_ERR_COUNT - , "Calls" - , NETDATA_FILE_GROUP - , 971 - , netdata_create_global_dimension - , publish_aggregated - , 2); - } + if (fd > 2) + close (fd); - netdata_create_chart(NETDATA_EBPF_FAMILY - , NETDATA_VFS_FILE_CLEAN_COUNT - , "Calls" - , NETDATA_VFS_GROUP - , 972 - , netdata_create_global_dimension - , &publish_aggregated[NETDATA_DEL_START] - , 1); - - netdata_create_chart(NETDATA_EBPF_FAMILY - , NETDATA_VFS_FILE_IO_COUNT - , "Calls" - , NETDATA_VFS_GROUP - , 973 - , netdata_create_global_dimension - , &publish_aggregated[NETDATA_IN_START_BYTE] - , 2); - - if(mode < MODE_ENTRY) { - netdata_create_io_chart(NETDATA_EBPF_FAMILY - , NETDATA_VFS_IO_FILE_BYTES - , "bytes/s" - , NETDATA_VFS_GROUP - , 974); - - netdata_create_chart(NETDATA_EBPF_FAMILY - , NETDATA_VFS_FILE_ERR_COUNT - , "Calls" - , NETDATA_VFS_GROUP - , 975 - , netdata_create_global_dimension - , &publish_aggregated[2] - , NETDATA_VFS_ERRORS); + int sid = setsid(); + if(sid >= 0) { + sleep(1); + debug(D_EXIT, "Wait for father %d die", event_pid); - } - - netdata_create_chart(NETDATA_EBPF_FAMILY - , NETDATA_PROCESS_SYSCALL - , "Calls" - , NETDATA_PROCESS_GROUP - , 976 - , netdata_create_global_dimension - , &publish_aggregated[NETDATA_PROCESS_START] - , 2); - - netdata_create_chart(NETDATA_EBPF_FAMILY - , NETDATA_EXIT_SYSCALL - , "Calls" - , NETDATA_PROCESS_GROUP - , 977 - , netdata_create_global_dimension - , &publish_aggregated[NETDATA_EXIT_START] - , 2); - - netdata_process_status_chart(NETDATA_EBPF_FAMILY - , NETDATA_PROCESS_STATUS_NAME - , "Total" - , NETDATA_PROCESS_GROUP - , 978); - - if(mode < MODE_ENTRY) { - netdata_create_chart(NETDATA_EBPF_FAMILY - , NETDATA_PROCESS_ERROR_NAME - , "Calls" - , NETDATA_PROCESS_GROUP - , 979 - , netdata_create_global_dimension - , &publish_aggregated[NETDATA_PROCESS_START] - , 2); - } - -} - - -static void netdata_create_charts() { - netdata_global_charts_create(); -} - -static void netdata_update_publish(netdata_publish_syscall_t *publish - , netdata_publish_vfs_common_t *pvc - , netdata_syscall_stat_t *input) { - - netdata_publish_syscall_t *move = publish; - while(move) { - if(input->call != move->pcall) { - //This condition happens to avoid initial values with dimensions higher than normal values. - if(move->pcall) { - move->ncall = (input->call > move->pcall)?input->call - move->pcall: move->pcall - input->call; - move->nbyte = (input->bytes > move->pbyte)?input->bytes - move->pbyte: move->pbyte - input->bytes; - move->nerr = (input->ecall > move->nerr)?input->ecall - move->perr: move->perr - input->ecall; - } else { - move->ncall = 0; - move->nbyte = 0; - move->nerr = 0; - } - - move->pcall = input->call; - move->pbyte = input->bytes; - move->perr = input->ecall; + for (event_pid = 0; ebpf_modules[event_pid].probes; event_pid++) + clean_kprobe_events(NULL, (int)ebpf_modules[event_pid].thread_id, ebpf_modules[event_pid].probes); } else { - move->ncall = 0; - move->nbyte = 0; - move->nerr = 0; + error("Cannot become session id leader, so I won't try to clean kprobe_events.\n"); } - - input = input->next; - move = move->next; + } else { //parent + exit(0); } - pvc->write = -((long)publish[2].nbyte); - pvc->read = (long)publish[3].nbyte; - - pvc->running = (long)publish[7].ncall - (long)publish[8].ncall; - publish[6].ncall = -publish[6].ncall; // release - pvc->zombie = (long)publish[5].ncall + (long)publish[6].ncall; + exit(sig); } -static inline void write_begin_chart(char *family, char *name) +/***************************************************************** + * + * FUNCTIONS TO CREATE CHARTS + * + *****************************************************************/ + +/** + * Write begin command on standard output + * + * @param family the chart family name + * @param name the chart name + */ +void write_begin_chart(char *family, char *name) { int ret = printf( "BEGIN %s.%s\n" - , family - , name); + , family + , name); (void)ret; } -static inline void write_chart_dimension(char *dim, long long value) +/** + * Write set command on standard output + * + * @param dim the dimension name + * @param value the value for the dimension + */ +void write_chart_dimension(char *dim, long long value) { int ret = printf("SET %s = %lld\n", dim, value); (void)ret; } -static void write_global_count_chart(char *name, char *family, netdata_publish_syscall_t *move, int end) { +/** + * Call the necessary functions to create a chart. + * + * @param name the chart name + * @param family the chart family + * @param move the pointer with the values that will be published + * @param end the number of values that will be written on standard output + */ +void write_count_chart(char *name, char *family, netdata_publish_syscall_t *move, int end) { write_begin_chart(family, name); int i = 0; @@ -451,7 +196,15 @@ static void write_global_count_chart(char *name, char *family, netdata_publish_s printf("END\n"); } -static void write_global_err_chart(char *name, char *family, netdata_publish_syscall_t *move, int end) { +/** + * Call the necessary functions to create a chart. + * + * @param name the chart name + * @param family the chart family + * @param move the pointer with the values that will be published + * @param end the number of values that will be written on standard output + */ +void write_err_chart(char *name, char *family, netdata_publish_syscall_t *move, int end) { write_begin_chart(family, name); int i = 0; @@ -465,176 +218,129 @@ static void write_global_err_chart(char *name, char *family, netdata_publish_sys printf("END\n"); } -static void write_io_chart(char *family, netdata_publish_vfs_common_t *pvc) { - write_begin_chart(family, NETDATA_VFS_IO_FILE_BYTES); - - write_chart_dimension(id_names[3], (long long) pvc->write); - write_chart_dimension(id_names[4], (long long) pvc->read); - - printf("END\n"); -} -static void write_status_chart(char *family, netdata_publish_vfs_common_t *pvc) { - write_begin_chart(family, NETDATA_PROCESS_STATUS_NAME); +/** + * Call the necessary functions to create a chart. + * + * @param family the chart family + * @param move the pointer with the values that will be published + */ +void write_io_chart(char *chart, char *family, char *dwrite, char *dread, netdata_publish_vfs_common_t *pvc) { + write_begin_chart(family, chart); - write_chart_dimension(status[0], (long long) pvc->running); - write_chart_dimension(status[1], (long long) pvc->zombie); + write_chart_dimension(dwrite, (long long) pvc->write); + write_chart_dimension(dread, (long long) pvc->read); printf("END\n"); } -static void netdata_publish_data() { - netdata_publish_vfs_common_t pvc; - netdata_update_publish(publish_aggregated, &pvc, aggregated_data); - - write_global_count_chart(NETDATA_FILE_OPEN_CLOSE_COUNT, NETDATA_EBPF_FAMILY, publish_aggregated, 2); - write_global_count_chart(NETDATA_VFS_FILE_CLEAN_COUNT, NETDATA_EBPF_FAMILY, &publish_aggregated[NETDATA_DEL_START], 1); - write_global_count_chart(NETDATA_VFS_FILE_IO_COUNT, NETDATA_EBPF_FAMILY, &publish_aggregated[NETDATA_IN_START_BYTE], 2); - write_global_count_chart(NETDATA_EXIT_SYSCALL, NETDATA_EBPF_FAMILY, &publish_aggregated[NETDATA_EXIT_START], 2); - write_global_count_chart(NETDATA_PROCESS_SYSCALL, NETDATA_EBPF_FAMILY, &publish_aggregated[NETDATA_PROCESS_START], 2); - - write_status_chart(NETDATA_EBPF_FAMILY, &pvc); - if(mode < MODE_ENTRY) { - write_global_err_chart(NETDATA_FILE_OPEN_ERR_COUNT, NETDATA_EBPF_FAMILY, publish_aggregated, 2); - write_global_err_chart(NETDATA_VFS_FILE_ERR_COUNT, NETDATA_EBPF_FAMILY, &publish_aggregated[2], NETDATA_VFS_ERRORS); - write_global_err_chart(NETDATA_PROCESS_ERROR_NAME, NETDATA_EBPF_FAMILY, &publish_aggregated[NETDATA_PROCESS_START], 2); - - write_io_chart(NETDATA_EBPF_FAMILY, &pvc); - } -} - -void *process_publisher(void *ptr) +/** + * Write chart cmd on standard output + * + * @param type the chart type + * @param id the chart id + * @param axis the axis label + * @param web the group name used to attach the chart on dashaboard + * @param order the chart order + */ +void ebpf_write_chart_cmd(char *type + , char *id + , char *axis + , char *web + , int order) { - (void)ptr; - netdata_create_charts(); - - usec_t step = update_every * USEC_PER_SEC; - heartbeat_t hb; - heartbeat_init(&hb); - while(!close_plugin) { - usec_t dt = heartbeat_next(&hb, step); - (void)dt; - - pthread_mutex_lock(&lock); - netdata_publish_data(); - pthread_mutex_unlock(&lock); - - fflush(stdout); - } - - return NULL; -} - -static void move_from_kernel2user_global() { - uint64_t idx; - netdata_idx_t res[NETDATA_GLOBAL_VECTOR]; - - netdata_idx_t *val = hash_values; - for (idx = 0; idx < NETDATA_GLOBAL_VECTOR; idx++) { - if(!bpf_map_lookup_elem(map_fd[1], &idx, val)) { - uint64_t total = 0; - int i; - int end = (mykernel < NETDATA_KERNEL_V4_15)?1:nprocs; - for (i = 0; i < end; i++) - total += val[i]; - - res[idx] = total; - } else { - res[idx] = 0; - } - } - - aggregated_data[0].call = res[NETDATA_KEY_CALLS_DO_SYS_OPEN]; - aggregated_data[1].call = res[NETDATA_KEY_CALLS_CLOSE_FD]; - aggregated_data[2].call = res[NETDATA_KEY_CALLS_VFS_UNLINK]; - aggregated_data[3].call = res[NETDATA_KEY_CALLS_VFS_READ] + res[NETDATA_KEY_CALLS_VFS_READV]; - aggregated_data[4].call = res[NETDATA_KEY_CALLS_VFS_WRITE] + res[NETDATA_KEY_CALLS_VFS_WRITEV]; - aggregated_data[5].call = res[NETDATA_KEY_CALLS_DO_EXIT]; - aggregated_data[6].call = res[NETDATA_KEY_CALLS_RELEASE_TASK]; - aggregated_data[7].call = res[NETDATA_KEY_CALLS_DO_FORK]; - aggregated_data[8].call = res[NETDATA_KEY_CALLS_SYS_CLONE]; - - aggregated_data[0].ecall = res[NETDATA_KEY_ERROR_DO_SYS_OPEN]; - aggregated_data[1].ecall = res[NETDATA_KEY_ERROR_CLOSE_FD]; - aggregated_data[2].ecall = res[NETDATA_KEY_ERROR_VFS_UNLINK]; - aggregated_data[3].ecall = res[NETDATA_KEY_ERROR_VFS_READ] + res[NETDATA_KEY_ERROR_VFS_READV]; - aggregated_data[4].ecall = res[NETDATA_KEY_ERROR_VFS_WRITE] + res[NETDATA_KEY_ERROR_VFS_WRITEV]; - aggregated_data[7].ecall = res[NETDATA_KEY_ERROR_DO_FORK]; - aggregated_data[8].ecall = res[NETDATA_KEY_ERROR_SYS_CLONE]; - - aggregated_data[2].bytes = (uint64_t)res[NETDATA_KEY_BYTES_VFS_WRITE] + (uint64_t)res[NETDATA_KEY_BYTES_VFS_WRITEV]; - aggregated_data[3].bytes = (uint64_t)res[NETDATA_KEY_BYTES_VFS_READ] + (uint64_t)res[NETDATA_KEY_BYTES_VFS_READV]; -} - -static void move_from_kernel2user() + printf("CHART %s.%s '' '' '%s' '%s' '' line %d 1 ''\n" + , type + , id + , axis + , web + , order); +} + +/** + * Write the dimension command on standard output + * + * @param n the dimension name + * @param d the dimension information + */ +void ebpf_write_global_dimension(char *n, char *d) { - move_from_kernel2user_global(); + printf("DIMENSION %s %s absolute 1 1\n", n, d); } -void *process_collector(void *ptr) +/** + * Call ebpf_write_global_dimension to create the dimensions for a specific chart + * + * @param ptr a pointer to a structure of the type netdata_publish_syscall_t + * @param end the number of dimensions for the structure ptr + */ +void ebpf_create_global_dimension(void *ptr, int end) { - (void)ptr; - - usec_t step = 778879ULL; - heartbeat_t hb; - heartbeat_init(&hb); - while(!close_plugin) { - usec_t dt = heartbeat_next(&hb, step); - (void)dt; - - pthread_mutex_lock(&lock); - move_from_kernel2user(); - pthread_mutex_unlock(&lock); - } - - return NULL; -} - -static int netdata_store_bpf(void *data, int size) { - (void)size; - - if (close_plugin) - return 0; - - if(!debug_log) - return -2; //LIBBPF_PERF_EVENT_CONT; + netdata_publish_syscall_t *move = ptr; - netdata_error_report_t *e = data; - fprintf(developer_log - ,"%llu %s %u: %s, %d\n" - , now_realtime_usec() ,e->comm, e->pid, dimension_names[e->type], e->err); - fflush(developer_log); + int i = 0; + while (move && i < end) { + ebpf_write_global_dimension(move->name, move->dimension); - return -2; //LIBBPF_PERF_EVENT_CONT; + move = move->next; + i++; + } } -void *process_log(void *ptr) +/** + * Call write_chart_cmd to create the charts + * + * @param family the chart family + * @param name the chart name + * @param axis the axis label + * @param web the group name used to attach the chart on dashaboard + * @param order the order number of the specified chart + * @param ncd a pointer to a function called to create dimensions + * @param move a pointer for a structure that has the dimensions + * @param end number of dimensions for the chart created + */ +void ebpf_create_chart(char *family + , char *name + , char *axis + , char *web + , int order + , void (*ncd)(void *, int) + , void *move + , int end) { - (void) ptr; - - if (mode == MODE_DEVMODE && debug_log) { - netdata_perf_loop_multi(pmu_fd, headers, nprocs, &close_plugin, netdata_store_bpf, page_cnt); - } + ebpf_write_chart_cmd(family, name, axis, web, order); - return NULL; + ncd(move, end); } -void set_global_labels() { +/***************************************************************** + * + * FUNCTIONS TO DEFINE OPTIONS + * + *****************************************************************/ + +/** + * Define labels used to generate charts + * + * @param is structure with information about number of calls made for a function. + * @param pio structure used to generate charts. + * @param dim a pointer for the dimensions name + * @param name a pointer for the tensor with the name of the functions. + * @param end the number of elements in the previous 4 arguments. + */ +void ebpf_global_labels(netdata_syscall_stat_t *is, netdata_publish_syscall_t *pio, char **dim, char **name, int end) { int i; - netdata_syscall_stat_t *is = aggregated_data; netdata_syscall_stat_t *prev = NULL; - - netdata_publish_syscall_t *pio = publish_aggregated; netdata_publish_syscall_t *publish_prev = NULL; - for (i = 0; i < NETDATA_MAX_MONITOR_VECTOR; i++) { + for (i = 0; i < end; i++) { if(prev) { prev->next = &is[i]; } prev = &is[i]; - pio[i].dimension = dimension_names[i]; - pio[i].name = id_names[i]; + pio[i].dimension = dim[i]; + pio[i].name = name[i]; if(publish_prev) { publish_prev->next = &pio[i]; } @@ -642,294 +348,37 @@ void set_global_labels() { } } -int allocate_global_vectors() { - aggregated_data = callocz(NETDATA_MAX_MONITOR_VECTOR, sizeof(netdata_syscall_stat_t)); - if(!aggregated_data) { - return -1; - } - - publish_aggregated = callocz(NETDATA_MAX_MONITOR_VECTOR, sizeof(netdata_publish_syscall_t)); - if(!publish_aggregated) { - return -1; - } - - hash_values = callocz(nprocs, sizeof(netdata_idx_t)); - if(!hash_values) { - return -1; - } - - return 0; -} - -static void build_complete_path(char *out, size_t length,char *path, char *filename) { - if(path){ - snprintf(out, length, "%s/%s", path, filename); - } else { - snprintf(out, length, "%s", filename); - } -} - -static int map_memory() { - int i; - for (i = 0; i < nprocs; i++) { - pmu_fd[i] = set_bpf_perf_event(i, 2); - - if (perf_event_mmap_header(pmu_fd[i], &headers[i], page_cnt) < 0) { - return -1; - } - } - return 0; -} - -static int ebpf_load_libraries() -{ - char *err = NULL; - char lpath[4096]; - char netdatasl[128]; - char *libbase = { "libnetdata_ebpf.so" }; - - snprintf(netdatasl, 127, "%s.%s", libbase, kernel_string); - build_complete_path(lpath, 4096, plugin_dir, netdatasl); - libnetdata = dlopen(lpath, RTLD_LAZY); - if (!libnetdata) { - info("[EBPF_PROCESS] Cannot load library %s for the current kernel.", lpath); - - //Update kernel - char *library = ebpf_library_suffix(mykernel, (isrh < 0)?0:1); - size_t length = strlen(library); - strncpyz(kernel_string, library, length); - kernel_string[length] = '\0'; - - //Try to load the default version - snprintf(netdatasl, 127, "%s.%s", libbase, kernel_string); - build_complete_path(lpath, 4096, plugin_dir, netdatasl); - libnetdata = dlopen(lpath, RTLD_LAZY); - if (!libnetdata) { - error("[EBPF_PROCESS] Cannot load %s default library.", lpath); - return -1; - } else { - info("[EBPF_PROCESS] Default shared library %s loaded with success.", lpath); - } - } else { - info("[EBPF_PROCESS] Current shared library %s loaded with success.", lpath); - } - - load_bpf_file = dlsym(libnetdata, "load_bpf_file"); - if ((err = dlerror()) != NULL) { - error("[EBPF_PROCESS] Cannot find load_bpf_file: %s", err); - return -1; - } - - map_fd = dlsym(libnetdata, "map_fd"); - if ((err = dlerror()) != NULL) { - error("[EBPF_PROCESS] Cannot find map_fd: %s", err); - return -1; - } - - bpf_map_lookup_elem = dlsym(libnetdata, "bpf_map_lookup_elem"); - if ((err = dlerror()) != NULL) { - error("[EBPF_PROCESS] Cannot find bpf_map_lookup_elem: %s", err); - return -1; - } - - if(mode == 1) { - set_bpf_perf_event = dlsym(libnetdata, "set_bpf_perf_event"); - if ((err = dlerror()) != NULL) { - error("[EBPF_PROCESS] Cannot find set_bpf_perf_event: %s", err); - return -1; - } - - perf_event_unmap = dlsym(libnetdata, "perf_event_unmap"); - if ((err = dlerror()) != NULL) { - error("[EBPF_PROCESS] Cannot find perf_event_unmap: %s", err); - return -1; - } - - perf_event_mmap_header = dlsym(libnetdata, "perf_event_mmap_header"); - if ((err = dlerror()) != NULL) { - error("[EBPF_PROCESS] Cannot find perf_event_mmap_header: %s", err); - return -1; - } - - if(mode == MODE_DEVMODE) { - set_bpf_perf_event = dlsym(libnetdata, "set_bpf_perf_event"); - if ((err = dlerror()) != NULL) { - error("[EBPF_PROCESS] Cannot find set_bpf_perf_event: %s", err); - return -1; - } - - perf_event_unmap = dlsym(libnetdata, "perf_event_unmap"); - if ((err = dlerror()) != NULL) { - error("[EBPF_PROCESS] Cannot find perf_event_unmap: %s", err); - return -1; - } - - perf_event_mmap_header = dlsym(libnetdata, "perf_event_mmap_header"); - if ((err = dlerror()) != NULL) { - error("[EBPF_PROCESS] Cannot find perf_event_mmap_header: %s", err); - return -1; - } - - netdata_perf_loop_multi = dlsym(libnetdata, "netdata_perf_loop_multi"); - if ((err = dlerror()) != NULL) { - error("[EBPF_PROCESS] Cannot find netdata_perf_loop_multi: %s", err); - return -1; - } - } - } - - return 0; -} - -int select_file(char *name, int length) { - int ret = -1; - if (!mode) - ret = snprintf(name, (size_t)length, "rnetdata_ebpf_process.%s.o", kernel_string); - else if(mode == 1) - ret = snprintf(name, (size_t)length, "dnetdata_ebpf_process.%s.o", kernel_string); - else if(mode == 2) - ret = snprintf(name, (size_t)length, "pnetdata_ebpf_process.%s.o", kernel_string); - - return ret; -} - -int process_load_ebpf() -{ - char lpath[4096]; - char name[128]; - - int test = select_file(name, 127); - if (test < 0 || test > 127) - return -1; - - build_complete_path(lpath, 4096, plugin_dir, name); - event_pid = getpid(); - if (load_bpf_file(lpath, event_pid)) { - error("[EBPF_PROCESS] Cannot load program: %s", lpath); - return -1; - } else { - info("[EBPF PROCESS]: The eBPF program %s was loaded with success.", name); - } - - return 0; -} - -void set_global_variables() { - //Get environment variables - plugin_dir = getenv("NETDATA_PLUGINS_DIR"); - if(!plugin_dir) - plugin_dir = PLUGINS_DIR; - - user_config_dir = getenv("NETDATA_USER_CONFIG_DIR"); - if(!user_config_dir) - user_config_dir = CONFIG_DIR; - - stock_config_dir = getenv("NETDATA_STOCK_CONFIG_DIR"); - if(!stock_config_dir) - stock_config_dir = LIBCONFIG_DIR; - - netdata_configured_log_dir = getenv("NETDATA_LOG_DIR"); - if(!netdata_configured_log_dir) - netdata_configured_log_dir = LOG_DIR; - - page_cnt *= (int)sysconf(_SC_NPROCESSORS_ONLN); - - nprocs = (int)sysconf(_SC_NPROCESSORS_ONLN); - if (nprocs > NETDATA_MAX_PROCESSOR) { - nprocs = NETDATA_MAX_PROCESSOR; - } - - isrh = get_redhat_release(); -} - -sta |