← Back to list

AF_XDP and Kyber Key Exchange in Userspace: Efficient, Flexible, and Modern

Introduction to eBPF and XDP (Quick Primer)

Nikhil Jangid · 2025-09-19 03:48 · 5 claps · 8.3 min read
#ebpf #pqc #kernel #linux #networking
Open on Medium ↗
Wiki topics: 🔓 · Open Source 🔭 · Astronomy & Space

AF_XDP and Kyber Key Exchange in Userspace: Efficient, Flexible, and Modern

Introduction to eBPF and XDP (Quick Primer)

eBPF (extended Berkeley Packet Filter) is a powerful technology that allows sandboxed programs to run inside the Linux kernel without modifying kernel source code. Originally designed for filtering packets, eBPF has evolved into a general-purpose framework used for performance monitoring, security, and networking. If you want to know more about it go through their official **documentation**.

XDP (eXpress Data Path) is one of the most exciting applications of eBPF, allowing packet processing to occur as early as possible — right at the driver level. This means packets can be dropped, redirected, or modified before any higher-level networking stack (IP, TCP, etc.) sees them.

What makes XDP fast:

  • Operates at the earliest possible stage of the networking stack.
  • Zero-copy and kernel-bypass capabilities.
  • Minimal overhead and maximum performance.

This makes XDP especially well-suited for high-performance, low-latency use cases such as DDoS mitigation, load balancing, and custom packet filtering. More on XDP Here.

Why AF_XDP for Flexible Network Stack Bypass

AF_XDP is a socket type that pairs beautifully with XDP to provide user-space applications direct access to network packets. Built atop XDP and eBPF, it allows applications to process packets without going through the traditional Linux networking stack — a big win when you want performance and full control over network behavior.

Advantages of AF_XDP:

  • Bypasses the kernel network stack completely.
  • Provides zero-copy packet delivery between NIC and user space.
  • Works with standard socket interfaces, making integration easier.

In cases where custom protocol handling is needed — like implementing new cryptographic key exchange protocols — AF_XDP provides the best of both worlds: speed and flexibility.

Kyber Key Exchange: An Overview

Kyber is a post-quantum key encapsulation mechanism (KEM) that is part of the NIST-approved suite of algorithms resilient against quantum computer attacks. The basic idea is that two parties can securely exchange a shared key over an insecure channel.

However, Kyber’s computational and data footprint is significantly higher than classical key exchange protocols. This creates two challenges:

  • Payload Size: Kyber’s encapsulated keys and ciphertexts are larger.
  • Latency Sensitivity: Adding key exchange logic in userspace means the kernel’s networking stack becomes an unnecessary overhead.

These challenges make Kyber a great candidate for AF_XDP-based delivery systems.

But why AF_XDP for Kyber Key Exchange?

Here’s the insight: If the entire key exchange logic happens in userspace using libraries like CIRCL (Cloudflare’s cryptographic library for Kyber), why should the packets traverse the kernel’s complex networking stack at all?

Instead, AF_XDP allows us to:

  • Exchange Kyber payloads (public key, ciphertext, shared key) directly between two user-space applications.
  • Avoid any kernel-side TCP/IP stack overhead.
  • Tune performance more precisely (MTU, buffers, batch processing, etc.).

This minimizes CPU usage, improves determinism, and ensures faster and more reliable secure communication channels.

This makes AF_XDP the perfect delivery mechanism for something like Kyber, which simply needs to reliably send a few specific packets between two user-space applications.

The result? A fast, reliable, kernel-bypassing, post-quantum key exchange that respects neither the kernel’s bureaucracy nor outdated networking norms.

Architecture of the Solution: Bringing Kyber to AF_XDP

After understanding AF_XDP and kyber, let’s walk through the architecture we’ve implemented — a system designed to demonstrate how a Kyber key exchange can be performed entirely in user space at high speed, bypassing the traditional network stack.

This section covers two components:

  1. A reference/testbed implementation using Go + CIRCL library
  2. The AF_XDP-powered version, showing how we eliminate kernel overhead

Part 1: Testbed Kyber Key Exchange using CIRCL

To validate the cryptographic part of the system, I started by replicating the shared key generation using Cloudflare’s CIRCL Kyber implementation in Go. This served as a testbed to verify the correctness and usability of the Kyber primitives.

How Kyber Works (Quick Recap)

  • Server generates a Kyber public/private keypair.
  • Client uses the server’s public key to encapsulate a shared secret and sends the ciphertext.
  • Server decapsulates the ciphertext that contains the client’s public key to obtain the same shared secret.
  • Now both parties have a common symmetric key — ideal for secure sessions.

