eBPF(4)--tracepoint程序类型

寻找插桩点

# 列出所有 tracepoint 插桩点
bpftrace -l "tracepoint:*:*"

确定函数上下文

跟踪点程序的上下文是指向结构体的指针,每个跟踪事件的上下文都不相同,通过如下命令可读取到对应事件的上下文

cat /sys/kernel/tracing/events/sched/sched_process_exec/format

# 一般输出如下
name: sched_process_exec
ID: 322
# 下面每一行就是一个参数,也代表了插桩点的上下文
format:
	# 这一个区域不能在bpf中进行输出
	field:unsigned short common_type;	offset:0;	size:2;	signed:0;
	field:unsigned char common_flags;	offset:2;	size:1;	signed:0;
	field:unsigned char common_preempt_count;	offset:3;	size:1;	signed:0;
	field:int common_pid;	offset:4;	size:4;	signed:1;

	# 这个区域的参数可以在bpf程序中进行输出
	field:__data_loc char[] filename;	offset:8;	size:4;	signed:0;
	field:pid_t pid;	offset:12;	size:4;	signed:1;
	field:pid_t old_pid;	offset:16;	size:4;	signed:1;

print fmt: "filename=%s pid=%d old_pid=%d", __get_str(filename), REC->pid, REC->old_pid

定义插桩函数

自定义上下文

根据函数上下文可以重构上下文结构体,并定义插桩函数:

// 根据上下文重构结构体
struct raw_exec_ctx {
	u16 common_type;
	u8 common_flags;
	u8 common_preempt_count;
	int common_pid;

	u32 __data_loc_filename;
	pid_t pid;
	pid_t old_pid;
};

SEC("tp/sched/sched_process_exec")
int handle_exec(struct raw_exec_ctx *ctx)
{
	...
        
    bpf_printk("filename:%d pid:%d old_pid:%d\n", ctx->__data_loc_filename, ctx->pid, ctx->old_pid);

    ...
        
    return 0;
}

使用vmlinux定义好的上下文

在 vmlinux.h 中也会定义部分 tracepoint 插桩点的上下文结构体,一般定义格式为`trace_event_raw_*`,`*`表示要插桩的函数,但 vmlinux.h 中不一定定义了所有的插桩函数上下文结构体,所以推荐还是使用自定义上下文。

SEC("tp/sched/sched_process_exec")
int handle_exec(struct trace_event_raw_sched_process_exec *ctx)
{
	...

    bpf_printk("filename:%d pid:%d old_pid:%d\n", ctx->__data_loc_filename, ctx->pid, ctx->old_pid);

    ...
        
    return 0;
}

### eBPF 程序类型及其用途 #### 1. Socket 过滤器 (Socket Filters) 这类程序用于过滤到达套接字的数据包。通过挂载到特定的 socket 上,能够决定哪些数据包应该传递给应用程序,哪些应当被丢弃。这使得开发者能够在应用层面上实现高效的流量控制机制。 ```c SEC("socket") int sock_filter(struct __sk_buff *skb) { // 对传入的数据包执行某些操作... } ``` 这种类型的 BPF 程序可以直接访问 `struct __sk_buff` 提供的信息[^3],从而允许对网络数据包的内容进行深入分析和处理。 #### 2. Kprobe 和 Uprobes Kprobes 允许在内核函数入口处插入探测点;Uprobes 则是在用户空间进程中设置断点。这两种探针都可以触发关联的 BPF 程序运行,以便收集性能统计数据或调试信息。 ```c // 定义一个kprobe事件处理器 SEC("kprobe/do_sys_open") int handle_do_sys_open(struct pt_regs *ctx){ // 执行日志记录或其他动作... } // 用户态uprobe示例 SEC("uprobe/bin/bash:/usr/bin/bash:do_execve") int uprobe_handler(struct pt_regs *ctx, const char *filename) { // 处理execve调用... } ``` 此类程序对于追踪系统行为非常有用,并且可以通过 bpftool 工具与 kallsyms 结合使用来解析辅助函数地址[^1]。 #### 3. TC Classifier and Action Programs TC(Traffic Control)分类器负责根据预定义规则区分不同类别的网络流;而动作程序则决定了如何处置这些已分类的数据包——比如重新路由、修改报文头部等。两者共同作用于Linux Traffic Control子系统之上。 ```bash # 使用tc命令加载ebpf程序作为qdisc的一部分 $ tc qdisc add dev eth0 clsact $ tc filter add dev eth0 ingress bpf da obj classifier.o sec prog ``` 上述配置将使指定网卡上的所有进入流量经过由 ebpf 编写的分类逻辑判断后再做相应处理。 #### 4. XDP (eXpress Data Path) XDP 是一种位于驱动层面的工作模式,它让 BPF 程序尽可能早地介入到数据接收路径当中,以此获得极低延迟下的高性能表现。适用于构建高速防火墙、DDoS防护等功能模块。 ```c SEC("xdp") int xdp_drop_all(struct xdp_md *ctx) { return XDP_DROP; } ``` 此代码片段展示了一个简单的 XDP 程序实例,该程序会无条件拒绝所有收到的数据帧。 #### 5. Tracepoints Tracepoint 类型的 BPF 程序可以附加到预先设定好的跟踪点上,当达到某个感兴趣的事件时就会激活对应的回调函数。这种方式提供了轻量级的日志记录能力而不必担心引入过多开销。 ```c SEC("tracepoint/block:block_rq_issue") int trace_block_request(struct trace_event_raw_block_rq *ctx) { // 记录磁盘I/O请求详情... } ``` 以上就是几种常见的 eBPF 应用场景概述。每种类型都有其独特的优势所在,可以根据实际需求灵活选用合适的方案来进行开发实践。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值