---
title: "BPF, XDP, Packet Filters and UDP"
description: "Deploying unmodified UDP applications across an anycast edge and worker network is harder than proxying HTTP, because UDP carries no convenient metadata for forwarding the original socket addresses. The initial implementation used userland services, AF_PACKET sockets, and custom proxying, but the post argues that kernel-level packet handling is a better fit than adding and monitoring another service. It explains BPF’s evolution into eBPF, then describes using XDP for fast ingress processing, XDP_REDIRECT around WireGuard limitations, and TC BPF on the worker side; Firecracker tap devices make reply traffic appear as host ingress. The verifier requires bounds checks and debugging benefits from dropwatch and perf-based packet tracing. The result is a beta deployment path for UDP applications on Fly.io."
---

# BPF, XDP, Packet Filters and UDP

[Fly.io](https://yomu.fyi/company/fly-io) · Oct 20, 2020

**Type:** Explainer

## Summary

Deploying unmodified UDP applications across an anycast edge and worker network is harder than proxying HTTP, because UDP carries no convenient metadata for forwarding the original socket addresses. The initial implementation used userland services, AF\_PACKET sockets, and custom proxying, but the post argues that kernel-level packet handling is a better fit than adding and monitoring another service. It explains BPF’s evolution into eBPF, then describes using XDP for fast ingress processing, XDP\_REDIRECT around WireGuard limitations, and TC BPF on the worker side; Firecracker tap devices make reply traffic appear as host ingress. The verifier requires bounds checks and debugging benefits from dropwatch and perf-based packet tracing. The result is a beta deployment path for UDP applications on Fly.io.

## Context

Unmodified UDP applications are difficult to proxy across edge and worker servers because, unlike HTTP, UDP does not provide convenient metadata for carrying the original source and destination socket addresses. A userland implementation also adds a service that must be monitored on every server.

## Approach / What changed

The implementation uses kernel packet processing with eBPF, XDP, XDP\_REDIRECT, and TC BPF. XDP handles ingress traffic, Firecracker tap devices allow VM replies to appear as host ingress, and TC BPF handles the worker side because XDP does not work directly on WireGuard. dropwatch and perf-based packet tracing support debugging.

## Takeaways

- The initial UDP implementation relied on AF\_PACKET sockets and userland services to add and remove proxy metadata, but the post describes service overhead and operational monitoring as the main drawbacks.
- XDP handles ingress packets but not ordinary transmitted packets; Firecracker tap devices provide a path for VM replies, while WireGuard’s lack of link-layer headers requires XDP\_REDIRECT and TC BPF workarounds.
- eBPF programs must satisfy the verifier’s bounds-safety checks, and packet snapshots sent through perf proved more useful for debugging than printk(); dropwatch also diagnosed many packet-handling bugs.

**Tags:** [BPF](https://yomu.fyi/topic/bpf), [Firecracker](https://yomu.fyi/topic/firecracker), [UDP](https://yomu.fyi/topic/udp), [WireGuard](https://yomu.fyi/topic/wireguard), [XDP](https://yomu.fyi/topic/xdp)

- Source: [Fly.io](https://fly.io/blog/bpf-xdp-packet-filters-and-udp)
- Source URL: https://fly.io/blog/bpf-xdp-packet-filters-and-udp
- Ingested by Yomu: 2026-09-02T11:57:05.169Z

[Read original post](https://fly.io/blog/bpf-xdp-packet-filters-and-udp)
