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

Cilium eBPF BPF-to-BPF Tail-Call Stack Frame Depth Budget Standard

Enforces strict limits on combined stack frame depth and nested programmable tail-call chains within Cilium eBPF datapath hooks. Eliminates kernel-level packet drops, latency jitter, and BPF verifier complexity aborts across high-throughput multi-tenant ingress nodes.

Prohibited Anti-Pattern: Unbounded Stack Allocations Across Nested BPF-to-BPF Calls Combined with Runtime Datapath Tail-Calls

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Cilium eBPF BPF-to-BPF Tail-Call Stack Frame Depth Budget Standard - Enforces strict limits on combined stack frame depth and nested programmable tail-call chains within Cilium eBPF datapath hooks. Eliminates kernel-level packet drops, latency jitter, and BPF verifier complexity aborts across high-throughput multi-tenant ingress nodes.
globs: bpf/**/*.c, bpf/**/*.h, pkg/datapath/**/*.go, pkg/ebpf/**/*.go
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/cilium-ebpf-tail-call-stack-budget-standard"
---

# Cilium eBPF BPF-to-BPF Tail-Call Stack Frame Depth Budget Standard

> **Severity**: CRITICAL | **Category**: devops
> **Anti-Pattern Warning**: Unbounded Stack Allocations Across Nested BPF-to-BPF Calls Combined with Runtime Datapath Tail-Calls

## System Constraints
You are a Principal Systems Architect enforcing kernel datapath stability, Cilium eBPF invariants, and tail-call budget governance. Your objective is to prevent instruction-limit verifier failures (BPF_COMPLEXITY_LIMIT), stack frame overflows (>512 bytes across combined call paths), and non-deterministic tail-call jitter on multi-tenant ingress datapaths.

Mandate strict separation between deep BPF-to-BPF functional decomposition and BPF tail calls (`bpf_tail_call`). BPF-to-BPF subprograms consume stack frame budgets from the kernel-enforced 512-byte total budget. Mixing deep subprograms with tail calls in Linux kernels (5.10+) triggers verifier state-space explosions, pipeline stalling, or runtime drops. All datapath code must conform to strict static stack allocation boundaries, explicit leaf tail-calls, and per-CPU scratchpad buffers.

## Strict Guidelines
- Engineers MUST ALWAYS limit individual BPF function stack frames to <= 128 bytes using compiler flag `-Wframe-larger-than=128`, keeping cumulative BPF-to-BPF call chains <= 384 bytes to leave headroom under the hard 512-byte kernel ceiling.
- Engineers MUST NOT invoke `tail_call` or `cilium_tail_call` from within a nested BPF-to-BPF subprogram; tail calls MUST execute exclusively from the top-level root program frame or terminal dispatch points.
- Engineers MUST NEVER allocate variable-length arrays or large local packet parsing structs on the BPF stack; packet metadata exceeding 64 bytes MUST use direct packet pointer arithmetic (`ctx->data`, `ctx->data_end`) or per-CPU scratch maps.
- Services MUST enforce a maximum tail-call hop budget of <= 4 hops in custom programmable datapath chains (e.g., ingress -> parse -> policy -> encap), explicitly preventing cyclical or unmetered tail-call loops.
- Components MUST statically assert the compiler unroll count with `#pragma unroll` on all packet byte traversals to keep verifier instruction count per hook strictly below 250,000 instructions (well under the 1,000,000 limit).
- Datapath hooks MUST implement fallback dropping with atomic Prometheus metrics logging whenever a tail call fails to resolve (`bpf_tail_call` falls through), preventing silent datapath leaks.

## Bad vs Good Implementations
### eBPF Datapath Ingress Hook Stack & Tail-Call Implementation

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Allocating 320 bytes on the stack in a subprogram exceeds safe stack budgeting and risks exceeding the 512-byte total BPF stack limit. Executing `bpf_tail_call` from inside a nested subprogram leads to exponential verifier state exploration, instruction aborts, and tail-call execution failures on multi-tenant kernels.
```c
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>

struct parse_ctx {
    char payload[320]; // VIOLATION: Excessive stack allocation, pushes frame near 512-byte limit
    __u32 marks[8];
};

static __noinline int deep_packet_inspection(struct __sk_buff *skb) {
    struct parse_ctx ctx;
    // Heavy stack manipulation...
    bpf_skb_load_bytes(skb, 0, ctx.payload, sizeof(ctx.payload));

    // VIOLATION: Tail-call inside nested BPF-to-BPF subprogram with heavy stack frame
    // Triggers verifier rejection or kernel stack overflow across tail hops
    bpf_tail_call(skb, &cilium_tail_jmp_map, 2);
    return 0;
}

SEC("tc/ingress")
int cilium_custom_ingress(struct __sk_buff *skb) {
    return deep_packet_inspection(skb);
}
```

