BPF Tail Calls

A tail call lets one eBPF program hand control to another eBPF program and never come back — it behaves like a goto into a different program, not like a function call. The running program issues bpf_tail_call(ctx, &prog_array, index); the kernel looks up program number index in a special BPF_MAP_TYPE_PROG_ARRAY map, resets the BPF stack, and jumps to the first instruction of that program with the context (R1) preserved. Control flow does not return to the caller — there is no return value to collect, no continuation. This is the mechanism that lets eBPF build dispatch tables and program chains that far exceed what a single verifier-bounded program can hold, because each tail-call target is a separate program with its own fresh complexity budget (ebpf.io tail calls; man7 bpf-helpers). To stop a chain from looping forever, the kernel caps the number of tail calls per initial invocation at MAX_TAIL_CALL_CNT = 33 (verified below against the v6.12 source) — after which bpf_tail_call simply fails and, unusually, the caller continues running its next instruction.

This is the cousin of BPF-to-BPF Function Calls. The contrast is the whole point: a bpf2bpf call returns with a value and shares one program’s stack and complexity budget; a tail call replaces the program, resets the stack, and gives the target a brand-new budget. The two also share a combined call-depth budget and interact through the JIT in ways covered below. The prog-array map that holds tail-call targets is one of the specialized maps; the stack and register conventions a tail call resets are defined in The BPF Calling Convention and Stack.

Mental Model — A goto Between Programs

The cleanest way to think about a tail call is as a replacement, not a nesting. When bpf_tail_call succeeds, the current program is done: its stack frame is torn down and the CPU begins executing the next program in its place, on the same call stack depth, with only the context pointer carried across. Nothing about the caller survives — not its stack variables, not its registers (other than the context), not a return path. Compare a bpf2bpf call, which pushes a new frame below the caller and pops back up to it with R0 set.

flowchart LR
  subgraph TC["Tail call — replace (goto)"]
    A["prog A"] -->|"bpf_tail_call(ctx,&pa,2)<br/>stack reset, ctx kept"| B["prog at index 2<br/>(A is gone)"]
    B -->|"bpf_tail_call(...)"| C["prog at index 5"]
  end
  subgraph FC["bpf2bpf call — nest (call/ret)"]
    M["main"] -->|"call"| F["subfunc"]
    F -->|"ret R0"| M
  end

Tail call versus function call. What it shows: a tail call (left) is a one-way jump — A vanishes and the index-2 program runs in its place at the same stack depth, then it can jump onward to index 5, forming a chain; a bpf2bpf call (right) nests and returns. The insight: because each tail-call target is an independent program, the chain can be arbitrarily long in code (up to 33 jumps) while staying flat in stack — this is how eBPF builds large pipelines and dispatch tables without ever exceeding one program’s 512-byte stack or one-million-instruction verifier limit. The cap on the number of jumps is what makes “a goto between programs” terminate.

The prog-array Map — Where Targets Live

Tail-call targets are stored in a map of type BPF_MAP_TYPE_PROG_ARRAY: an array whose values are file descriptors of loaded BPF programs rather than ordinary data (ebpf.io tail calls). The index argument to bpf_tail_call is the array slot. Userspace (or another BPF program) populates the slots by updating the map with program FDs; an empty or out-of-range slot makes the tail call a no-op (the caller continues). This indirection is exactly what makes tail calls a dynamic dispatch table: you can swap the program at index 2 at runtime without touching the program that jumps to it, and you can build a jump table indexed by, say, an L4 protocol number or a syscall number. See Specialized Maps (prog-array, sockmap, cgroup-storage) for the map family this belongs to.

There are conditions on what may be placed in a prog-array. The programs must be of a compatible type and attach context, and historically a program that makes tail calls and one that is a target must agree on whether they also use bpf2bpf calls — the kernel records the “owner” properties of the prog-array on first insert and rejects incompatible programs later. The key practical rule: every tail-call target is treated as a fresh program — “starting with a zero stack and only a context at R1” (ebpf.io tail calls) — so each target passes the verifier independently and earns its own complexity budget.

Semantics — What bpf_tail_call Actually Does

The helper signature, from the kernel BPF helper documentation (man7 bpf-helpers):

long bpf_tail_call(void *ctx, struct bpf_map *prog_array_map, u32 index);

