教程:Tracing01 - 监控 xdp 跟踪点
在本课中,我们将展示如何创建和加载挂钩到 xdp:exception 跟踪点的 eBPF 程序,并将其值获取到用户空间统计应用程序。
XDP 跟踪点
eBPF 程序也可以附加到跟踪点。有几个与 xdp 跟踪点子系统相关的跟踪点:
ls /sys/kernel/debug/tracing/events/xdp/
xdp_cpumap_enqueue
xdp_cpumap_kthread
xdp_devmap_xmit
xdp_exception
xdp_redirect
xdp_redirect_err
xdp_redirect_map
xdp_redirect_map_err跟踪点程序节
bpf 库期望跟踪点 eBPF 程序存储在具有以下名称的节中:
tracepoint/<sys>/<tracepoint>其中 <sys> 是跟踪点子系统,<tracepoint> 是跟踪点名称, 可以使用以下结构完成:
SEC("tracepoint/xdp/xdp_exception")
int trace_xdp_exception(struct xdp_exception_ctx *ctx)跟踪点参数
有一个程序指针参数指向定义跟踪点字段的结构。
例如对于 xdp:xdp_exception 跟踪点:
struct xdp_exception_ctx {
__u64 __pad; // 前 8 个字节不能被 bpf 代码访问
__s32 prog_id; // offset:8; size:4; signed:1;
__u32 act; // offset:12; size:4; signed:0;
__s32 ifindex; // offset:16; size:4; signed:1;
};
int trace_xdp_exception(struct xdp_exception_ctx *ctx)此结构在跟踪点格式文件中导出:
# cat /sys/kernel/debug/tracing/events/xdp/xdp_exception/format
...
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;
field:int prog_id; offset:8; size:4; signed:1;
field:u32 act; offset:12; size:4; signed:0;
field:int ifindex; offset:16; size:4; signed:1;
...跟踪点附加
要为此示例加载跟踪点程序,我们使用以下 bpf 库辅助函数:
bpf_object__open_file(cfg->filename, NULL);bpf_object__load(obj);要将程序附加到跟踪点,我们需要创建一个跟踪点 perf 事件,并使用其 文件描述符将 eBPF 程序附加到它。在底层,此函数设置 PERF_EVENT_IOC_SET_BPF ioctl 调用:
bpf_program__attach_tracepoint(prog, "xdp", "xdp_exception");请查看 trace_load_and_stats.c 中的 load_bpf_and_trace_attach 函数 了解所有细节。
HASH 映射
此示例使用 PERCPU HASH 映射,存储每个接口的中止数据包数量:
struct {
__uint(type, BPF_MAP_TYPE_PERCPU_HASH);
__type(key, __s32);
__type(value, __u64);
__uint(max_entries, 10);
} xdp_stats_map SEC(".maps");接口与 ARRAY 映射类似,除了如果元素不存在,我们需要在哈希中 专门创建新元素:
/* 在内核 BPF 端查找返回指向实际数据的指针。 */
valp = bpf_map_lookup_elem(&xdp_stats_map, &key);
/* 如果没有接口的记录,我们需要创建一个,
* 数据包数 == 1
*/
if (!valp) {
__u64 one = 1;
return bpf_map_update_elem(&xdp_stats_map, &key, &one, 0) ? 1 : 0;
}
(*valp)++;请查看 trace_prog_kern.c 了解完整代码。
作业
作业 1:设置测试环境
在本课中,我们将使用前一课的设置: Basic02 - 按名称加载程序 https://github.com/xdp-project/xdp-tutorial/tree/master/basic02-prog-by-name#assignment-2-add-xdp_abort-program
并从 xdp_prog_kern.o 加载 XDP 程序,它将中止每个传入的数据包:
SEC("xdp_abort")
int xdp_drop_func(struct xdp_md *ctx)
{
return XDP_ABORTED;
}使用 xdp-loader: 作业 2:添加 xdp_abort 程序 https://github.com/xdp-project/xdp-tutorial/tree/master/basic02-prog-by-name#assignment-2-add-xdp_abort-program
设置环境:
$ sudo ../testenv/testenv.sh setup --name veth-basic02加载产生中止数据包的 XDP 程序:
$ sudo xdp-loader load veth-basic02 xdp_prog_kern.o -n xdp_drop_func并生成一些数据包:
$ sudo ../testenv/testenv.sh enter --name veth-basic02
# ping fc00:dead:cafe:1::1
PING fc00:dead:cafe:1::1(fc00:dead:cafe:1::1) 56 data bytes作业 2:加载跟踪点监控程序
现在当你运行 trace_load_and_stats 应用程序时,它将加载并附加 跟踪点 eBPF 程序,并显示每个接口的中止数据包数量:
# ./trace_load_and_stats
Success: Loaded BPF-object(trace_prog_kern.o)
Collecting stats from BPF map
- BPF map (bpf_map_type:1) id:46 name:xdp_stats_map key_size:4 value_size:4 max_entries:10
veth-basic02 (2)
veth-basic02 (4)
veth-basic02 (6)
...