#### Production Standard (Correct)
> **Standard**: Inlines lightweight packet inspection functions without allocating heavy stack buffers (direct pointer access), maintains a minimal stack frame (<64 bytes), and performs the tail-call exclusively from the root frame with an explicit fallthrough policy.
```c
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>

#define MAX_TAIL_HOPS 4

// Keep subprogram stack footprint strictly under 128 bytes
static __always_inline int validate_packet_header(struct __sk_buff *skb, __u32 *proto_out) {
    void *data = (void *)(long)skb->data;
    void *data_end = (void *)(long)skb->data_end;
    
    // Use direct packet access instead of allocating local stack buffers
    struct ethhdr *eth = data;
    if ((void *)(eth + 1) > data_end)
        return -1;
        
    *proto_out = eth->h_proto;
    return 0;
}

SEC("tc/ingress")
int cilium_custom_ingress(struct __sk_buff *skb) {
    __u32 proto = 0;
    
    if (validate_packet_header(skb, &proto) < 0)
        return TC_ACT_SHOT;
        
    // Root-level terminal dispatch: execute tail call ONLY from the root frame
    // Prevents nested stack propagation and guarantees predictable verifier complexity
    bpf_tail_call(skb, &cilium_tail_jmp_map, 2);
    
    // Mandatory fallthrough handler for failed tail-call resolution
    return TC_ACT_OK;
}
```

Recommended MCP Servers (mcp-serverlist.com)

Equip agent with system tools to verify code for this stack.

Recommended Agent Skills (askills.dev)

Ready-to-use executable skill functions tailored to this stack.

Architectural Specification & Invariant Rationale

Architectural Invariant Design: Cilium eBPF BPF-to-BPF Tail-Call Stack Frame Depth Budget Standard

Cilium eBPF BPF-to-BPF Tail-Call Stack Frame Depth Budget Standard defines an industrial-grade behavioral standard for devops engineering. Enforces strict limits on combined stack frame depth and nested programmable tail-call chains within Cilium eBPF datapath hooks. Eliminates kernel-level packet drops, latency jitter, and BPF verifier complexity aborts across high-throughput multi-tenant ingress nodes. 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 Stack Allocations Across Nested BPF-to-BPF Calls Combined with Runtime Datapath Tail-Calls 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 Stack Allocations Across Nested BPF-to-BPF Calls Combined with Runtime Datapath Tail-CallsCritical
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 limit individual BPF function stack frames to <= 128 bytes using compiler flag `-Wframe-larger-than=128`, keeping cumulative BPF-to-BPF call chains <= 384 bytes to leave headroom under the hard 512-byte kernel ceiling.

Engineers MUST ALWAYS limit individual BPF function stack frames to <= 128 bytes using compiler flag `-Wframe-larger-than=128`, keeping cumulative BPF-to-BPF call chains <= 384 bytes to leave headroom under the hard 512-byte kernel ceiling.

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 invoke `tail_call` or `cilium_tail_call` from within a nested BPF-to-BPF subprogram

Engineers MUST NOT invoke `tail_call` or `cilium_tail_call` from within a nested BPF-to-BPF subprogram; tail calls MUST execute exclusively from the top-level root program frame or terminal dispatch points.

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 NEVER allocate variable-length arrays or large local packet parsing structs on the BPF stack

Engineers MUST NEVER allocate variable-length arrays or large local packet parsing structs on the BPF stack; packet metadata exceeding 64 bytes MUST use direct packet pointer arithmetic (`ctx->data`, `ctx->data_end`) or per-CPU scratch maps.

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

Services MUST enforce a maximum tail-call hop budget of <= 4 hops in custom programmable datapath chains (e.g., ingress -> parse -> policy -> encap), explicitly preventing cyclical or unmetered tail-call loops.

Services MUST enforce a maximum tail-call hop budget of <= 4 hops in custom programmable datapath chains (e.g., ingress -> parse -> policy -> encap), explicitly preventing cyclical or unmetered tail-call loops.

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

Components MUST statically assert the compiler unroll count with `#pragma unroll` on all packet byte traversals to keep verifier instruction count per hook strictly below 250,000 instructions (well under the 1,000,000 limit).

Components MUST statically assert the compiler unroll count with `#pragma unroll` on all packet byte traversals to keep verifier instruction count per hook strictly below 250,000 instructions (well under the 1,000,000 limit).

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

Datapath hooks MUST implement fallback dropping with atomic Prometheus metrics logging whenever a tail call fails to resolve (`bpf_tail_call` falls through), preventing silent datapath leaks.

Datapath hooks MUST implement fallback dropping with atomic Prometheus metrics logging whenever a tail call fails to resolve (`bpf_tail_call` falls through), preventing silent datapath leaks.

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 Cilium eBPF BPF-to-BPF Tail-Call Stack Frame Depth Budget Standard critical for AI coding assistants?

Enforces strict limits on combined stack frame depth and nested programmable tail-call chains within Cilium eBPF datapath hooks. Eliminates kernel-level packet drops, latency jitter, and BPF verifier complexity aborts across high-throughput multi-tenant ingress nodes. 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 Stack Allocations Across Nested BPF-to-BPF Calls Combined with Runtime Datapath Tail-Calls) 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

Cilium