From e9fbd43a593bda2f7943a9f0e58be99c7389900b Mon Sep 17 00:00:00 2001 From: yunwei37 <1067852565@qq.com> Date: Tue, 30 May 2023 17:23:30 +0800 Subject: [PATCH] fix document style violations --- chatGPT.md => ChatGPT.md | 994 ++++++++++++++++++----------------- src/0-introduce/README.md | 3 +- src/1-helloworld/README.md | 4 +- src/14-tcpstates/README.md | 122 ++--- src/19-lsm-connect/README.md | 8 +- src/20-tc/README.md | 7 +- src/21-xdp/README.md | 12 +- 7 files changed, 586 insertions(+), 564 deletions(-) rename chatGPT.md => ChatGPT.md (77%) diff --git a/chatGPT.md b/ChatGPT.md similarity index 77% rename from chatGPT.md rename to ChatGPT.md index 6997ee2..badf819 100644 --- a/chatGPT.md +++ b/ChatGPT.md @@ -7,6 +7,7 @@ > eBPF 是一种内核的网络程序。它可以在内核空间中执行,并且可以实时地监控内核的行为。eunomia-bpf 是一个工具,可以用来编写 eBPF 程序。它提供了一个简单的接口,使用户可以编写 eBPF 程序来实现特定的目标。例如,eBPF 程序可以用来监控内核网络流量,或者实现虚拟机监控等功能。 这是一个使用 eunomia-bpf 的例子: + ```c #include "vmlinux.h" #include @@ -18,23 +19,23 @@ char LICENSE[] SEC("license") = "Dual BSD/GPL"; SEC("kprobe/do_unlinkat") int BPF_KPROBE(do_unlinkat, int dfd, struct filename *name) { - pid_t pid; - const char *filename; + pid_t pid; + const char *filename; - pid = bpf_get_current_pid_tgid() >> 32; - filename = BPF_CORE_READ(name, name); - bpf_printk("KPROBE ENTRY pid = %d, filename = %s\n", pid, filename); - return 0; + pid = bpf_get_current_pid_tgid() >> 32; + filename = BPF_CORE_READ(name, name); + bpf_printk("KPROBE ENTRY pid = %d, filename = %s\n", pid, filename); + return 0; } SEC("kretprobe/do_unlinkat") int BPF_KRETPROBE(do_unlinkat_exit, long ret) { - pid_t pid; + pid_t pid; - pid = bpf_get_current_pid_tgid() >> 32; - bpf_printk("KPROBE EXIT: pid = %d, ret = %ld\n", pid, ret); - return 0; + pid = bpf_get_current_pid_tgid() >> 32; + bpf_printk("KPROBE EXIT: pid = %d, ret = %ld\n", pid, ret); + return 0; } ``` @@ -65,9 +66,9 @@ $ sudo cat /sys/kernel/debug/tracing/trace_pipe ``` > 这段程序使用 eBPF 实现了一个 kprobe,用来监控内核中 do_unlinkat() 函数的调用。kprobe 的目的是实时监控内核函数的调用情况,通过记录调用时的参数和返回值,来提供实时状态的反馈。在这个例子中,kprobe 记录了进入 do_unlinkat() 函数时的 PID 和文件名,并在函数返回时记录了返回值。 -> +> > eBPF 程序使用 ecc 工具编译成二进制文件,然后通过 ecli 工具运行。运行时,ecli 会将 eBPF 程序附加到内核上,并通过 /sys/kernel/debug/tracing/trace_pipe 文件来输出 kprobe 的日志信息。 -> +> > 这个程序的作用是实时监控内核中 do_unlinkat() 函数的调用情况,并记录相关信息。通过这种方式,我们可以对内核的行为进行实时监控,并及时发现可能的异常情况。 请帮我编写一个eBPF 程序,通过定义两个函数 tracepoint__syscalls__sys_enter_open 和 tracepoint__syscalls__sys_enter_openat 并使用 SEC 宏把它们附加到 sys_enter_open 和 sys_enter_openat 两个 tracepoint(即在进入 open 和 openat 系统调用时执行)。这两个函数通过使用 bpf_get_current_pid_tgid 函数获取调用 open 或 openat 系统调用的进程 ID,并使用 bpf_printk 函数在内核日志中打印出来。 @@ -123,11 +124,11 @@ char LICENSE[] SEC("license") = "Dual BSD/GPL"; SEC("tp/syscalls/sys_enter_write") int handle_tp(void *ctx) { - pid_t pid = bpf_get_current_pid_tgid() >> 32; - if (pid_filter && pid != pid_filter) - return 0; - bpf_printk("BPF triggered from PID %d.\n", pid); - return 0; + pid_t pid = bpf_get_current_pid_tgid() >> 32; + if (pid_filter && pid != pid_filter) + return 0; + bpf_printk("BPF triggered from PID %d.\n", pid); + return 0; } ``` @@ -169,6 +170,7 @@ $ sudo cat /sys/kernel/debug/tracing/trace_pipe <...>-3840345 [010] d... 3220701.101143: bpf_trace_printk: write system call from PID 3840345. <...>-3840345 [010] d... 3220701.101143: bpf_trace_printk: write system call from PID 3840345. ``` + 请告诉我如何编译运行实时监控内核中 open 和 openat 系统调用的 eBPF 程序。 > 要编译和运行实时监控内核中 open 和 openat 系统调用的 eBPF 程序,可以按照下面的步骤进行: @@ -215,7 +217,6 @@ Runing eBPF program... > 查看 /sys/kernel/debug - 请继续。查看 /sys/kernel/debug > 运行 eBPF 程序后,可以通过查看 /sys/kernel/debug/tracing/trace_pipe 文件来查看 eBPF 程序的输出。例如,如果有进程在调用 open 或 openat 系统调用,那么可以看到类似下面的输出: @@ -229,85 +230,84 @@ sys_enter_openat: pid = 456 > 这些输出表明,在运行 eBPF 程序的过程中,有两个进程(PID 为 123 和 456)分别调用了 open 和 openat 系统调用。对于每个系统调用,eBPF 程序都会记录调用进程的 ID,并在内核日志中输出。 > 需要注意的是,如果内核中有多个进程同时调用 open 或 openat 系统调用,那么输出结果可能会有所不同。例如,可能会有多个进程的 ID 同时出现在内核日志中。这取决于系统的具体情况。 - ```c #include #include #include "sigsnoop.h" -#define MAX_ENTRIES 10240 +#define MAX_ENTRIES 10240 struct { - __uint(type, BPF_MAP_TYPE_HASH); - __uint(max_entries, MAX_ENTRIES); - __type(key, __u32); - __type(value, struct event); + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, MAX_ENTRIES); + __type(key, __u32); + __type(value, struct event); } values SEC(".maps"); static int probe_entry(pid_t tpid, int sig) { - struct event event = {}; - __u64 pid_tgid; - __u32 pid, tid; + struct event event = {}; + __u64 pid_tgid; + __u32 pid, tid; - pid_tgid = bpf_get_current_pid_tgid(); - pid = pid_tgid >> 32; - event.pid = pid; - event.tpid = tpid; - event.sig = sig; - bpf_get_current_comm(event.comm, sizeof(event.comm)); - bpf_map_update_elem(&values, &tid, &event, BPF_ANY); - return 0; + pid_tgid = bpf_get_current_pid_tgid(); + pid = pid_tgid >> 32; + event.pid = pid; + event.tpid = tpid; + event.sig = sig; + bpf_get_current_comm(event.comm, sizeof(event.comm)); + bpf_map_update_elem(&values, &tid, &event, BPF_ANY); + return 0; } static int probe_exit(void *ctx, int ret) { - __u64 pid_tgid = bpf_get_current_pid_tgid(); - __u32 tid = (__u32)pid_tgid; - struct event *eventp; + __u64 pid_tgid = bpf_get_current_pid_tgid(); + __u32 tid = (__u32)pid_tgid; + struct event *eventp; - eventp = bpf_map_lookup_elem(&values, &tid); - if (!eventp) - return 0; + eventp = bpf_map_lookup_elem(&values, &tid); + if (!eventp) + return 0; - eventp->ret = ret; - bpf_printk("PID %d (%s) sent signal %d to PID %d, ret = %d", - eventp->pid, eventp->comm, eventp->sig, eventp->tpid, eventp->ret); + eventp->ret = ret; + bpf_printk("PID %d (%s) sent signal %d to PID %d, ret = %d", + eventp->pid, eventp->comm, eventp->sig, eventp->tpid, eventp->ret); cleanup: - bpf_map_delete_elem(&values, &tid); - return 0; + bpf_map_delete_elem(&values, &tid); + return 0; } SEC("tracepoint/syscalls/sys_enter_kill") int kill_entry(struct trace_event_raw_sys_enter *ctx) { - pid_t tpid = (pid_t)ctx->args[0]; - int sig = (int)ctx->args[1]; + pid_t tpid = (pid_t)ctx->args[0]; + int sig = (int)ctx->args[1]; - return probe_entry(tpid, sig); + return probe_entry(tpid, sig); } SEC("tracepoint/syscalls/sys_exit_kill") int kill_exit(struct trace_event_raw_sys_exit *ctx) { - return probe_exit(ctx, ctx->ret); + return probe_exit(ctx, ctx->ret); } SEC("tracepoint/syscalls/sys_enter_tkill") int tkill_entry(struct trace_event_raw_sys_enter *ctx) { - pid_t tpid = (pid_t)ctx->args[0]; - int sig = (int)ctx->args[1]; + pid_t tpid = (pid_t)ctx->args[0]; + int sig = (int)ctx->args[1]; - return probe_entry(tpid, sig); + return probe_entry(tpid, sig); } SEC("tracepoint/syscalls/sys_exit_tkill") int tkill_exit(struct trace_event_raw_sys_exit *ctx) { - return probe_exit(ctx, ctx->ret); + return probe_exit(ctx, ctx->ret); } char LICENSE[] SEC("license") = "Dual BSD/GPL"; @@ -316,13 +316,13 @@ char LICENSE[] SEC("license") = "Dual BSD/GPL"; 上面的代码定义了一个 eBPF 程序,用于捕获进程发送信号的系统调用,包括 kill、tkill 和 tgkill。它通过使用 tracepoint 来捕获系统调用的进入和退出事件,并在这些事件发生时执行指定的探针函数,例如 probe_entry 和 probe_exit。 > 在探针函数中,我们使用 bpf_map 存储捕获的事件信息,包括发送信号的进程 ID、接收信号的进程 ID、信号值和系统调用的返回值。在系统调用退出时,我们将获取存储在 bpf_map 中的事件信息,并使用 bpf_printk 打印进程 ID、进程名称、发送的信号和系统调用的返回值。 -> +> > 要编译这段 eBPF 程序,需要使用 LLVM Clang 工具链,并确保安装了 eBPF 相关的头文件,例如 vmlinux.h 和 bpf_helpers.h。 -> +> > 首先,按照以下命令编译 eBPF 程序: -> +> > $ clang -O2 -Wall -target bpf -c sigsnoop.c -o sigsnoop.o -> +> > 编译完成后,可以使用 bpftool 工具将 eBPF 字节码文件加载到内核中: > > $ sudo bpftool prog load sigsnoop.o /sys/fs/bpf/sigsnoop @@ -345,62 +345,62 @@ $ sudo cat /sys/kernel/debug/tracing/trace_pipe #include #include "sigsnoop.h" -#define MAX_ENTRIES 10240 +#define MAX_ENTRIES 10240 struct { - __uint(type, BPF_MAP_TYPE_HASH); - __uint(max_entries, MAX_ENTRIES); - __type(key, __u32); - __type(value, struct event); + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, MAX_ENTRIES); + __type(key, __u32); + __type(value, struct event); } values SEC(".maps"); static int probe_stat_entry(void *ctx) { - struct event event = {}; - __u64 pid_tgid; - __u32 pid, tid; + struct event event = {}; + __u64 pid_tgid; + __u32 pid, tid; - pid_tgid = bpf_get_current_pid_tgid(); - pid = pid_tgid >> 32; - event.pid = pid; - bpf_get_current_comm(event.comm, sizeof(event.comm)); - bpf_map_update_elem(&values, &tid, &event, BPF_ANY); - return 0; + pid_tgid = bpf_get_current_pid_tgid(); + pid = pid_tgid >> 32; + event.pid = pid; + bpf_get_current_comm(event.comm, sizeof(event.comm)); + bpf_map_update_elem(&values, &tid, &event, BPF_ANY); + return 0; } static int probe_stat_exit(void *ctx, int ret) { - __u64 pid_tgid = bpf_get_current_pid_tgid(); - __u32 tid = (__u32)pid_tgid; - struct event *eventp; + __u64 pid_tgid = bpf_get_current_pid_tgid(); + __u32 tid = (__u32)pid_tgid; + struct event *eventp; - eventp = bpf_map_lookup_elem(&values, &tid); - if (!eventp) - return 0; + eventp = bpf_map_lookup_elem(&values, &tid); + if (!eventp) + return 0; - eventp->ret = ret; - if (ret == 0) - bpf_probe_read_str(eventp->path, sizeof(eventp->path), (void *)ctx->args[0]); + eventp->ret = ret; + if (ret == 0) + bpf_probe_read_str(eventp->path, sizeof(eventp->path), (void *)ctx->args[0]); - bpf_printk("PID %d (%s) executed stat syscall, file path = %s, ret = %d", - eventp->pid, eventp->comm, eventp->path, eventp->ret); + bpf_printk("PID %d (%s) executed stat syscall, file path = %s, ret = %d", + eventp->pid, eventp->comm, eventp->path, eventp->ret); cleanup: - bpf_map_delete_elem(&values, &tid); - return 0; + bpf_map_delete_elem(&values, &tid); + return 0; } SEC("kprobe/sys_stat") int sys_stat_entry(struct pt_regs *ctx) { - return probe_stat_entry(ctx); + return probe_stat_entry(ctx); } SEC("kretprobe/sys_stat") int sys_stat_exit(struct pt_regs *ctx) { - return probe_stat_exit(ctx, PT_REGS_RC(ctx)); + return probe_stat_exit(ctx, PT_REGS_RC(ctx)); } SEC("kprobe/sys_fstat") @@ -416,52 +416,53 @@ int sys #include struct { - __uint(type, BPF_MAP_TYPE_HASH); - __uint(max_entries, 1024); - __type(key, int); - __type(value, struct event); + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1024); + __type(key, int); + __type(value, struct event); } events SEC(".maps"); SEC("tracepoint/syscalls/sys_enter_stat") int sys_enter_stat(struct trace_event_raw_sys_enter *ctx) { - struct event event = {}; - __u64 pid_tgid; - __u32 pid; - int fd = (int)ctx->args[0]; + struct event event = {}; + __u64 pid_tgid; + __u32 pid; + int fd = (int)ctx->args[0]; - pid_tgid = bpf_get_current_pid_tgid(); - pid = pid_tgid >> 32; - event.pid = pid; - bpf_get_current_comm(event.comm, sizeof(event.comm)); - bpf_map_update_elem(&events, &fd, &event, BPF_ANY); + pid_tgid = bpf_get_current_pid_tgid(); + pid = pid_tgid >> 32; + event.pid = pid; + bpf_get_current_comm(event.comm, sizeof(event.comm)); + bpf_map_update_elem(&events, &fd, &event, BPF_ANY); - return 0; + return 0; } SEC("tracepoint/syscalls/sys_exit_stat") int sys_exit_stat(struct trace_event_raw_sys_exit *ctx) { - struct event *eventp; - __u64 pid_tgid = bpf_get_current_pid_tgid(); - __u32 tid = (__u32)pid_tgid; - int fd = (int)ctx->args[0]; + struct event *eventp; + __u64 pid_tgid = bpf_get_current_pid_tgid(); + __u32 tid = (__u32)pid_tgid; + int fd = (int)ctx->args[0]; - eventp = bpf_map_lookup_elem(&events, &fd); - if (!eventp) - return 0; + eventp = bpf_map_lookup_elem(&events, &fd); + if (!eventp) + return 0; - eventp->ret = ctx->ret; - bpf_printk("PID %d (%s) called stat on fd %d, ret = %d\n", - eventp->pid, eventp->comm, fd, eventp->ret); + eventp->ret = ctx->ret; + bpf_printk("PID %d (%s) called stat on fd %d, ret = %d\n", + eventp->pid, eventp->comm, fd, eventp->ret); - bpf_map_delete_elem(& + bpf_map_delete_elem(& ``` 请继续。 > 编译运行 eBPF 程序的方法与之前给出的方法类似,首先使用 ecc 编译程序: + ```console $ ecc stat.bpf.c Compiling bpf object... @@ -480,6 +481,7 @@ docker run -it -v `pwd`/:/src/ yunwei37/ebpm:latest $ sudo ecli run ./package.json Runing eBPF program... ``` + > 运行这段程序后,可以通过查看 /sys/kernel/debug/tracing/trace_pipe 文件来查看 eBPF 程序的输出: ```console @@ -497,6 +499,7 @@ Running 'record' for 'bpf_printk' (5 secs): [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.178 MB perf.data (~1623 samples) ] ``` + > 使用 perf script 命令来查看 perf.data 中的输出: ``` @@ -519,25 +522,26 @@ char LICENSE[] SEC("license") = "Dual BSD/GPL"; SEC("kprobe/do_syscall_64") int BPF_KPROBE(do_syscall_64, struct pt_regs *regs, long id) { - pid_t pid; - const char *func; + pid_t pid; + const char *func; - pid = bpf_get_current_pid_tgid() >> 32; - func = __func__; - bpf_printk("KPROBE ENTRY pid = %d, func = %s, id = %d\n", pid, func, id); - return 0; + pid = bpf_get_current_pid_tgid() >> 32; + func = __func__; + bpf_printk("KPROBE ENTRY pid = %d, func = %s, id = %d\n", pid, func, id); + return 0; } SEC("kretprobe/do_syscall_64") int BPF_KRETPROBE(do_syscall_64_exit, long ret) { - pid_t pid; + pid_t pid; - pid = bpf_get_current_pid_tgid() >> 32; - bpf_printk("KPROBE EXIT: pid = %d, ret = %ld\n", pid, ret); - return 0; + pid = bpf_get_current_pid_tgid() >> 32; + bpf_printk("KPROBE EXIT: pid = %d, ret = %ld\n", pid, ret); + return 0; } ``` + > 要编译这段代码,可以使用 ecc 工具: ``` @@ -561,12 +565,12 @@ Packing ebpf object and config into package.json... #define TASK_COMM_LEN 16 struct event { - int pid; - int ppid; - int uid; - int retval; - bool is_exit; - char comm[TASK_COMM_LEN]; + int pid; + int ppid; + int uid; + int retval; + bool is_exit; + char comm[TASK_COMM_LEN]; }; #endif /* __EXECSNOOP_H */ @@ -582,58 +586,58 @@ struct event { #include "execsnoop.bpf.h" struct { - __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); - __uint(key_size, sizeof(u32)); - __uint(value_size, sizeof(u32)); + __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); + __uint(key_size, sizeof(u32)); + __uint(value_size, sizeof(u32)); } events SEC(".maps"); SEC("tracepoint/syscalls/sys_enter_execve") int tracepoint__syscalls__sys_enter_execve(struct trace_event_raw_sys_enter* ctx) { - u64 id; - pid_t pid, tgid; - unsigned int ret; - struct event event; - struct task_struct *task; - const char **args = (const char **)(ctx->args[1]); - const char *argp; + u64 id; + pid_t pid, tgid; + unsigned int ret; + struct event event; + struct task_struct *task; + const char **args = (const char **)(ctx->args[1]); + const char *argp; - uid_t uid = (u32)bpf_get_current_uid_gid(); - int i; - id = bpf_get_current_pid_tgid(); - pid = (pid_t)id; - tgid = id >> 32; + uid_t uid = (u32)bpf_get_current_uid_gid(); + int i; + id = bpf_get_current_pid_tgid(); + pid = (pid_t)id; + tgid = id >> 32; - event.pid = tgid; - event.uid = uid; - task = (struct task_struct*)bpf_get_current_task(); - bpf_probe_read_str(&event.comm, sizeof(event.comm), task->comm); - event.is_exit = false; - bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event)); - return 0; + event.pid = tgid; + event.uid = uid; + task = (struct task_struct*)bpf_get_current_task(); + bpf_probe_read_str(&event.comm, sizeof(event.comm), task->comm); + event.is_exit = false; + bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event)); + return 0; } SEC("tracepoint/syscalls/sys_exit_execve") int tracepoint__syscalls__sys_exit_execve(struct trace_event_raw_sys_exit* ctx) { - u64 id; - pid_t pid; - int ret; - struct event event; + u64 id; + pid_t pid; + int ret; + struct event event; - u32 uid = (u32)bpf_get_current_uid_gid(); + u32 uid = (u32)bpf_get_current_uid_gid(); - id = bpf_get_current_pid_tgid(); - pid = (pid_t)id; + id = bpf_get_current_pid_tgid(); + pid = (pid_t)id; - ret = ctx->ret; - event.retval = ret; - event.pid = pid; - event.uid = uid; - event.is_exit = true; - bpf_get_current_comm(&event.comm, sizeof(event.comm)); - bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event)); - return 0; + ret = ctx->ret; + event.retval = ret; + event.pid = pid; + event.uid = uid; + event.is_exit = true; + bpf_get_current_comm(&event.comm, sizeof(event.comm)); + bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event)); + return 0; } char LICENSE[] SEC("license") = "GPL"; @@ -642,33 +646,33 @@ char LICENSE[] SEC("license") = "GPL"; > 这段代码定义了两个 eBPF 程序,一个用于捕获进程执行 execve 系统调用的入口,另一个用于捕获进程执行 execve 系统调用的出口。 > 在入口程序中,我们首先获取了当前进程的进程 ID 和用户 ID,然后通过 bpf_get_current_task 函数获取了当前进程的 task_struct 结构体,并通过 bpf_probe_read_str 函数读取了进程名称。最后,我们通过 bpf_perf_event_output 函数将进程执行事件输出到 perf buffer。 -> +> > 在出口程序中,我们首先获取了进程的进程 ID 和用户 ID,然后通过 bpf_get_current_comm 函数获取了进程的名称,最后通过 bpf_perf_event_output 函数将进程执行事件输出到 perf buffer。 -> +> > 使用这段代码,我们就可以捕获 Linux 内核中进程执行的事件。我们可以通过工具(例如 eunomia-bpf)来查看这些事件,并分析进程的执行情况。 -> +> > 接着,使用如下命令编译这个 eBPF 程序: -> +> > clang -O2 -emit-llvm -c -g execsnoop.bpf.c -> +> > llc -march=bpf -filetype=obj -o execsnoop.o execsnoop.bpf.ll -> +> > 编译后的文件 execsnoop.o 就可以使用 eunomia-bpf 工具来运行了。例如,可以使用如下命令运行这个程序: -> +> > eunomia-bpf -o execsnoop.o -> +> > 执行这个命令后,程序将在内核中运行,并在追踪到进程执行 execve 系统调用时向用户态命令行打印输出。 -> +> > 可以通过使用 -p 参数指定进程 ID,来只监控指定的进程。例如: > > eunomia-bpf -p 1234 -o execsnoop.o -> +> > 这样就只会监控进程 ID 为 1234 的进程的执行。 -> +> > 还可以通过使用 -C 参数来指定要监控的系统调用,例如: > > eunomia-bpf -C execve -o execsnoop.o -> +> > 这样就只会监 please give me an eBPF program Trace all stat syscall variants with perf event output. @@ -729,38 +733,38 @@ int tracepoint__syscalls__sys_enter_stat(struct trace_event_raw_sys_enter *ctx) #define MAX_ENTRIES 10240 struct { - __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); - __uint(key_size, sizeof(u32)); - __uint(value_size, sizeof(u32)); + __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); + __uint(key_size, sizeof(u32)); + __uint(value_size, sizeof(u32)); } events SEC(".maps"); SEC("tracepoint/syscalls/sys_enter_stat") int tracepoint__syscalls__sys_enter_stat(struct trace_event_raw_sys_enter* ctx) { - u64 id = bpf_get_current_pid_tgid(); - u32 pid = (u32)id; - u32 tgid = id >> 32; - const char *filename = (const char*)(ctx->args[0]); - struct stat *stat = (struct stat*)(ctx->args[1]); - int ret = ctx->ret; + u64 id = bpf_get_current_pid_tgid(); + u32 pid = (u32)id; + u32 tgid = id >> 32; + const char *filename = (const char*)(ctx->args[0]); + struct stat *stat = (struct stat*)(ctx->args[1]); + int ret = ctx->ret; - bpf_probe_read_str(&filename, sizeof(filename), filename); - bpf_probe_read(&stat, sizeof(stat), stat); + bpf_probe_read_str(&filename, sizeof(filename), filename); + bpf_probe_read(&stat, sizeof(stat), stat); - struct data_t { - u32 pid; - u32 tgid; - int ret; - char filename[256]; - } data = { - .pid = pid, - .tgid = tgid, - .ret = ret, - }; + struct data_t { + u32 pid; + u32 tgid; + int ret; + char filename[256]; + } data = { + .pid = pid, + .tgid = tgid, + .ret = ret, + }; - bpf_probe_read_str(&data.filename, sizeof(data.filename), filename); - bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &data, sizeof(data)); - return 0; + bpf_probe_read_str(&data.filename, sizeof(data.filename), filename); + bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &data, sizeof(data)); + return 0; } char LICENSE[] SEC("license") = "GPL"; @@ -778,39 +782,39 @@ char LICENSE[] SEC("license") = "GPL"; #include struct { - __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); - __uint(key_size, sizeof(u32)); - __uint(value_size, sizeof(u32)); + __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); + __uint(key_size, sizeof(u32)); + __uint(value_size, sizeof(u32)); } events SEC(".maps"); SEC("tracepoint/syscalls/sys_enter_fstat") int tracepoint__syscalls__sys_enter_fstat(struct trace_event_raw_sys_enter* ctx) { - struct stat *st = (struct stat *)(ctx->args[1]); - struct event { - int pid; - int fd; - char comm[TASK_COMM_LEN]; - bool is_exit; - int retval; - } event = {}; + struct stat *st = (struct stat *)(ctx->args[1]); + struct event { + int pid; + int fd; + char comm[TASK_COMM_LEN]; + bool is_exit; + int retval; + } event = {}; - event.fd = (int)(ctx->args[0]); - event.pid = (int)(bpf_get_current_pid_tgid() >> 32); - bpf_get_current_comm(&event.comm, sizeof(event.comm)); - event.is_exit = false; - bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event)); + event.fd = (int)(ctx->args[0]); + event.pid = (int)(bpf_get_current_pid_tgid() >> 32); + bpf_get_current_comm(&event.comm, sizeof(event.comm)); + event.is_exit = false; + bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event)); - return 0; + return 0; } SEC("tracepoint/syscalls/sys_exit_fstat") int tracepoint__syscalls__sys_exit_fstat(struct trace_event_raw_sys_exit* ctx) { - struct event { - int pid; - int fd; - char comm + struct event { + int pid; + int fd; + char comm ``` @@ -840,12 +844,15 @@ int handle_tp(void *ctx) char _license[] SEC("license") = "GPL"; ``` + > 这个 eBPF 程序通过定义一个 handle_tp 函数并使用 SEC 宏把它附加到 sys_enter_write tracepoint。在进入 write 系统调用时,handle_tp 函数会被执行。该函数会使用 bpf_get_current_pid_tgid 函数获取调用 write 系统调用的进程 ID,然后使用 bpf_printk 函数在内核日志中打印出来。 > > eBPF 程序的输出结果将是内核日志中打印的调用 write 系统调用的进程的 PID。例如,如果进程 42 调用了 write 系统调用,则输出结果将是: + ``` PID of process calling write: 42 ``` + > 需要注意的是,在使用此 eBPF 程序之前,需要编译它并将其加载到内核中。此外,由于 eBPF 程序在内核态运行,因此它可能需要特殊权限才能加载和使用。 ```c @@ -864,13 +871,14 @@ char LICENSE[] SEC("license") = "Dual BSD/GPL"; SEC("tp/syscalls/sys_enter_write") int handle_tp(void *ctx) { - pid_t pid = bpf_get_current_pid_tgid() >> 32; - if (pid_filter && pid != pid_filter) - return 0; - bpf_printk("BPF triggered from PID %d.\n", pid); - return 0; + pid_t pid = bpf_get_current_pid_tgid() >> 32; + if (pid_filter && pid != pid_filter) + return 0; + bpf_printk("BPF triggered from PID %d.\n", pid); + return 0; } ``` + 不。代码应该是这样的。 > 您的代码看起来正确。它定义了一个 handle_tp 函数,并使用 SEC 宏把它附加到 sys_enter_write tracepoint。在进入 write 系统调用时,handle_tp 函数会被执行。该函数会使用 bpf_get_current_pid_tgid 函数获取调用 write 系统调用的进程 ID,然后使用 bpf_printk 函数在内核日志中打印出来。如果需要,还可以使用 pid_filter 变量来过滤进程。如果您需要进一步改进您的 eBPF 程序,请告诉我您的需求,我可以帮助您实现它。 @@ -907,9 +915,11 @@ $ sudo cat /sys/kernel/debug/tracing/trace_pipe > 您的描述是正确的。eBPF 程序需要编译才能运行。可以使用 ecc 工具来编译 eBPF 程序,也可以使用 docker 镜像进行编译。运行 eBPF 程序的方法有多种,可以使用 ecli 命令运行编译后的程序,也可以使用其他工具。输出结果将在内核日志中打印,可以通过查看 /sys/kernel/debug/tracing/trace_pipe 文件来查看。 > > 请注意,使用 ecc 编译程序后,会生成一个 package.json 文件,其中包含编译后的 eBPF 程序和配置信息。运行 eBPF 程序时,需要指定该文件,以便 ecli 命令能够找到并运行 eBPF 程序。例如,可以使用以下命令运行 eBPF 程序: + ``` -$ sudo ecli run ./package.json +sudo ecli run ./package.json ``` + > 如果您还有任何问题,请随时告诉我,我很乐意帮助您解决问题。 ```c @@ -923,23 +933,23 @@ char LICENSE[] SEC("license") = "Dual BSD/GPL"; SEC("kprobe/do_unlinkat") int BPF_KPROBE(do_unlinkat, int dfd, struct filename *name) { - pid_t pid; - const char *filename; + pid_t pid; + const char *filename; - pid = bpf_get_current_pid_tgid() >> 32; - filename = BPF_CORE_READ(name, name); - bpf_printk("KPROBE ENTRY pid = %d, filename = %s\n", pid, filename); - return 0; + pid = bpf_get_current_pid_tgid() >> 32; + filename = BPF_CORE_READ(name, name); + bpf_printk("KPROBE ENTRY pid = %d, filename = %s\n", pid, filename); + return 0; } SEC("kretprobe/do_unlinkat") int BPF_KRETPROBE(do_unlinkat_exit, long ret) { - pid_t pid; + pid_t pid; - pid = bpf_get_current_pid_tgid() >> 32; - bpf_printk("KPROBE EXIT: pid = %d, ret = %ld\n", pid, ret); - return 0; + pid = bpf_get_current_pid_tgid() >> 32; + bpf_printk("KPROBE EXIT: pid = %d, ret = %ld\n", pid, ret); + return 0; } ``` @@ -956,6 +966,7 @@ clang -O2 -target bpf -c my_bpf_prog.c -o my_bpf_prog.o # 运行 eBPF 程序 sudo ./bcc.py run my_bpf_prog.o ``` + > 这样,就会编译并运行您的 eBPF 程序。在运行 eBPF 程序时,会在内核日志中打 不对,使用 eunomia-bpf 工具编译。要编译这个程序,请使用 ecc 工具: @@ -998,33 +1009,34 @@ char LICENSE[] SEC("license") = "Dual BSD/GPL"; SEC("fentry/do_unlinkat") int BPF_PROG(do_unlinkat, int dfd, struct filename *name) { - pid_t pid; + pid_t pid; - pid = bpf_get_current_pid_tgid() >> 32; - bpf_printk("fentry: pid = %d, filename = %s\n", pid, name->name); - return 0; + pid = bpf_get_current_pid_tgid() >> 32; + bpf_printk("fentry: pid = %d, filename = %s\n", pid, name->name); + return 0; } SEC("fexit/do_unlinkat") int BPF_PROG(do_unlinkat_exit, int dfd, struct filename *name, long ret) { - pid_t pid; + pid_t pid; - pid = bpf_get_current_pid_tgid() >> 32; - bpf_printk("fexit: pid = %d, filename = %s, ret = %ld\n", pid, name->name, ret); - return 0; + pid = bpf_get_current_pid_tgid() >> 32; + bpf_printk("fexit: pid = %d, filename = %s, ret = %ld\n", pid, name->name, ret); + return 0; } ``` 这段程序通过定义两个函数,分别附加到 do_unlinkat 和 do_unlinkat_exit 上。这两个函数分别在进入 do_unlinkat 和离开 do_unlinkat 时执行。这两个函数通过使用 bpf_get_current_pid_tgid 和 bpf_printk 函数来获取调用 do_unlinkat 的进程 ID,文件名和返回值,并在内核日志中打印出来。请告诉我如何编译运行这段程序。 > 您的 eBPF 程序定义了两个函数:do_unlinkat 和 do_unlinkat_exit。这两个函数都使用 BPF_PROG 宏附加到 do_unlinkat 和 do_unlinkat_exit 函数上。do_unlinkat 函数在进入 do_unlinkat 时执行,do_unlinkat_exit 函数在离开 do_unlinkat 时执行。这两个函数通过使用 bpf_get_current_pid_tgid 和 bpf_printk 函数来获取调用 do_unlinkat 的进程 ID,文件名和返回值,并在内核日志中打印出来。 -> +> > 要编译和运行这段程序,您可以使用 bcc 工具集。首先,在终端中输入以下命令来安装 bcc 工具集: ``` sudo apt install bcc-tools libbcc-examples linux-headers-$(uname -r) ``` + > 然后,在终端中输入以下命令来编译您的 eBPF 程序: 我不希望你继续使用 BCC 工具集,请使用 eunomia-bpf @@ -1034,13 +1046,17 @@ sudo apt install bcc-tools libbcc-examples linux-headers-$(uname -r) sudo npm install -g eunomia-bpf > 然后,在终端中输入以下命令来编译您的 eBPF 程序: + ``` ecc kprobe-link.bpf.c ``` + > 编译后,您会得到一个 package.json 文件。您可以使用 ecli 命令运行该程序: + ``` sudo ecli run package.json ``` + > 运行该程序后,您可以查看 /sys/kernel/debug/tracing/trace_pipe 文件,以查看程序的输出。请注意,编译和运行 eBPF 程序的步骤可能会有所不同,具体取决于使用的工具和系统环境。如果您在编 我们需要编写一段 eBPF 程序来捕获进程打开文件的系统调用,具体实现如下: @@ -1060,27 +1076,27 @@ const volatile int pid_target = 0; SEC("tracepoint/syscalls/sys_enter_open") int tracepoint__syscalls__sys_enter_open(struct trace_event_raw_sys_enter* ctx) { - u64 id = bpf_get_current_pid_tgid(); - u32 pid = id; + u64 id = bpf_get_current_pid_tgid(); + u32 pid = id; - if (pid_target && pid_target != pid) - return false; - // Use bpf_printk to print the process information - bpf_printk("Process ID: %d enter sys open\n", pid); - return 0; + if (pid_target && pid_target != pid) + return false; + // Use bpf_printk to print the process information + bpf_printk("Process ID: %d enter sys open\n", pid); + return 0; } SEC("tracepoint/syscalls/sys_enter_openat") int tracepoint__syscalls__sys_enter_openat(struct trace_event_raw_sys_enter* ctx) { - u64 id = bpf_get_current_pid_tgid(); - u32 pid = id; + u64 id = bpf_get_current_pid_tgid(); + u32 pid = id; - if (pid_target && pid_target != pid) - return false; - // Use bpf_printk to print the process information - bpf_printk("Process ID: %d enter sys openat\n", pid); - return 0; + if (pid_target && pid_target != pid) + return false; + // Use bpf_printk to print the process information + bpf_printk("Process ID: %d enter sys openat\n", pid); + return 0; } /// Trace open family syscalls. @@ -1102,13 +1118,14 @@ Packing ebpf object and config into package.json... ``` sudo ecli run package.json ``` + > 在 /sys/kernel/debug/tracing/trace_pipe 文件中,应该能看到类似下面的输出: ``` $ sudo cat /sys/kernel/debug/tracing/trace_pipe cat-9349 [005] d..3 4710.951696: bpf_trace_printk: Process ID: 9349 enter sys open cat-9349 [005] d..3 4710.951696: bpf_trace_printk: Process ID: 9349 enter sys openat -``` +``` > 如果想要只跟踪特定的进程,可以在程序中设置 pid_target 变量的值,例如: @@ -1135,21 +1152,21 @@ const volatile int pid_target = 1234; SEC("uprobe//bin/bash:readline") int BPF_KRETPROBE(printret, const void *ret) { - char str[MAX_LINE_SIZE]; - char comm[TASK_COMM_LEN]; - u32 pid; + char str[MAX_LINE_SIZE]; + char comm[TASK_COMM_LEN]; + u32 pid; - if (!ret) - return 0; + if (!ret) + return 0; - bpf_get_current_comm(&comm, sizeof(comm)); + bpf_get_current_comm(&comm, sizeof(comm)); - pid = bpf_get_current_pid_tgid() >> 32; - bpf_probe_read_user_str(str, sizeof(str), ret); + pid = bpf_get_current_pid_tgid() >> 32; + bpf_probe_read_user_str(str, sizeof(str), ret); - bpf_printk("PID %d (%s) read: %s ", pid, comm, str); + bpf_printk("PID %d (%s) read: %s ", pid, comm, str); - return 0; + return 0; }; char LICENSE[] SEC("license") = "GPL"; @@ -1170,7 +1187,7 @@ SEC("uprobe//bin/bash:readline") 这表示我们要捕获的是 /bin/bash 二进制文件中的 readline 函数。 > 是的,你描述得很清楚。 -> +> > 编译这段程序的方法与其他 eBPF 程序的编译方法相同,需要使用 eunomia-bpf 工具集。首先使用 ecc 编译程序: ``` @@ -1185,6 +1202,7 @@ Packing ebpf object and config into package.json... $ sudo ecli run ./package.json Runing eBPF program... ``` + > 在 /sys/kernel/debug/tracing/trace_pipe 文件中,应该能看到类似下面的输出: ``` @@ -1193,6 +1211,7 @@ PID 1234 (bash) read: some command line input PID 1234 (bash) read: another command line input ... ``` + > 这些输出表示有一个进程 ID 为 1234,名称为 bash 的进程在调用 readline 函数时输入了相应的命令行输入。 ```c @@ -1200,79 +1219,79 @@ PID 1234 (bash) read: another command line input #include #include "sigsnoop.h" -#define MAX_ENTRIES 10240 +#define MAX_ENTRIES 10240 struct { - __uint(type, BPF_MAP_TYPE_HASH); - __uint(max_entries, MAX_ENTRIES); - __type(key, __u32); - __type(value, struct event); + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, MAX_ENTRIES); + __type(key, __u32); + __type(value, struct event); } values SEC(".maps"); static int probe_entry(pid_t tpid, int sig) { - struct event event = {}; - __u64 pid_tgid; - __u32 pid, tid; + struct event event = {}; + __u64 pid_tgid; + __u32 pid, tid; - pid_tgid = bpf_get_current_pid_tgid(); - pid = pid_tgid >> 32; - event.pid = pid; - event.tpid = tpid; - event.sig = sig; - bpf_get_current_comm(event.comm, sizeof(event.comm)); - bpf_map_update_elem(&values, &tid, &event, BPF_ANY); - return 0; + pid_tgid = bpf_get_current_pid_tgid(); + pid = pid_tgid >> 32; + event.pid = pid; + event.tpid = tpid; + event.sig = sig; + bpf_get_current_comm(event.comm, sizeof(event.comm)); + bpf_map_update_elem(&values, &tid, &event, BPF_ANY); + return 0; } static int probe_exit(void *ctx, int ret) { - __u64 pid_tgid = bpf_get_current_pid_tgid(); - __u32 tid = (__u32)pid_tgid; - struct event *eventp; + __u64 pid_tgid = bpf_get_current_pid_tgid(); + __u32 tid = (__u32)pid_tgid; + struct event *eventp; - eventp = bpf_map_lookup_elem(&values, &tid); - if (!eventp) - return 0; + eventp = bpf_map_lookup_elem(&values, &tid); + if (!eventp) + return 0; - eventp->ret = ret; - bpf_printk("PID %d (%s) sent signal %d to PID %d, ret = %d", - eventp->pid, eventp->comm, eventp->sig, eventp->tpid, eventp->ret); + eventp->ret = ret; + bpf_printk("PID %d (%s) sent signal %d to PID %d, ret = %d", + eventp->pid, eventp->comm, eventp->sig, eventp->tpid, eventp->ret); cleanup: - bpf_map_delete_elem(&values, &tid); - return 0; + bpf_map_delete_elem(&values, &tid); + return 0; } SEC("tracepoint/syscalls/sys_enter_kill") int kill_entry(struct trace_event_raw_sys_enter *ctx) { - pid_t tpid = (pid_t)ctx->args[0]; - int sig = (int)ctx->args[1]; + pid_t tpid = (pid_t)ctx->args[0]; + int sig = (int)ctx->args[1]; - return probe_entry(tpid, sig); + return probe_entry(tpid, sig); } SEC("tracepoint/syscalls/sys_exit_kill") int kill_exit(struct trace_event_raw_sys_exit *ctx) { - return probe_exit(ctx, ctx->ret); + return probe_exit(ctx, ctx->ret); } SEC("tracepoint/syscalls/sys_enter_tkill") int tkill_entry(struct trace_event_raw_sys_enter *ctx) { - pid_t tpid = (pid_t)ctx->args[0]; - int sig = (int)ctx->args[1]; + pid_t tpid = (pid_t)ctx->args[0]; + int sig = (int)ctx->args[1]; - return probe_entry(tpid, sig); + return probe_entry(tpid, sig); } SEC("tracepoint/syscalls/sys_exit_tkill") int tkill_exit(struct trace_event_raw_sys_exit *ctx) { - return probe_exit(ctx, ctx->ret); + return probe_exit(ctx, ctx->ret); } char LICENSE[] SEC("license") = "Dual BSD/GPL"; @@ -1292,58 +1311,58 @@ char LICENSE[] SEC("license") = "Dual BSD/GPL"; #include "execsnoop.bpf.h" struct { - __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); - __uint(key_size, sizeof(u32)); - __uint(value_size, sizeof(u32)); + __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); + __uint(key_size, sizeof(u32)); + __uint(value_size, sizeof(u32)); } events SEC(".maps"); SEC("tracepoint/syscalls/sys_enter_execve") int tracepoint__syscalls__sys_enter_execve(struct trace_event_raw_sys_enter* ctx) { - u64 id; - pid_t pid, tgid; - unsigned int ret; - struct event event; - struct task_struct *task; - const char **args = (const char **)(ctx->args[1]); - const char *argp; + u64 id; + pid_t pid, tgid; + unsigned int ret; + struct event event; + struct task_struct *task; + const char **args = (const char **)(ctx->args[1]); + const char *argp; - uid_t uid = (u32)bpf_get_current_uid_gid(); - int i; - id = bpf_get_current_pid_tgid(); - pid = (pid_t)id; - tgid = id >> 32; + uid_t uid = (u32)bpf_get_current_uid_gid(); + int i; + id = bpf_get_current_pid_tgid(); + pid = (pid_t)id; + tgid = id >> 32; - event.pid = tgid; - event.uid = uid; - task = (struct task_struct*)bpf_get_current_task(); - bpf_probe_read_str(&event.comm, sizeof(event.comm), task->comm); - event.is_exit = false; - bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event)); - return 0; + event.pid = tgid; + event.uid = uid; + task = (struct task_struct*)bpf_get_current_task(); + bpf_probe_read_str(&event.comm, sizeof(event.comm), task->comm); + event.is_exit = false; + bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event)); + return 0; } SEC("tracepoint/syscalls/sys_exit_execve") int tracepoint__syscalls__sys_exit_execve(struct trace_event_raw_sys_exit* ctx) { - u64 id; - pid_t pid; - int ret; - struct event event; + u64 id; + pid_t pid; + int ret; + struct event event; - u32 uid = (u32)bpf_get_current_uid_gid(); + u32 uid = (u32)bpf_get_current_uid_gid(); - id = bpf_get_current_pid_tgid(); - pid = (pid_t)id; + id = bpf_get_current_pid_tgid(); + pid = (pid_t)id; - ret = ctx->ret; - event.retval = ret; - event.pid = pid; - event.uid = uid; - event.is_exit = true; - bpf_get_current_comm(&event.comm, sizeof(event.comm)); - bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event)); - return 0; + ret = ctx->ret; + event.retval = ret; + event.pid = pid; + event.uid = uid; + event.is_exit = true; + bpf_get_current_comm(&event.comm, sizeof(event.comm)); + bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event)); + return 0; } char LICENSE[] SEC("license") = "GPL"; @@ -1359,6 +1378,7 @@ char LICENSE[] SEC("license") = "GPL"; 使用这段代码,我们就可以捕获 Linux 内核中进程执行的事件。我们可以通过工具(例如 eunomia-bpf)来查看这些事件,并分析进程的执行情况。 > 是的,这段代码通过定义两个 eBPF 程序来捕获进程执行 execve 系统调用的入口和出口事件。在入口程序中,我们获取了当前进程的进程 ID 和用户 ID,并通过 bpf_get_current_task 函数获取了当前进程的 task_struct 结构体,并通过 bpf_probe_read_str 函数读取了进程名称。在出口程序中,我们获取了当前进程的进程 ID 和用户 ID,并获取了 execve 系统调用的返回值。最后,在 + ``` #include #include @@ -1366,7 +1386,7 @@ char LICENSE[] SEC("license") = "GPL"; #include #define TC_ACT_OK 0 -#define ETH_P_IP 0x0800 /* Internet Protocol packet */ +#define ETH_P_IP 0x0800 /* Internet Protocol packet */ /// @tchook {"ifindex":1, "attach_point":"BPF_TC_INGRESS"} /// @tcopts {"handle":1, "priority":1} @@ -1400,12 +1420,13 @@ char __license[] SEC("license") = "GPL"; 需要注意的是,我们在代码中使用了一些 BPF 库函数,例如 bpf_htons 和 bpf_ntohs 函数,它们用于进行网络字节序和主机字节序之间的转换。此外,我们还使用了一些注释来为 TC 提供附加点和选项信息。例如,在这段代码的开头,我们使用了以下注释: -``` +```c /// @tchook {"ifindex":1, "attach_point":"BPF_TC_INGRESS"} /// @tcopts {"handle":1, "priority":1} ``` + > 这些注释告诉 TC 将 eBPF 程序附加到网络接口的 ingress 附加点,并指定了 handle 和 priority 选项的值。 -> +> > 总之,这段代码实现了一个简单的 eBPF 程序,用于捕获数据包并打印出它们的信息。 编译运行 @@ -1432,7 +1453,7 @@ Successfully started! Please run `sudo cat /sys/kernel/debug/tracing/trace_pipe` The `tc` output in `/sys/kernel/debug/tracing/trace_pipe` should look something like this: -``` +```console $ sudo cat /sys/kernel/debug/tracing/trace_pipe node-1254811 [007] ..s1 8737831.671074: 0: Got IP packet: tot_len: 79, ttl: 64 sshd-1254728 [006] ..s1 8737831.674334: 0: Got IP packet: tot_len: 79, ttl: 64 @@ -1444,244 +1465,245 @@ $ sudo cat /sys/kernel/debug/tracing/trace_pipe 这段代码还使用了 @tchook 和 @tcopts 注释,用于指定该 eBPF 程序的挂载点和处理方式。例如,@tchook 注释中的 ifindex 参数指定了该 eBPF 程序 -``` +```c const volatile __u64 min_us = 0; const volatile pid_t targ_pid = 0; const volatile pid_t targ_tgid = 0; struct { - __uint(type, BPF_MAP_TYPE_HASH); - __uint(max_entries, 10240); - __type(key, u32); - __type(value, u64); + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 10240); + __type(key, u32); + __type(value, u64); } start SEC(".maps"); struct { - __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); - __uint(key_size, sizeof(u32)); - __uint(value_size, sizeof(u32)); + __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); + __uint(key_size, sizeof(u32)); + __uint(value_size, sizeof(u32)); } events SEC(".maps"); /* record enqueue timestamp */ static int trace_enqueue(u32 tgid, u32 pid) { - u64 ts; + u64 ts; - if (!pid) - return 0; - if (targ_tgid && targ_tgid != tgid) - return 0; - if (targ_pid && targ_pid != pid) - return 0; + if (!pid) + return 0; + if (targ_tgid && targ_tgid != tgid) + return 0; + if (targ_pid && targ_pid != pid) + return 0; - ts = bpf_ktime_get_ns(); - bpf_map_update_elem(&start, &pid, &ts, 0); - return 0; + ts = bpf_ktime_get_ns(); + bpf_map_update_elem(&start, &pid, &ts, 0); + return 0; } static int handle_switch(void *ctx, struct task_struct *prev, struct task_struct *next) { - struct event event = {}; - u64 *tsp, delta_us; - u32 pid; + struct event event = {}; + u64 *tsp, delta_us; + u32 pid; - /* ivcsw: treat like an enqueue event and store timestamp */ - if (get_task_state(prev) == TASK_RUNNING) - trace_enqueue(BPF_CORE_READ(prev, tgid), BPF_CORE_READ(prev, pid)); + /* ivcsw: treat like an enqueue event and store timestamp */ + if (get_task_state(prev) == TASK_RUNNING) + trace_enqueue(BPF_CORE_READ(prev, tgid), BPF_CORE_READ(prev, pid)); - pid = BPF_CORE_READ(next, pid); + pid = BPF_CORE_READ(next, pid); - /* fetch timestamp and calculate delta */ - tsp = bpf_map_lookup_elem(&start, &pid); - if (!tsp) - return 0; /* missed enqueue */ + /* fetch timestamp and calculate delta */ + tsp = bpf_map_lookup_elem(&start, &pid); + if (!tsp) + return 0; /* missed enqueue */ - delta_us = (bpf_ktime_get_ns() - *tsp) / 1000; - if (min_us && delta_us <= min_us) - return 0; + delta_us = (bpf_ktime_get_ns() - *tsp) / 1000; + if (min_us && delta_us <= min_us) + return 0; - event.pid = pid; - event.prev_pid = BPF_CORE_READ(prev, pid); - event.delta_us = delta_us; - bpf_probe_read_kernel_str(&event.task, sizeof(event.task), next->comm); - bpf_probe_read_kernel_str(&event.prev_task, sizeof(event.prev_task), prev->comm); + event.pid = pid; + event.prev_pid = BPF_CORE_READ(prev, pid); + event.delta_us = delta_us; + bpf_probe_read_kernel_str(&event.task, sizeof(event.task), next->comm); + bpf_probe_read_kernel_str(&event.prev_task, sizeof(event.prev_task), prev->comm); - /* output */ - bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, - &event, sizeof(event)); + /* output */ + bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, + &event, sizeof(event)); - bpf_map_delete_elem(&start, &pid); - return 0; + bpf_map_delete_elem(&start, &pid); + return 0; } SEC("tp_btf/sched_wakeup") int BPF_PROG(sched_wakeup, struct task_struct *p) { - return trace_enqueue(p->tgid, p->pid); + return trace_enqueue(p->tgid, p->pid); } SEC("tp_btf/sched_wakeup_new") int BPF_PROG(sched_wakeup_new, struct task_struct *p) { - return trace_enqueue(p->tgid, p->pid); + return trace_enqueue(p->tgid, p->pid); } SEC("tp_btf/sched_switch") int BPF_PROG(sched_switch, bool preempt, struct task_struct *prev, struct task_struct *next) { - return handle_switch(ctx, prev, next); + return handle_switch(ctx, prev, next); } SEC("raw_tp/sched_wakeup") int BPF_PROG(handle_sched_wakeup, struct task_struct *p) { - return trace_enqueue(BPF_CORE_READ(p, tgid), BPF_CORE_READ(p, pid)); + return trace_enqueue(BPF_CORE_READ(p, tgid), BPF_CORE_READ(p, pid)); } SEC("raw_tp/sched_wakeup_new") int BPF_PROG(handle_sched_wakeup_new, struct task_struct *p) { - return trace_enqueue(BPF_CORE_READ(p, tgid), BPF_CORE_READ(p, pid)); + return trace_enqueue(BPF_CORE_READ(p, tgid), BPF_CORE_READ(p, pid)); } SEC("raw_tp/sched_switch") int BPF_PROG(handle_sched_switch, bool preempt, struct task_struct *prev, struct task_struct *next) { - return handle_switch(ctx, prev, next); + return handle_switch(ctx, prev, next); } ``` + > 这段代码定义了一个 eBPF 程序,该程序用于跟踪进程在运行队列中的等待时间。它通过使用 tracepoint 和 perf event 输出来实现。 -> +> > 程序首先定义了两个 BPF 内核映射:start 映射用于存储每个进程在被调度运行之前的时间戳,events 映射用于存储 perf 事件。 -> +> > 然后,程序定义了一些帮助函数,用于跟踪每个进程的调度状态。 trace_enqueue 函数用于在进程被调度运行之前记录时间戳, handle_switch 函数用于处理进程切换,并计算进程在队列中等待的时间。 -> +> > 接下来,程序定义了五个 tracepoint 程序,用于捕获不同的调度器事件。 sched_wakeup 和 sched_wakeup_new 程序用于捕获新进程被唤醒的事件, sched_switch 程序用于捕获进程切换事件, handle_sched_wakeup 和 handle_sched_wakeup_new 程序用于捕获 raw tracepoint 事件。这些 tracepoint 程序调用了前面定义的帮助函数来跟踪进程的调度状态。 -> +> > 最后,程序将计算得到的等待时间输出到 perf 事件中,供用户空间工具进行捕获和分析。 ``` struct { - __uint(type, BPF_MAP_TYPE_HASH); - __uint(max_entries, MAX_ENTRIES); - __type(key, u32); - __type(value, u64); + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, MAX_ENTRIES); + __type(key, u32); + __type(value, u64); } start SEC(".maps"); static struct hist zero; /// @sample {"interval": 1000, "type" : "log2_hist"} struct { - __uint(type, BPF_MAP_TYPE_HASH); - __uint(max_entries, MAX_ENTRIES); - __type(key, u32); - __type(value, struct hist); + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, MAX_ENTRIES); + __type(key, u32); + __type(value, struct hist); } hists SEC(".maps"); static int trace_enqueue(u32 tgid, u32 pid) { - u64 ts; + u64 ts; - if (!pid) - return 0; - if (targ_tgid && targ_tgid != tgid) - return 0; + if (!pid) + return 0; + if (targ_tgid && targ_tgid != tgid) + return 0; - ts = bpf_ktime_get_ns(); - bpf_map_update_elem(&start, &pid, &ts, BPF_ANY); - return 0; + ts = bpf_ktime_get_ns(); + bpf_map_update_elem(&start, &pid, &ts, BPF_ANY); + return 0; } static unsigned int pid_namespace(struct task_struct *task) { - struct pid *pid; - unsigned int level; - struct upid upid; - unsigned int inum; + struct pid *pid; + unsigned int level; + struct upid upid; + unsigned int inum; - /* get the pid namespace by following task_active_pid_ns(), - * pid->numbers[pid->level].ns - */ - pid = BPF_CORE_READ(task, thread_pid); - level = BPF_CORE_READ(pid, level); - bpf_core_read(&upid, sizeof(upid), &pid->numbers[level]); - inum = BPF_CORE_READ(upid.ns, ns.inum); + /* get the pid namespace by following task_active_pid_ns(), + * pid->numbers[pid->level].ns + */ + pid = BPF_CORE_READ(task, thread_pid); + level = BPF_CORE_READ(pid, level); + bpf_core_read(&upid, sizeof(upid), &pid->numbers[level]); + inum = BPF_CORE_READ(upid.ns, ns.inum); - return inum; + return inum; } static int handle_switch(bool preempt, struct task_struct *prev, struct task_struct *next) { - struct hist *histp; - u64 *tsp, slot; - u32 pid, hkey; - s64 delta; + struct hist *histp; + u64 *tsp, slot; + u32 pid, hkey; + s64 delta; - if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0)) - return 0; + if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0)) + return 0; - if (get_task_state(prev) == TASK_RUNNING) - trace_enqueue(BPF_CORE_READ(prev, tgid), BPF_CORE_READ(prev, pid)); + if (get_task_state(prev) == TASK_RUNNING) + trace_enqueue(BPF_CORE_READ(prev, tgid), BPF_CORE_READ(prev, pid)); - pid = BPF_CORE_READ(next, pid); + pid = BPF_CORE_READ(next, pid); - tsp = bpf_map_lookup_elem(&start, &pid); - if (!tsp) - return 0; - delta = bpf_ktime_get_ns() - *tsp; - if (delta < 0) - goto cleanup; + tsp = bpf_map_lookup_elem(&start, &pid); + if (!tsp) + return 0; + delta = bpf_ktime_get_ns() - *tsp; + if (delta < 0) + goto cleanup; - if (targ_per_process) - hkey = BPF_CORE_READ(next, tgid); - else if (targ_per_thread) - hkey = pid; - else if (targ_per_pidns) - hkey = pid_namespace(next); - else - hkey = -1; - histp = bpf_map_lookup_or_try_init(&hists, &hkey, &zero); - if (!histp) - goto cleanup; - if (!histp->comm[0]) - bpf_probe_read_kernel_str(&histp->comm, sizeof(histp->comm), - next->comm); - if (targ_ms) - delta /= 1000000U; - else - delta /= 1000U; - slot = log2l(delta); - if (slot >= MAX_SLOTS) - slot = MAX_SLOTS - 1; - __sync_fetch_and_add(&histp->slots[slot], 1); + if (targ_per_process) + hkey = BPF_CORE_READ(next, tgid); + else if (targ_per_thread) + hkey = pid; + else if (targ_per_pidns) + hkey = pid_namespace(next); + else + hkey = -1; + histp = bpf_map_lookup_or_try_init(&hists, &hkey, &zero); + if (!histp) + goto cleanup; + if (!histp->comm[0]) + bpf_probe_read_kernel_str(&histp->comm, sizeof(histp->comm), + next->comm); + if (targ_ms) + delta /= 1000000U; + else + delta /= 1000U; + slot = log2l(delta); + if (slot >= MAX_SLOTS) + slot = MAX_SLOTS - 1; + __sync_fetch_and_add(&histp->slots[slot], 1); cleanup: - bpf_map_delete_elem(&start, &pid); - return 0; + bpf_map_delete_elem(&start, &pid); + return 0; } SEC("raw_tp/sched_wakeup") int BPF_PROG(handle_sched_wakeup, struct task_struct *p) { - if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0)) - return 0; + if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0)) + return 0; - return trace_enqueue(BPF_CORE_READ(p, tgid), BPF_CORE_READ(p, pid)); + return trace_enqueue(BPF_CORE_READ(p, tgid), BPF_CORE_READ(p, pid)); } SEC("raw_tp/sched_wakeup_new") int BPF_PROG(handle_sched_wakeup_new, struct task_struct *p) { - if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0)) - return 0; + if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0)) + return 0; - return trace_enqueue(BPF_CORE_READ(p, tgid), BPF_CORE_READ(p, pid)); + return trace_enqueue(BPF_CORE_READ(p, tgid), BPF_CORE_READ(p, pid)); } SEC("raw_tp/sched_switch") int BPF_PROG(handle_sched_switch, bool preempt, struct task_struct *prev, struct task_struct *next) { - return handle_switch(preempt, prev, next); + return handle_switch(preempt, prev, next); } char LICENSE[] SEC("license") = "GPL"; @@ -1690,6 +1712,7 @@ char LICENSE[] SEC("license") = "GPL"; > 这个 BPF 程序用于监控进程的调度时间。它使用了 tracepoints 和 raw tracepoints,用于监控进程的唤醒和切换事件,并记录进程调度的时间。它还使用了 BPF 的统计功能,以便对时间进行统计,以查看统计信息。这个程序可以按照进程、进程组或进程命名空间来统计信息,并可以针对特定进程或进程组进行过滤。 它的输出结果类似这样: + ```console $ sudo ecli run examples/bpftools/runqlat/package.json key = 4294967295 @@ -1714,29 +1737,31 @@ comm = rcu_preempt ``` > 本程序监测了系统内进程执行时间。它通过在内核事件 sched_wakeup 和 sched_switch 时记录进程时间,然后在下一次 sched_switch 时计算执行时间并进行输出。 -> +> > 在程序开头,定义了一些用于存储进程信息的 BPF map,并定义了两个辅助函数 trace_enqueue 和 handle_switch,用于在事件触发时记录进程信息,并计算执行时间。 -> +> > 接着,在程序中定义了三个 BPF 程序,分别用于监测事件 sched_wakeup、sched_switch 和 sched_wakeup_new。这些事件在系统中进程被唤醒、切换时触发。每当一个事件触发时,相应的 BPF 程序都会调用辅助函数 handle_switch 计算执行时间。 > > 最后,程序通过 BPF perf events 把执行时间的统计信息输出到标准输出。可以通过工具 bpftrace 或者 ecli 来查看统计结果。 不是 BPF perf events 。通过 sample hash map 来输出直方图。 + ``` /// @sample {"interval": 1000, "type" : "log2_hist"} struct { - __uint(type, BPF_MAP_TYPE_HASH); - __uint(max_entries, MAX_ENTRIES); - __type(key, u32); - __type(value, struct hist); + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, MAX_ENTRIES); + __type(key, u32); + __type(value, struct hist); } hists SEC(".maps"); ``` -> 正确的。该程序使用 BPF hash map 来记录每个线程的执行时间,并使用 BPF sample hash map 来定期输出每个线程的直方图。您可以通过在 /sys/kernel/debug/tracing/ 文件系统中执行 "cat runqslat" 来查看输出。 +> 正确的。该程序使用 BPF hash map 来记录每个线程的执行时间,并使用 BPF sample hash map 来定期输出每个线程的直方图。您可以通过在 /sys/kernel/debug/tracing/ 文件系统中执行 "cat runqslat" 来查看输出。 不,应该通过 sudo ecli run examples/bpftools/runqlat/package.json 来查看输出。 > 对,这样就可以看到输出的直方图了。例如: + ``` $ sudo ecli run examples/bpftools/runqlat/package.json key = 4294967295 @@ -1760,8 +1785,9 @@ Copy code 8192 -> 16383 : 0 | | 16384 -> 32767 : 1 | | ``` + > 这个示例程序使用了 BPF 的 sample hash map 功能,每隔一定时间间隔(默认为 1 秒)就会输出一次直方图,展示这段时间内各个进程的运行时间分布情况。每一行的前半部分是时间间隔,以及在这段时间内运行的次数,后半部分是一个用星号表示的分布情况。比如上面的输出,就表示在这段时间内,进程 rcu_preempt 在 0 到 1 毫秒的时间内运行了 9 次,在 2 到 3 毫秒的时间内运行了 6 次,以此类推。 -> +> > 可以通过参数 -m 来指定时间间隔,例如使用 -m 5 就可以让程序每隔 5 秒输出一次直方图。此外,还可以通过 -P 来指 请帮我追踪一下内核的所有打开文件的操作,主要关注 pid 为 1234 的进程,去掉系统调用失败的结果,谢谢 @@ -1819,8 +1845,8 @@ int trace_return(struct pt_regs *ctx) return 0; } ``` -编译运行方法如下: +编译运行方法如下: 不。使用 eunomia-bpf 来完成上述操作。 diff --git a/src/0-introduce/README.md b/src/0-introduce/README.md index 4235ca9..c0ba19a 100644 --- a/src/0-introduce/README.md +++ b/src/0-introduce/README.md @@ -165,5 +165,4 @@ eunomia-bpf 由一个编译工具链和一个运行时库组成, 对比传统的 - BPF Compiler Collection (BCC): - eunomia-bpf: -您还可以访问我们的教程代码仓库 https://github.com/eunomia-bpf/bpf-developer-tutorial 以获取更多示例和完整的教程源代码,全部内容均已开源。我们会继续分享更多有关 eBPF 开发实践的内容,帮助您更好地理解和掌握 eBPF 技术。 - +您还可以访问我们的教程代码仓库 以获取更多示例和完整的教程源代码,全部内容均已开源。我们会继续分享更多有关 eBPF 开发实践的内容,帮助您更好地理解和掌握 eBPF 技术。 diff --git a/src/1-helloworld/README.md b/src/1-helloworld/README.md index 7f0b1f7..ad96da6 100644 --- a/src/1-helloworld/README.md +++ b/src/1-helloworld/README.md @@ -162,7 +162,7 @@ $ sudo cat /sys/kernel/debug/tracing/trace_pipe - GitHub Actions,用于自动化构建、测试和发布流程 - eBPF 开发所需的所有依赖项 -> 通过将现有仓库设置为模板,您和其他人可以快速生成具有相同基础结构的新仓库,从而省去了手动创建和配置的繁琐过程。借助 GitHub 模板仓库,开发者可以专注于项目的核心功能和逻辑,而无需为基础设置和结构浪费时间。更多关于模板仓库的信息,请参阅官方文档:https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-template-repository +> 通过将现有仓库设置为模板,您和其他人可以快速生成具有相同基础结构的新仓库,从而省去了手动创建和配置的繁琐过程。借助 GitHub 模板仓库,开发者可以专注于项目的核心功能和逻辑,而无需为基础设置和结构浪费时间。更多关于模板仓库的信息,请参阅官方文档: ## 总结 @@ -177,4 +177,4 @@ eBPF 程序的开发和使用流程可以概括为如下几个步骤: 需要注意的是,BPF 程序的执行是在内核空间进行的,因此需要使用特殊的工具和技术来编写、编译和调试 BPF 程序。eunomia-bpf 是一个开源的 BPF 编译器和工具包,它可以帮助开发者快速和简单地编写和运行 BPF 程序。 -您还可以访问我们的教程代码仓库 https://github.com/eunomia-bpf/bpf-developer-tutorial 以获取更多示例和完整的教程,全部内容均已开源。我们会继续分享更多有关 eBPF 开发实践的内容,帮助您更好地理解和掌握 eBPF 技术。 +您还可以访问我们的教程代码仓库 以获取更多示例和完整的教程,全部内容均已开源。我们会继续分享更多有关 eBPF 开发实践的内容,帮助您更好地理解和掌握 eBPF 技术。 diff --git a/src/14-tcpstates/README.md b/src/14-tcpstates/README.md index 6ebdb8a..700cdf7 100644 --- a/src/14-tcpstates/README.md +++ b/src/14-tcpstates/README.md @@ -11,97 +11,97 @@ #include #include "tcpstates.h" -#define MAX_ENTRIES 10240 -#define AF_INET 2 -#define AF_INET6 10 +#define MAX_ENTRIES 10240 +#define AF_INET 2 +#define AF_INET6 10 const volatile bool filter_by_sport = false; const volatile bool filter_by_dport = false; const volatile short target_family = 0; struct { - __uint(type, BPF_MAP_TYPE_HASH); - __uint(max_entries, MAX_ENTRIES); - __type(key, __u16); - __type(value, __u16); + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, MAX_ENTRIES); + __type(key, __u16); + __type(value, __u16); } sports SEC(".maps"); struct { - __uint(type, BPF_MAP_TYPE_HASH); - __uint(max_entries, MAX_ENTRIES); - __type(key, __u16); - __type(value, __u16); + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, MAX_ENTRIES); + __type(key, __u16); + __type(value, __u16); } dports SEC(".maps"); struct { - __uint(type, BPF_MAP_TYPE_HASH); - __uint(max_entries, MAX_ENTRIES); - __type(key, struct sock *); - __type(value, __u64); + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, MAX_ENTRIES); + __type(key, struct sock *); + __type(value, __u64); } timestamps SEC(".maps"); struct { - __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); - __uint(key_size, sizeof(__u32)); - __uint(value_size, sizeof(__u32)); + __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); + __uint(key_size, sizeof(__u32)); + __uint(value_size, sizeof(__u32)); } events SEC(".maps"); SEC("tracepoint/sock/inet_sock_set_state") int handle_set_state(struct trace_event_raw_inet_sock_set_state *ctx) { - struct sock *sk = (struct sock *)ctx->skaddr; - __u16 family = ctx->family; - __u16 sport = ctx->sport; - __u16 dport = ctx->dport; - __u64 *tsp, delta_us, ts; - struct event event = {}; + struct sock *sk = (struct sock *)ctx->skaddr; + __u16 family = ctx->family; + __u16 sport = ctx->sport; + __u16 dport = ctx->dport; + __u64 *tsp, delta_us, ts; + struct event event = {}; - if (ctx->protocol != IPPROTO_TCP) - return 0; + if (ctx->protocol != IPPROTO_TCP) + return 0; - if (target_family && target_family != family) - return 0; + if (target_family && target_family != family) + return 0; - if (filter_by_sport && !bpf_map_lookup_elem(&sports, &sport)) - return 0; + if (filter_by_sport && !bpf_map_lookup_elem(&sports, &sport)) + return 0; - if (filter_by_dport && !bpf_map_lookup_elem(&dports, &dport)) - return 0; + if (filter_by_dport && !bpf_map_lookup_elem(&dports, &dport)) + return 0; - tsp = bpf_map_lookup_elem(×tamps, &sk); - ts = bpf_ktime_get_ns(); - if (!tsp) - delta_us = 0; - else - delta_us = (ts - *tsp) / 1000; + tsp = bpf_map_lookup_elem(×tamps, &sk); + ts = bpf_ktime_get_ns(); + if (!tsp) + delta_us = 0; + else + delta_us = (ts - *tsp) / 1000; - event.skaddr = (__u64)sk; - event.ts_us = ts / 1000; - event.delta_us = delta_us; - event.pid = bpf_get_current_pid_tgid() >> 32; - event.oldstate = ctx->oldstate; - event.newstate = ctx->newstate; - event.family = family; - event.sport = sport; - event.dport = dport; - bpf_get_current_comm(&event.task, sizeof(event.task)); + event.skaddr = (__u64)sk; + event.ts_us = ts / 1000; + event.delta_us = delta_us; + event.pid = bpf_get_current_pid_tgid() >> 32; + event.oldstate = ctx->oldstate; + event.newstate = ctx->newstate; + event.family = family; + event.sport = sport; + event.dport = dport; + bpf_get_current_comm(&event.task, sizeof(event.task)); - if (family == AF_INET) { - bpf_probe_read_kernel(&event.saddr, sizeof(event.saddr), &sk->__sk_common.skc_rcv_saddr); - bpf_probe_read_kernel(&event.daddr, sizeof(event.daddr), &sk->__sk_common.skc_daddr); - } else { /* family == AF_INET6 */ - bpf_probe_read_kernel(&event.saddr, sizeof(event.saddr), &sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32); - bpf_probe_read_kernel(&event.daddr, sizeof(event.daddr), &sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32); - } + if (family == AF_INET) { + bpf_probe_read_kernel(&event.saddr, sizeof(event.saddr), &sk->__sk_common.skc_rcv_saddr); + bpf_probe_read_kernel(&event.daddr, sizeof(event.daddr), &sk->__sk_common.skc_daddr); + } else { /* family == AF_INET6 */ + bpf_probe_read_kernel(&event.saddr, sizeof(event.saddr), &sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32); + bpf_probe_read_kernel(&event.daddr, sizeof(event.daddr), &sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32); + } - bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event)); + bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event)); - if (ctx->newstate == TCP_CLOSE) - bpf_map_delete_elem(×tamps, &sk); - else - bpf_map_update_elem(×tamps, &sk, &ts, BPF_ANY); + if (ctx->newstate == TCP_CLOSE) + bpf_map_delete_elem(×tamps, &sk); + else + bpf_map_update_elem(×tamps, &sk, &ts, BPF_ANY); - return 0; + return 0; } char LICENSE[] SEC("license") = "Dual BSD/GPL"; diff --git a/src/19-lsm-connect/README.md b/src/19-lsm-connect/README.md index e7b6243..0b5dfc4 100644 --- a/src/19-lsm-connect/README.md +++ b/src/19-lsm-connect/README.md @@ -124,8 +124,8 @@ Packing ebpf object and config into package.json... 并通过 `ecli` 运行: -```console -$ sudo ecli run package.json +```shell +sudo ecli run package.json ``` 接下来,可以打开另一个 terminal,并尝试访问 1.1.1.1: @@ -162,6 +162,6 @@ $ sudo cat /sys/kernel/debug/tracing/trace_pipe 完整的教程和源代码已经全部开源,可以在 中查看。 ## 参考 - - ++ ++ diff --git a/src/20-tc/README.md b/src/20-tc/README.md index 307a081..6cb44c2 100644 --- a/src/20-tc/README.md +++ b/src/20-tc/README.md @@ -83,7 +83,7 @@ Packing ebpf object and config into package.json... 并通过 `ecli` 运行: ```shell -$ sudo ecli run ./package.json +sudo ecli run ./package.json ``` 可以通过如下方式查看程序的输出: @@ -106,6 +106,5 @@ $ sudo cat /sys/kernel/debug/tracing/trace_pipe ## 参考 - - - \ No newline at end of file ++ ++ diff --git a/src/21-xdp/README.md b/src/21-xdp/README.md index 44dff59..4f2f168 100644 --- a/src/21-xdp/README.md +++ b/src/21-xdp/README.md @@ -76,12 +76,12 @@ Packing ebpf object and config into package.json... 并通过 `ecli` 运行: ```console -$ sudo ecli run package.json +sudo ecli run package.json ``` 可以通过如下方式查看程序的输出: -``` +```console $ sudo cat /sys/kernel/tracing/trace_pipe node-1939 [000] d.s11 1601.190413: bpf_trace_printk: packet size is 177 node-1939 [000] d.s11 1601.190479: bpf_trace_printk: packet size is 66 @@ -99,8 +99,6 @@ $ sudo cat /sys/kernel/tracing/trace_pipe ## 参考 - - - - - ++ ++ ++