In the Go testbed, this was implemented over traditional Go networking (TCP/UDP), but it proved the core functionality and packet sizes required.

However, the networking overhead in this setup was a bottleneck — hence the need for AF_XDP.

Part 2: High-Speed Kyber Exchange using AF_XDP

Now comes the core solution — a fully functional Kyber key exchange system built on AF_XDP.

  • Two veth pairs connecting two isolated network namespaces.
  • XDP program attached to veth interfaces, enabling redirection.
int xdp_sock_prog(struct xdp_md *ctx) {
        ...
        struct tcphdr *tcp = (void *)(ip + 1);
        if ((void *)(tcp + 1) > data_end)
            return XDP_ABORTED;

        __u16 src_port = bpf_ntohs(tcp->source);
        __u16 dst_port = bpf_ntohs(tcp->dest);
        bpf_printk("TCP src port: %d, dst port: %d\\n", src_port, dst_port);
        if (dst_port == 8080){
            bpf_printk("Redirecting TCP packet\n");
            return bpf_redirect_map(&xsks_map, index, 0);
        }
        ...
}
  • AF_XDP sockets bound to the interfaces in both client and server namespaces.
  • XSK map, used for redirecting packets to AF_XDP sockets.
struct {
    __uint(type, BPF_MAP_TYPE_XSKMAP);
    __uint(max_entries, 64);
    __type(key, __u32);
    __type(value, __u32);
} xsks_map SEC(".maps");

Project Structure Highlights

  • Replicated the shared key establishment process using CIRCL in Go as a baseline.
  • Implemented the same using AF_XDP sockets for raw, direct packet transfer.
  • Cilium’s ebpf2go for compiling and loading XDP programs.
  • slavc bindings and helpers to manage AF_XDP sockets.

Flow:

  1. Server Initiates Key Generation: The server starts by generating its own Kyber key pair using the CIRCL library in Go. It then sends the public key directly to the client over the veth interface via AF_XDP sockets. This packet is redirected efficiently by the XDP program attached to the interface, ensuring minimal overhead.
  2. Client Processes Server’s Public Key and Generates Shared Secret: Upon receiving, the client generates its own Kyber key pair. It then creates a shared secret by encapsulating a random key using the server's public key (this step involves the client's logic but doesn't directly use its private key for encapsulation—rather, encapsulation relies on pk_s). The client produces a ciphertext ct_c containing the encapsulated shared key.
  3. Client Responds with Ciphertext and Its Public Key: The client sends the ciphertext ct_c (which effectively includes or is bundled with its public key pk_c in an encrypted form) back to the server via AF_XDP. This mirrors the process, allowing the server to participate in the exchange.
  4. Server Decapsulates and Creates Shared Key: The server receives ct_c and uses its private key sk_s to decapsulate it, retrieving the shared secret. At this point, both sides have derived the same shared key independently (the server through decapsulation, and the client from its initial encapsulation).
  5. Communication Begins: With the mutual shared key established, secure communication can start. The applications can now encrypt and exchange data using this key, all handled in user space with AF_XDP for zero-copy efficiency. This setup is ideal for custom protocols in security-focused environments, like implementing runtime security checks or observability probes in Kubernetes clusters.

You can also test it on your own system. Here is my repository.

[embed]GitHub - Nikhil690/AFXDP-Kyber-KeyExchange: Kyber Key exchange using AF_XDP Kyber Key exchange using AF_XDP. Contribute to Nikhil690/AFXDP-Kyber-KeyExchange development by creating an account on…github.com

Traffic Flow using AF_XDP

Traffic Flow using AF_XDP

Benchmarks and Performance Evaluation

While AF_XDP is often praised for its low latency and high throughput, in cryptographic protocols like Kyber, predictability and consistency can be equally (if not more) important than sheer speed.

In this section, we compare two versions of our Kyber key exchange implementation:In this section, we compare two versions of our Kyber key exchange implementation:

  1. A traditional user-space version using Go + CIRCL + TCP/UDP
  2. A fully user-space, AF_XDP-accelerated version that bypasses the kernel networking stack

Benchmark Setup

  • Operation measured: Complete Kyber key exchange (encapsulation + decapsulation) per transaction.
  • Total iterations: 4000–5000

Metrics captured:

  • Execution time (in milliseconds)
  • Variance across runs
  • Moving average trends
  • Failures or errors encountered

Refer to this for python scripts.

| Metric              | Traditional Go Stack | AF_XDP-based Stack |
|---------------------|----------------------|---------------------|
| Mean Latency        | 2.15 ms              | 2.05 ms             |
| Variance / Std Dev  | High (±0.99 ms)      | Low (±0.53 ms)      |
| IQR (Boxplot)       | 0.351 ms             | 0.279 ms            |
| Failures            | 1050/5000            | 0/5000              |
| Stability           | Moderate             | Excellent           |
| Kernel Bypass       | ❌ No                | ✅ Yes              |

