From 8ec69743c9bc2f8685b941ef71fdd9790b06c489 Mon Sep 17 00:00:00 2001 From: Monkey857 Date: Fri, 13 Dec 2024 19:21:07 +0800 Subject: [PATCH] add func --- .../kvm_watcher/include/bpf/container.h | 93 ++++++------- eBPF_Supermarket/kvm_watcher/include/common.h | 8 ++ .../kvm_watcher/src/kvm_watcher.bpf.c | 81 ++++++++++-- .../kvm_watcher/src/kvm_watcher.c | 124 ++++++++++++++++-- 4 files changed, 229 insertions(+), 77 deletions(-) diff --git a/eBPF_Supermarket/kvm_watcher/include/bpf/container.h b/eBPF_Supermarket/kvm_watcher/include/bpf/container.h index 5271054ef..0bb0ae68e 100644 --- a/eBPF_Supermarket/kvm_watcher/include/bpf/container.h +++ b/eBPF_Supermarket/kvm_watcher/include/bpf/container.h @@ -24,7 +24,7 @@ #include #include #include -#define MAX_NODENAME_LEN 64 +#define MAX_NODENAME_LEN 13 struct { __uint(type,BPF_MAP_TYPE_HASH); __uint(max_entries, 8192); @@ -46,6 +46,12 @@ struct { __type(value,struct container_id); }container_id_map SEC(".maps"); +struct { + __uint(type,BPF_MAP_TYPE_HASH); + __uint(max_entries, 80); + __type(key, pid_t); + __type(value,struct syscall_value); //记录容器ID、进程名、系统调用号、每个调用号的次数、单位时间内的总延迟 +}proc_syscall_info SEC(".maps"); static int trace_container_sys_entry(struct trace_event_raw_sys_enter *args){ u64 st = bpf_ktime_get_ns(); @@ -62,8 +68,8 @@ static int trace_container_sys_exit(struct trace_event_raw_sys_exit *args,void * u64 *st = bpf_map_lookup_elem(&time_info,&pid); if( st !=0){ start_time = *st; - delay = (exit_time - start_time)/1000; - bpf_map_delete_elem(&time_info, &pid); + delay = (exit_time - start_time)/1000; + bpf_map_delete_elem(&time_info, &pid); }else{ return 0; } @@ -72,65 +78,44 @@ static int trace_container_sys_exit(struct trace_event_raw_sys_exit *args,void * syscallid = *sc_id; bpf_map_delete_elem(&id, &pid); }else{ - return 0; + return 0; } const void *contain_id = bpf_map_lookup_elem(&container_id_map,&pid); - if(contain_id != NULL){ - bpf_printk("hostname=%s\n",contain_id); - }else{ + if(contain_id == NULL){ + return 0; + } + //用指针去获取用户定义好的结构体,不然结构体过大会导致栈溢出 + struct syscall_value *syscall_value = bpf_map_lookup_elem(&proc_syscall_info, &pid); + if (!syscall_value) { return 0; } - RESERVE_RINGBUF_ENTRY(rb, e); - e->syscall_data.delay = delay; - bpf_get_current_comm(&e->syscall_data.comm, sizeof(e->syscall_data.comm)); - e->syscall_data.pid = pid; - bpf_probe_read_kernel_str(&(e->syscall_data.container_id),sizeof(e->syscall_data.container_id),contain_id); - e->syscall_data.syscall_id = syscallid; - bpf_ringbuf_submit(e, 0); + + // 读取 container_id + int ret = bpf_probe_read_kernel_str(syscall_value->container_id, sizeof(syscall_value->container_id), contain_id); + if (ret < 0) { + bpf_printk("Failed to read container_id from kernel space, error code: %d\n", ret); + return 0; + } + + // 打印读取的 container_id + bpf_printk("container_id: %s\n", syscall_value->container_id); + + // 获取进程名并存储 + ret = bpf_get_current_comm(syscall_value->proc_name, sizeof(syscall_value->proc_name)); + if (ret < 0) { + bpf_printk("Failed to read process name, error code: %d\n", ret); + return 0; + } + //检查 syscallid 是否超出范围 + if (syscallid >= MAX_SYSCALL_NUM || syscallid < 0) { + return 0; // 如果超出范围,直接返回 + } + syscall_value->syscall_total_delay[syscallid] += delay; // 加上 delay 的值 + syscall_value->syscall_id_counts[syscallid] += 1; // 计数加 1 return 0; } struct data_t { char nodename[MAX_NODENAME_LEN]; }; -static bool is_container_task(const volatile char hostname[MAX_NODENAME_LEN]){ - struct task_struct *task; - struct nsproxy *ns; - struct uts_namespace *uts; - struct data_t data = {}; - // 获取当前任务的 task_struct - task = (struct task_struct *)bpf_get_current_task(); - - // 获取 nsproxy - bpf_probe_read_kernel(&ns, sizeof(ns), &task->nsproxy); - if (!ns) { - return false; - } - - // 获取 uts_namespace - bpf_probe_read_kernel(&uts, sizeof(uts), &ns->uts_ns); - if (!uts) { - return false; - } - // 读取主机名 - bpf_probe_read_kernel_str(&data.nodename, sizeof(data.nodename), uts->name.nodename); - // 打印主机名 - bool is_equal = true; - for(int i = 0;insproxy); + if (!ns) { + return false; + } + + // 获取 uts_namespace + bpf_probe_read_kernel(&uts, sizeof(uts), &ns->uts_ns); + if (!uts) { + return false; + } + // 读取主机名 + bpf_probe_read_kernel_str(&data.nodename, sizeof(data.nodename), uts->name.nodename); + // 打印主机名 + + for(int i = 0;insproxy); + if (!ns) { + return false; + } + + // 获取 uts_namespace + bpf_probe_read_kernel(&uts, sizeof(uts), &ns->uts_ns); + if (!uts) { + return false; + } + // 读取主机名 + bpf_probe_read_kernel_str(&data.nodename, sizeof(data.nodename), uts->name.nodename); + // 打印主机名 + + for(int i = 0;ishow){ - printf("%-9s %10s\n", "DELAY(us)","SYSCALLID"); + //printf("%-13s %-10s %-10s %-10s %-10s %-10s\n","ContainerID", "Comm","Pid","SYSCALLID","Counts","avage_DELAY(us)"); }else{ - printf("%-8s %-22s %-9s %10s %-16s\n", "PID", "CONTAINER_ID", - "DELAY(us)", "SYSCALLID", "COMM"); + //printf("%-13s %-10s %-10s %-10s %-10s %-10s\n","ContainerID", "Comm","Pid","SYSCALLID","Counts","avage_DELAY(us)"); } break; case EXIT: @@ -1027,6 +1026,7 @@ int print_hc_map(struct kvm_watcher_bpf *skel) { struct hc_key next_key = {}; struct hc_value hc_value = {}; int first_run = 1; + // Iterate over the map while (!bpf_map_get_next_key(fd, &lookup_key, &next_key)) { if (first_run) { @@ -1238,6 +1238,100 @@ int print_exit_map(struct kvm_watcher_bpf *skel) { __print_exit_map(userspace_exit_fd, EXIT_USERSPACE_NR); return 0; } +int memset_big_struct(struct kvm_watcher_bpf *skel){ + //对占用大内存的结构体的map进行初始化 + int fd_memset = bpf_map__fd(skel->maps.proc_syscall_info); + int fd_proc = bpf_map__fd(skel->maps.container_id_map); + pid_t pid ,next_pid; + while (!bpf_map_get_next_key(fd_proc, &pid, &next_pid)) { + struct syscall_value new_value = {}; + int err = bpf_map_lookup_elem(fd_memset,&next_pid,&new_value); + //填充 new_value + strncpy(new_value.container_id, "", sizeof(new_value.container_id)); + strncpy(new_value.proc_name, "", sizeof(new_value.proc_name)); + // 初始化 syscalls 的 counts 和延迟为0 + memset(new_value.syscall_id_counts, 0, sizeof(new_value.syscall_id_counts)); + memset(new_value.syscall_total_delay, 0, sizeof(new_value.syscall_total_delay)); + // 在 BPF map 中插入初始化的值 + int ret = bpf_map_update_elem(fd_memset, &next_pid, &new_value, BPF_ANY); + if (ret < 0) { + perror("Error updating BPF map"); + return -1; + } + pid = next_pid; + } + //清除记录容器pid的map,不然无法重新给系统调用信息的map赋值 + memset(&pid, 0, sizeof(pid_t)); + memset(&next_pid, 0, sizeof(pid_t)); + while (!bpf_map_get_next_key(fd_proc, pid, next_pid)) { + int err = bpf_map_delete_elem(fd_proc, next_pid); + if (err < 0) { + fprintf(stderr, "failed to cleanup map: %d\n", err); + return -1; + } + pid = next_pid; + } + return 0; +} +int print_container_syscall(struct kvm_watcher_bpf *skel){ + OUTPUT_INTERVAL(2); + memset_big_struct(skel); + OUTPUT_INTERVAL(5); + int fd = bpf_map__fd(skel->maps.proc_syscall_info); + int fd1 = bpf_map__fd(skel->maps.container_id_map); + struct syscall_value values; + pid_t lookup_key,next_key; + + int err ; + //打印表头 + printf("%-13s %-10s %-10s %-10s %-10s %-10s\n","ContainerID", "Comm","Pid","SYSCALLID","Counts","avage_DELAY(us)"); + while(!bpf_map_get_next_key(fd,&lookup_key,&next_key)){ + err = bpf_map_lookup_elem(fd,&next_key,&values); + if (err < 0) { + fprintf(stderr, "failed to lookup values: %d\n", err); + return -1; + } + //找出最大的前五个系统调用号 + int max[5] = {-1, -1, -1, -1, -1}; // 记录前五个最大值的下标 + int top_values[5] = {0,0,0,0,0}; // 记录前五个最大值 + for (int i = 0; i < 462; i++) { + for (int j = 0; j < 5; j++) { + if (values.syscall_id_counts[i] > top_values[j]) { + // 将当前值插入到正确的位置,后面的值依次后移 + for (int k = 5 - 1; k > j; k--) { + top_values[k] = top_values[k - 1]; + max[k] = max[k - 1]; + } + top_values[j] = values.syscall_id_counts[i]; + max[j] = i; + break; + } + } + } + for(int i = 0;i<5;i++){ + if(max[i] == -1){ + continue; + } + uint64_t result = values.syscall_total_delay[max[i]] / values.syscall_id_counts[max[i]]; + printf("%-13s %-10s %-10d %-10d %-10d %llu\n",values.container_id,values.proc_name,next_key, + max[i],values.syscall_id_counts[max[i]],result); + } + lookup_key = next_key; + } + memset(&lookup_key, 0, sizeof(pid_t)); + memset(&next_key, 0, sizeof(pid_t)); + while (!bpf_map_get_next_key(fd, lookup_key, next_key)) { + err = bpf_map_delete_elem(fd, next_key); + if (err < 0) { + fprintf(stderr, "failed to cleanup map: %d\n", err); + return -1; + } + lookup_key = next_key; + } + printf("--------------------------\n"); + return 0; + +} void print_map_and_check_error(int (*print_func)(struct kvm_watcher_bpf *), struct kvm_watcher_bpf *skel, const char *map_name, int err) { @@ -1262,6 +1356,7 @@ int attach_probe(struct kvm_watcher_bpf *skel) { return kvm_watcher_bpf__attach(skel); } int main(int argc, char **argv) { + // 定义一个环形缓冲区 struct ring_buffer *rb = NULL; struct kvm_watcher_bpf *skel; @@ -1325,6 +1420,7 @@ int main(int argc, char **argv) { fprintf(stderr, "Please specify an option using %s.\n", OPTIONS_LIST); goto cleanup; } + //打印结果 while (!exiting) { err = ring_buffer__poll(rb, RING_BUFFER_TIMEOUT_MS /* timeout, ms */); if (env.execute_hypercall) { @@ -1340,6 +1436,10 @@ int main(int argc, char **argv) { print_map_and_check_error(print_vcpu_load_map, skel, "vcpu_load", err); } + if (env.execute_container_syscall){ + //print_map_and_check_error(print_container_syscall,skel,"container_syscall",err); + print_container_syscall(skel); + } /* Ctrl-C will cause -EINTR */ if (err == -EINTR) { err = 0;