|
@@ -28,11 +28,22 @@ int running_on_kernel = 0;
|
|
|
int ebpf_nprocs;
|
|
|
int isrh = 0;
|
|
|
int main_thread_id = 0;
|
|
|
+int process_pid_fd = -1;
|
|
|
|
|
|
pthread_mutex_t lock;
|
|
|
pthread_mutex_t ebpf_exit_cleanup;
|
|
|
pthread_mutex_t collect_data_mutex;
|
|
|
-pthread_cond_t collect_data_cond_var;
|
|
|
+
|
|
|
+struct netdata_static_thread cgroup_integration_thread = {
|
|
|
+ .name = "EBPF CGROUP INT",
|
|
|
+ .config_section = NULL,
|
|
|
+ .config_name = NULL,
|
|
|
+ .env_name = NULL,
|
|
|
+ .enabled = 1,
|
|
|
+ .thread = NULL,
|
|
|
+ .init_routine = NULL,
|
|
|
+ .start_routine = NULL
|
|
|
+};
|
|
|
|
|
|
ebpf_module_t ebpf_modules[] = {
|
|
|
{ .thread_name = "process", .config_name = "process", .enabled = 0, .start_routine = ebpf_process_thread,
|
|
@@ -451,6 +462,14 @@ ebpf_plugin_stats_t plugin_statistics = {.core = 0, .legacy = 0, .running = 0, .
|
|
|
|
|
|
#ifdef LIBBPF_MAJOR_VERSION
|
|
|
struct btf *default_btf = NULL;
|
|
|
+struct cachestat_bpf *cachestat_bpf_obj = NULL;
|
|
|
+struct dc_bpf *dc_bpf_obj = NULL;
|
|
|
+struct fd_bpf *fd_bpf_obj = NULL;
|
|
|
+struct mount_bpf *mount_bpf_obj = NULL;
|
|
|
+struct shm_bpf *shm_bpf_obj = NULL;
|
|
|
+struct socket_bpf *socket_bpf_obj = NULL;
|
|
|
+struct swap_bpf *bpf_obj = NULL;
|
|
|
+struct vfs_bpf *vfs_bpf_obj = NULL;
|
|
|
#else
|
|
|
void *default_btf = NULL;
|
|
|
#endif
|
|
@@ -515,10 +534,12 @@ static void ebpf_exit()
|
|
|
#endif
|
|
|
printf("DISABLE\n");
|
|
|
|
|
|
+ pthread_mutex_lock(&mutex_cgroup_shm);
|
|
|
if (shm_ebpf_cgroup.header) {
|
|
|
- munmap(shm_ebpf_cgroup.header, shm_ebpf_cgroup.header->body_length);
|
|
|
+ ebpf_unmap_cgroup_shared_memory();
|
|
|
shm_unlink(NETDATA_SHARED_MEMORY_EBPF_CGROUP_NAME);
|
|
|
}
|
|
|
+ pthread_mutex_unlock(&mutex_cgroup_shm);
|
|
|
|
|
|
exit(0);
|
|
|
}
|
|
@@ -545,6 +566,126 @@ static void ebpf_unload_legacy_code(struct bpf_object *objects, struct bpf_link
|
|
|
bpf_object__close(objects);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * Unload Unique maps
|
|
|
+ *
|
|
|
+ * This function unload all BPF maps from threads using one unique BPF object.
|
|
|
+ */
|
|
|
+static void ebpf_unload_unique_maps()
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ for (i = 0; ebpf_modules[i].thread_name; i++) {
|
|
|
+ if (ebpf_modules[i].enabled != NETDATA_THREAD_EBPF_STOPPED) {
|
|
|
+ if (ebpf_modules[i].enabled != NETDATA_THREAD_EBPF_NOT_RUNNING)
|
|
|
+ error("Cannot unload maps for thread %s, because it is not stopped.", ebpf_modules[i].thread_name);
|
|
|
+
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ ebpf_unload_legacy_code(ebpf_modules[i].objects, ebpf_modules[i].probe_links);
|
|
|
+ switch (i) {
|
|
|
+ case EBPF_MODULE_CACHESTAT_IDX: {
|
|
|
+#ifdef LIBBPF_MAJOR_VERSION
|
|
|
+ if (cachestat_bpf_obj)
|
|
|
+ cachestat_bpf__destroy(cachestat_bpf_obj);
|
|
|
+#endif
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case EBPF_MODULE_DCSTAT_IDX: {
|
|
|
+#ifdef LIBBPF_MAJOR_VERSION
|
|
|
+ if (dc_bpf_obj)
|
|
|
+ dc_bpf__destroy(dc_bpf_obj);
|
|
|
+#endif
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case EBPF_MODULE_FD_IDX: {
|
|
|
+#ifdef LIBBPF_MAJOR_VERSION
|
|
|
+ if (fd_bpf_obj)
|
|
|
+ fd_bpf__destroy(fd_bpf_obj);
|
|
|
+#endif
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case EBPF_MODULE_MOUNT_IDX: {
|
|
|
+#ifdef LIBBPF_MAJOR_VERSION
|
|
|
+ if (mount_bpf_obj)
|
|
|
+ mount_bpf__destroy(mount_bpf_obj);
|
|
|
+#endif
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case EBPF_MODULE_SHM_IDX: {
|
|
|
+#ifdef LIBBPF_MAJOR_VERSION
|
|
|
+ if (shm_bpf_obj)
|
|
|
+ shm_bpf__destroy(shm_bpf_obj);
|
|
|
+#endif
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case EBPF_MODULE_SOCKET_IDX: {
|
|
|
+#ifdef LIBBPF_MAJOR_VERSION
|
|
|
+ if (socket_bpf_obj)
|
|
|
+ socket_bpf__destroy(socket_bpf_obj);
|
|
|
+#endif
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case EBPF_MODULE_SWAP_IDX: {
|
|
|
+#ifdef LIBBPF_MAJOR_VERSION
|
|
|
+ if (bpf_obj)
|
|
|
+ swap_bpf__destroy(bpf_obj);
|
|
|
+#endif
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case EBPF_MODULE_VFS_IDX: {
|
|
|
+#ifdef LIBBPF_MAJOR_VERSION
|
|
|
+ if (vfs_bpf_obj)
|
|
|
+ vfs_bpf__destroy(vfs_bpf_obj);
|
|
|
+#endif
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case EBPF_MODULE_PROCESS_IDX:
|
|
|
+ case EBPF_MODULE_DISK_IDX:
|
|
|
+ case EBPF_MODULE_HARDIRQ_IDX:
|
|
|
+ case EBPF_MODULE_SOFTIRQ_IDX:
|
|
|
+ case EBPF_MODULE_OOMKILL_IDX:
|
|
|
+ case EBPF_MODULE_MDFLUSH_IDX:
|
|
|
+ default:
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Unload filesystem maps
|
|
|
+ *
|
|
|
+ * This function unload all BPF maps from filesystem thread.
|
|
|
+ */
|
|
|
+static void ebpf_unload_filesystems()
|
|
|
+{
|
|
|
+ if (ebpf_modules[EBPF_MODULE_FILESYSTEM_IDX].enabled == NETDATA_THREAD_EBPF_NOT_RUNNING ||
|
|
|
+ ebpf_modules[EBPF_MODULE_SYNC_IDX].enabled == NETDATA_THREAD_EBPF_RUNNING)
|
|
|
+ return;
|
|
|
+
|
|
|
+ int i;
|
|
|
+ for (i = 0; localfs[i].filesystem != NULL; i++) {
|
|
|
+ ebpf_unload_legacy_code(localfs[i].objects, localfs[i].probe_links);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Unload sync maps
|
|
|
+ *
|
|
|
+ * This function unload all BPF maps from sync thread.
|
|
|
+ */
|
|
|
+static void ebpf_unload_sync()
|
|
|
+{
|
|
|
+ if (ebpf_modules[EBPF_MODULE_SYNC_IDX].enabled == NETDATA_THREAD_EBPF_NOT_RUNNING ||
|
|
|
+ ebpf_modules[EBPF_MODULE_SYNC_IDX].enabled == NETDATA_THREAD_EBPF_RUNNING)
|
|
|
+ return;
|
|
|
+
|
|
|
+ int i;
|
|
|
+ for (i = 0; local_syscalls[i].syscall != NULL; i++) {
|
|
|
+ ebpf_unload_legacy_code(local_syscalls[i].objects, local_syscalls[i].probe_links);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
int ebpf_exit_plugin = 0;
|
|
|
/**
|
|
|
* Close the collector gracefully
|
|
@@ -556,7 +697,6 @@ static void ebpf_stop_threads(int sig)
|
|
|
UNUSED(sig);
|
|
|
static int only_one = 0;
|
|
|
|
|
|
- int i;
|
|
|
// Child thread should be closed by itself.
|
|
|
pthread_mutex_lock(&ebpf_exit_cleanup);
|
|
|
if (main_thread_id != gettid() || only_one) {
|
|
@@ -564,13 +704,26 @@ static void ebpf_stop_threads(int sig)
|
|
|
return;
|
|
|
}
|
|
|
only_one = 1;
|
|
|
- for (i = 0; ebpf_threads[i].name != NULL; i++) {
|
|
|
- if (ebpf_threads[i].enabled != NETDATA_THREAD_EBPF_STOPPED)
|
|
|
- netdata_thread_cancel(*ebpf_threads[i].thread);
|
|
|
+ int i;
|
|
|
+ for (i = 0; ebpf_modules[i].thread_name != NULL; i++) {
|
|
|
+ if (ebpf_modules[i].enabled == NETDATA_THREAD_EBPF_RUNNING) {
|
|
|
+ netdata_thread_cancel(*ebpf_modules[i].thread->thread);
|
|
|
+#ifdef NETDATA_DEV_MODE
|
|
|
+ info("Sending cancel for thread %s", ebpf_modules[i].thread_name);
|
|
|
+#endif
|
|
|
+ }
|
|
|
}
|
|
|
pthread_mutex_unlock(&ebpf_exit_cleanup);
|
|
|
|
|
|
+ pthread_mutex_lock(&mutex_cgroup_shm);
|
|
|
+ netdata_thread_cancel(*cgroup_integration_thread.thread);
|
|
|
+#ifdef NETDATA_DEV_MODE
|
|
|
+ info("Sending cancel for thread %s", cgroup_integration_thread.name);
|
|
|
+#endif
|
|
|
+ pthread_mutex_unlock(&mutex_cgroup_shm);
|
|
|
+
|
|
|
ebpf_exit_plugin = 1;
|
|
|
+
|
|
|
usec_t max = USEC_PER_SEC, step = 100000;
|
|
|
while (i && max) {
|
|
|
max -= step;
|
|
@@ -578,42 +731,18 @@ static void ebpf_stop_threads(int sig)
|
|
|
i = 0;
|
|
|
int j;
|
|
|
pthread_mutex_lock(&ebpf_exit_cleanup);
|
|
|
- for (j = 0; ebpf_threads[j].name != NULL; j++) {
|
|
|
- if (ebpf_threads[j].enabled != NETDATA_THREAD_EBPF_STOPPED)
|
|
|
+ for (j = 0; ebpf_modules[j].thread_name != NULL; j++) {
|
|
|
+ if (ebpf_modules[j].enabled == NETDATA_THREAD_EBPF_RUNNING)
|
|
|
i++;
|
|
|
}
|
|
|
pthread_mutex_unlock(&ebpf_exit_cleanup);
|
|
|
}
|
|
|
|
|
|
- if (!i) {
|
|
|
- //Unload threads(except sync and filesystem)
|
|
|
- pthread_mutex_lock(&ebpf_exit_cleanup);
|
|
|
- for (i = 0; ebpf_threads[i].name != NULL; i++) {
|
|
|
- if (ebpf_threads[i].enabled == NETDATA_THREAD_EBPF_STOPPED && i != EBPF_MODULE_FILESYSTEM_IDX &&
|
|
|
- i != EBPF_MODULE_SYNC_IDX)
|
|
|
- ebpf_unload_legacy_code(ebpf_modules[i].objects, ebpf_modules[i].probe_links);
|
|
|
- }
|
|
|
- pthread_mutex_unlock(&ebpf_exit_cleanup);
|
|
|
-
|
|
|
- //Unload filesystem
|
|
|
- pthread_mutex_lock(&ebpf_exit_cleanup);
|
|
|
- if (ebpf_threads[EBPF_MODULE_FILESYSTEM_IDX].enabled == NETDATA_THREAD_EBPF_STOPPED) {
|
|
|
- for (i = 0; localfs[i].filesystem != NULL; i++) {
|
|
|
- ebpf_unload_legacy_code(localfs[i].objects, localfs[i].probe_links);
|
|
|
- }
|
|
|
- }
|
|
|
- pthread_mutex_unlock(&ebpf_exit_cleanup);
|
|
|
-
|
|
|
- //Unload Sync
|
|
|
- pthread_mutex_lock(&ebpf_exit_cleanup);
|
|
|
- if (ebpf_threads[EBPF_MODULE_SYNC_IDX].enabled == NETDATA_THREAD_EBPF_STOPPED) {
|
|
|
- for (i = 0; local_syscalls[i].syscall != NULL; i++) {
|
|
|
- ebpf_unload_legacy_code(local_syscalls[i].objects, local_syscalls[i].probe_links);
|
|
|
- }
|
|
|
- }
|
|
|
- pthread_mutex_unlock(&ebpf_exit_cleanup);
|
|
|
-
|
|
|
- }
|
|
|
+ pthread_mutex_lock(&ebpf_exit_cleanup);
|
|
|
+ ebpf_unload_unique_maps();
|
|
|
+ ebpf_unload_filesystems();
|
|
|
+ ebpf_unload_sync();
|
|
|
+ pthread_mutex_unlock(&ebpf_exit_cleanup);
|
|
|
|
|
|
ebpf_exit();
|
|
|
}
|
|
@@ -624,6 +753,58 @@ static void ebpf_stop_threads(int sig)
|
|
|
*
|
|
|
*****************************************************************/
|
|
|
|
|
|
+/**
|
|
|
+ * Create apps charts
|
|
|
+ *
|
|
|
+ * Call ebpf_create_chart to create the charts on apps submenu.
|
|
|
+ *
|
|
|
+ * @param root a pointer for the targets.
|
|
|
+ */
|
|
|
+static void ebpf_create_apps_charts(struct ebpf_target *root)
|
|
|
+{
|
|
|
+ if (unlikely(!ebpf_all_pids))
|
|
|
+ return;
|
|
|
+
|
|
|
+ struct ebpf_target *w;
|
|
|
+ int newly_added = 0;
|
|
|
+
|
|
|
+ for (w = root; w; w = w->next) {
|
|
|
+ if (w->target)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (unlikely(w->processes && (debug_enabled || w->debug_enabled))) {
|
|
|
+ struct ebpf_pid_on_target *pid_on_target;
|
|
|
+
|
|
|
+ fprintf(
|
|
|
+ stderr, "ebpf.plugin: target '%s' has aggregated %u process%s:", w->name, w->processes,
|
|
|
+ (w->processes == 1) ? "" : "es");
|
|
|
+
|
|
|
+ for (pid_on_target = w->root_pid; pid_on_target; pid_on_target = pid_on_target->next) {
|
|
|
+ fprintf(stderr, " %d", pid_on_target->pid);
|
|
|
+ }
|
|
|
+
|
|
|
+ fputc('\n', stderr);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!w->exposed && w->processes) {
|
|
|
+ newly_added++;
|
|
|
+ w->exposed = 1;
|
|
|
+ if (debug_enabled || w->debug_enabled)
|
|
|
+ debug_log_int("%s just added - regenerating charts.", w->name);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!newly_added)
|
|
|
+ return;
|
|
|
+
|
|
|
+ int counter;
|
|
|
+ for (counter = 0; ebpf_modules[counter].thread_name; counter++) {
|
|
|
+ ebpf_module_t *current = &ebpf_modules[counter];
|
|
|
+ if (current->enabled == NETDATA_THREAD_EBPF_RUNNING && current->apps_charts && current->apps_routine)
|
|
|
+ current->apps_routine(current, root);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* Get a value from a structure.
|
|
|
*
|
|
@@ -1044,7 +1225,7 @@ void ebpf_global_labels(netdata_syscall_stat_t *is, netdata_publish_syscall_t *p
|
|
|
|
|
|
pio[i].dimension = dim[i];
|
|
|
pio[i].name = name[i];
|
|
|
- pio[i].algorithm = strdupz(ebpf_algorithms[algorithm[i]]);
|
|
|
+ pio[i].algorithm = ebpf_algorithms[algorithm[i]];
|
|
|
if (publish_prev) {
|
|
|
publish_prev->next = &pio[i];
|
|
|
}
|
|
@@ -1442,21 +1623,13 @@ static void read_local_addresses()
|
|
|
* Start Pthread Variable
|
|
|
*
|
|
|
* This function starts all pthread variables.
|
|
|
- *
|
|
|
- * @return It returns 0 on success and -1.
|
|
|
*/
|
|
|
-int ebpf_start_pthread_variables()
|
|
|
+void ebpf_start_pthread_variables()
|
|
|
{
|
|
|
pthread_mutex_init(&lock, NULL);
|
|
|
pthread_mutex_init(&ebpf_exit_cleanup, NULL);
|
|
|
pthread_mutex_init(&collect_data_mutex, NULL);
|
|
|
-
|
|
|
- if (pthread_cond_init(&collect_data_cond_var, NULL)) {
|
|
|
- error("Cannot start conditional variable to control Apps charts.");
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
+ pthread_mutex_init(&mutex_cgroup_shm, NULL);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -2320,10 +2493,7 @@ int main(int argc, char **argv)
|
|
|
signal(SIGTERM, ebpf_stop_threads);
|
|
|
signal(SIGPIPE, ebpf_stop_threads);
|
|
|
|
|
|
- if (ebpf_start_pthread_variables()) {
|
|
|
- error("Cannot start mutex to control overall charts.");
|
|
|
- ebpf_exit();
|
|
|
- }
|
|
|
+ ebpf_start_pthread_variables();
|
|
|
|
|
|
netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX");
|
|
|
if(verify_netdata_host_prefix() == -1) ebpf_exit(6);
|
|
@@ -2342,6 +2512,12 @@ int main(int argc, char **argv)
|
|
|
|
|
|
ebpf_set_static_routine();
|
|
|
|
|
|
+ cgroup_integration_thread.thread = mallocz(sizeof(netdata_thread_t));
|
|
|
+ cgroup_integration_thread.start_routine = ebpf_cgroup_integration;
|
|
|
+
|
|
|
+ netdata_thread_create(cgroup_integration_thread.thread, cgroup_integration_thread.name,
|
|
|
+ NETDATA_THREAD_OPTION_DEFAULT, ebpf_cgroup_integration, NULL);
|
|
|
+
|
|
|
int i;
|
|
|
for (i = 0; ebpf_threads[i].name != NULL; i++) {
|
|
|
struct netdata_static_thread *st = &ebpf_threads[i];
|
|
@@ -2352,30 +2528,37 @@ int main(int argc, char **argv)
|
|
|
if (em->enabled || !i) {
|
|
|
st->thread = mallocz(sizeof(netdata_thread_t));
|
|
|
em->thread_id = i;
|
|
|
- st->enabled = NETDATA_THREAD_EBPF_RUNNING;
|
|
|
+ em->enabled = NETDATA_THREAD_EBPF_RUNNING;
|
|
|
netdata_thread_create(st->thread, st->name, NETDATA_THREAD_OPTION_DEFAULT, st->start_routine, em);
|
|
|
} else {
|
|
|
- st->enabled = NETDATA_THREAD_EBPF_STOPPED;
|
|
|
+ em->enabled = NETDATA_THREAD_EBPF_NOT_RUNNING;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
usec_t step = USEC_PER_SEC;
|
|
|
- int counter = NETDATA_EBPF_CGROUP_UPDATE - 1;
|
|
|
heartbeat_t hb;
|
|
|
heartbeat_init(&hb);
|
|
|
+ int update_apps_every = (int) EBPF_CFG_UPDATE_APPS_EVERY_DEFAULT;
|
|
|
+ int update_apps_list = update_apps_every - 1;
|
|
|
//Plugin will be killed when it receives a signal
|
|
|
while (!ebpf_exit_plugin) {
|
|
|
(void)heartbeat_next(&hb, step);
|
|
|
|
|
|
- // We are using a small heartbeat time to wake up thread,
|
|
|
- // but we should not update so frequently the shared memory data
|
|
|
- if (++counter >= NETDATA_EBPF_CGROUP_UPDATE) {
|
|
|
- counter = 0;
|
|
|
- if (!shm_ebpf_cgroup.header)
|
|
|
- ebpf_map_cgroup_shared_memory();
|
|
|
-
|
|
|
- ebpf_parse_cgroup_shm_data();
|
|
|
+ pthread_mutex_lock(&ebpf_exit_cleanup);
|
|
|
+ if (ebpf_modules[i].enabled == NETDATA_THREAD_EBPF_RUNNING && process_pid_fd != -1) {
|
|
|
+ pthread_mutex_lock(&collect_data_mutex);
|
|
|
+ if (++update_apps_list == update_apps_every) {
|
|
|
+ update_apps_list = 0;
|
|
|
+ cleanup_exited_pids();
|
|
|
+ collect_data_for_all_processes(process_pid_fd);
|
|
|
+
|
|
|
+ pthread_mutex_lock(&lock);
|
|
|
+ ebpf_create_apps_charts(apps_groups_root_target);
|
|
|
+ pthread_mutex_unlock(&lock);
|
|
|
+ }
|
|
|
+ pthread_mutex_unlock(&collect_data_mutex);
|
|
|
}
|
|
|
+ pthread_mutex_unlock(&ebpf_exit_cleanup);
|
|
|
}
|
|
|
|
|
|
ebpf_stop_threads(0);
|