This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
devopscritical PriorityID: ebpf-tail-call-stack-limit-standard

eBPF BPF-to-BPF Tail-Call Recursion & Stack-Limit Standard

Enforces strict stack frame boundaries and deterministic execution limits across chained BPF programs to eliminate kernel stack exhaustion and verifier rejections during high-frequency L4 ingress tracing. Mitigates kernel panic vectors stemming from unbounded BPF-to-BPF function nesting combined with dynamic tail-call recursion. Mandates per-CPU scratchpad offloading for payload parsing buffers exceeding eBPF's 512-byte stack frame limit.

Prohibited Anti-Pattern: Unbounded prog_array tail-call dispatch with deep stack-allocated L4 ingress parsing buffers

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: eBPF BPF-to-BPF Tail-Call Recursion & Stack-Limit Standard - Enforces strict stack frame boundaries and deterministic execution limits across chained BPF programs to eliminate kernel stack exhaustion and verifier rejections during high-frequency L4 ingress tracing. Mitigates kernel panic vectors stemming from unbounded BPF-to-BPF function nesting combined with dynamic tail-call recursion. Mandates per-CPU scratchpad offloading for payload parsing buffers exceeding eBPF's 512-byte stack frame limit.
globs: bpf/**/*.c, bpf/**/*.h, **/*.bpf.c, src/bpf/**/*.c
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/ebpf-tail-call-stack-limit-standard"
---

# eBPF BPF-to-BPF Tail-Call Recursion & Stack-Limit Standard

> **Severity**: CRITICAL | **Category**: devops
> **Anti-Pattern Warning**: Unbounded prog_array tail-call dispatch with deep stack-allocated L4 ingress parsing buffers

## System Constraints
You are a Principal Systems Engineer and Kernel Security Architect enforcing strict eBPF compilation standards. You must ensure that all eBPF programs (XDP, TC, Socket Filter) strictly adhere to kernel stack constraints (<512 bytes per frame), avoid unverified mixed BPF-to-BPF subprogram calls with tail-calls, and eliminate cycles in BPF_MAP_TYPE_PROG_ARRAY routing.

## Strict Guidelines
- Engineers MUST ALWAYS keep BPF stack frame utilization strictly under 512 bytes across all subprograms and callers; stack usage SHOULD stay under 256 bytes per frame for safety margin.
- Engineers MUST NOT allocate packet buffers, large structs, or cryptographic state on the eBPF stack; allocate via BPF_MAP_TYPE_PERCPU_ARRAY scratch buffers instead.
- Engineers MUST ALWAYS structure tail-call dispatch chains as a strictly monotonic, forward-only Directed Acyclic Graph (DAG) with compile-time bounded progression indices.
- Engineers MUST NOT mix arbitrary BPF-to-BPF subprograms with bpf_tail_call() inside sub-frames if the target kernel version exhibits call-stack expansion or verifier rejection on frame unwinding.
- Engineers MUST ALWAYS handle the bpf_tail_call() fallback path explicitly, ensuring default drop (XDP_DROP/TC_ACT_SHOT) or strict error telemetry if the tail call misses or exceeds the MAX_TAIL_CALL_CNT (33).
- Services MUST validate that all prog_array map entries are initialized or sanitized prior to hot path ingress packet processing.

## Bad vs Good Implementations
### L4 Ingress Packet Parsing with Stack Offloading and Monotonic Tail Calls

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Allocating 420 bytes on the stack easily breaches the 512-byte limit once BPF-to-BPF sub-functions or compiler spills occur. Dynamic dispatch into the prog_array allows cyclic execution, risking hitting the kernel 33-call execution limit or verifier rejection, and the silent fallthrough conceals dispatch misses.
```c
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>

struct {
    __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
    __uint(max_entries, 16);
    __type(key, __u32);
    __type(value, __u32);
} jmp_table SEC(".maps");

SEC("xdp")
int xdp_ingress_bad(struct xdp_md *ctx) {
    // ANTI-PATTERN: Large stack allocation pushes frame near 512B limit
    char scratch_buf[420];
    void *data = (void *)(long)ctx->data;
    void *data_end = (void *)(long)ctx->data_end;

    if (data + sizeof(scratch_buf) > data_end)
        return XDP_DROP;

    __builtin_memcpy(scratch_buf, data, sizeof(scratch_buf));

    // ANTI-PATTERN: Dynamic, unverified loop index tail-call creates recursion/cycles
    __u32 next_stage = *(__u32 *)scratch_buf % 16;
    bpf_tail_call(ctx, &jmp_table, next_stage);

    // ANTI-PATTERN: Silent fallthrough on tail-call failure
    return XDP_PASS;
}
```

