ebpf初学者问题:bpf_trace_printk导致错误?

ebpf beginner question: bpf_trace_printk causing error?

我是 ebpf 的新手,正在尝试使用 ebpf 检查 tcp 数据包。

我在 tcp_v4_rcv() 上连接了 kprobe,我的程序如下(只是修改了一个 helloworld 程序):

//hello_kern.c

#include <linux/tcp.h>
#include <uapi/linux/bpf.h>
#include <uapi/linux/tcp.h>
#include "bpf_helpers.h"

SEC("kprobe/tcp_v4_rcv")
int bpf_prog(void *ctx, struct sk_buff* skb)
{
    struct tcphdr* th;
    int dest;
    char msg[] = "hello world! My dest is %d\n";

    th = tcp_hdr(skb);
    dest = th->dest;
    bpf_trace_printk(msg, sizeof(msg), dest); //comment this line can make program run
    return 0;
}

char _license[] SEC("license") = "GPL";
//hello_user.c

#include "bpf_load.h"

int main(void)
{
    if (load_bpf_file("hello_kern.o"))
        return -1;
    read_trace_pipe();

    return 0;
}

编译就好了。但是当我运行这个程序时,发生了以下错误:

bpf_load_program() err=13
0: (b7) r1 = 680997
1: (63) *(u32 *)(r10 -8) = r1
2: (18) r1 = 0x2073692074736564
4: (7b) *(u64 *)(r10 -16) = r1
5: (18) r1 = 0x20794d2021646c72
7: (7b) *(u64 *)(r10 -24) = r1
8: (18) r1 = 0x6f77206f6c6c6568
10: (7b) *(u64 *)(r10 -32) = r1
11: (69) r1 = *(u16 *)(r2 +178)
R2 !read_ok
processed 9 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0

我尝试注释“bpf_trace_printk”这一行,并且只成功编程 运行(没有打印出任何内容)。我用错了bpf_trace_printk吗?

顺便说一句,有没有组织良好的 ebpf 教程或文档我可以参考?我只能找到一些教程博客。如果有人知道请告诉我。谢谢:)

反正我试了很多次,下面的代码终于可以用了。

要点: 1. 使用bpf_probe_read读取内核中的地址space; 2. 不要使用tcp_hdr().

#include <linux/tcp.h>
#include <linux/skbuff.h>
#include <uapi/linux/bpf.h>
#include <uapi/linux/tcp.h>
#include "bpf_helpers.h"

SEC("kprobe/tcp_v4_rcv")
int bpf_prog(struct pt_regs *ctx)
{
    struct sk_buff *skb= (struct sk_buff *)PT_REGS_PARM1(ctx);

    struct tcphdr *th;
    unsigned short dest;
    char msg[] = "hello world! My dest is %u\n";

    bpf_probe_read(&th, sizeof(struct tcphdr *), &(skb->data));
    // bpf_probe_read(th, sizeof(struct tcphdr *), (skb->data)); Wrong! idk why.
    bpf_probe_read(&dest, sizeof(unsigned short), &(th->dest));
    bpf_trace_printk(msg, sizeof(msg), ntohs(dest));
    return 0;
}

char _license[] SEC("license") = "GPL";