summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt5
-rw-r--r--Makefile.am4
-rw-r--r--collectors/ebpf.plugin/README.md6
-rw-r--r--collectors/ebpf.plugin/ebpf.c1306
-rw-r--r--collectors/ebpf.plugin/ebpf.conf7
-rw-r--r--collectors/ebpf.plugin/ebpf.h118
-rw-r--r--collectors/ebpf.plugin/ebpf_process.c514
-rw-r--r--collectors/ebpf.plugin/ebpf_process.h71
-rw-r--r--collectors/ebpf.plugin/ebpf_socket.c387
-rw-r--r--collectors/ebpf.plugin/ebpf_socket.h40
-rw-r--r--libnetdata/ebpf/ebpf.c100
-rw-r--r--libnetdata/ebpf/ebpf.h22
12 files changed, 1659 insertions, 921 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8fc9190b0a..90581fefd5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -426,6 +426,11 @@ set(SLABINFO_PLUGIN_FILES
set(EBPF_PROCESS_PLUGIN_FILES
collectors/ebpf.plugin/ebpf.c
+ collectors/ebpf.plugin/ebpf.h
+ collectors/ebpf.plugin/ebpf_process.c
+ collectors/ebpf.plugin/ebpf_process.h
+ collectors/ebpf.plugin/ebpf_socket.c
+ collectors/ebpf.plugin/ebpf_socket.h
)
set(PROC_PLUGIN_FILES
diff --git a/Makefile.am b/Makefile.am
index 717c1758bf..30a8297b7e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -266,6 +266,10 @@ PERF_PLUGIN_FILES = \
EBPF_PLUGIN_FILES = \
collectors/ebpf.plugin/ebpf.c \
+ collectors/ebpf.plugin/ebpf_process.c \
+ collectors/ebpf.plugin/ebpf_process.h \
+ collectors/ebpf.plugin/ebpf_socket.c \
+ collectors/ebpf.plugin/ebpf_socket.h \
collectors/ebpf.plugin/ebpf.h \
$(LIBNETDATA_FILES) \
$(NULL)
diff --git a/collectors/ebpf.plugin/README.md b/collectors/ebpf.plugin/README.md
index 8b7a02984d..5f0649d268 100644
--- a/collectors/ebpf.plugin/README.md
+++ b/collectors/ebpf.plugin/README.md
@@ -130,14 +130,14 @@ cd /etc/netdata/ # Replace with your Netdata configuration directory, if not /
The `[global]` section defines settings for the whole eBPF collector.
-#### load
+#### ebpf load mode
The collector has two different eBPF programs. These programs monitor the same functions inside the kernel, but they
monitor, process, and display different kinds of information.
By default, this plugin uses the `entry` mode. Changing this mode can create significant overhead on your operating
-system, but also offer valuable information if you are developing or debugging software. The `load` option accepts the
-following values: ​
+system, but also offer valuable information if you are developing or debugging software. The `ebpf load mode` option
+accepts the following values: ​
- `entry`: This is the default mode. In this mode, the eBPF collector only monitors calls for the functions described
in the sections above, and does not show charts related to errors.
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);