我在一个程序中有一个函数调用,这个函数是 depreciated.Is 我可以在我的代码中使用的任何更新版本 | perf_buffer__new 在 ebpf 中

I have a function call in one program and this function is depreciated.Is there any newer version that I can use in my code | perf_buffer__new in ebpf

我有这个功能已经贬值了。首先,如何找到已贬值功能的新替代品。该函数存在于 libbpf 库中,perf_buffer__new 是确切的名称。所以基本上顾名思义,它用于创建性能缓冲区以在用户空间和内核之间共享信息。首先我想知道 perf 缓冲区是否仅特定于 ebpf 过滤器。并不意味着我可以在任何地方使用 perf 缓冲区。例如,如果我有一些驱动程序代码,那么我只需添加 perf 缓冲区,以便在某些用户空间应用程序和驱动程序之间共享信息。所以在网上搜索了一下,我发现它专门 link 到 ebpf,这是真的吗?

所以这是我调用 perf_buffer__new 的代码,但该函数已贬值,libbpf 的 libbpf.h 头文件声明中的此函数已被注释掉

所以我想知道我可以在我的代码中使用的新替代方法是什么,如果 api 有变化,那么我想让你知道我正在尝试在 SEC 中共享缓冲区参数("kprobe/__x64_sys_recvfrom") 到用户空间,因为我已经使用 PT_REGS_PARM2 和 bpf_probe_read_kernel 并将参数包含在地图数据中。所以如果 api 改变了那么如何完成这个这是我的用户空间和 ebpf 程序

Userspace.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("hello\n");
    
    printf(" _____________________________________________________%d \n________%s\n",e->pid,e->buf);
    i++;


    //printf("received map value = %s\n",e->cookie);
    /*if (e->cookie != 0x12345678) {
        printf("BUG pid %llx cookie %d sized %d\n",
               e->pid, e->cookie, size);
        return;
    }

    cnt++;

    if (cnt == MAX_CNT) {
        printf("recv %lld events per sec\n",
               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 failed\n");
        return 0;
    }

    /* load BPF program */
    if (bpf_object__load(obj)) {
        fprintf(stderr, "ERROR: loading BPF object file failed\n");
        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 failed\n");
        goto cleanup;
    }
    printf("before\n");
    prog = bpf_object__find_program_by_name(obj, "bpf_prog1");
    if (libbpf_get_error(prog)) {
        fprintf(stderr, "ERROR: finding a prog in obj file failed\n");
        goto cleanup;
    }
    printf("after\n");

    link = bpf_program__attach(prog);
        printf("after\n");
    if (libbpf_get_error(link)) {
        fprintf(stderr, "ERROR: bpf_program__attach failed\n");
        link = NULL;
        goto cleanup;
    }
    printf("after\n");
    pb_opts.sample_cb = print_bpf_output;
    pb = perf_buffer__new_deprecated(map_fd, 8, &pb_opts);//error
    printf("after\n");
    ret = libbpf_get_error(pb);
    if (ret) {
        printf("failed to setup perf_buffer: %d\n", 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

编译和 link 程序用户空间时

我收到错误和警告

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 代替。您永远不应该调用名称中已经包含 'deprecated' 的函数。

2. 看看header: 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)

所以有2个函数:

  • 旧:pef_buffer_new 有 3 个参数
  • 新:perf_buffer_new 有 6 个参数。

使用宏,libbpf 也可以编译旧代码,同时告诉您更改函数调用。 您现在正在使用旧版本(带有 3 个参数)。切换到带有 6 个参数的新版本,因为 3-arguments-variant 将被删除。

新函数(见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);

您也可以在 header 中找到 sample_cblost_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_buffers 使用相同的处理程序,这将很有用。否则,您可以直接输入 NULL。