While zero-copy network transmission (MSG_ZEROCOPY) is widely adopted for outbound streaming, high-throughput ingest pipelines—such as distributed message brokers, packet capture systems, and real-time database replicas—face severe CPU bottlenecks on inbound data. Standard network reads copy packet payloads from kernel network ring buffers into application memory. Linux TCP zero-copy receive eliminates this memory copy by allowing applications to map network packet buffers directly into user address space using mmap() and tcp_zerocopy_receive(). Using eBPF, systems engineers can trace zero-copy receive latencies, monitor page remapping overhead, and tune network queues.
Understanding TCP Zero-Copy Receive Architecture
Inbound zero-copy networking relies on hardware header-data splitting and memory remapping:
- The network interface card (NIC) splits incoming frames into protocol headers and data payloads.
- Data payloads are allocated into page-aligned page pool buffers.
- The user application calls
getsockopt(fd, SOL_TCP, TCP_ZEROCOPY_RECEIVE, &zc, sizeof(zc)), which remaps kernel pages directly into an address space previously allocated viammap(). - Trade-Off: Page remapping incurs TLB (Translation Lookaside Buffer) invalidations and kernel page table manipulation, which can outweigh copy savings on small payloads.
Tracing Zero-Copy Ingest with bpftrace
Deploy a real-time eBPF script targeting the kernel entry point tcp_zerocopy_receive():
# Install bpftrace on Ubuntu/Debian
sudo apt-get update && sudo apt-get install -y bpftrace linux-headers-$(uname -r)
# Trace TCP zero-copy receive invocations and remapped bytes
sudo bpftrace -e '
kprobe:tcp_zerocopy_receive {
@start[tid] = nsecs;
}
kretprobe:tcp_zerocopy_receive /@start[tid]/ {
$dur_us = (nsecs - @start[tid]) / 1000;
@mmap_rx_lat_us = hist($dur_us);
if (retval == 0) {
@rx_success[comm] = count();
} else {
@rx_fallback[comm] = count();
}
delete(@start[tid]);
}'
If @rx_fallback is high, unaligned packet boundaries or lack of hardware header-data splitting is forcing the kernel into traditional copy paths.
Verifying Hardware and Socket Prerequisites
Inspect system-level zero-copy receive prerequisites:
# Check whether network interface supports header-data splitting
ethtool -k eth0 | grep -E "tcp-data-split|rx-gro"
# Enable header-data splitting on supported NICs
sudo ethtool -K eth0 tcp-data-split on
Tuning Inbound Page Mapping Buffers
To optimize zero-copy receive performance for production workloads:
- Payload Alignment: Ensure incoming TCP payloads align to page boundaries (4096 bytes or hugepages). Unaligned payloads fall back to copying.
- Batch Ingest Operations: Map multiple pages simultaneously per
getsockopt()invocation to amortize TLB shootdown costs across megabyte-scale chunks. - NIC Ring Sizing: Expand network device RX ring buffers (
ethtool -G eth0 rx 4096) to prevent packet drops while page tables are modified.