The Linux kernel provides two primary mechanisms for moving telemetry data from eBPF programs running in kernel context to userspace collectors: the legacy perf buffer (perf_buffer) and the modern BPF_MAP_TYPE_RINGBUF introduced in kernel 5.8. Understanding their memory allocation strategies is critical for diagnosing bottlenecks in high-throughput AI cluster monitoring where network telemetry arrives at 800Gbps+ rates.
Perf Buffer Architecture and Per-CPU Allocation
The perf_buffer (BPF_MAP_TYPE_PERF_ARRAY) allocates one independent ring buffer per CPU core on the system. When an eBPF program executes on CPU-0, it writes to CPU-0's dedicated buffer; CPU-1 writes to its own buffer. This design eliminates cross-CPU synchronization overhead—no spinlocks, no atomic compare-and-swap operations—making it extremely fast for kernel-side writes. The kernel allocates contiguous memory pages for each per-CPU buffer, typically 4KB or 8KB pages, and maps them into both kernel address space and the userspace collector process's virtual address space.
The memory layout follows this pattern: kernel allocates a buffer descriptor (metadata), followed by the actual ring data. The kernel maintains write pointers and read pointers for each per-CPU buffer. When userspace reads from the perf_buffer, it must poll each CPU's buffer independently, iterating through all cores to collect events. On a 128-core system, this means checking 128 separate memory regions. At 800Gbps network load, where individual telemetry frames arrive in microsecond intervals, the polling overhead compounds: cache misses accumulate as userspace jumps between per-CPU regions, and if a single CPU's buffer fills faster than userspace can drain it, events on that core silently drop without notification to the userspace collector.
BPF_MAP_TYPE_RINGBUF and Unified Ring Architecture
BPF_MAP_TYPE_RINGBUF (introduced in kernel 5.8) replaces per-CPU buffers with a single unified ring buffer shared across all CPUs. The kernel allocates one contiguous memory region and uses atomic operations to manage a global write pointer. Multiple eBPF programs on different CPUs compete to claim space in this shared ring using compare-and-swap (CAS) instructions. This eliminates the polling problem: userspace reads from one location and retrieves events from all CPUs in order.
The ringbuf memory layout consists of: (1) a fixed-size header containing the producer position (write pointer), consumer position (read pointer), and mask for power-of-two sizing; (2) the actual ring data area, sized as a power of two (typically 256KB to 64MB). When an eBPF program needs to write a telemetry record, it atomically reserves space by incrementing the producer position. If the ring is full, the reservation fails and the write is dropped.
Zero-Copy Semantics and Page-Cache Bypass
Both mechanisms achieve zero-copy by mapping kernel-allocated pages directly into userspace's virtual address space. When the kernel writes telemetry data to the ring buffer, it writes to physical memory. Userspace reads from the same physical pages via its own virtual mappings—no data copy occurs. This is fundamentally different from socket-based IPC or pipe-based communication, where data moves through kernel buffers and is copied into userspace.
However, "zero-copy" is a qualified term. The kernel still bypasses the page cache (the filesystem cache), which is the critical distinction. Page-cache copying would require: (1) kernel writes data to page cache, (2) userspace reads from page cache, (3) page cache evicts data when full. Ring buffers eliminate step 2 and 3 by allowing userspace to read directly from kernel-allocated memory.
Why Kernel-Side Writes Bypass Page-Cache Copying
Ring buffers use memory-mapped I/O (mmap) semantics. The kernel allocates pages via `alloc_pages()` or similar, then uses `remap_pfn_range()` or `vm_insert_page()` to install those pages into both kernel and userspace page tables. When the eBPF program writes to the ring buffer, it's writing to kernel virtual addresses that map to physical pages. Userspace reads from userspace virtual addresses that map to the same physical pages. The CPU's memory management unit (MMU) translates both virtual addresses to the same physical location, so the data never moves.
The page cache is specifically for filesystem data. When a process writes to `/dev/null` or a socket, the kernel typically copies data into page-cache buffers first, then userspace reads from those buffers. Ring buffers bypass this because they're not associated with any filesystem inode or socket—they're anonymous memory regions shared via explicit mmap calls.
At 800Gbps network load, this zero-copy property is essential. If telemetry data had to traverse the page cache, the kernel would need to allocate page-cache buffers for each incoming network packet, manage their lifecycle, and schedule page-cache eviction. Under sustained high load, page-cache allocation itself becomes a bottleneck. Ring buffers avoid this entirely by writing directly to pre-allocated, fixed-size regions.