#### Production Standard (Correct)
> **Standard**: Uses a BPF_MAP_TYPE_PERCPU_ARRAY scratchpad to bypass the 512-byte stack frame ceiling completely. Tail-call progression is strictly monotonic (compile-time bounded stage), precluding cyclic recursion, and handles dispatch misses defensively with an explicit XDP_DROP and trace notification.
```c
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>

#define STAGE_L4_PARSE 0
#define STAGE_INSPECT  1

struct scratch_buf {
    __u8 payload[512];
};

struct {
    __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
    __uint(max_entries, 1);
    __type(key, __u32);
    __type(value, struct scratch_buf);
} percpu_scratch SEC(".maps");

struct {
    __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
    __uint(max_entries, 2);
    __type(key, __u32);
    __type(value, __u32);
} jmp_table SEC(".maps");

SEC("xdp")
int xdp_ingress_good(struct xdp_md *ctx) {
    __u32 zero = 0;
    // PRODUCTION FIX: Offload payload buffer to per-CPU array, keeping stack usage minimal
    struct scratch_buf *buf = bpf_map_lookup_elem(&percpu_scratch, &zero);
    if (!buf)
        return XDP_DROP;

    void *data = (void *)(long)ctx->data;
    void *data_end = (void *)(long)ctx->data_end;
    if (data + sizeof(buf->payload) > data_end)
        return XDP_DROP;

    __builtin_memcpy(buf->payload, data, sizeof(buf->payload));

    // PRODUCTION FIX: Enforce deterministic, monotonic DAG progression index
    __u32 next_stage = STAGE_INSPECT;
    bpf_tail_call(ctx, &jmp_table, next_stage);

    // PRODUCTION FIX: Explicit fallback handling on tail-call failure (exhaustion/unloaded)
    bpf_printk("Tail-call dispatch failed at stage %u\n", next_stage);
    return XDP_DROP;
}
```

Architectural Specification & Invariant Rationale

Architectural Invariant Design: eBPF BPF-to-BPF Tail-Call Recursion & Stack-Limit Standard

eBPF BPF-to-BPF Tail-Call Recursion & Stack-Limit Standard defines an industrial-grade behavioral standard for devops engineering. Enforces strict stack frame boundaries and deterministic execution limits across chained BPF programs to eliminate kernel stack exhaustion and verifier rejections during high-frequency L4 ingress tracing. Mitigates kernel panic vectors stemming from unbounded BPF-to-BPF function nesting combined with dynamic tail-call recursion. Mandates per-CPU scratchpad offloading for payload parsing buffers exceeding eBPF's 512-byte stack frame limit. Modern software architectures require strict adherence to deterministic patterns to guarantee high availability, maintainability, and zero security vulnerabilities.

Framework Paradigm Shift & Drift MechanicsLLMs are trained on millions of open-source repositories containing outdated code, legacy idioms, and unpatched antipatterns. When coding assistants generate implementations for this stack, they default to common statistical tokens: Unbounded prog_array tail-call dispatch with deep stack-allocated L4 ingress parsing buffers Without an explicit system instruction file, developers spend hours debugging silent failures.
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
AI Hallucination & Deprecation DriftUnbounded prog_array tail-call dispatch with deep stack-allocated L4 ingress parsing buffersCritical
Violating this industrial standard introduces regression bugs, security risks, and unexpected runtime failures in production.
Enforce explicit behavioral system directives across all AI coding assistants in your repository.
Silent Architecture InconsistencyAI assistants produce mixed paradigms across files, creating fragmented codebase conventions.Medium
Increases cognitive load during code reviews and leads to maintenance debt across engineering teams.
Pin project conventions in .cursor/rules, CLAUDE.md, and AGENTS.md so all team agents follow identical guardrails.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

