【问题标题】:Attach eBPF bytecode to SOCK_STREAM socket将 eBPF 字节码附加到 SOCK_STREAM 套接字
【发布时间】:2019-04-22 07:23:15
【问题描述】:

我在这个例子中使用https://elixir.bootlin.com/linux/v4.9.137/source/samples/bpf/sockex3_kern.c,但是我使用普通的AF_INET6/SOCK_STREAM和BPF_PROG_TYPE_SOCKET_FILTER而不是RAW套接字。

我不明白为什么用 load_half 来读取 proto。前 32 位是长度字段:

SEC("socket/0")
int bpf_prog(struct __sk_buff *skb)
{
    __u32 proto = load_half(skb, 12);

    char fmt[] = "PROTO %x\n";
    bpf_trace_printk(fmt, sizeof(fmt), proto);
}

或者如果我尝试这样做:

SEC("socket/0")
int bpf_prog(struct __sk_buff *skb)
{
    u64 proto = load_half(skb, 12);
    char fmt[] = "PROTO %x %u\n";
    void *data = (void *)(long)skb->data;
    struct ethhdr *eth = data;
    void *data_end = (void *)(long)skb->data_end;
    ...
}

我收到“无效的 bpf_context 访问关闭=80 大小=4”错误。据我了解,我应该从此处的“数据”字段中读取所有数据。

那么,也许有人可以告诉我当前 sk_buff 的前 34 个字节(eth + ip 标头)在哪里修剪?在 tcp_v4_rcv 的某个地方?

是否可以使用 SOCK_STREAM 套接字访问 IP 标头字段?

UPD: 看起来没有办法直接从过滤器访问数据:

https://elixir.bootlin.com/linux/v4.9.137/source/net/core/filter.c#L2647

switch (off) {
case offsetof(struct __sk_buff, tc_classid):
case offsetof(struct __sk_buff, data):
case offsetof(struct __sk_buff, data_end):
    return false;
}

【问题讨论】:

    标签: linux sockets kernel bpf


    【解决方案1】:

    根据最新的内核来源,协议是 16 字节偏移,而不是 12!

    https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/bpf.h#L2305

    【讨论】:

    • 谢谢,我用的是4.9内核版本。
    • 4.9.137 中的相同内容。他们说“只能将新字段添加到此结构的末尾” - 他们几乎没有在 4.19 的开头添加新字段:elixir.bootlin.com/linux/v4.9.137/source/include/uapi/linux/…
    • load_half() 转换为“绝对加载”类型的指令,该指令实际上从数据包数据的开头获取偏移量,而不是在struct __sk_buff 中(例如skb->data 而不是skb) .因此,在这种情况下,偏移量 12 是 ethertype 字段的正确偏移量,位于 MAC 目标地址和源地址之后。
    • @Qeole 我认为您应该将您的评论变成答案。它回答了 OP 的所有问题。
    • @pchaigno 这很有帮助,但仅适用于 RAW 套接字。我找不到修剪 eth/ip 级别的位置。
    猜你喜欢
    • 2021-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-16
    • 2023-03-05
    • 2021-08-26
    • 2021-03-21
    • 2017-09-29
    相关资源
    最近更新 更多