Performance using AF_XDP

Performance using AF_XDP

Performance without using AF_XDP

Performance without using AF_XDP

According to the graphs and results, the speed and latency are marginally better, but the major improvements are in sustainability and reliability.

Issues, Limitations, and Future Improvements

Building a Kyber key exchange mechanism entirely in userspace using AF_XDP was an exciting and insightful journey, but not without its fair share of challenges. Let’s look at some of the core issues faced during implementation and discuss areas for future improvements.

1. The TCP State Machine: Reinventing the Wheel?

The first major challenge arose from the nature of AF_XDP itself — it operates entirely in userspace and bypasses the kernel’s network stack. While this is excellent for performance, it means you lose access to the kernel’s mature and battle-tested TCP stack, which handles connection management, retransmissions, congestion control, and more.

To achieve a functioning communication channel, we had to re-implement a minimal TCP state machine in userspace. This includes handling the 3-way handshake, connection teardown, and state transitions (e.g., SYN_SENT, ESTABLISHED, FIN_WAIT). Though this doesn’t cause significant overhead in a controlled lab/testbed environment, it adds complexity and fragility in real-world scenarios, especially when reliability, packet loss, or reordering comes into play.

Future Direction: Consider supporting UDP-based transport such as QUIC protocol.

2. Fragmentation and MTU Limitations

A second major issue was the lack of kernel-managed IP fragmentation and reassembly. Because everything happens in userspace, large payloads — especially Kyber ciphertexts and shared secrets — can exceed the typical Ethernet MTU (1500 bytes). This results in truncated or dropped packets unless:

  • We manually handle fragmentation and reassembly in our userland code.
  • Or we increase the MTU of the veth interfaces on both the server and client side (e.g., up to 2500 bytes for jumbo frames).

Currently, we have opted for the latter: increasing the MTU to support larger key exchange payloads. However, this introduces a tradeoff:

  • Not all networks support jumbo frames.
  • It becomes hard to scale or migrate this system outside a controlled environment.

🛠 Future Ideas:

  • Explore a custom fragmentation/reassembly protocol tailored to Kyber’s payload size.
  • Consider using multiple XDP sockets or channels to chunk large data dynamically.

3. Observability and Debugging

One unexpected difficulty was the lack of introspection tools. Unlike kernel-based networking, userspace packet processing lacks conventional logging or tracing mechanisms. Tools like tcpdump don’t help with AF_XDP unless packets also hit the traditional stack.

Future Improvements

1. Efficient Fragmentation Handling in User Space

A promising direction is to implement custom reassembly logic based on sequence numbers or application-layer framing. This can help support larger payloads without depending on MTU tuning. Alternatively, implementing a lightweight layer over UDP with packet sequencing might be feasible.

2. Kernel-Bound Optimizations

Although the current solution works entirely in user space, some hybrid models may allow us to offload certain tasks back to the kernel (e.g., TCP state tracking), using shared memory or eBPF tail calls to optimize performance without duplicating kernel logic.

3. Packaging as a Pluggable Module

Ultimately, we envision this entire setup — Kyber key exchange using AF_XDP — as a modular, reusable component that can be plugged into existing systems.

We aim to:

  • Package this as a Go module.
  • Provide a standardized API for initiating Kyber key exchange over AF_XDP.
  • Integrate with service meshes, proxies, or even IoT platforms that need secure and fast post-quantum key exchange without kernel traversal.

Conclusion

This project is an exciting proof-of-concept demonstrating how modern cryptography (Kyber) and modern networking (AF_XDP, eBPF) can work hand in hand to build secure, performant, and programmable communication systems — all from userspace.

It shows how Linux’s programmable networking stack is not just fast, but flexible enough to accommodate emerging technologies like post-quantum cryptography.

Stay tuned for the open-source release and next iteration as a reusable module!


메타데이터
post_id
d787d1c6dcef
slug
af-xdp-and-kyber-key-exchange-in-userspace-efficient-flexible-and-modern-d787d1c6dcef
url
https://medium.com/@Nikhil690/af-xdp-and-kyber-key-exchange-in-userspace-efficient-flexible-and-modern-d787d1c6dcef
canonical_url
https://medium.com/@Nikhil690/af-xdp-and-kyber-key-exchange-in-userspace-efficient-flexible-and-modern-d787d1c6dcef
author_url
https://medium.com/@Nikhil690
status
ok
fetched_at
2026-07-17 10:26:55