我有一个折旧的函数。首先,如何找到折旧函数的新替代方案。函数存在于libbpf库中,perf_buffer__new
是确切的名称。因此,基本上正如名称所示,它用于创建perf缓冲区,以便在用户空间和内核之间共享信息。首先我想知道的是perf缓冲区是否只针对ebpf过滤器。并不意味着我可以在任何事情中使用perf缓冲区。例如,如果我有一些驱动程序代码,所以我只添加perf缓冲区,以便在一些用户空间应用程序和驱动程序之间共享信息。所以我在网上搜索了一下,发现它专门链接到ebpf,这是真的吗?
因此,这是我的代码,它使用对perf_buffer__new
的调用,但该函数已折旧,libbpf的libbpf.h头文件声明中的该函数已注释掉
因此,我想知道我可以在代码中使用的新替代方案是什么,如果api发生了变化,那么我想让你知道我正在尝试将SEC中的缓冲区参数("kprobe/__x64_sys_recvfrom"(共享给用户空间,因为我已经使用了PT_REGS_PARM2和bpf_probe_read_kernel,并将该参数包含在映射数据中。因此,如果api被更改,那么如何实现这一点是我的用户空间和ebpf程序
用户空间.c
// SPDX-License-Identifier: GPL-2.0-only
#include <stdio.h>
#include <fcntl.h>
#include <poll.h>
#include <time.h>
#include <signal.h>
#include <bpf/libbpf.h>
//create .o file root@this:/home/ubuntu/Desktop/ebpf/kern# clang -I /lib/modules/5.14.1/build -I /usr/include/bpf/ -O2 -Wall -c trace_output_user.c
static __u64 time_get_ns(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * 1000000000ull + ts.tv_nsec;
}
static __u64 start_time;
static __u64 cnt;
#define MAX_CNT 100000ll
static void print_bpf_output(void *ctx, int cpu, void *data, __u32 size)
{
struct {
int pid;
char cookie[90];
char *buf;
} *e = data;
int i=0;
printf("hellon");
printf(" _____________________________________________________%d n________%sn",e->pid,e->buf);
i++;
//printf("received map value = %sn",e->cookie);
/*if (e->cookie != 0x12345678) {
printf("BUG pid %llx cookie %d sized %dn",
e->pid, e->cookie, size);
return;
}
cnt++;
if (cnt == MAX_CNT) {
printf("recv %lld events per secn",
MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
return;
}*/
}
int main(int argc, char **argv)
{
struct perf_buffer_opts pb_opts = {};
struct bpf_link *link = NULL;
struct bpf_program *prog;
struct perf_buffer *pb;
struct bpf_object *obj;
int map_fd, ret = 0;
char filename[256];
FILE *f;
//snprintf(filename, sizeof(filename), "..o", argv[0]);
obj = bpf_object__open_file("./kprobe_send.o", NULL);
if (libbpf_get_error(obj)) {
fprintf(stderr, "ERROR: opening BPF object file failedn");
return 0;
}
/* load BPF program */
if (bpf_object__load(obj)) {
fprintf(stderr, "ERROR: loading BPF object file failedn");
goto cleanup;
}
map_fd = bpf_object__find_map_fd_by_name(obj, "my_map");
if (map_fd < 0) {
fprintf(stderr, "ERROR: finding a map in obj file failedn");
goto cleanup;
}
printf("beforen");
prog = bpf_object__find_program_by_name(obj, "bpf_prog1");
if (libbpf_get_error(prog)) {
fprintf(stderr, "ERROR: finding a prog in obj file failedn");
goto cleanup;
}
printf("aftern");
link = bpf_program__attach(prog);
printf("aftern");
if (libbpf_get_error(link)) {
fprintf(stderr, "ERROR: bpf_program__attach failedn");
link = NULL;
goto cleanup;
}
printf("aftern");
pb_opts.sample_cb = print_bpf_output;
pb = perf_buffer__new_deprecated(map_fd, 8, &pb_opts);//error
printf("aftern");
ret = libbpf_get_error(pb);
if (ret) {
printf("failed to setup perf_buffer: %dn", ret);
return 1;
}
f = popen("taskset 1 dd if=/dev/zero of=/dev/null", "r");
(void) f;
start_time = time_get_ns();
while ((ret = perf_buffer__poll(pb, 1000)) >= 0 && cnt < MAX_CNT) {
}
kill(0, SIGINT);
cleanup:
bpf_link__destroy(link);
bpf_object__close(obj);
return ret;
}
Kernel.c
#include <linux/ptrace.h>
#include <linux/version.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <string.h>
#include <sys/sendfile.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include </usr/include/bpf/bpf_tracing.h>
#include <linux/seccomp.h>
#define RAND_MAX 0x7fff
#define PERF_SAMPLE_RAW 1U << 0
#define randrange(N) rand() / (RAND_MAX/(N) + 1)
#define MAX 100000000 /* Values will be in the range (1 .. MAX) */
struct {
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
__uint(key_size, sizeof(int));
__uint(value_size, sizeof(int));
__uint(max_entries, 100);
} my_map SEC(".maps");
SEC("kprobe/__x64_sys_recvfrom")
int bpf_prog1(struct pt_regs *ctx)
{
static int vektor[100000000];
int candidates[MAX];
int i;
long key;
//srand(time(NULL)); /* Seed the random number generator. */
/*for (i=0; i<MAX; i++)
candidates[i] = i;
for (i = 0; i < MAX-1; i++) {
int c = randrange(MAX-i);
int t = candidates[i];
candidates[i] = candidates[i+c];
candidates[i+c] = t;
}
for (i=0; i<10; i++)
vektor[i] = candidates[i] + 1;*/
struct S {
int pid;
char cookie[90];
char *ptr;
} data={1,""};
//char *ptr = PT_REGS_PARM2(ctx);
struct seccomp_data sd;
bpf_probe_read_kernel(&sd, sizeof(sd), (void *)PT_REGS_PARM2(ctx));
if (sd.args[2] > 128 && sd.args[2] <= 1024) {
char fmt[] = "read(fd=%d, buf=%p, size=%d)n";
bpf_trace_printk(fmt, sizeof(fmt),
sd.args[0], sd.args[1], sd.args[2]);
data.ptr=(char *)sd.args[1];
// memcpy(data.ptr,sd.args[1],sizeof(char)*220);
}
//data.pid =count;// bpf_get_current_pid_tgid();
//if(buf==NULL)
//memcpy(data.cookie,buf,20);
//data.ptr=ptr;
// data.cookie[0]=buf[0];
//bpf_get_current_comm(&data.cookie, sizeof(data.cookie));
//key=vektor[i];
//bpf_map_update_elem(fd,&key,&data,BPF_ANY);
//bpf_perf_event_output(ctx, &my_map, 1, &data, sizeof(data));
return 0;
}
char _license[] SEC("license") = "GPL";
int _version SEC("version") = 99;
当我编译并将程序用户空间与root@this:/home/ubuntu/Desktop/ebpf/Linux-exFilter-main/pkg/probe/bpf# clang -v trace_output_user.c -o trace -lbpf
链接时
我得到错误,并警告
trace_output_user.c:101:7: warning: 'perf_buffer__new_deprecated' is deprecated: libbpf v0.7+: use new variant of perf_buffer__new() instead [-Wdeprecated-declarations]
pb = perf_buffer__new_deprecated(map_fd, 8, &pb_opts);
^
/usr/include/bpf/libbpf.h:949:12: note: 'perf_buffer__new_deprecated' has been explicitly marked deprecated here
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "use new variant of perf_buffer__new() instead")
^
/usr/include/bpf/libbpf_common.h:24:4: note: expanded from macro 'LIBBPF_DEPRECATED_SINCE'
(LIBBPF_DEPRECATED("libbpf v" # major "." # minor "+: " msg))
^
/usr/include/bpf/libbpf_common.h:19:47: note: expanded from macro 'LIBBPF_DEPRECATED'
#define LIBBPF_DEPRECATED(msg) __attribute__((deprecated(msg)))
^
1 warning generated.
"/usr/bin/ld" -z relro --hash-style=gnu --build-id --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o trace /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../x86_64-linux-gnu/crt1.o /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../x86_64-linux-gnu/crti.o /usr/bin/../lib/gcc/x86_64-linux-gnu/10/crtbegin.o -L/usr/bin/../lib/gcc/x86_64-linux-gnu/10 -L/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../x86_64-linux-gnu -L/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../lib64 -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib64 -L/usr/lib/x86_64-linux-gnu/../../lib64 -L/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../.. -L/usr/lib/llvm-12/bin/../lib -L/lib -L/usr/lib /tmp/trace_output_user-ec780e.o -lbpf -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/bin/../lib/gcc/x86_64-linux-gnu/10/crtend.o /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../x86_64-linux-gnu/crtn.o
/usr/bin/ld: /tmp/trace_output_user-ec780e.o: in function `main':
trace_output_user.c:(.text+0x1e2): undefined reference to `perf_buffer__new_deprecated'
一些细节perf_buffer_new_deprecated和perf_buffer_new在最新版本的libbpf中折旧我的内核版本是5.14.1
1.您在代码中显式使用perf_buffer__new_deprecated
-不要这样做:改为使用perf_buffer_new
。您永远不应该调用名称中已包含"弃用"的函数。
2.查看标题:libbpf/libbpf.h
perf_buffer_new
的定义如下:
#define perf_buffer__new(...) ___libbpf_overload(___perf_buffer_new, __VA_ARGS__)
#define ___perf_buffer_new6(map_fd, page_cnt, sample_cb, lost_cb, ctx, opts)
perf_buffer__new(map_fd, page_cnt, sample_cb, lost_cb, ctx, opts)
#define ___perf_buffer_new3(map_fd, page_cnt, opts)
perf_buffer__new_deprecated(map_fd, page_cnt, opts)
因此有两个功能:
- 旧:带3个参数的pef_buffer_new
- 新增:perf_buffer_New,包含6个参数
使用宏,libbpf
也可以编译旧代码,同时告诉您更改函数调用。您现在使用的是旧版本(有3个参数(。切换到具有6个参数的新版本,因为3个参数的变体将被删除。
新函数(请参见libbpf/libbpf.h(:
/**
* @brief **perf_buffer__new()** creates BPF perfbuf manager for a specified
* BPF_PERF_EVENT_ARRAY map
* @param map_fd FD of BPF_PERF_EVENT_ARRAY BPF map that will be used by BPF
* code to send data over to user-space
* @param page_cnt number of memory pages allocated for each per-CPU buffer
* @param sample_cb function called on each received data record
* @param lost_cb function called when record loss has occurred
* @param ctx user-provided extra context passed into *sample_cb* and *lost_cb*
* @return a new instance of struct perf_buffer on success, NULL on error with
* *errno* containing an error code
*/
LIBBPF_API struct perf_buffer *
perf_buffer__new(int map_fd, size_t page_cnt,
perf_buffer_sample_fn sample_cb, perf_buffer_lost_fn lost_cb, void *ctx,
const struct perf_buffer_opts *opts);
您还可以在标题中找到sample_cb
和lost_cb
的定义:从上面我们知道sample_cb
具有perf_buffer_sample_fn
类型。对于另一个回调,它是类似的。两者都在libbpf.h:中定义
typedef void (*perf_buffer_sample_fn)(void *ctx, int cpu,
void *data, __u32 size);
typedef void (*perf_buffer_lost_fn)(void *ctx, int cpu, __u64 cnt);
参见libbpf/libbpf.h
因此,一个有效的回调函数可以是void myCallbackForNewData(void* ctx, int cpu, void*data, __u32 size) {}
请注意,ctx*
与BPF无关——它是您可以在perf_buffer__new
中自由定义的。如果对多个perf_buffer使用相同的处理程序,这将非常有用。否则,您可以只输入NULL。