From 9fe00b7058942621bbdaa3724b57f7cf375590d4 Mon Sep 17 00:00:00 2001 From: Jiping Yin Date: Tue, 23 Apr 2024 10:22:20 +0800 Subject: [PATCH] [eBPF] Reducing CPU consumption for process events exec/exit Replace `sched_process_fork` with `sys_exit_fork` and `sys_exit_clone` tracepoints because sched_process_fork cannot distinguish between processes and threads, leading to excessive threads being pushed to the upper layer unnecessarily. `sys_exit_fork` and `sys_exit_clone` only push process information. Use spin locks to protect the process event list instead of thread mutex locks to avoid frequent context switches. --- agent/src/ebpf/README.md | 2 +- agent/src/ebpf/kernel/uprobe_base.bpf.c | 47 ++++----- agent/src/ebpf/user/config.h | 4 + agent/src/ebpf/user/go_tracer.c | 89 +++++++---------- agent/src/ebpf/user/socket.c | 6 +- agent/src/ebpf/user/ssl_tracer.c | 127 +++++++++++++----------- agent/src/ebpf/user/tracer.c | 79 +++++++++++---- agent/src/ebpf/user/tracer.h | 31 ++++++ 8 files changed, 228 insertions(+), 157 deletions(-) diff --git a/agent/src/ebpf/README.md b/agent/src/ebpf/README.md index 1c229d5c120..88db76f7f3f 100644 --- a/agent/src/ebpf/README.md +++ b/agent/src/ebpf/README.md @@ -456,7 +456,7 @@ graph LR - 8 rust extra events callback - We provide a function that the user can register a callback interface for a specific event. e.g. Use rust function process these events. - 9.1 add_event_to_proc_header - - Add `struct process_event` to list-head(proc_events_head), need to set a expire time in `struct process_event`, see the description of [TLS/SSL Tracing](https://github.com/deepflowio/deepflow/tree/main/agent/src/ebpf#tlsssl-tracing) for the reason. + - Add `struct probe_process_event` to list-head(proc_events_head), need to set a expire time in `struct probe_process_event`, see the description of [TLS/SSL Tracing](https://github.com/deepflowio/deepflow/tree/main/agent/src/ebpf#tlsssl-tracing) for the reason. - 14.2.1 clear_probes_by_pid - Clear all probe, when process id == pid (event fetched). - 14.2.2 proc_parse_and_register diff --git a/agent/src/ebpf/kernel/uprobe_base.bpf.c b/agent/src/ebpf/kernel/uprobe_base.bpf.c index 74398962801..c3ab70c8825 100644 --- a/agent/src/ebpf/kernel/uprobe_base.bpf.c +++ b/agent/src/ebpf/kernel/uprobe_base.bpf.c @@ -641,29 +641,20 @@ int bpf_func_sched_process_exit(struct sched_comm_exit_ctx *ctx) return 0; } -// /sys/kernel/debug/tracing/events/sched/sched_process_fork/format -SEC("tracepoint/sched/sched_process_fork") -int bpf_func_sched_process_fork(struct sched_comm_fork_ctx *ctx) +static inline int kernel_clone_exit(struct syscall_comm_exit_ctx *ctx) { - /* - * When you find that the golang process starts, sometimes you - * don't get the process start information, all you get is - * threads. Take the following example: - * - * # pstree -p 4157 - * deepflow-server(4157)─┬─{deepflow-server}(4214) - * ├─{deepflow-server}(4216) - * ├─{deepflow-server}(4217) - * ├─{deepflow-server}(4218) - * ├─{deepflow-server}(4219) - * ├─{deepflow-server}(4229) - * - * fetch data: - * .... 296916.616252: 0: parent_pid 4216 child_pid 4218 - * .... 296916.616366: 0: parent_pid 4218 child_pid 4219 - * - * To get process startup information we add probe 'sched_process_exec'. - */ + __u64 id = bpf_get_current_pid_tgid(); + long ret = ctx->ret; + + // error or parent process + if (ret != 0) + return 0; + + int pid = (int)id; + int tgid = (int)(id >> 32); + // filter threads + if (pid != tgid) + return 0; struct member_fields_offset *offset = retrieve_ready_kern_offset(); if (offset == NULL) @@ -671,7 +662,7 @@ int bpf_func_sched_process_fork(struct sched_comm_fork_ctx *ctx) struct process_event_t data; data.meta.event_type = EVENT_TYPE_PROC_EXEC; - data.pid = ctx->child_pid; + data.pid = pid; bpf_get_current_comm(data.name, sizeof(data.name)); bpf_perf_event_output(ctx, &NAME(socket_data), BPF_F_CURRENT_CPU, &data, sizeof(data)); @@ -679,6 +670,16 @@ int bpf_func_sched_process_fork(struct sched_comm_fork_ctx *ctx) return 0; } +// /sys/kernel/debug/tracing/events/syscalls/sys_exit_fork/format +TPPROG(sys_exit_fork) (struct syscall_comm_exit_ctx * ctx) { + return kernel_clone_exit(ctx); +} + +// /sys/kernel/debug/tracing/events/syscalls/sys_exit_clone/format +TPPROG(sys_exit_clone) (struct syscall_comm_exit_ctx * ctx) { + return kernel_clone_exit(ctx); +} + // /sys/kernel/debug/tracing/events/sched/sched_process_exec/format SEC("tracepoint/sched/sched_process_exec") int bpf_func_sched_process_exec(struct sched_comm_exec_ctx *ctx) diff --git a/agent/src/ebpf/user/config.h b/agent/src/ebpf/user/config.h index aa675a33c4d..afe066ed222 100644 --- a/agent/src/ebpf/user/config.h +++ b/agent/src/ebpf/user/config.h @@ -67,7 +67,11 @@ enum { //thread index for bihash enum { + // cp-reader-0 THREAD_PROFILER_READER_IDX = 0, + // proc-events + THREAD_PROC_EVENTS_IDX, + // sk-reader-0 ... THREAD_PROC_ACT_IDX_BASE }; diff --git a/agent/src/ebpf/user/go_tracer.c b/agent/src/ebpf/user/go_tracer.c index d4123e66bee..ffec6f614b4 100644 --- a/agent/src/ebpf/user/go_tracer.c +++ b/agent/src/ebpf/user/go_tracer.c @@ -50,23 +50,11 @@ #include "socket.h" #include "elf.h" -/* *INDENT-OFF* */ -// For process execute/exit events. -struct process_event { - struct list_head list; // list add to proc_events_head - struct bpf_tracer *tracer; // link to struct bpf_tracer - uint8_t type; // EVENT_TYPE_PROC_EXEC or EVENT_TYPE_PROC_EXIT - char *path; // Full path "/proc//root/..." - int pid; // Process ID - uint32_t expire_time; // Expiration Date, the number of seconds since the system started. -}; -/* *INDENT-ON* */ - extern uint32_t k_version; +extern struct proc_events_record proc_ev_record; + static char build_info_magic[] = "\xff Go buildinf:"; static struct list_head proc_info_head; // For pid-offsets correspondence lists. -static struct list_head proc_events_head; // For process execute/exit events list. -static pthread_mutex_t mutex_proc_events_lock; /* *INDENT-OFF* */ /* ------------- offsets info -------------- */ @@ -595,10 +583,8 @@ static int resolve_bin_file(const char *path, int pid, for (int k = 0; k < NELEMS(offsets); k++) { off = &offsets[k]; int offset = struct_member_offset_analyze(binary_path, - off-> - structure, - off-> - field_name); + off->structure, + off->field_name); if (offset == ETR_INVAL) offset = off->default_offset; @@ -744,9 +730,7 @@ int collect_go_uprobe_syms_from_procfs(struct tracer_probes_conf *conf) struct dirent *entry = NULL; DIR *fddir = NULL; - init_list_head(&proc_events_head); init_list_head(&proc_info_head); - pthread_mutex_init(&mutex_proc_events_lock, NULL); if (!is_feature_enabled(FEATURE_UPROBE_GOLANG)) return ETR_OK; @@ -966,26 +950,12 @@ static void process_execute_handle(int pid, struct bpf_tracer *tracer) pthread_mutex_unlock(&tracer->mutex_probes_lock); } -// The caller needs 'mutex_proc_events_lock' for protection -static inline void find_and_clear_event_from_list(int pid) -{ - struct process_event *pe; - struct list_head *p, *n; - list_for_each_safe(p, n, &proc_events_head) { - pe = container_of(p, struct process_event, list); - if (pe->pid == pid) { - list_head_del(&pe->list); - free(pe->path); - free(pe); - } - } -} - static void process_exit_handle(int pid, struct bpf_tracer *tracer) { - pthread_mutex_lock(&mutex_proc_events_lock); - find_and_clear_event_from_list(pid); - pthread_mutex_unlock(&mutex_proc_events_lock); + struct proc_events_record *r = &proc_ev_record; + proc_events_lock(r->golang_list_lock); + find_and_clear_event_from_list(pid, &r->golang_events_head); + proc_events_unlock(r->golang_list_lock); // Protect the probes operation in multiple threads, similar to process_execute_handle() pthread_mutex_lock(&tracer->mutex_probes_lock); @@ -1011,7 +981,7 @@ static void add_event_to_proc_header(struct bpf_tracer *tracer, int pid, return; } - struct process_event *pe = calloc(1, sizeof(struct process_event)); + struct probe_process_event *pe = calloc(1, sizeof(struct probe_process_event)); if (pe == NULL) { free(path); ebpf_warning("Without memory.\n"); @@ -1024,10 +994,10 @@ static void add_event_to_proc_header(struct bpf_tracer *tracer, int pid, pe->type = type; pe->expire_time = get_sys_uptime() + PROC_EVENT_DELAY_HANDLE_DEF; - pthread_mutex_lock(&mutex_proc_events_lock); - find_and_clear_event_from_list(pid); - list_add_tail(&pe->list, &proc_events_head); - pthread_mutex_unlock(&mutex_proc_events_lock); + struct proc_events_record *r = &proc_ev_record; + proc_events_lock(r->golang_list_lock); + list_add_tail(&pe->list, &r->golang_events_head); + proc_events_unlock(r->golang_list_lock); } /** @@ -1077,19 +1047,20 @@ void go_process_exit(int pid) */ void go_process_events_handle(void) { - struct process_event *pe; + struct proc_events_record *r = &proc_ev_record; + struct probe_process_event *pe; do { - // Multithreaded safe fetch 'struct process_event' - pthread_mutex_lock(&mutex_proc_events_lock); - if (!list_empty(&proc_events_head)) { - pe = list_first_entry(&proc_events_head, - struct process_event, list); + // Multithreaded safe fetch 'struct probe_process_event' + proc_events_lock(r->golang_list_lock); + if (!list_empty(&r->golang_events_head)) { + pe = list_first_entry(&r->golang_events_head, + struct probe_process_event, list); } else { pe = NULL; } if (pe == NULL) { - pthread_mutex_unlock(&mutex_proc_events_lock); + proc_events_unlock(r->golang_list_lock); break; } @@ -1101,16 +1072,26 @@ void go_process_events_handle(void) list_head_del(&pe->list); free(pe->path); free(pe); - pthread_mutex_unlock(&mutex_proc_events_lock); + proc_events_unlock(r->golang_list_lock); + if (path == NULL) + break; + if (type == EVENT_TYPE_PROC_EXEC) { if (access(path, F_OK) == 0) { - process_execute_handle(pid, tracer); + struct version_info go_version; + memset(&go_version, 0, + sizeof(go_version)); + if (fetch_go_elf_version + (path, &go_version)) { + process_execute_handle(pid, + tracer); + } } } - free(path); + free(path); } else { - pthread_mutex_unlock(&mutex_proc_events_lock); + proc_events_unlock(r->golang_list_lock); break; } } while (true); diff --git a/agent/src/ebpf/user/socket.c b/agent/src/ebpf/user/socket.c index af333513d0e..8275e47ddb0 100644 --- a/agent/src/ebpf/user/socket.c +++ b/agent/src/ebpf/user/socket.c @@ -44,7 +44,7 @@ static struct list_head events_list; // Use for extra register events static pthread_t proc_events_pthread; // Process exec/exit thread - +extern __thread uword thread_index; // for bihash /* * tracer_hooks_detach() and tracer_hooks_attach() will become terrible * when the number of probes is very large. Because we have to spend a @@ -174,7 +174,8 @@ static void socket_tracer_set_probes(struct tracer_probes_conf *tps) tps_set_symbol(tps, "tracepoint/syscalls/sys_exit_accept"); tps_set_symbol(tps, "tracepoint/syscalls/sys_exit_accept4"); // process execute - tps_set_symbol(tps, "tracepoint/sched/sched_process_fork"); + tps_set_symbol(tps, "tracepoint/syscalls/sys_exit_fork"); + tps_set_symbol(tps, "tracepoint/syscalls/sys_exit_clone"); tps_set_symbol(tps, "tracepoint/sched/sched_process_exec"); // 周期性触发用于缓存的数据的超时检查 @@ -1183,6 +1184,7 @@ static void check_datadump_timeout(void) static void process_events_handle_main(__unused void *arg) { prctl(PR_SET_NAME, "proc-events"); + thread_index = THREAD_PROC_EVENTS_IDX; struct bpf_tracer *t = arg; for (;;) { /* diff --git a/agent/src/ebpf/user/ssl_tracer.c b/agent/src/ebpf/user/ssl_tracer.c index 1cc2e09f1ca..8548e000e09 100644 --- a/agent/src/ebpf/user/ssl_tracer.c +++ b/agent/src/ebpf/user/ssl_tracer.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Yunshan Networks +* Copyright (c) 2022 Yunshan Networks * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,17 +31,8 @@ #include extern uint32_t k_version; - -struct ssl_process_create_event { - struct list_head list; - int pid; - uint32_t expire_time; - struct bpf_tracer *tracer; -}; - -static struct list_head proc_events_list; -static pthread_mutex_t proc_events_list_mutex; - +extern struct proc_events_record proc_ev_record; +/* *INDENT-OFF* */ static struct symbol openssl_syms[] = { { .type = OPENSSL_UPROBE, @@ -81,6 +72,7 @@ static struct bcc_symbol_option bcc_elf_foreach_sym_option = { .lazy_symbolize = 1, .use_symbol_type = bcc_use_symbol_type, }; +/* *INDENT-ON* */ struct bcc_elf_foreach_sym_payload { uint64_t addr; @@ -92,7 +84,7 @@ struct bcc_elf_foreach_sym_payload { static inline bool openssl_kern_check(void) { return ((k_version == KERNEL_VERSION(3, 10, 0)) - || (k_version >= KERNEL_VERSION(4, 17, 0))); + || (k_version >= KERNEL_VERSION(4, 17, 0))); } static inline bool openssl_process_check(int pid) @@ -266,7 +258,7 @@ static void clear_ssl_probes_by_pid(struct bpf_tracer *tracer, int pid) struct list_head *p, *n; struct symbol_uprobe *sym_uprobe; - list_for_each_safe (p, n, &tracer->probes_head) { + list_for_each_safe(p, n, &tracer->probes_head) { probe = container_of(p, struct probe, list); if (!(probe->type == UPROBE && probe->private_data != NULL)) continue; @@ -286,44 +278,27 @@ static void clear_ssl_probes_by_pid(struct bpf_tracer *tracer, int pid) } } -static void add_event_to_proc_list(struct bpf_tracer *tracer, int pid) +static void add_event_to_proc_list(struct bpf_tracer *tracer, int pid, + char *path) { static const uint32_t PROC_EVENT_HANDLE_DELAY = 120; - struct ssl_process_create_event *event = NULL; + struct probe_process_event *event = NULL; - event = calloc(1, sizeof(struct ssl_process_create_event)); + event = calloc(1, sizeof(struct probe_process_event)); if (!event) { ebpf_warning("no memory.\n"); return; } + event->path = path; event->tracer = tracer; event->pid = pid; event->expire_time = get_sys_uptime() + PROC_EVENT_HANDLE_DELAY; - pthread_mutex_lock(&proc_events_list_mutex); - list_add_tail(&event->list, &proc_events_list); - pthread_mutex_unlock(&proc_events_list_mutex); - return; -} - -static struct ssl_process_create_event *get_first_event(void) -{ - struct ssl_process_create_event *event = NULL; - pthread_mutex_lock(&proc_events_list_mutex); - if (!list_empty(&proc_events_list)) { - event = list_first_entry(&proc_events_list, - struct ssl_process_create_event, list); - } - pthread_mutex_unlock(&proc_events_list_mutex); - return event; -} - -static void remove_event(struct ssl_process_create_event *event) -{ - pthread_mutex_lock(&proc_events_list_mutex); - list_head_del(&event->list); - pthread_mutex_unlock(&proc_events_list_mutex); + struct proc_events_record *r = &proc_ev_record; + proc_events_lock(r->ssl_list_lock); + list_add_tail(&event->list, &r->ssl_events_head); + proc_events_unlock(r->ssl_list_lock); } int collect_ssl_uprobe_syms_from_procfs(struct tracer_probes_conf *conf) @@ -337,13 +312,11 @@ int collect_ssl_uprobe_syms_from_procfs(struct tracer_probes_conf *conf) return ETR_OK; if (!openssl_kern_check()) { - ebpf_warning("Uprobe openssl requires Linux version 4.17+ or Linux 3.10.0\n"); + ebpf_warning + ("Uprobe openssl requires Linux version 4.17+ or Linux 3.10.0\n"); return ETR_OK; } - init_list_head(&proc_events_list); - pthread_mutex_init(&proc_events_list_mutex, NULL); - fddir = opendir("/proc/"); if (!fddir) { ebpf_warning("Failed to open %s.\n"); @@ -375,25 +348,31 @@ void ssl_process_exec(int pid) if (!openssl_kern_check()) return; path = get_elf_path_by_pid(pid); + if (path == NULL) + return; + matched = is_feature_matched(FEATURE_UPROBE_OPENSSL, path); - free(path); if (!matched) - return; + goto exit; tracer = find_bpf_tracer(SK_TRACER_NAME); if (tracer == NULL) - return; + goto exit; if (tracer->state != TRACER_RUNNING) - return; + goto exit; if (tracer->probes_count > OPEN_FILES_MAX) { ebpf_warning("Probes count too many. The maximum is %d\n", OPEN_FILES_MAX); - return; + goto exit; } - add_event_to_proc_list(tracer, pid); + add_event_to_proc_list(tracer, pid, path); + return; + +exit: + free(path); } void ssl_process_exit(int pid) @@ -413,6 +392,11 @@ void ssl_process_exit(int pid) if (tracer->state != TRACER_RUNNING) return; + struct proc_events_record *r = &proc_ev_record; + proc_events_lock(r->ssl_list_lock); + find_and_clear_event_from_list(pid, &r->ssl_events_head); + proc_events_unlock(r->ssl_list_lock); + pthread_mutex_lock(&tracer->mutex_probes_lock); clear_ssl_probes_by_pid(tracer, pid); pthread_mutex_unlock(&tracer->mutex_probes_lock); @@ -420,28 +404,53 @@ void ssl_process_exit(int pid) void ssl_events_handle(void) { - struct ssl_process_create_event *event = NULL; + struct probe_process_event *event = NULL; struct bpf_tracer *tracer = NULL; int count = 0; + struct proc_events_record *r = &proc_ev_record; do { - event = get_first_event(); - if (!event) + proc_events_lock(r->ssl_list_lock); + if (!list_empty(&r->ssl_events_head)) { + event = list_first_entry(&r->ssl_events_head, + struct probe_process_event, + list); + } else { + event = NULL; + } + + if (event == NULL) { + proc_events_unlock(r->ssl_list_lock); break; + } - if (get_sys_uptime() < event->expire_time) + if (get_sys_uptime() < event->expire_time) { + proc_events_unlock(r->ssl_list_lock); break; + } tracer = event->tracer; + char *path = strdup(event->path); + int pid = event->pid; + list_head_del(&event->list); + free(event->path); + free(event); + proc_events_unlock(r->ssl_list_lock); + if (path == NULL) + break; + + if (access(path, F_OK) != 0) { + free(path); + break; + } + + free(path); + if (tracer) { pthread_mutex_lock(&tracer->mutex_probes_lock); - openssl_parse_and_register(event->pid, tracer->tps); + openssl_parse_and_register(pid, tracer->tps); tracer_uprobes_update(tracer); tracer_hooks_process(tracer, HOOK_ATTACH, &count); pthread_mutex_unlock(&tracer->mutex_probes_lock); } - - remove_event(event); - free(event); - } while (true); } diff --git a/agent/src/ebpf/user/tracer.c b/agent/src/ebpf/user/tracer.c index a3fbbad059f..9785df57c80 100644 --- a/agent/src/ebpf/user/tracer.c +++ b/agent/src/ebpf/user/tracer.c @@ -76,8 +76,6 @@ static volatile int ready_flag_cpus[MAX_CPU_NR]; /* Registration of additional transactions 额外事务处理的注册 */ static struct list_head extra_waiting_head; -/* Registration for periodic event handling 周期性事件处理的注册 */ -static struct list_head period_events_head; int sys_cpus_count; bool *cpu_online; // 用于判断CPU是否是online @@ -93,6 +91,28 @@ static int perf_reader_setup(struct bpf_perf_reader *perf_readerm, int thread_nr); static void perf_reader_release(struct bpf_perf_reader *perf_reader); +/* Registration for periodic event handling 周期性事件处理的注册 */ +static struct list_head period_events_head; + +// Detecting process start and exit events. +struct proc_events_record proc_ev_record; + +// The caller needs 'mutex_proc_events_lock' for protection +void find_and_clear_event_from_list(int pid, struct list_head *head) +{ + struct probe_process_event *pe; + struct list_head *p, *n; + list_for_each_safe(p, n, head) { + pe = container_of(p, struct probe_process_event, list); + if (pe->pid == pid) { + list_head_del(&pe->list); + if (pe->path) + free(pe->path); + free(pe); + } + } +} + /* * 内核版本依赖检查 */ @@ -254,7 +274,7 @@ int enable_tracer_reader_work(const char *prefix_name, int idx, char name[TASK_COMM_LEN]; snprintf(name, sizeof(name), "%s-%d", prefix_name, idx); ret = pthread_create(&tracer->perf_worker[idx], NULL, fn, - (void *)(uint64_t)idx); + (void *)(uint64_t) idx); if (ret) { ebpf_warning("tracer reader(%s), pthread_create " "is error:%s\n", name, strerror(errno)); @@ -968,21 +988,18 @@ int tracer_hooks_process(struct bpf_tracer *tracer, enum tracer_hook_type type, if (obj->progs[i].type == BPF_PROG_TYPE_PERF_EVENT) { errno = 0; int ret = - program__attach_perf_event(obj->progs[i]. - prog_fd, + program__attach_perf_event(obj-> + progs[i].prog_fd, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, 0, /* sample_period */ - tracer-> - sample_freq, + tracer->sample_freq, -1, /* pid, current process */ -1, /* cpu, no binding */ -1, /* new event group is created */ - tracer-> - per_cpu_fds, + tracer->per_cpu_fds, ARRAY_SIZE - (tracer-> - per_cpu_fds)); + (tracer->per_cpu_fds)); if (!ret) { ebpf_info ("tracer \"%s\" attach perf event prog successful.\n", @@ -1010,8 +1027,8 @@ int tracer_hooks_process(struct bpf_tracer *tracer, enum tracer_hook_type type, errno = 0; int ret = program__detach_perf_event(tracer->per_cpu_fds, - ARRAY_SIZE(tracer-> - per_cpu_fds)); + ARRAY_SIZE + (tracer->per_cpu_fds)); if (!ret) { ebpf_info ("tracer \"%s\" detach perf event prog successful.\n", @@ -1169,7 +1186,7 @@ static int perf_reader_setup(struct bpf_perf_reader *perf_reader, int thread_nr) spread_id = 0; struct reader_forward_info *fwd_info = - malloc(sizeof(struct reader_forward_info)); + malloc(sizeof(struct reader_forward_info)); if (fwd_info == NULL) { ebpf_error("reader_forward_info malloc() failed.\n"); return ETR_NOMEM; @@ -1180,12 +1197,10 @@ static int perf_reader_setup(struct bpf_perf_reader *perf_reader, int thread_nr) ebpf_info("Perf buffer reader cpu(%d) -> queue(%d)\n", fwd_info->cpu_id, fwd_info->queue_id); - reader = - (struct perf_reader *) + reader = (struct perf_reader *) bpf_open_perf_buffer(perf_reader->raw_cb, perf_reader->lost_cb, - (void *)fwd_info, -1, i, - pages_cnt); + (void *)fwd_info, -1, i, pages_cnt); if (reader == NULL) { ebpf_error("bpf_open_perf_buffer() failed.\n"); return ETR_NORESOURCE; @@ -1581,6 +1596,31 @@ bool is_feature_matched(int feature, const char *path) return !error; } +static int init_proc_events_record(const char *name) +{ + init_list_head(&proc_ev_record.golang_events_head); + init_list_head(&proc_ev_record.ssl_events_head); + + proc_ev_record.golang_list_lock = + clib_mem_alloc_aligned("go_proc_ev_lock", + CLIB_CACHE_LINE_BYTES, + CLIB_CACHE_LINE_BYTES, NULL); + proc_ev_record.ssl_list_lock = + clib_mem_alloc_aligned("ssl_proc_ev_lock", + CLIB_CACHE_LINE_BYTES, + CLIB_CACHE_LINE_BYTES, NULL); + if (proc_ev_record.golang_list_lock == NULL || + proc_ev_record.ssl_list_lock == NULL) { + ebpf_error("process events lock alloc memory failed.\n"); + return (-1); + } + + proc_ev_record.golang_list_lock[0] = 0; + proc_ev_record.ssl_list_lock[0] = 0; + + return (0); +} + int bpf_tracer_init(const char *log_file, bool is_stdout) { init_list_head(&extra_waiting_head); @@ -1668,6 +1708,9 @@ int bpf_tracer_init(const char *log_file, bool is_stdout) if ((err = sockopt_register(&trace_sockopts)) != ETR_OK) return err; + if (init_proc_events_record("proc_event_record")) + return ETR_INVAL; + err = pthread_create(&ctrl_pthread, NULL, (void *)&ctrl_main, NULL); if (err) { ebpf_info("<%s> ctrl_pthread, pthread_create is error:%s\n", diff --git a/agent/src/ebpf/user/tracer.h b/agent/src/ebpf/user/tracer.h index 6c4c9e2d871..754b5a0730e 100644 --- a/agent/src/ebpf/user/tracer.h +++ b/agent/src/ebpf/user/tracer.h @@ -519,6 +519,37 @@ static int inline __reclaim_map(int map_fd, struct list_head *h) #define CACHE_LINE_BYTES 64 +/* *INDENT-OFF* */ +// For process execute/exit events. +struct probe_process_event { + struct list_head list; // list add to proc_events_head + struct bpf_tracer *tracer; // link to struct bpf_tracer + uint8_t type; // EVENT_TYPE_PROC_EXEC or EVENT_TYPE_PROC_EXIT + char *path; // Full path "/proc//root/..." + int pid; // Process ID + uint32_t expire_time; // Expiration Date, the number of seconds since the system started. +}; +/* *INDENT-ON* */ + +struct proc_events_record { + volatile uint32_t *golang_list_lock; + struct list_head golang_events_head; + volatile uint32_t *ssl_list_lock; + struct list_head ssl_events_head; +}; + +static inline void proc_events_lock(volatile uint32_t *lock) +{ + while (__atomic_test_and_set(lock, __ATOMIC_ACQUIRE)) + CLIB_PAUSE(); +} + +static inline void proc_events_unlock(volatile uint32_t *lock) +{ + __atomic_clear(lock, __ATOMIC_RELEASE); +} + +void find_and_clear_event_from_list(int pid, struct list_head *head); int set_allow_port_bitmap(void *bitmap); int set_bypass_port_bitmap(void *bitmap); int enable_ebpf_protocol(int protocol);