XDP Programming¶
🚀 Learning Objectives
- Understand XDP (Express Data Path)
- Write high-performance XDP programs
- Process packets at line rate
- Implement DDoS protection
- Build load balancers with XDP
Introduction to XDP¶
XDP (Express Data Path) runs eBPF programs at the earliest point in the Linux kernel networking stack, before any kernel networking processing.
XDP Performance
XDP can process packets at line rate (10M+ packets/second) with minimal CPU overhead.
XDP Program Structure¶
Basic XDP Program¶
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/in.h>
SEC("xdp")
int xdp_pass(struct xdp_md *ctx) {
return XDP_PASS;
}
char LICENSE[] SEC("license") = "GPL";
XDP Return Codes¶
XDP_PASS // Pass packet to kernel stack
XDP_DROP // Drop packet
XDP_ABORTED // Error occurred
XDP_REDIRECT // Redirect to another interface/CPU
XDP_TX // Transmit packet back out same interface
Packet Parsing¶
Parse Ethernet and IP Headers¶
SEC("xdp")
int parse_packet(struct xdp_md *ctx) {
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;
struct ethhdr *eth = data;
struct iphdr *ip;
// Check Ethernet header bounds
if ((void *)(eth + 1) > data_end) {
return XDP_DROP;
}
// Check for IP
if (eth->h_proto != __constant_htons(ETH_P_IP)) {
return XDP_PASS;
}
// Check IP header bounds
ip = (struct iphdr *)(eth + 1);
if ((void *)(ip + 1) > data_end) {
return XDP_DROP;
}
// Process IP packet
bpf_printk("Packet: %pI4 -> %pI4", &ip->saddr, &ip->daddr);
return XDP_PASS;
}
DDoS Protection¶
Rate Limiting¶
struct {
__uint(type, BPF_MAP_TYPE_LRU_HASH);
__uint(max_entries, 10000);
__type(key, u32); // Source IP
__type(value, u64); // Packet count
} rate_limit SEC(".maps");
SEC("xdp")
int ddos_protection(struct xdp_md *ctx) {
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;
struct ethhdr *eth = data;
struct iphdr *ip;
u64 *count, zero = 0, one = 1;
u64 now = bpf_ktime_get_ns();
if ((void *)(eth + 1) > data_end) return XDP_DROP;
if (eth->h_proto != __constant_htons(ETH_P_IP)) return XDP_PASS;
ip = (struct iphdr *)(eth + 1);
if ((void *)(ip + 1) > data_end) return XDP_DROP;
// Rate limit per source IP
count = bpf_map_lookup_elem(&rate_limit, &ip->saddr);
if (!count) {
bpf_map_update_elem(&rate_limit, &ip->saddr, &one, BPF_ANY);
return XDP_PASS;
}
if (*count > 1000) { // Threshold
return XDP_DROP;
}
__sync_fetch_and_add(count, 1);
return XDP_PASS;
}
Load Balancing¶
Simple Load Balancer¶
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, 10);
__type(key, u32);
__type(value, u32); // Backend IP
} backends SEC(".maps");
SEC("xdp")
int load_balance(struct xdp_md *ctx) {
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;
struct ethhdr *eth = data;
struct iphdr *ip;
u32 backend_idx = 0;
u32 *backend_ip;
if ((void *)(eth + 1) > data_end) return XDP_DROP;
if (eth->h_proto != __constant_htons(ETH_P_IP)) return XDP_PASS;
ip = (struct iphdr *)(eth + 1);
if ((void *)(ip + 1) > data_end) return XDP_DROP;
// Simple round-robin (in production, use hash)
backend_ip = bpf_map_lookup_elem(&backends, &backend_idx);
if (backend_ip) {
// Rewrite destination IP
ip->daddr = *backend_ip;
// Recalculate checksum
ip->check = 0;
// Update checksum (simplified)
}
return XDP_PASS;
}
Packet Modification¶
Rewrite Packet Headers¶
SEC("xdp")
int rewrite_packet(struct xdp_md *ctx) {
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;
struct ethhdr *eth = data;
struct iphdr *ip;
if ((void *)(eth + 1) > data_end) return XDP_DROP;
if (eth->h_proto != __constant_htons(ETH_P_IP)) return XDP_PASS;
ip = (struct iphdr *)(eth + 1);
if ((void *)(ip + 1) > data_end) return XDP_DROP;
// Modify TTL
if (ip->ttl > 1) {
ip->ttl--;
// Recalculate checksum
ip->check = 0;
}
return XDP_PASS;
}
Best Practices¶
XDP Best Practices
- Check bounds: Always validate packet boundaries
- Early returns: Drop invalid packets quickly
- Minimize processing: Keep programs simple and fast
- Use appropriate maps: LRU hash for rate limiting
- Handle errors: Return appropriate XDP codes
Next Steps: - Learn BPF CO-RE (Chapter 12) - Explore advanced techniques (Chapter 13) - Review research papers (Chapter 14)
Previous: Performance Profiling
Next: BPF CO-RE