eBPF 的 perf_submit() 也可以用在 socket_filter 程序中吗?
Can eBPF's perf_submit() be used in a socket_filter program as well?
所以我尝试使用 perf_submit.
从内核 space 程序向用户 space 程序发送一些数据
我做了一些研究,在这里(https://github.com/iovisor/bcc/issues/2423),yonghong-song 回答(最后一条评论)socket_filter 程序无法访问 bpf_perf_event_output 助手,因此它只能用于跟踪程序类型。
但是,在 BCC 参考站点 (https://github.com/iovisor/bcc/blob/master/docs/reference_guide.md#2-bpf_perf_output) 上,如果您按 ctrl+f 并搜索 : 3. perf_submit()
, 它在第五行说 "for SOCKET_FILTER programs, the struct __sk_buff *skb must be used instead."
我相信这意味着 perf_submit() 也可以用于 socket_filter 程序?
所以我很难确定 perf_submit() 是否确实可以用于套接字过滤器程序。可能宋永红回答了上面的问题后又增加了一些功能?
我正在检查 perf_submit() 是否可以与套接字过滤器一起使用,实际上并没有一行代码可以获取 perf_submit 输出的数据,因为只是 addint perf_submit ()在内核程序中已经遗漏了一个错误。
这是我的程序的代码:
from bcc import BPF
# Network interface to be monoitored
INTERFACE = "br-netrome"
bpf_text = """
#include <uapi/linux/ptrace.h>
#include <net/sock.h>
#include <bcc/proto.h>
#include <linux/bpf.h>
#define IP_TCP 6
#define IP_UDP 17
#define IP_ICMP 1
#define ETH_HLEN 14
BPF_PERF_OUTPUT(events); // has to be delcared outside any function
int packet_monitor(struct __sk_buff *skb) {
u8 *cursor = 0;
u64 saddr;
u64 daddr;
u64 ttl;
u64 hchecksum;
struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
if (!(ethernet -> type == 0x0800)) {
return 0; // drop
}
struct ip_t *ip = cursor_advance(cursor, sizeof(*ip));
/*
if (ip->nextp != IP_TCP)
{
if (ip -> nextp != IP_UDP)
{
if (ip -> nextp != IP_ICMP)
return 0;
}
}
*/
saddr = ip -> src;
daddr = ip -> dst;
ttl = ip -> ttl;
hchecksum = ip -> hchecksum;
events.perf_submit(skb, &saddr, sizeof(saddr));
// bpf_trace_printk("saddr = %llu, daddr = %llu, ttl = %llu", saddr, daddr, ttl); // only three arguments can be passed using printk
// bpf_trace_printk("Incoming packet!!\n");
return -1;
}
这是错误代码:
R0=inv2048 R6=ctx(id=0,off=0,imm=0) R7=inv0 R10=fp0,call_-1
4: (20) r0 = *(u32 *)skb[26]
5: (7b) *(u64 *)(r10 -8) = r0
6: (18) r2 = 0xffff9bde204ffa00
8: (18) r7 = 0xffffffff
10: (bf) r4 = r10
11: (07) r4 += -8
12: (bf) r1 = r6
13: (18) r3 = 0xffffffff
15: (b7) r5 = 8
16: (85) call bpf_perf_event_output#25
unknown func bpf_perf_event_output#25
Traceback (most recent call last):
File "packet_monitor.py", line 68, in <module>
function_skb_matching = bpf.load_func("packet_monitor", BPF.SOCKET_FILTER)
File "/usr/lib/python2.7/dist-packages/bcc/__init__.py", line 397, in load_func
(func_name, errstr))
TL;DR. BPF_PROG_TYPE_SOCKET_FILTER
类型的 BPF 程序只能使用 bpf_perf_event_output
starting with Linux 5.4.
给定的 BPF 程序可以访问哪些助手由对象 struct bpf_verifier_ops
的 get_func_proto
成员定义。可以通过读取函数find_prog_type()
and file bpf_types.h
. In the case of BPF_PROG_TYPE_SOCKET_FILTER
, the corresponding function is sk_filter_func_proto()
.
找到哪个bpf_verifier_ops
对象对应哪个程序类型
如果你 git blame
在最近的内核源代码上运行该功能,你将得到类似下面的东西(你可以用 GitHub 的 blame 功能做同样的事情):
$ git blame net/core/filter.c
[...]
2492d3b867043 (Daniel Borkmann 2017-01-24 01:06:27 +0100 6080) static const struct bpf_func_proto *
5e43f899b03a3 (Andrey Ignatov 2018-03-30 15:08:00 -0700 6081) sk_filter_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
2492d3b867043 (Daniel Borkmann 2017-01-24 01:06:27 +0100 6082) {
2492d3b867043 (Daniel Borkmann 2017-01-24 01:06:27 +0100 6083) switch (func_id) {
2492d3b867043 (Daniel Borkmann 2017-01-24 01:06:27 +0100 6084) case BPF_FUNC_skb_load_bytes:
2492d3b867043 (Daniel Borkmann 2017-01-24 01:06:27 +0100 6085) return &bpf_skb_load_bytes_proto;
4e1ec56cdc597 (Daniel Borkmann 2018-05-04 01:08:15 +0200 6086) case BPF_FUNC_skb_load_bytes_relative:
4e1ec56cdc597 (Daniel Borkmann 2018-05-04 01:08:15 +0200 6087) return &bpf_skb_load_bytes_relative_proto;
91b8270f2a4d1 (Chenbo Feng 2017-03-22 17:27:34 -0700 6088) case BPF_FUNC_get_socket_cookie:
91b8270f2a4d1 (Chenbo Feng 2017-03-22 17:27:34 -0700 6089) return &bpf_get_socket_cookie_proto;
6acc5c2910689 (Chenbo Feng 2017-03-22 17:27:35 -0700 6090) case BPF_FUNC_get_socket_uid:
6acc5c2910689 (Chenbo Feng 2017-03-22 17:27:35 -0700 6091) return &bpf_get_socket_uid_proto;
7c4b90d79d0f4 (Allan Zhang 2019-07-23 17:07:24 -0700 6092) case BPF_FUNC_perf_event_output:
7c4b90d79d0f4 (Allan Zhang 2019-07-23 17:07:24 -0700 6093) return &bpf_skb_event_output_proto;
2492d3b867043 (Daniel Borkmann 2017-01-24 01:06:27 +0100 6094) default:
2492d3b867043 (Daniel Borkmann 2017-01-24 01:06:27 +0100 6095) return bpf_base_func_proto(func_id);
2492d3b867043 (Daniel Borkmann 2017-01-24 01:06:27 +0100 6096) }
2492d3b867043 (Daniel Borkmann 2017-01-24 01:06:27 +0100 6097) }
[...]
如您所见,BPF_FUNC_perf_event_output
最近才添加到这些 BPF 程序可以调用的助手列表中。添加此支持的提交 7c4b90d79d0f4
已合并到 Linux v5.4:
$ git describe --contains 7c4b90d79d0f4
v5.4-rc1~131^2~248^2~20
所以我尝试使用 perf_submit.
从内核 space 程序向用户 space 程序发送一些数据我做了一些研究,在这里(https://github.com/iovisor/bcc/issues/2423),yonghong-song 回答(最后一条评论)socket_filter 程序无法访问 bpf_perf_event_output 助手,因此它只能用于跟踪程序类型。
但是,在 BCC 参考站点 (https://github.com/iovisor/bcc/blob/master/docs/reference_guide.md#2-bpf_perf_output) 上,如果您按 ctrl+f 并搜索 : 3. perf_submit() , 它在第五行说 "for SOCKET_FILTER programs, the struct __sk_buff *skb must be used instead." 我相信这意味着 perf_submit() 也可以用于 socket_filter 程序?
所以我很难确定 perf_submit() 是否确实可以用于套接字过滤器程序。可能宋永红回答了上面的问题后又增加了一些功能?
我正在检查 perf_submit() 是否可以与套接字过滤器一起使用,实际上并没有一行代码可以获取 perf_submit 输出的数据,因为只是 addint perf_submit ()在内核程序中已经遗漏了一个错误。
这是我的程序的代码:
from bcc import BPF
# Network interface to be monoitored
INTERFACE = "br-netrome"
bpf_text = """
#include <uapi/linux/ptrace.h>
#include <net/sock.h>
#include <bcc/proto.h>
#include <linux/bpf.h>
#define IP_TCP 6
#define IP_UDP 17
#define IP_ICMP 1
#define ETH_HLEN 14
BPF_PERF_OUTPUT(events); // has to be delcared outside any function
int packet_monitor(struct __sk_buff *skb) {
u8 *cursor = 0;
u64 saddr;
u64 daddr;
u64 ttl;
u64 hchecksum;
struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
if (!(ethernet -> type == 0x0800)) {
return 0; // drop
}
struct ip_t *ip = cursor_advance(cursor, sizeof(*ip));
/*
if (ip->nextp != IP_TCP)
{
if (ip -> nextp != IP_UDP)
{
if (ip -> nextp != IP_ICMP)
return 0;
}
}
*/
saddr = ip -> src;
daddr = ip -> dst;
ttl = ip -> ttl;
hchecksum = ip -> hchecksum;
events.perf_submit(skb, &saddr, sizeof(saddr));
// bpf_trace_printk("saddr = %llu, daddr = %llu, ttl = %llu", saddr, daddr, ttl); // only three arguments can be passed using printk
// bpf_trace_printk("Incoming packet!!\n");
return -1;
}
这是错误代码:
R0=inv2048 R6=ctx(id=0,off=0,imm=0) R7=inv0 R10=fp0,call_-1
4: (20) r0 = *(u32 *)skb[26]
5: (7b) *(u64 *)(r10 -8) = r0
6: (18) r2 = 0xffff9bde204ffa00
8: (18) r7 = 0xffffffff
10: (bf) r4 = r10
11: (07) r4 += -8
12: (bf) r1 = r6
13: (18) r3 = 0xffffffff
15: (b7) r5 = 8
16: (85) call bpf_perf_event_output#25
unknown func bpf_perf_event_output#25
Traceback (most recent call last):
File "packet_monitor.py", line 68, in <module>
function_skb_matching = bpf.load_func("packet_monitor", BPF.SOCKET_FILTER)
File "/usr/lib/python2.7/dist-packages/bcc/__init__.py", line 397, in load_func
(func_name, errstr))
TL;DR. BPF_PROG_TYPE_SOCKET_FILTER
类型的 BPF 程序只能使用 bpf_perf_event_output
starting with Linux 5.4.
给定的 BPF 程序可以访问哪些助手由对象 struct bpf_verifier_ops
的 get_func_proto
成员定义。可以通过读取函数find_prog_type()
and file bpf_types.h
. In the case of BPF_PROG_TYPE_SOCKET_FILTER
, the corresponding function is sk_filter_func_proto()
.
bpf_verifier_ops
对象对应哪个程序类型
如果你 git blame
在最近的内核源代码上运行该功能,你将得到类似下面的东西(你可以用 GitHub 的 blame 功能做同样的事情):
$ git blame net/core/filter.c
[...]
2492d3b867043 (Daniel Borkmann 2017-01-24 01:06:27 +0100 6080) static const struct bpf_func_proto *
5e43f899b03a3 (Andrey Ignatov 2018-03-30 15:08:00 -0700 6081) sk_filter_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
2492d3b867043 (Daniel Borkmann 2017-01-24 01:06:27 +0100 6082) {
2492d3b867043 (Daniel Borkmann 2017-01-24 01:06:27 +0100 6083) switch (func_id) {
2492d3b867043 (Daniel Borkmann 2017-01-24 01:06:27 +0100 6084) case BPF_FUNC_skb_load_bytes:
2492d3b867043 (Daniel Borkmann 2017-01-24 01:06:27 +0100 6085) return &bpf_skb_load_bytes_proto;
4e1ec56cdc597 (Daniel Borkmann 2018-05-04 01:08:15 +0200 6086) case BPF_FUNC_skb_load_bytes_relative:
4e1ec56cdc597 (Daniel Borkmann 2018-05-04 01:08:15 +0200 6087) return &bpf_skb_load_bytes_relative_proto;
91b8270f2a4d1 (Chenbo Feng 2017-03-22 17:27:34 -0700 6088) case BPF_FUNC_get_socket_cookie:
91b8270f2a4d1 (Chenbo Feng 2017-03-22 17:27:34 -0700 6089) return &bpf_get_socket_cookie_proto;
6acc5c2910689 (Chenbo Feng 2017-03-22 17:27:35 -0700 6090) case BPF_FUNC_get_socket_uid:
6acc5c2910689 (Chenbo Feng 2017-03-22 17:27:35 -0700 6091) return &bpf_get_socket_uid_proto;
7c4b90d79d0f4 (Allan Zhang 2019-07-23 17:07:24 -0700 6092) case BPF_FUNC_perf_event_output:
7c4b90d79d0f4 (Allan Zhang 2019-07-23 17:07:24 -0700 6093) return &bpf_skb_event_output_proto;
2492d3b867043 (Daniel Borkmann 2017-01-24 01:06:27 +0100 6094) default:
2492d3b867043 (Daniel Borkmann 2017-01-24 01:06:27 +0100 6095) return bpf_base_func_proto(func_id);
2492d3b867043 (Daniel Borkmann 2017-01-24 01:06:27 +0100 6096) }
2492d3b867043 (Daniel Borkmann 2017-01-24 01:06:27 +0100 6097) }
[...]
如您所见,BPF_FUNC_perf_event_output
最近才添加到这些 BPF 程序可以调用的助手列表中。添加此支持的提交 7c4b90d79d0f4
已合并到 Linux v5.4:
$ git describe --contains 7c4b90d79d0f4
v5.4-rc1~131^2~248^2~20