Reputation: 11
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