ebpf开发笔记
ebpf开发笔记
内核函数 Hook
Kprobe
Kprobe 是一种动态追踪技术,允许您在几乎所有内核函数的入口和返回点插入探针。这使得它成为 eBPF 程序中最常用的 Hook 点之一。
验证函数是否可以 Hook
在开发 eBPF 程序之前,需要确认目标内核函数是否存在且可以被 Hook:
1
cat /proc/kallsyms | grep nf_nat_ipv4_manip_pkt
查看 Tracepoint 格式
在使用 tracepoint 时,需要了解其数据格式:
1
cat /sys/kernel/debug/tracing/events/sock/inet_sock_set_state/format
Ref:
- https://mozillazg.com/2022/05/ebpf-libbpf-raw-tracepoint-common-questions.html#hidsec
系统信息获取
进程和线程信息
在 eBPF 程序中,经常需要获取当前进程和线程的信息:
1
2
3
4
5
// 获取当前线程ID
__u32 tid = bpf_get_current_pid_tgid();
// 获取当前进程ID(通过右移32位获取)
__u32 pid = bpf_get_current_pid_tgid() >> 32;
说明:
bpf_get_current_pid_tgid()
返回一个64位的值- 低32位是线程ID (tid)
- 高32位是进程ID (pid)
- 在Linux中,线程也被视为轻量级进程,tid实际上是线程的进程ID
CPU信息
获取当前CPU的ID:
1
2
// 获取当前CPU的ID
__u32 cid = bpf_get_smp_processor_id();
说明:
bpf_get_smp_processor_id()
返回当前正在执行eBPF程序的CPU编号- 这个值在SMP(对称多处理器)系统中特别有用
- 可以用于分析负载分布或实现per-CPU的数据结构
调试技巧
直接打印调试信息
在 eBPF 程序开发过程中,相比使用复杂的 map 和 perf 输出机制,可以使用 bpf_printk
快速打印调试信息:
1
2
3
4
#include <bpf/bpf_helpers.h>
// 在 Hook 函数中使用
bpf_printk("hook here...");
查看调试输出:
1
sudo cat /sys/kernel/debug/tracing/trace_pipe
注意:这种方式输出的信息不会打印到标准输出,而是通过管道输出到用户空间。
Ref:
https://docs.ebpf.io/ebpf-library/libbpf/ebpf/bpf_printk/
https://docs.ebpf.io/linux/helper-function/bpf_trace_printk/
数据处理
字节序转换
内核空间
内核中的网络相关数据通常使用大端序(Big Endian)存储,数据类型通常标记为 be16
、be32
等。
1
2
// 端口号转换(大端序到主机字节序)
event.R_port = bpf_ntohs(event.R_port);
用户空间
在用户空间进行字节序转换需要使用 arpa/inet.h
提供的函数:
1
2
3
4
5
6
7
8
#include <arpa/inet.h>
// 端口号转换
uint16_t port = ntohs(_event->R_port);
// IP 地址转换
unsigned int ip = 3232252161;
ip = htonl(ip);
IP 地址转换
将 IP 地址转换为字符串格式:
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <arpa/inet.h>
// IPv4 地址转换
char local_ip[INET_ADDRSTRLEN];
char external_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &_event->L_ip_v4, local_ip, sizeof(local_ip));
inet_ntop(AF_INET, &_event->R_ip_v4, external_ip, sizeof(external_ip));
// IPv6 地址转换
char local_ip[INET6_ADDRSTRLEN];
char external_ip[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &_event->L_ip_v6, local_ip, sizeof(local_ip));
inet_ntop(AF_INET6, &_event->R_ip_v6, external_ip, sizeof(external_ip));
This post is licensed under CC BY 4.0 by the author.