Mr. Pascal
Mr. Pascal

Reputation: 11

eBPF ring-buffers are not printing event to the stdout, evt struct is populated and printed when printing to trace_pipe

I have the following program structure: src/main.bpf.c:

#include "../vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_endian.h>
#include <bpf/bpf_core_read.h>
#include "../include/omega.h"


#define ETH_P_IP 0x0800

/*
 * NOTES:
 *  __builtin_memcpy HAS TO BE USED BEFORE bpf_ringbuf_submit otherwise it will generate an error!
*/


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


SEC("xdp")
int xdp_packet_filter(struct xdp_md *ctx) {
    struct packet_evt *evt = {0};
    
    evt = bpf_ringbuf_reserve(&rb, sizeof(*evt), 0);
    if (!evt) {
        return XDP_PASS;
    }
    
    void *data = (void *)(long)ctx->data;
    void *data_end = (void *)(long)ctx->data_end;
    
    struct ethhdr *eth = data;
    if ((void *)(eth + 1) > data_end) {
        goto failure;
    }

    if (eth->h_proto != bpf_htons(ETH_P_IP)) {
        goto failure;
    }

    struct iphdr *ip = data + sizeof(struct ethhdr);
    if ((void *)(ip + 1) > data_end) {
        goto failure;
    }

    if (ip->protocol == IPPROTO_UDP) {
        struct udphdr *udp = (void *)ip + sizeof(struct iphdr);
        if ((void *)(udp + 1) > data_end) {
            goto failure;
        }

        __u16 src_port = bpf_ntohs(udp->source);
        __u16 dest_port = bpf_ntohs(udp->dest);

        if (evt) {
            evt->src_ip = ip->saddr;
            evt->dst_ip = ip->daddr;
            evt->src_port = src_port;
            evt->dst_port = dest_port;

            bpf_printk("Submitting Event: SRC IP: %x DST IP: %x SRC PORT: %d DST PORT: %d\n",
            evt->src_ip, evt->dst_ip, evt->src_port, evt->dst_port);
            //bpf_printk("TCP packet from %x:%d to %x:%d\n",
            //ip->saddr, src_port, ip->daddr, dest_port);
        } else {
            bpf_printk("Ring buffer reservation failed\n");
            goto failure;
        }


        
        //PACKET FROM TO
        //bpf_printk("UDP|%x:%d|%x:%d\n",
        //    ip->saddr, src_port, ip->daddr, dest_port);
    } else if (ip->protocol == IPPROTO_TCP) {
        struct tcphdr *tcp = (void *)ip + sizeof(struct iphdr);
        if ((void *)(tcp + 1) > data_end) {
            goto failure;
        }

        __u16 src_port = bpf_ntohs(tcp->source);
        __u16 dest_port = bpf_ntohs(tcp->dest);

        if (evt) {
            evt->src_ip = ip->saddr;
            evt->dst_ip = ip->daddr;
            evt->src_port = src_port;
            evt->dst_port = dest_port;

            bpf_printk("Submitting Event: SRC IP: %x DST IP: %x SRC PORT: %d DST PORT: %d\n",
            evt->src_ip, evt->dst_ip, evt->src_port, evt->dst_port);
            //bpf_printk("TCP packet from %x:%d to %x:%d\n",
            //ip->saddr, src_port, ip->daddr, dest_port);
        } else {
            bpf_printk("Ring buffer reservation failed\n");
            goto failure;
        }

        // PACKET FROM TO
       // bpf_printk("TCP|%x:%d|%x:%d\n",
       //     ip->saddr, src_port, ip->daddr, dest_port);
    }


    bpf_ringbuf_submit(evt, 0);
    bpf_printk("Evt submit done!\n");
    return XDP_PASS;

    failure:
        bpf_printk("Failure!\n");
        bpf_ringbuf_discard(evt, 0);
        return XDP_PASS;
}


char LICENSE[] SEC("license") = "GPL";

include/omega.h:

#ifndef __OMEGA_H__
#define __OMEGA_H__


#define MAX_EVENT_LEN 24



struct packet_evt {
    __u32 src_ip;
    __u32 dst_ip;
    __u16 src_port;
    __u16 dst_port;
};

#endif // __OMEGA_H__

src/loader.c

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/resource.h>
#include <bpf/libbpf.h>
#include <bpf/bpf.h>

#include "../omega.skel.h"
#include "../include/omega.h"


static volatile int stop = 0;

static void bump_memlock_rlimit(void) {
    struct rlimit rlim_new = {
        .rlim_cur   = RLIM_INFINITY,
        .rlim_max   = RLIM_INFINITY,
    };

    if (setrlimit(RLIMIT_MEMLOCK, &rlim_new)) {
        fprintf(stderr, "Failed to increase RLIMIT_MEMLOCK limit!\n");
        exit(1);
    }
}

void handle_signal(int sig) {
    stop = 1;
}

static int handle_evt(void *ctx, void *data, size_t sz) {
    const struct packet_evt *evt = data;    

    fprintf(stdout, "Received Event: SRC IP: %u DST IP: %u SRC PORT: %u DST PORT: %u\n",
        evt->src_ip, evt->dst_ip, evt->src_port, evt->dst_port);
    fflush(stdout);

    return 0;
}

int main(void) {
    struct omega *skel = NULL;
    struct ring_buffer *rb = NULL;
    
    signal(SIGINT, handle_signal);
    signal(SIGTERM, handle_signal);

    // Increase rlimit for BPF memory lock
    bump_memlock_rlimit();

    skel = omega__open();
    if (!skel) {
        fprintf(stderr, "Failed to open BPF skeleton\n");
        return 1;
    }

    if (omega__load(skel)) {
        fprintf(stderr, "Failed to load BPF skeleton\n");
        omega__destroy(skel);
        return 1;
    }

    if (omega__attach(skel)) {
        fprintf(stderr, "Failed to attach BPF skeleton\n");
        omega__destroy(skel);
        return 1;
    }

    // Set up ring buffer
    int rb_fd = bpf_map__fd(skel->maps.rb);
    if (rb_fd < 0) {
        fprintf(stderr, "Failed to get ring buffer FD\n");
        omega__destroy(skel);
        return 1;
    }

    rb = ring_buffer__new(rb_fd, handle_evt, NULL, NULL);
    if (!rb) {
        fprintf(stderr, "Failed to create ring buffer\n");
        omega__destroy(skel);
        return 1;
    }

    printf("Ring buffer successfully created. Waiting for events...\n");

    while (!stop) {
        int err = ring_buffer__poll(rb, 1000);
        if (err < 0) {
            fprintf(stderr, "Error polling ring buffer: %d\n", err);
            break;
        }
    }

    printf("Cleaning up...\n");
    ring_buffer__free(rb);
    omega__destroy(skel);

    return 0;
}

when I cat /sys/kernel/debug/tracing/trace_pipe bpf_trace_printk: Submitting Event: SRC IP: 108ca203 DST IP: 6d00a8c0 SRC PORT: 443 DST PORT: 55938

Also when I run loader I get. Ring buffer successfully created. Waiting for events...

Also it prints Evt submit done! so code for sure comes to rinbuf_submit.

I tried adding flag for forcefully waking up fd for rb when submitting ring buffer but it didn't solve the issue (https://www.kernel.org/doc/html/v6.2/bpf/ringbuf.html).

I'm not sure what could be potential fix or next debug steps. I assume handle_evt is never called since submitting to ring buffer works and handle_evt is never called from what I saw while running debugger and trying to print at the start of the function.

Upvotes: 1

Views: 62

Answers (0)

Related Questions