Its behavior is precisely specified by the man page and confirmed by the interpreter source:

  • On success it does not return. “If the call succeeds, the kernel immediately runs the first instruction of the new program. This is not a function call, and it never returns to the previous program.” The context ctx (in R1) is carried to the new program; everything else is reset.
  • On failure the caller keeps running. “If the call fails, then the helper has no effect, and the caller continues to run its subsequent instructions.” A failure happens when the index is out of range, the target slot is empty, or the tail-call limit has been reached. This is the surprising part: a failed bpf_tail_call does not abort the program — execution falls through to the instruction after the helper call. Code that assumes the tail call “always replaces me” is wrong on the failure path.

The ground-truth implementation is the interpreter’s JMP_TAIL_CALL block in kernel/bpf/core.c (v6.12, ~line 2021), which is the clearest statement of the semantics:

JMP_TAIL_CALL: {
    struct bpf_map *map = (struct bpf_map *) (unsigned long) BPF_R2;
    struct bpf_array *array = container_of(map, struct bpf_array, map);
    struct bpf_prog *prog;
    u32 index = BPF_R3;
 
    if (unlikely(index >= array->map.max_entries))
        goto out;                              /* out-of-range -> fall through */
    if (unlikely(tail_call_cnt >= MAX_TAIL_CALL_CNT))
        goto out;                              /* limit hit  -> fall through  */
    tail_call_cnt++;
    prog = READ_ONCE(array->ptrs[index]);
    if (!prog)
        goto out;                              /* empty slot -> fall through  */
    insn = prog->insnsi;
    goto select_insn;                          /* JUMP into the new program   */
out:
    CONT;                                      /* continue current program    */
}

Reading it line by line: BPF_R2 carries the prog-array map pointer, BPF_R3 the index. The three goto out paths — bad index, exhausted counter, empty slot — all fall through to CONT, i.e. the caller resumes at the next instruction. Only if all three checks pass does it set insn = prog->insnsi and goto select_insn, which begins executing the target program’s instruction stream without growing the call stack — the same tail_call_cnt local persists, the same dispatch loop continues. There is no call, no new frame: that is what “tail” means.

The Limit — MAX_TAIL_CALL_CNT = 33, Verified

Defined in include/linux/bpf.h:1929:

#define MAX_TAIL_CALL_CNT 33

Walking the counter logic from the interpreter above with tail_call_cnt starting at 0: the check is tail_call_cnt >= 33 before the increment. So the 1st tail call sees 0 >= 33 (false) and proceeds, bumping the counter to 1; the 33rd tail call sees 32 >= 33 (false) and proceeds, bumping it to 33; the 34th sees 33 >= 33 (true) and fails. Exactly 33 tail-call jumps are permitted per initial invocation. Since the entry program also runs, the maximum number of programs that execute in one chain is the entry program plus 33 targets — 34 programs total.

This is a frequent source of off-by-one confusion in documentation. Two facts explain it. First, the constant was 32 until Linux 5.16, where it was changed to 33 by commit ebf7f6f0a6cd (whose GitHub commit page lists v5.16 as the earliest containing release); its changelog notes that even when the macro said 32, the actual achievable limit was already 33 — the rename merely made MAX_TAIL_CALL_CNT match reality. Second, some docs (including the ebpf.io page) still phrase it as “32 tail calls / 33 programs,” reflecting either the old value or a different counting convention. The authoritative statement for a 6.12 kernel is the source above: MAX_TAIL_CALL_CNT == 33, and the man page agrees it is “currently set to 33” (man7 bpf-helpers).

Uncertain

Documentation phrasing of the limit varies (“32 tail calls”, “33 programs”, “33 tail calls”). The kernel constant MAX_TAIL_CALL_CNT == 33 in v6.12 is verified directly from source, and the >=-before-++ interpreter logic implies 33 permitted jumps / 34 programs maximum per initial entry. Some references still cite 32, which is the pre-5.16 value. If a precise “how many programs ran” matters for a test, verify against the running kernel’s macro and the JIT path for your architecture (JIT and interpreter must agree). uncertain

State Is Reset — How to Pass Data Across a Tail Call

Because the target starts with a zeroed stack and clobbered registers, you cannot share state through the stack or general registers across a tail call (ebpf.io tail calls). Only the context pointer survives. There are three idiomatic workarounds:

  1. Context metadata fields. For socket/packet programs, opaque scratch fields travel inside the context: __sk_buff->cb[5] (control-block scratch) and xdp_md->data_meta (a metadata area ahead of the packet) are preserved across tail calls and are the canonical place to stash per-packet state for the next program in the chain.
  2. A single-entry per-CPU map. Because a BPF program never migrates to another CPU mid-execution, a per-CPU array map with one entry acts as a per-invocation scratchpad shared across tail calls on the same CPU. The ebpf.io documentation flags a real caveat: on PREEMPT_RT (real-time) kernels a program may be interrupted and re-run later, so per-CPU scratch should be scoped to the same task, not treated as globally exclusive (ebpf.io tail calls).
  3. An ordinary map keyed by something stable (a flow tuple, a PID) when the chain spans contexts where per-CPU assumptions do not hold.

