Linux AF_XDP Explained: User-Space Packet Processing
Linux AF_XDP is a socket interface for applications that need to process network packets in user space at high rates. It connects an early Linux packet-processing hook, XDP, to application-managed memory and queues. This makes AF_XDP relevant to network software developers, infrastructure engineers, and operators evaluating packet-processing performance. The interface does not guarantee zero-copy operation or replace ordinary sockets for typical applications; its value depends on the network driver, queue layout, workload, and the application’s ability to manage buffers efficiently.
Why AF_XDP Is Discussed
Packet-processing applications often need to inspect or transform traffic faster than a conventional socket path allows. Routers, load balancers, packet analyzers, and some validator clients may benefit from handling frames in a specialized user-space loop. AF_XDP provides a Linux-supported path for this without requiring every part of packet classification and redirection to run in a custom kernel module.
Interest in AF_XDP comes from its position between kernel networking and user-space code. An XDP program can make an early decision about a received frame, then redirect selected traffic to an AF_XDP socket. The application gets direct access to frame buffers through shared rings, while the kernel and network device still handle important parts of setup and delivery. As a result, AF_XDP is a specific data-path design, not a general replacement for TCP/IP or the Linux networking stack.
What Is Linux AF_XDP?
AF_XDP is a Linux address family optimized for high-performance packet processing. An application creates an AF_XDP socket, associates it with a memory region and one or more rings, then binds it to a network interface and queue. An XDP program uses the XDP_REDIRECT action and an XSKMAP to send matching frames to that socket. The Linux kernel’s AF_XDP documentation describes the socket, memory, ring, and redirect interfaces.
AF_XDP is specific to Linux and does not define a protocol exchanged between machines. It provides local access to received or transmitted frames; higher-level protocol behavior remains separate. For example, IETF RFC 9293 specifies TCP’s transport behavior, while AF_XDP does not change what a TCP peer sends or expects.
The distinction matters when planning an application. A user-space program using AF_XDP may need to parse Ethernet, IP, and transport headers itself, or hand work to other components. Redirected traffic does not automatically pass through the usual kernel protocol stack in the same way as traffic delivered to a conventional TCP socket. An application should use AF_XDP only when it needs this lower-level control.
The Problem AF_XDP Solves
With a conventional socket, a received packet typically travels through the network device’s receive path, kernel protocol processing, socket buffering, and the system-call interface before application code reads it. That path is appropriate for most applications because it supplies mature protocol handling, congestion control, and familiar socket semantics. But repeated data movement, protocol work, and system calls can become significant in specialized packet-processing workloads.
AF_XDP lets an application select traffic earlier and work with packet buffers through a queue-oriented interface. The design can reduce per-packet overhead and allow the application to batch work. It also exposes responsibilities that ordinary sockets hide: the program must keep buffers available, consume descriptors correctly, return memory for reuse, and coordinate ring access.
This is not a universal performance fix. If an application spends most of its time doing expensive payload inspection or business logic, changing the receive interface may make little difference. If the driver cannot use zero-copy, copying remains in the path. A simpler socket API may also be more reliable and easier to maintain than a custom user-space networking loop.
How AF_XDP Works
AF_XDP depends on two cooperating parts: an XDP program in the kernel and an AF_XDP application in user space. The XDP program determines whether a frame should continue through the regular networking stack, be dropped, or be redirected. To redirect a frame, it selects an entry in an XSKMAP. That entry must refer to a socket bound to the same network device and receive queue as the packet; otherwise the kernel drops the frame rather than delivering it to a mismatched socket.
The application binds its socket to a specific interface and queue identifier. Network devices often expose multiple queues, allowing work to be distributed across CPU cores. Because a socket is tied to a queue, the application and XDP program must agree on queue assignment. It is common to create multiple sockets for multiple queues, but the application must avoid directing more work to a queue than its buffers and processing loop can handle.
The packet data lives in UMEM, a region of application-allocated memory divided into fixed-size frames. The kernel documentation describes four single-producer, single-consumer rings:
- FILL: The application supplies available UMEM frame addresses for incoming packets.
- RX: The kernel places descriptors here when received frames are ready for the application.
- TX: The application submits descriptors for packets it wants to transmit.
- COMPLETION: The kernel returns frame addresses after it has finished with transmitted or rejected TX descriptors.
On receive, the application places free buffers on FILL. A matching XDP program redirects a packet to the socket, the kernel or driver writes it into an available buffer, and a descriptor appears on RX. After processing the packet, the application recycles the buffer by returning its address to FILL. On transmit, the application writes packet data into UMEM, submits a descriptor on TX, and later reuses the frame after its address returns through COMPLETION. A completion means the kernel is finished with that buffer; it is not proof that the remote system received the packet.
The rings are memory-mapped to user space, which supports batch-oriented operation. They are single-producer/single-consumer structures, not general multi-threaded queues. Applications that use several threads must assign ring ownership or add their own synchronization. The libbpf overview explains how libbpf loads BPF programs and manages their lifecycle; its XDP socket helpers can also simplify AF_XDP setup.
Key Components and Modes
| Mode or choice | What it means | Main dependency | Practical trade-off |
|---|---|---|---|
Generic XDP (XDP_SKB) |
Runs XDP after the kernel has created an SKB | Works without a driver-native XDP path | Broad compatibility, but adds work in the normal kernel receive path |
Driver/native XDP (XDP_DRV) |
Runs XDP in a supported driver’s earlier receive path | Driver support and compatible device setup | Avoids some ordinary stack work, but does not by itself mean packet data is zero-copy |
| AF_XDP copy mode | Transfers packet data to or from UMEM with copying | Supported AF_XDP socket path | Easier to support across devices, but retains copy cost |
| AF_XDP zero-copy mode | Lets a supported driver and device use UMEM buffers directly for packet I/O | Driver, device, and setup support | Can reduce copying, but may be unavailable and still requires careful buffer management |
These are related but distinct choices. XDP’s generic or driver mode describes where the XDP program runs. AF_XDP’s copy or zero-copy mode describes how packet data is transferred between the device path and UMEM. A native XDP program can still use AF_XDP copy mode. The kernel tries zero-copy when available unless the application forces a mode; an application can request copy mode or require zero-copy and fail if the requested mode cannot be provided.
Zero-copy support is not guaranteed by the name of a network interface or by a recent kernel alone. The driver and device must support the relevant path, and the application can query the socket’s XDP_OPTIONS_ZEROCOPY option to confirm whether zero-copy was selected. Multi-buffer packets also need explicit support in both the AF_XDP socket and XDP program; without it, packets larger than one frame may be dropped.
Real-World Use Cases
AF_XDP is useful where applications need a custom packet data path and have the engineering capacity to operate it:
- High-rate packet processing: A specialized user-space router or load balancer can classify traffic and apply application-specific forwarding.
- Security and traffic analysis: An inspection service can redirect selected frames to a dedicated process, while maintaining a separate policy for traffic that should continue through the kernel stack.
- Network appliances and test systems: Packet generators, protocol implementations, and performance tools can control buffers and queue placement directly.
- Validator networking: A blockchain validator may use AF_XDP as one part of its packet ingress design. For example, Firedancer documents AF_XDP in its network path; this is an implementation choice, not a requirement for Solana validators generally.
AF_XDP is less attractive for ordinary web services, command-line tools, or applications that only need reliable byte streams. Standard TCP and UDP sockets provide protocol behavior and portability that a raw frame path would otherwise require the application to build or integrate.
Getting Started: Inspect AF_XDP Support
Start on a test Linux host with local or console access. Package names differ by distribution, but Debian/Ubuntu and Fedora systems commonly provide the following development and inspection tools:
# Debian or Ubuntu
sudo apt update
sudo apt install clang llvm libbpf-dev libxdp-dev bpftool iproute2 ethtool
# Fedora (use this instead of the Debian/Ubuntu commands above)
sudo dnf install clang llvm libbpf-devel libxdp-devel bpftool iproute ethtool
The Linux kernel project publishes kernel source and release information, but a kernel version alone does not establish that a particular network driver supports native XDP or AF_XDP zero-copy. Check the running system and the device:
uname -r
ip -brief link
# Replace enp1s0 with the interface you intend to evaluate.
IFACE=enp1s0
ip -details link show dev "$IFACE"
sudo ethtool -i "$IFACE"
sudo bpftool feature probe dev "$IFACE"
These commands inspect the kernel, interface, driver, and exposed BPF features. They do not prove that an AF_XDP application will bind successfully or that zero-copy will be enabled. For that, use the kernel’s AF_XDP example application on a controlled interface, then query the socket’s zero-copy option and monitor its drop statistics. First verify which queue the XDP program redirects to, that a socket is bound to the same device and queue, and that FILL buffers are available. Do not attach an unfamiliar redirect or drop program to a production interface: a queue mismatch or empty XSKMAP can cause traffic loss.
When evaluating throughput, compare equivalent packet sizes and traffic patterns, monitor CPU utilization and drops, and test recovery when the application stops consuming rings. Record whether the test used copy or zero-copy mode; otherwise results from different hardware and setup paths are not comparable.
Common Misconceptions
“AF_XDP always means zero-copy.” No. Copy mode is supported and often the fallback. Zero-copy requires a compatible driver and device and should be confirmed through the socket rather than inferred from a configuration label.
“Native XDP and AF_XDP are the same feature.” Native XDP is a driver-supported execution mode for an XDP program. AF_XDP is a socket path that allows the program to redirect packets into user-space buffers. They work together but describe different parts of the data path.
“AF_XDP replaces the Linux network stack.” It does not replace the stack for every packet or provide TCP socket behavior by itself. It gives a selected application a lower-level packet interface; the operator must decide what happens to other traffic and which protocol responsibilities remain in the kernel.
Related Articles
- eBPF Observability: How Kernel Tracing Works
- Network Troubleshooting in Linux
- Solana Firedancer Validator Client Architecture Explained
Changelog and Last Updated
Last updated: November 10. Initial publication.

