-
Notifications
You must be signed in to change notification settings - Fork 7
Custom BPF Handlers
Custom handlers work only with the XDP backend. Auto XDP exposes two BPF_PROG_TYPE_XDP tail-call tables:
- Protocol slots, indexed by final IP protocol number 0–255, for GRE, ESP, SCTP, and other L4 protocols.
- Port handlers, indexed by TCP or UDP destination port 1–65535, for application-specific validation.
Include handlers/xdp_slot_ctx.h and call get_slot_ctx(ctx) to reuse fields already parsed and validated by the main program:
struct xdp_slot_ctx {
__u8 family; /* IPv4=2, IPv6=10 */
__u8 ip_proto; /* final protocol after IPv6 extension headers */
__u16 l3_offset;
__u16 inner_offset; /* L4/payload offset */
__be16 sport;
__be16 dport;
__u16 _pad;
__u32 saddr[4];
__u32 daddr[4];
};
static __always_inline struct xdp_slot_ctx *get_slot_ctx(struct xdp_md *ctx);Native XDP reads packet metadata. Generic XDP falls back to the per-CPU slot_ctx_map. IPv4 uses only address word 0. Ports are in network byte order and are normally zero for protocol-level handlers.
// SPDX-License-Identifier: GPL-2.0
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>
#include "xdp_slot_ctx.h"
struct gre_hdr {
__be16 flags;
__be16 proto;
};
SEC("xdp/gre")
int xdp_gre_handler(struct xdp_md *ctx)
{
struct xdp_slot_ctx *sc = get_slot_ctx(ctx);
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;
struct gre_hdr *gre;
if (!sc)
return XDP_PASS;
gre = data + sc->inner_offset;
if ((void *)(gre + 1) > data_end)
return XDP_PASS;
if ((bpf_ntohs(gre->flags) & 0x7) != 0)
return XDP_DROP;
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";Every packet access still needs a verifier-provable data_end check. Whether an unrecognized/truncated optional format should pass or drop is part of the handler's security policy.
The repository Makefile supplies architecture-specific includes and BPF flags:
make -C handlersEquivalent direct compilation is approximately:
clang -O3 -g -target bpf -mcpu=v3 -fno-stack-protector \
-Wall -Ihandlers -Ibpf/include -I/usr/include -I/usr/include/bpf \
-c my_handler.c -o my_handler.oThe administration command also accepts a .c path and invokes the project compiler path. Validate verifier behavior on every target kernel and architecture.
# Built-ins
sudo axdp slot load gre
sudo axdp slot load esp
sudo axdp slot load sctp
# Custom IP protocol
sudo axdp slot load 47 ./my_gre_handler.o
# TCP/UDP destination ports
sudo axdp port-handler load tcp 25565 ./my_handler.o
sudo axdp port-handler load udp 53 ./dns_handler.c
sudo axdp slot list
sudo axdp port-handler listThe transactional load path:
- Compiles a
.cinput if necessary and loads a candidate program. - Reads its program ID.
- Updates the relevant program-array entry and reads it back.
- Moves the candidate pin/file to the live name.
- Restores the old entry and pin if any step fails.
- Normally copies the persistent object under
/etc/auto_xdp/handlersand updates TOML.
--no-config-update is for temporary experiments and does not survive restart.
TCP/UDP port handlers run after base parsing and the main admission/rate policy for the port. Trusted or ACL-admitted UDP traffic can bypass a port handler. TCP handlers can use project-shared maps for multi-packet validation; the repository's Minecraft handler demonstrates pending dispatch, temporary validation state, and source blocking.
- GRE: validates the minimum GRE header and rejects unsupported/unsafe version or flag combinations.
- ESP: validates the minimum ESP structure and basic SPI constraints.
- SCTP: uses configured permanent SCTP ports and shared conntrack maps.
With slots.default_action = "drop", any unhandled non-TCP/UDP/ICMP protocol is denied. Inventory tunnels and VPN protocols before enabling that policy.
sudo axdp backend
sudo axdp slot list
sudo axdp port-handler list
sudo bpftool prog show
sudo bpftool map dump pinned /sys/fs/bpf/xdp_fw/proto_handlers- Test allow, deny, truncated, maximum-length, and state-transition cases.
- Test IPv4/IPv6 where relevant and both native/generic XDP.
- Verify a failed reload leaves the old handler active.
- For stateful handlers, verify capacity, TTL, and cleanup.
- Do not assume the handler runs under nftables fallback.
Auto XDP documentation · Repository · Releases · MPL-2.0