Engineers MUST ALWAYS keep BPF stack frame utilization strictly under 512 bytes across all subprograms and callers

Engineers MUST ALWAYS keep BPF stack frame utilization strictly under 512 bytes across all subprograms and callers; stack usage SHOULD stay under 256 bytes per frame for safety margin.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

Engineers MUST NOT allocate packet buffers, large structs, or cryptographic state on the eBPF stack

Engineers MUST NOT allocate packet buffers, large structs, or cryptographic state on the eBPF stack; allocate via BPF_MAP_TYPE_PERCPU_ARRAY scratch buffers instead.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Engineers MUST ALWAYS structure tail-call dispatch chains as a strictly monotonic, forward-only Directed Acyclic Graph (DAG) with compile-time bounded progression indices.

Engineers MUST ALWAYS structure tail-call dispatch chains as a strictly monotonic, forward-only Directed Acyclic Graph (DAG) with compile-time bounded progression indices.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

Engineers MUST NOT mix arbitrary BPF-to-BPF subprograms with bpf_tail_call() inside sub-frames if the target kernel version exhibits call-stack expansion or verifier rejection on frame unwinding.

Engineers MUST NOT mix arbitrary BPF-to-BPF subprograms with bpf_tail_call() inside sub-frames if the target kernel version exhibits call-stack expansion or verifier rejection on frame unwinding.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
5

Engineers MUST ALWAYS handle the bpf_tail_call() fallback path explicitly, ensuring default drop (XDP_DROP/TC_ACT_SHOT) or strict error telemetry if the tail call misses or exceeds the MAX_TAIL_CALL_CNT (33).

Engineers MUST ALWAYS handle the bpf_tail_call() fallback path explicitly, ensuring default drop (XDP_DROP/TC_ACT_SHOT) or strict error telemetry if the tail call misses or exceeds the MAX_TAIL_CALL_CNT (33).

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
6

Services MUST validate that all prog_array map entries are initialized or sanitized prior to hot path ingress packet processing.

Services MUST validate that all prog_array map entries are initialized or sanitized prior to hot path ingress packet processing.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is eBPF BPF-to-BPF Tail-Call Recursion & Stack-Limit Standard critical for AI coding assistants?

Enforces strict stack frame boundaries and deterministic execution limits across chained BPF programs to eliminate kernel stack exhaustion and verifier rejections during high-frequency L4 ingress tracing. Mitigates kernel panic vectors stemming from unbounded BPF-to-BPF function nesting combined with dynamic tail-call recursion. Mandates per-CPU scratchpad offloading for payload parsing buffers exceeding eBPF's 512-byte stack frame limit. Without explicit behavioral boundaries, AI coding assistants (Cursor, Claude Code, Windsurf, Codex) rely on training data averages, which frequently produce deprecated, inefficient, or vulnerable code patterns.

Q:How does adopting this rule prevent AI hallucinations?

This rule explicitly declares what the AI must avoid (Unbounded prog_array tail-call dispatch with deep stack-allocated L4 ingress parsing buffers) and prescribes verified positive examples. Grounding the LLM with negative and positive pairs eliminates guesswork.

Q:Which AI coding environments are supported?

This specification is multi-platform compatible: Cursor (.cursor/rules/*.mdc & .cursorrules), Anthropic Claude Code (CLAUDE.md), Windsurf (.windsurfrules), Codex / Cline (AGENTS.md), and GitHub Copilot (.github/copilot-instructions.md).

Q:Can I combine this rule with other technology stacks?

Yes. Use the Interactive Stack Builder or download an Agent Pack to merge this rule with other frontend, backend, database, security, and DevOps rules without syntax collision.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

1 Rule in Stack

eBPF