XDP Packet Processing
XDP Fundamentals and Packet Parsing
XDP (eXpress Data Path) - packet processing at the driver level, before entering the kernel stack. The fastest eBPF hook point.
XDP Fundamentals and Packet Parsing
What you will learn in this lab:
- XDP modes: Generic (test), Native (production), Offload (NIC)
- XDP actions:
XDP_PASS- forward the packet to the kernel stackXDP_DROP- drop the packet (fastest)XDP_TX- send the packet back out the same interfaceXDP_REDIRECT- redirect to another interfaceXDP_ABORTED- error, drop the packet + trace
struct xdp_mdcontext (data,data_end,data_meta)- Ethernet header parsing (
struct ethhdr) - IPv4/IPv6 header parsing
- TCP/UDP header parsing
- ICMP parsing
- Byte order:
bpf_ntohs(),bpf_htons()
Packet Parsing Pattern
SEC("xdp")
int xdp_parser(struct xdp_md *ctx) {
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;
struct ethhdr *eth = data;
if (data + sizeof(*eth) > data_end)
return XDP_PASS;
if (eth->h_proto == bpf_htons(ETH_P_IP)) {
struct iphdr *ip = data + sizeof(*eth);
if ((void *)(ip + 1) > data_end)
return XDP_PASS;
// IPv4 packet processing...
}
return XDP_PASS;
}
Full parse chain: Ethernet → IP → TCP/UDP
Extending the basic pattern above into a complete L3/L4 parser:
SEC("xdp")
int xdp_full_parse(struct xdp_md *ctx) {
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;
// L2: Ethernet
struct ethhdr *eth = data;
if (data + sizeof(*eth) > data_end)
return XDP_PASS;
if (eth->h_proto != bpf_htons(ETH_P_IP))
return XDP_PASS; // not IPv4, skip
// L3: IPv4
struct iphdr *ip = data + sizeof(*eth);
if ((void *)(ip + 1) > data_end)
return XDP_PASS;
// L4: TCP or UDP
void *l4 = (void *)ip + (ip->ihl * 4); // IP header can be variable length
if (ip->protocol == IPPROTO_TCP) {
struct tcphdr *tcp = l4;
if ((void *)(tcp + 1) > data_end)
return XDP_PASS;
// tcp->dest has the destination port (network byte order)
if (tcp->dest == bpf_htons(80))
return XDP_DROP; // drop HTTP traffic
} else if (ip->protocol == IPPROTO_UDP) {
struct udphdr *udp = l4;
if ((void *)(udp + 1) > data_end)
return XDP_PASS;
// udp->dest has the destination port
if (udp->dest == bpf_htons(53))
return XDP_DROP; // drop DNS traffic
}
return XDP_PASS;
}
Notice the pattern: every pointer dereference requires a bounds check against data_end. The verifier enforces this. Skip any check and your program will not load.
xdp-tutorial: packet01-parsing/ - do it yourself!
How to work through xdp-tutorial:
- Read
README.orgfirst (understand the assignments) - Read
xdp_prog_kern.c, inspectparsing_helpers.h - Do the assignments yourself
- If you get stuck, check the
packet-solutions/folder
Prerequisite reading: XDP Paper (~15 pages)
Inspect in xdp-tutorial: setup_dependencies.org - dependencies (clang, llvm, libelf, kernel headers, bpftool, libxdp, libbpf).
xdp-tutorial Directory Guide
The xdp-tutorial repository is organized into progressive folders. Use this table to know which folder to study and when.
| Folder | What It Teaches | When to Use |
|---|---|---|
basic01-xdp-pass | Minimal XDP program that passes all packets | Start here; first XDP program |
basic02-prog-by-name | Loading and attaching XDP programs by section name | Right after basic01 |
basic03-map-counter | Using BPF maps to count packets | When learning maps (Chapter 2+) |
basic04-pinning-maps | Pinning maps to the BPF filesystem for persistence | After basic03, before multi-program setups |
packet01-parsing | Parsing Ethernet, IP, and TCP/UDP headers safely | Core skill; study before building any filter |
packet02-rewriting | Rewriting packet headers (MAC, IP) | Needed for load balancer and NAT projects |
packet03-redirecting | Redirecting packets between interfaces with bpf_redirect | Load balancer and forwarding use cases |
tracing01-xdp-simple | Tracing XDP events with bpf_printk | Debugging any XDP program |
tracing02-xdp-perf-event | Perf event output from XDP programs | When you need structured event output |
advanced01-xdp-load-balancer | Full XDP load balancer example | After completing packet01-03; compare with your own LB |
advanced03-AF_XDP | AF_XDP socket for user-space packet processing | Optional; only if you need user-space fast path |