This reset is a feature, not just a constraint: it is why each target gets a clean verifier slate and its own budget.

JIT Considerations — The Counter in a Register

The interpreter keeps tail_call_cnt as a C local, but JITed programs (the normal case) need the counter to live somewhere that survives the stack reset a tail call performs. The per-architecture JIT threads it through a register and the program prologue (Cloudflare: BPF tail calls on x86 and ARM; LWN 830520):

  • x86-64. The counter is carried in rax (which maps to BPF’s R0). The JIT prologue establishes it — the modern layout uses an xor eax, eax followed by push rax to initialize and preserve the counter so it can survive across boundaries — and emits, before each tail call, the equivalent of if (tail_call_cnt >= MAX_TAIL_CALL_CNT) goto out; then an increment. The target is reached with a jmp (not a call): the JIT loads array->ptrs[index], reads the program’s bpf_func entry, skips the target’s prologue (so the counter is not re-zeroed), and jumps. Stack is unwound before the jump so the frame is reused.
  • arm64. A dedicated register, x26, holds the tail-call counter. The crucial subtlety: only the main program’s prologue may initialize x26 to zero; subprograms must not reset it, or a bpf2bpf-then-tailcall pattern could reset the counter and exceed the real limit. The arm64 fix guards initialization with if (!ebpf_from_cbpf && is_main_prog). Before jumping, arm64 unwinds the BPF stack (add sp, sp, #0x200 for a 512-byte frame) and then enters the target.

The reason this matters beyond trivia is the bpf2bpf interaction below: to mix tail calls with subprogram calls safely, the counter must be passed from caller to callee across a bpf2bpf boundary so that a sub-function’s tail call increments the same counter the top-level program is using.

Mixing With bpf2bpf Calls — History and the 256-Byte Rule

Originally, tail calls and bpf2bpf calls were mutually exclusive: a program could use one or the other, never both (LWN 830520). The restriction was lifted incrementally, per architecture, because each JIT must learn to propagate the tail-call counter across the call boundary (ebpf.io functions):

ArchitectureMixing supported since
x86-64Linux 5.10 (commit e411901c0b77)
arm64Linux 6.0
s390Linux 6.3
LoongArchLinux 6.4

As of v6.12, exactly these four architectures support mixing. I verified this against the source: x86-64, arm64, s390, and LoongArch each define bpf_jit_supports_subprog_tailcalls() in their JIT, while arch/powerpc/net/bpf_jit_comp*.c does not at the v6.12 tag — so powerpc64 still rejects mixing there (a posted powerpc64 patch series existed but was not merged as of 6.12). Any architecture whose JIT lacks that predicate rejects a program that combines tail calls with bpf2bpf calls.

The cost of mixing is a stack-budget cut from 512 bytes to 256 bytes for any function on a path that can reach a tail call. The danger is concrete: a tail call reuses the current frame, but when issued from inside a subprogram the caller’s frames cannot be reclaimed (they sit below the tail-called program). Without a limit, a chain alternating subprogram calls and tail calls could reach 512 × 33 ≈ 16 KiB of BPF stack. Halving the per-function budget to 256 caps the worst case near 256 × 33 ≈ 8 KiB, which sits comfortably within the kernel’s per-thread stack (THREAD_SIZE, 16 KiB on x86-64/arm64 at 6.12) alongside the kernel’s own frames — the 8 KiB figure in the verifier comment is this BPF worst-case accumulation, not the thread stack size itself. The verifier enforces this in check_max_stack_depth_subprog (verifier.c, v6.12 ~line 6022):

if (idx && subprog[idx].has_tail_call && depth >= 256) {
    verbose(env,
        "tail_calls are not allowed when call stack of previous frames is %d bytes. Too large\n",
        depth);
    return -EACCES;
}

The same routine sets tail_call_reachable = true on every subprogram frame on a tail-call path, which is the signal the JIT uses to know it must preserve and propagate the counter through that subprogram’s prologue/epilogue. This shared budget is exactly why these two notes are siblings: the 8-frame, 512-byte (or 256-byte-when-mixed) accounting is one combined call-depth budget spanning both bpf2bpf calls and tail calls. See BPF-to-BPF Function Calls for the depth-accumulation walk-through.

Worked Example — A Dispatch Table

#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
 
/* prog-array: slots hold FDs of loaded BPF programs (the dispatch table). */
struct {
    __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
    __uint(max_entries, 256);
    __type(key, __u32);
    __type(value, __u32);                 /* prog FD stored by userspace */
} jmp_table SEC(".maps");
 
SEC("xdp")
int dispatcher(struct xdp_md *ctx)
{
    void *data     = (void *)(long)ctx->data;
    void *data_end = (void *)(long)ctx->data_end;
    struct ethhdr *eth = data;
 
    if ((void *)(eth + 1) > data_end)     /* bounds check: verifier demands it */
        return XDP_PASS;
 
    __u32 idx = eth->h_proto;             /* e.g. dispatch on ethertype */
    bpf_tail_call(ctx, &jmp_table, idx);  /* JUMP to per-protocol handler */
 
    /* Reached ONLY if the tail call failed (empty slot / index too big /
     * 34th call). NOT reached on success — control left for good. */
    return XDP_PASS;
}

Line-by-line: jmp_table is the BPF_MAP_TYPE_PROG_ARRAY; userspace loads per-protocol XDP programs and writes their FDs into slots. The dispatcher does the mandatory packet bounds check (the verifier rejects any unchecked packet read — see Verifier Memory Safety and Pointer Types), computes a dispatch index from the ethertype, and tail-calls. The return XDP_PASS after the helper is the fallthrough path: it runs only if the slot was empty, the index was out of range, or the 33-call limit was hit — a real and easy-to-forget code path. On success, the indexed program runs in the dispatcher’s place with the same ctx, having received a clean stack and its own verifier budget.

Failure Modes and Common Misunderstandings

  • “My code after bpf_tail_call mysteriously runs.” It runs whenever the tail call fails — bad index, empty slot, or limit reached. Always write the fallthrough as a meaningful default (e.g. XDP_PASS), never assume the helper always replaces you.
  • Stale or empty prog-array slots. Updating a prog-array is a live operation; a slot that has not been populated yet makes the tail call a silent no-op. Diagnose chains that “stop early” by checking the map contents (bpftool map dump).
  • Lost state across the jump. Stack locals and R6R9 do not survive. Symptoms are zeroed/garbage values in the target. Move shared state into __sk_buff->cb, data_meta, or a per-CPU scratch map.
  • “too large” verifier rejection when mixing. Combining tail calls with bpf2bpf calls and exceeding the 256-byte caller-stack cap yields "tail_calls are not allowed when call stack of previous frames is N bytes. Too large". Shrink the caller’s on-stack usage on the tail-call path.
  • Counting the limit wrong. Assuming 32 (or 31) jumps leads to off-by-one bugs in deep pipelines. The 6.12 value is 33 jumps (MAX_TAIL_CALL_CNT == 33); the 34th fails.
  • Architecture without mixing support. On an architecture not in the table above, a program that uses both tail calls and bpf2bpf calls is rejected at load. Either flatten to no subprograms or upgrade the kernel/architecture.

Alternatives and When to Choose Them

  • bpf2bpf subprograms — when you need a return value and want to share the caller’s stack and budget. Choose for “call this and continue.”
  • Tail calls (this note) — when you want to replace the program: program chaining, protocol/syscall dispatch tables, and breaking a too-complex program into independently verified stages each with a fresh budget. Choose for state-machine pipelines and dynamic dispatch.
  • [[Verifier Bounded Loops and Termination|Bounded loops / bpf_loop]] — when the repetition is data iteration within one program rather than a jump to different code. Often simpler than a self-referential tail-call loop.
  • Multiple independently attached programs — when stages are genuinely independent hooks rather than one logical pipeline; orchestrate from userspace instead of chaining in-kernel.

Production Notes

Tail calls predate bpf2bpf calls and were for years the way to escape the single-program complexity ceiling, so large datapaths are built around them. Cilium’s BPF datapath uses tail calls extensively to chain its packet-processing stages and to dispatch by traffic type, and libxdp’s multi-program XDP dispatcher composes independent XDP programs through a prog-array (Cilium BPF architecture). The Cloudflare engineering write-up on the x86/arm64 JIT implementation is the canonical deep dive on how the jump and counter are emitted in native code (Cloudflare). The recurring operational lesson: because tail-call targets are swappable at runtime via the prog-array, tail calls are also a deployment primitive — you can hot-update one stage of a chain by replacing a map entry — but that same liveness is what makes empty-slot fallthrough bugs and stale-program issues a real production hazard to monitor.

See Also