Console Login

eBPF & XDP: Crushing Network Latency on Linux (The 2019 Guide)

eBPF & XDP: The End of Linux Networking Bottlenecks?

Let's be honest. If you are still relying solely on iptables or nftables for high-volume packet filtering, you are doing it wrong. I've watched too many systems capsize under a moderate DDoS attack not because the hardware couldn't take it, but because the Linux kernel network stack was too polite. It tries to allocate an sk_buff for every piece of garbage hitting the NIC. By the time the kernel realizes the packet should be dropped, you've already wasted CPU cycles you'll never get back.

It is September 2019. We have better tools now. We have eBPF (extended Berkeley Packet Filter) and XDP (eXpress Data Path). If you are managing infrastructure in Norway—where latency to NIX (Norwegian Internet Exchange) is measured in single-digit milliseconds—you cannot afford software interrupts killing your edge performance.

The Problem: The Heavy Cost of sk_buff

In a standard Linux environment—like a generic VPS utilizing older virtualization—a packet traverses a long path. Ethernet driver -> sk_buff allocation -> GRO -> IP stack -> iptables -> Socket. That path is expensive. When you are pushing 10Gbps or handling millions of packets per second (PPS), that allocation overhead causes the CPU to spend 100% of its time in SoftIRQ context (ksoftirqd). The server isn't doing work; it's just shuffling papers.

Pro Tip: Check your SoftIRQ usage right now. Run mpstat -P ALL 1. If your %soft is over 30% on a single core during peak load, your network stack is the bottleneck.

The Solution: XDP (eXpress Data Path)

XDP allows us to run eBPF programs at the earliest possible point in the driver, before the kernel allocates the heavy sk_buff struct. It is essentially a programmable hook in the NIC driver. You can look at the packet, make a decision (Drop, Pass, Redirect), and execute it instantly.

This isn't theoretical. On a CoolVDS KVM instance running a modern kernel (4.18+ or the new Debian 10 Buster kernel), we can process roughly 10x to 15x more packets per second using XDP compared to standard iptables.

Writing a Basic XDP Drop Program

You don't need to be a kernel engineer to write this, but you do need C. Here is a minimal example of an XDP program that drops TCP packets on a specific port. This compiles into BPF bytecode that runs safely inside the kernel sandbox.

#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <netinet/in.h>

#define SEC(NAME) __attribute__((section(NAME), used))

SEC("prog")
int xdp_drop_tcp(struct xdp_md *ctx) {
    void *data_end = (void *)(long)ctx->data_end;
    void *data = (void *)(long)ctx->data;
    struct ethhdr *eth = data;

    // Bounds checking is mandatory for the BPF verifier
    if (data + sizeof(*eth) > data_end)
        return XDP_PASS;

    if (eth->h_proto != htons(ETH_P_IP))
        return XDP_PASS;

    struct iphdr *ip = data + sizeof(*eth);
    if ((void *)(ip + 1) > data_end)
        return XDP_PASS;

    if (ip->protocol == IPPROTO_TCP) {
        // Logic: If it's TCP, drop it (oversimplified example)
        // In production, you'd check destination ports or headers
        return XDP_DROP;
    }

    return XDP_PASS;
}

char _license[] SEC("license") = "GPL";

To compile this in 2019, you need clang and llvm installed. The command looks like this:

clang -O2 -target bpf -c xdp_prog.c -o xdp_prog.o

Loading the Program

Once compiled, we attach it to the network interface. On a CoolVDS instance, your primary interface is usually eth0 or ens3.

# Load the XDP object
ip link set dev eth0 xdp obj xdp_prog.o sec prog

# Verify it is loaded
ip link show eth0
# Output should contain: xdp loaded ...

When you are done testing, remove it:

ip link set dev eth0 xdp off

Observability: seeing the unseen

Performance isn't just about speed; it's about visibility. In Norway, Datatilsynet (The Data Protection Authority) takes GDPR strictly. You often need to audit data flows without impacting performance. Standard logging (syslog) is too slow for high-frequency trading or real-time bidding.

We use bpftrace (which is becoming the standard replacement for SystemTap) to inspect the system with zero overhead. Here is a one-liner to trace all new TCP connections live, useful for debugging microservice latency:

bpftrace -e 'kprobe:tcp_connect { 
    printf("Time: %s PID: %d Comm: %s\n", 
    strftime("%H:%M:%S", nsecs), pid, comm); 
}'

The Hardware Reality

Here is the hard truth: eBPF requires a modern kernel and genuine hardware virtualization. Many "cheap" VPS providers in Europe are still selling OpenVZ 6 containers rooted in the ancient 2.6.32 kernel era. You cannot run eBPF there. It simply won't work.

This is why we architect CoolVDS on KVM. We expose the CPU flags and support kernels like 4.19 LTS and 5.x. When you deploy a CoolVDS NVMe instance, you aren't fighting neighbors for kernel resources. You get the dedicated instructions needed to offload packet processing.

Feature Legacy VPS (OpenVZ) CoolVDS (KVM)
Kernel Version Shared (often old) Dedicated (4.19/5.x supported)
eBPF/XDP Support No Yes (Native)
Packet Drop Cost High (IP Stack) Zero (Driver Level)

Final Thoughts

The Linux networking stack is changing. With the rise of Kubernetes (and tools like Cilium using eBPF), the old ways of managing firewalls are fading. If you are building high-performance applications targeting the Nordic market, you need to be closer to the metal.

Stop letting interrupt handlers steal your CPU cycles. Switch to a platform that supports the tools of 2019, not 2009.

Ready to test XDP performance? Spin up a Debian 10 instance on CoolVDS today and see the difference raw NVMe and KVM isolation make.