Made by rpmn0ise https://rpmn0ise.neocities.org/
eBPF Subsystem Architecture
Notes on Helper Functions and Maps in Modern Kernels
1. Scope and Intent
This document is a knowledge base entry about the internal architecture of the eBPF subsystem, with a focused view on helper functions and maps as implemented in modern Linux kernels (roughly 5.x and newer).
It is written for technically experienced readers who already understand basic kernel concepts (syscalls, memory protection, networking stack, tracing) and want a clearer mental model of how eBPF programs interact with the kernel safely and efficiently.
This is not a tutorial, not a performance guide, and not an advocacy text.
The goal is understanding structure, constraints, and design trade-offs.
2. High-Level Architecture Reminder
At a high level, eBPF consists of:
- A restricted virtual machine executed inside the kernel
- A verifier enforcing safety and termination
- Program types attached to specific kernel hooks
- Helper functions acting as controlled syscalls
- Maps acting as persistent shared state
From an architectural point of view:
- Helpers are actions
- Maps are memory
Everything an eBPF program does outside its local stack goes through one of these two abstractions.
3. Helper Functions: Controlled Kernel Entry Points
3.1 Definition
Helper functions are kernel-provided functions that an eBPF program may call.
They are the only legal way for an eBPF program to:
- Interact with kernel subsystems
- Access contextual data beyond the immediate program context
- Emit data to user space
- Allocate or manipulate kernel-managed objects
Helpers are not dynamically callable.
Each helper is:
- Identified by a numeric ID
- Whitelisted per program type
- Statically validated by the verifier
3.2 Design Rationale
The helper model exists to enforce:
- Capability-based access
- Explicit trust boundaries
- Stable ABI contracts
Unlike syscalls:
- Helpers are not generic
- They expose narrow, purpose-built semantics
- They are tightly bound to the execution context
This reduces kernel attack surface while still allowing expressive programs.
3.3 Helper Categories (Conceptual)
Helpers can be grouped by intent rather than implementation.
Context Access Helpers
Used to read or interpret the execution context.
Examples:
- Packet data access in XDP or TC
- Register or stack inspection in tracing programs
Constraints:
- Read-only or limited write access
- Bounds enforced by verifier and runtime checks
State Manipulation Helpers
Used to interact with maps or kernel-managed state.
Examples:
- Map lookup, update, delete
- Per-CPU data access
These helpers are heavily constrained to prevent aliasing or lifetime errors.
Event and Output Helpers
Used to communicate with user space or other kernel paths.
Examples:
- Ring buffer submission
- Perf event output
- Trace printing (primarily for debugging)
These helpers often introduce observable overhead and are not guaranteed to be lossless.
Time and Randomness Helpers
Used to access kernel time or pseudo-random values.
Important limitation:
- No guarantees about monotonicity or entropy quality beyond kernel guarantees.
3.4 Verifier Interaction
The verifier reasons about helper calls in detail:
- Argument types must be known at verification time
- Pointer provenance is tracked across helper calls
- Return values may be constrained or marked as nullable
A helper call can invalidate assumptions:
- A pointer returned from a helper is often marked as unknown until checked
- Failure paths must be explicitly handled
This is a common source of rejected programs.
3.5 Stability and Evolution
Helper functions are append-only from a user perspective:
- Existing helpers cannot change semantics
- New helpers are added cautiously
- Some helpers are program-type specific and never generalized
However:
- Availability depends on kernel version
- CO-RE does not abstract helper availability
- Runtime feature probing is often required
4. Maps: Shared, Persistent State
4.1 Definition
Maps are kernel-resident data structures accessible by:
- One or more eBPF programs
- User space via file descriptors
They represent the only form of persistent state across program invocations.
Maps are created by user space and referenced by programs.
4.2 Architectural Role
Maps serve multiple roles simultaneously:
- Data storage
- Synchronization boundary
- ABI between kernel and user space
- State transfer across hooks
This multiplexing is powerful but creates design tension.
4.3 Core Map Properties
Every map is defined by:
- Key type and size
- Value type and size
- Maximum number of entries
- Map type
- Optional flags (per-CPU, NUMA-aware, read-only)
These properties are immutable after creation.
4.4 Common Map Types (Conceptual Overview)
Hash Maps
General-purpose key-value storage.
Trade-offs:
- Flexible
- Non-deterministic iteration
- Memory overhead per entry
Used for:
- Flow tracking
- State correlation
- Dynamic sets
Array Maps
Index-based storage with fixed size.
Trade-offs:
- Predictable access
- No dynamic growth
- Index must be known or computed
Often used for:
- Configuration
- Counters
- Lookup tables
Per-CPU Maps
Replicated values per CPU.
Benefits:
- Avoid contention
- Lock-free access patterns
Costs:
- Increased memory usage
- Aggregation required in user space
Ring Buffer Maps
Sequential data transfer to user space.
Characteristics:
- One-way communication
- Loss possible under pressure
- Designed for events, not state
4.5 Memory and Lifetime Semantics
Map memory is:
- Managed by the kernel
- Accounted against memory limits
- Not directly addressable by user space
Important constraints:
- No unbounded allocation
- No pointer persistence across helper calls unless explicitly allowed
- Map values may be copied, not referenced
Maps can outlive programs but are destroyed when all references are closed.
4.6 Concurrency Model
Maps are not transactional.
Concurrency rules depend on map type:
- Some maps provide implicit locking
- Per-CPU maps avoid locking by replication
- Atomic operations are limited and explicit
Design implication:
- Consistency is the programmer’s responsibility
- Many designs accept eventual consistency
5. Helpers and Maps Together
The helper–map interaction is central to eBPF design.
Key observations:
- Maps are never accessed directly
- All map operations go through helpers
- Helper semantics define allowed access patterns
The verifier tracks:
- Which map is accessed
- With what key/value types
- In which control-flow paths
This tight coupling allows aggressive static checking.
6. BTF, CO-RE, and Type Awareness
Modern kernels expose BTF (BPF Type Format):
- Kernel type metadata
- Program type introspection
- Safer access to complex structures
Implications for helpers and maps:
- Helpers can be type-aware
- Map values can reference structured data
- CO-RE allows portable field access, not portable helpers
Limits remain:
- Not all helpers are BTF-described
- Kernel internal layout changes still matter
7. Security Model and Limitations
eBPF is designed to be:
- Non-Turing complete (bounded loops only)
- Memory safe
- Non-crashing to the kernel
However:
- Complexity increases attack surface
- Helpers are frequent audit targets
- Map misuse can cause denial-of-service patterns
Common limitations:
- No unbounded loops
- No dynamic memory allocation
- No direct kernel pointer arithmetic
- No floating-point operations
These are design choices, not omissions.
8. Practical Design Trade-Offs
When designing around helpers and maps:
- Fewer helpers means safer programs, but less expressiveness
- More maps improve modularity, but increase overhead
- Per-CPU maps improve scalability, but complicate aggregation
- Ring buffers simplify output, but drop data under load
There is no universal “best” structure.
9. Areas of Active Evolution
As of modern kernels:
- New helpers are added conservatively
- Map types evolve faster than helpers
- Verifier precision improves gradually
- Tooling (bpftool, libbpf) carries much of the complexity
Kernel documentation often lags implementation.
Reading kernel source remains necessary for deep understanding.
10. Summary
Helper functions and maps are not implementation details.
They are the architecture of eBPF.
- Helpers define what is allowed
- Maps define what can persist
- The verifier defines what is safe
Understanding their constraints is more important than memorizing APIs.
For advanced usage, thinking in terms of capabilities and invariants is more productive than thinking in terms of features.