Consuming Ring buffer data in batches or pages in user space

22 views Asked by At

Q1 Kernel handler writes data to ring buffer, in user space callback , we write data to file. I am under assumption that, ring buffer callback invoked for every entry. (correct ?) But this will cause performance issue.(reading one entry from ring buffer and writing one at time)

Is there way to consume in multiples of pages from Ring buffer, so that we can write to file efficiently. (hack cache pages of data, then write to files ?)

Q2: Can we have multiple ring buffers in bpf programs, any known issues ?

//user space bpf
struct exec_evt {
    //int ring_no;    
    pid_t pid;
    pid_t tgid;
    char comm[32];
    char file[32];
};

// Handler invoked for each ring buffer entry
// Can we consume more than entry from ring buffer (preferably in pages) in call back
static int handle_evt(void *ctx, void *data, size_t sz)
{
    const struct exec_evt *evt = data;

    fprintf(stdout, "tgid: %d <> pid: %d -- comm: %s <> file: %s ring no %d\n", evt->tgid, evt->pid, evt->comm, evt->file);
     //Write Data to file in binary format;
    return 0;
}

int main(void)
{
   // bump_memlock_rlimit();

    struct exec *skel = exec__open();
    exec__load(skel);
    exec__attach(skel);

    struct ring_buffer *rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), handle_evt, NULL, NULL);

for(;;) {
        int err = ring_buffer__poll(rb, 100 /* timeout, ms */);
        /* Ctrl-C will cause -EINTR */
        if (err == -EINTR) {
            err = 0;
            break;
        }
        if (err < 0) {
            printf("Error polling perf buffer: %d\n", err);
            break;
        }
    }

//kernel space bpf

#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_core_read.h>
#include "exec.h"

struct {
    __uint(type, BPF_MAP_TYPE_RINGBUF);
    __uint(max_entries, 256 * 1024);
} rb SEC(".maps");

struct exec_params_t {
    u64 __unused;
    u64 __unused2;

    char *file;
};

SEC("tp/syscalls/sys_enter_execve")
int handle_execve(struct exec_params_t *params)
{
    struct task_struct *task = (struct task_struct*)bpf_get_current_task();
    struct exec_evt *evt = {0};

    evt = bpf_ringbuf_reserve(&rb, sizeof(*evt), 0);
    if (!evt) {
        bpf_printk("ringbuffer not reserved\n");
        return 0;
    }

    evt->tgid = BPF_CORE_READ(task, tgid);
    evt->pid = BPF_CORE_READ(task, pid);
    bpf_get_current_comm(&evt->comm, sizeof(evt->comm));
    bpf_probe_read_user_str(evt->file, sizeof(evt->file), params->file);
    bpf_ringbuf_submit(evt, 0);
}
0

There are 0 answers