
Table of Contents
By Khimananda Oli | Last reviewed: August 2026
When standard Linux networking stacks buckle under multi-gigabit traffic or sophisticated DDoS attacks, XDP: High-Performance Packet Processing provides a programmable escape hatch directly inside the network driver. Unlike traditional firewalling that inspects packets after significant kernel overhead, XDP executes eBPF bytecode at the earliest possible point in the ingress path. This capability allows you to drop, redirect, or modify millions of packets per second per core while maintaining full compatibility with existing observability tools like those discussed in our Prometheus metrics monitoring fundamentals guide.
What is XDP: High-Performance Packet Processing and how does it work?
XDP (eXpress Data Path) is not a separate product; it is a hook point within the Linux kernel's network receive path. When a network interface card (NIC) receives a frame via DMA, the kernel typically allocates an sk_buff structure and pushes the packet up through the netfilter, TCP/IP stack, and socket layers. XDP intercepts this flow immediately after the driver reads the descriptor ring but before any expensive metadata allocation occurs.
The mechanism relies on eBPF (extended Berkeley Packet Filter), a virtual machine inside the kernel that guarantees safety through static verification. Your C code compiles to eBPF bytecode, which the verifier checks for infinite loops, out-of-bounds memory access, and invalid instructions. Once verified, the program attaches to the XDP hook. Because this execution happens in the softirq context of the NIC driver, it avoids context switches and cache pollution associated with higher-layer processing.
In practice, this architecture means you can achieve drop rates exceeding 20 million packets per second (Mpps) on modern hardware, whereas iptables might saturate at 1–2 Mpps on the same CPU. For teams managing infrastructure in Nepal where upstream bandwidth can be expensive and asymmetric, stopping malicious traffic at the edge interface before it consumes routing resources is often the difference between uptime and outage.
How do you write and attach an XDP program safely?
Writing XDP programs requires discipline. The eBPF verifier is strict: no unbounded loops, no pointer arithmetic outside packet bounds, and limited stack usage (512 bytes). Most engineers use the libbpf CO-RE (Compile Once – Run Everywhere) approach with BTF (BPF Type Format) to handle kernel structure differences across versions.
Minimal XDP filter example
This program drops all UDP traffic on port 53 while passing everything else. Note the explicit bounds checking required by the verifier.
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/udp.h>
SEC("xdp")
int xdp_dns_filter(struct xdp_md *ctx) {
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
struct ethhdr *eth = data;
if ((void *)(eth + 1) > data_end)
return XDP_PASS;
if (eth->h_proto != __constant_htons(ETH_P_IP))
return XDP_PASS;
struct iphdr *ip = (struct iphdr *)(eth + 1);
if ((void *)(ip + 1) > data_end)
return XDP_PASS;
if (ip->protocol != IPPROTO_UDP)
return XDP_PASS;
struct udphdr *udp = (struct udphdr *)((void *)ip + sizeof(*ip));
if ((void *)(udp + 1) > data_end)
return XDP_PASS;
if (udp->dest == __constant_htons(53))
return XDP_DROP;
return XDP_PASS;
}
char _license[] SEC("license") = "GPL"; Loading and attaching the program
Never load XDP programs manually in production without testing. Use bpftool or a loader built with libbpf:
- Compile with clang:
clang -O2 -g -target bpf -c xdp_filter.c -o xdp_filter.o - Verify BTF support:
cat /sys/kernel/btf/vmlinuxmust exist for CO-RE. - Attach to interface:
bpftool prog load xdp_filter.o /sys/fs/bpf/xdp_dns type xdp pin /sys/fs/bpf/xdp_dns - Link to device:
bpftool net attach xdp pinned /sys/fs/bpf/xdp_dns dev eth0 - Verify attachment:
ip link show eth0should displayxdp/id:XXX.
A common mistake is forgetting to handle VLAN tags or IPv6. If your production environment uses 802.1Q tagging, your parser must account for the extra 4-byte header or you will misparse every packet. Always test with xdp-bench from the kernel samples before deploying to live interfaces.
XDP vs iptables vs DPDK: Which packet processing approach should you choose?
Choosing the right tool depends on your throughput requirements, operational complexity tolerance, and whether you need kernel integration. I have seen teams adopt DPDK when XDP would have sufficed, resulting in months of unnecessary maintenance burden. Conversely, I have seen iptables configurations that caused packet loss during legitimate traffic spikes because the team underestimated netfilter overhead.
| Criteria | XDP | iptables/nftables | DPDK |
|---|---|---|---|
| Max throughput (single core) | 10–25+ Mpps | 0.5–2 Mpps | Line-rate (hardware dependent) |
| Kernel integration | Native (shares stack) | Native | Bypasses kernel entirely |
| Development complexity | Moderate (C/eBPF) | Low (declarative rules) | High (userspace drivers) |
| Safety guarantees | Verifier-enforced | Kernel module risks | Userspace bugs possible |
| NIC compatibility | Driver-dependent | Universal | PMD-specific |
| Best use case | DDoS, LB, telemetry | Host firewall, NAT | Telco, HFT, dedicated appliances |
For most DevOps and SRE teams, XDP offers the optimal balance. It integrates with your existing Cilium eBPF networking for Kubernetes deployments, works alongside systemd and netplan, and doesn't require dedicating entire CPU cores exclusively to polling. Reserve DPDK for scenarios where you are building a dedicated network appliance and can afford to bypass the kernel entirely.
How do you debug and monitor XDP programs in production?
Observability is non-negotiable for XDP. A buggy program can silently drop legitimate traffic or fail open. You cannot rely on tcpdump alone because XDP actions occur before the packet reaches the capture point.
Use BPF maps to maintain per-CPU counters for dropped, passed, and redirected packets. Export these via a userspace exporter to Prometheus. For detailed debugging, use ring buffers (preferred over perf buffers in 2026 due to better memory efficiency) to send sampled packet headers to userspace. Always implement a kill switch: attach a secondary XDP program or use bpftool net detach as part of your incident response runbook.
When integrating with broader observability, ensure your XDP metrics align with your SLIs. If you define availability based on successful request processing, your XDP drop counter must distinguish between malicious traffic and legitimate requests. Misclassifying these leads to misleading error budgets. Refer to our guide on defining meaningful SLIs and SLOs for patterns that apply equally to eBPF-based infrastructure.
What are the practical limitations and security considerations of XDP?
XDP is powerful but constrained. Understanding these limits prevents production incidents:
- Driver support: Not all NIC drivers implement XDP natively. Generic XDP (SKB mode) works universally but loses the performance advantage. Check
ethtool -i eth0and consult the kernel documentation for your specific driver version. - Packet modification: You can adjust headers using
bpf_xdp_adjust_head, but growing the packet beyond the original buffer size is impossible. Encapsulation protocols that add significant headers may require TC-layer eBPF instead. - No stateful inspection: XDP operates statelessly per packet. Connection tracking requires maintaining state in BPF maps, which has memory and concurrency limits. For complex stateful logic, combine XDP (for fast-path filtering) with TC or netfilter (for stateful fallback).
- Verifier complexity: As programs grow, verification time increases exponentially. Use bounded loops (
#pragma unroll) and helper functions judiciously. Kernel 6.x improved verifier intelligence, but complex parsers still hit instruction limits.
Security-wise, treat XDP programs like kernel modules. Only load signed, verified bytecode. Restrict CAP_BPF and CAP_NET_ADMIN capabilities. Audit map contents regularly—an attacker who compromises your loader could inject malicious filtering rules. In regulated environments, document XDP behavior as part of your compliance evidence, just as you would for any security control.
Implementing XDP: High-Performance Packet Processing in your infrastructure
XDP: High-Performance Packet Processing transforms Linux from a general-purpose OS into a programmable dataplane capable of handling modern traffic volumes without specialized hardware. Start small: implement basic rate limiting or protocol filtering on a non-critical interface, measure the impact with proper observability, and iterate. Avoid premature optimization—if iptables handles your current load with headroom, XDP adds complexity you don't yet need.
When you do adopt it, integrate XDP into your existing GitOps and CI/CD workflows. Store eBPF source in version control, automate compilation and verification in your pipeline, and deploy via configuration management. The goal is reproducible, auditable network behavior—not ad-hoc scripts loaded manually at 2 AM during an incident.
If your team needs help designing eBPF-based networking, auditing existing XDP deployments, or integrating high-performance packet processing with your compliance requirements, reach out to discuss your infrastructure challenges. Production-grade XDP requires careful planning, but the payoff in resilience and performance is substantial.