eBPF Maps and Data Structures
Relevant source files
The following files were used as context for generating this wiki page:
This page documents all BPF maps and data structures used across eCapture modules for storing state, passing events, and managing memory within the constraints of the eBPF execution environment. These maps form the bridge between kernel-space eBPF programs and user-space event processing.
For information about how events are processed after being read from these maps, see Event Processing Pipeline. For details on event structure definitions and types, see Event Structures and Types.
Overview
eCapture uses BPF maps for three primary purposes:
- Event Output - Transmitting captured data from kernel to userspace via PERF_EVENT_ARRAY or RINGBUF
- State Storage - Maintaining context between function entry/exit probes using HASH and LRU_HASH maps
- Memory Management - Circumventing eBPF's 512-byte stack limit using PERCPU_ARRAY for heap allocation
All maps follow consistent naming conventions and are shared across eBPF programs within a module. Map definitions use the BTF-based declaration syntax with SEC(".maps") annotation.
Sources: kern/openssl.h:74-135, kern/tc.h:56-78, kern/gotls_kern.c:50-72, kern/openssl_masterkey.h:45-68
Map Type Overview
Map Type Selection Rationale:
| Map Type | Use Case | Why Used |
|---|---|---|
PERF_EVENT_ARRAY | Event output | Efficient bulk data transfer to userspace with minimal overhead |
HASH | Short-lived context | Fast lookup for entry/exit probe correlation (PID/TID key) |
LRU_HASH | Connection tracking | Auto-eviction prevents memory exhaustion for long-running processes |
PERCPU_ARRAY | Large structures | Bypasses 512-byte stack limit; no CPU contention |
ARRAY | Template storage | Single-entry arrays used as heap allocation templates |
Sources: kern/openssl.h:79-135, kern/tc.h:57-78
OpenSSL/BoringSSL Module Maps
Event Output Maps
tls_events
Type: BPF_MAP_TYPE_PERF_EVENT_ARRAY
Purpose: Transmit captured SSL/TLS plaintext data from kernel to userspace
Key: CPU ID (u32)
Value: Reference to perf ring buffer (u32)
Max Entries: 1024
This map outputs ssl_data_event_t structures containing decrypted TLS data captured via uprobe hooks on SSL_read and SSL_write. Each event includes the plaintext payload (up to 16KB), process metadata, file descriptor, TLS version, and BIO type.
Event Structure: ssl_data_event_t
type- kSSLRead (0) or kSSLWrite (1)timestamp_ns- Capture timestamppid,tid- Process/thread identifiersdata[MAX_DATA_SIZE_OPENSSL]- Plaintext payload (16KB max)data_len- Actual payload lengthcomm[TASK_COMM_LEN]- Process namefd- File descriptorversion- TLS protocol versionbio_type- OpenSSL BIO type (socket, file, etc.)
Sources: kern/openssl.h:79-84, kern/openssl.h:28-39, kern/openssl.h:164-191
connect_events
Type: BPF_MAP_TYPE_PERF_EVENT_ARRAY
Purpose: Track TCP connection lifecycle (connect, accept, destroy)
Key: CPU ID (u32)
Value: Reference to perf ring buffer (u32)
Max Entries: 1024
Outputs connect_event_t structures from kprobes on __sys_connect, __sys_accept4, and tcp_v4_destroy_sock. Used to associate file descriptors with network socket addresses.
Event Structure: connect_event_t
saddr,daddr- Source/destination IPv4/IPv6 addresses (128-bit)sport,dport- Source/destination portssock- Kernel socket structure addressfd- File descriptorfamily- AF_INET or AF_INET6is_destroy- Connection teardown flag- Packed attribute to avoid padding holes
Sources: kern/openssl.h:87-92, kern/openssl.h:41-55, kern/openssl.h:395-454
State Storage Maps
active_ssl_read_args_map and active_ssl_write_args_map
Type: BPF_MAP_TYPE_HASH
Purpose: Store SSL function arguments between entry and exit probes
Key: Thread ID from bpf_get_current_pid_tgid() (u64)
Value: active_ssl_buf structure
Max Entries: 1024
These maps implement the two-stage probe pattern: entry probe stores function arguments (SSL pointer, buffer pointer), then the return probe retrieves them to read the actual data after the function completes.
Value Structure: active_ssl_buf
version- SSL protocol versionfd- File descriptorbio_type- OpenSSL BIO typebuf- Pointer to data buffer
Sources: kern/openssl.h:97-109, kern/openssl.h:57-67, kern/openssl.h:268-323
tcp_fd_infos
Type: BPF_MAP_TYPE_HASH
Purpose: Associate file descriptors with kernel socket structures during connect/accept
Key: PID/TID (u64)
Value: tcp_fd_info structure
Max Entries: 10240
Used in a multi-stage kprobe sequence:
probe_connectstoresfdfrom syscall argumentsprobe_inet_stream_connectaddssockpointerretprobe_connectretrieves both to emit connection event
Value Structure: tcp_fd_info
sock- Kernel socket structure addressfd- File descriptor
Sources: kern/openssl.h:129-134, kern/openssl.h:69-72, kern/openssl.h:354-393
ssl_st_fd
Type: BPF_MAP_TYPE_HASH
Purpose: Store SSL structure to file descriptor mappings from SSL_set_fd()
Key: SSL structure address (u64)
Value: File descriptor (u64)
Max Entries: 10240
Handles cases where ssl->bio->num is zero by providing a fallback FD lookup when hooking SSL_set_fd, SSL_set_rfd, SSL_set_wfd functions.
Sources: kern/openssl.h:121-126, kern/openssl.h:528-543
Memory Management Maps
data_buffer_heap
Type: BPF_MAP_TYPE_PERCPU_ARRAY
Purpose: Heap allocation for large event structures (circumvents 512-byte stack limit)
Key: Always 0 (u32)
Value: ssl_data_event_t structure
Max Entries: 1
Per-CPU design eliminates locking overhead and prevents data races. The create_ssl_data_event() helper function retrieves the buffer, initializes metadata, and returns a pointer for the probe to populate.
// Memory allocation pattern used throughout eCapture eBPF programs
static __inline struct ssl_data_event_t* create_ssl_data_event(u64 current_pid_tgid) {
u32 kZero = 0;
// Lookup returns per-CPU instance, no contention
struct ssl_data_event_t* event = bpf_map_lookup_elem(&data_buffer_heap, &kZero);
if (event == NULL) return NULL;
// Initialize common fields
event->timestamp_ns = bpf_ktime_get_ns();
event->pid = current_pid_tgid >> 32;
event->tid = current_pid_tgid & 0xffffffff;
return event;
}Why PERCPU_ARRAY:
- eBPF stack limited to 512 bytes, but
ssl_data_event_tis ~16KB - Per-CPU design: no locking needed, no contention
- Single-entry array (key always 0) acts as a scratchpad
- Cheaper than dynamic heap allocation
Sources: kern/openssl.h:113-118, kern/openssl.h:141-158
Traffic Control (TC) Module Maps
Event Output Maps
skb_events
Type: BPF_MAP_TYPE_PERF_EVENT_ARRAY
Purpose: Output raw network packet metadata and payload
Key: CPU ID (u32)
Value: Reference to perf ring buffer (u32)
Max Entries: 10240
Outputs skb_data_event_t structures from TC classifier programs (egress_cls_func, ingress_cls_func). Each event includes packet metadata enriched with process context from network_map.
Event Structure: skb_data_event_t
ts- Timestamppid- Process ID (from network_map lookup)comm[TASK_COMM_LEN]- Process namelen- Packet lengthifindex- Network interface index
Sources: kern/tc.h:57-62, kern/tc.h:30-37
skb_data_buffer_heap
Type: BPF_MAP_TYPE_PERCPU_ARRAY
Purpose: Per-CPU allocation for SKB event structures
Key: Always 0 (u32)
Value: skb_data_event_t structure
Max Entries: 1
Follows the same heap allocation pattern as data_buffer_heap for OpenSSL events. Used by make_skb_data_event() helper function.
Sources: kern/tc.h:64-69, kern/tc.h:92-100
State Storage Maps
network_map
Type: BPF_MAP_TYPE_LRU_HASH
Purpose: Map network 5-tuple (protocol, IPs, ports) to process context
Key: net_id_t structure (5-tuple)
Value: net_ctx_t structure (PID, UID, comm)
Max Entries: 10240
Populated by kprobes on tcp_sendmsg and udp_sendmsg, then queried by TC classifiers to associate packets with processes. LRU eviction prevents memory exhaustion for servers handling many connections.
Key Structure: net_id_t
protocol- IPPROTO_TCP, IPPROTO_UDP, IPPROTO_ICMPsrc_ip4,dst_ip4- IPv4 addresses (u32)src_ip6[4],dst_ip6[4]- IPv6 addresses (u32 array)src_port,dst_port- Port numbers
Value Structure: net_ctx_t
pid- Process IDuid- User IDcomm[TASK_COMM_LEN]- Process name
Sources: kern/tc.h:72-77, kern/tc.h:39-54, kern/tc.h:285-333, kern/tc.h:135-271
Go TLS Module Maps
Event Output Maps
events (Go TLS data)
Type: BPF_MAP_TYPE_PERF_EVENT_ARRAY
Purpose: Output captured Go TLS plaintext data
Key: CPU ID (u32)
Value: Reference to perf ring buffer (u32)
Max Entries: 1024
Outputs go_tls_event structures from uprobes on Go's crypto/tls.(*Conn).writeRecordLocked and crypto/tls.(*Conn).Read functions. Separate probes exist for register-based ABI (Go ≥1.17) and stack-based ABI (Go <1.17).
Event Structure: go_tls_event
ts_ns- Timestamppid,tid- Process/thread identifiersdata_len- Payload lengthevent_type- GOTLS_EVENT_TYPE_WRITE (0) or GOTLS_EVENT_TYPE_READ (1)comm[TASK_COMM_LEN]- Process namedata[MAX_DATA_SIZE_OPENSSL]- Plaintext payload (16KB)
Sources: kern/gotls_kern.c:60-65, kern/gotls_kern.c:31-39
mastersecret_go_events
Type: BPF_MAP_TYPE_PERF_EVENT_ARRAY
Purpose: Capture TLS master secrets for keylog generation
Key: CPU ID (u32)
Value: Reference to perf ring buffer (u32)
Max Entries: 1024
Hooks crypto/tls.(*Config).writeKeyLog to extract TLS 1.3 traffic secrets and TLS 1.2 master keys. Each event contains the label string, client random, and secret bytes.
Event Structure: mastersecret_gotls_t
label[MASTER_SECRET_KEY_LEN]- Key label (e.g., "CLIENT_HANDSHAKE_TRAFFIC_SECRET")labellen- Label string lengthclient_random[EVP_MAX_MD_SIZE]- Client random bytesclient_random_len- Client random lengthsecret_[EVP_MAX_MD_SIZE]- Secret key materialsecret_len- Secret length
Sources: kern/gotls_kern.c:53-58, kern/gotls_kern.c:41-48, kern/gotls_kern.c:194-267
Memory Management Maps
gte_context_gen
Type: BPF_MAP_TYPE_PERCPU_ARRAY
Purpose: Per-CPU allocation for Go TLS event structures
Key: Always 0 (u32)
Value: go_tls_event structure
Max Entries: 1
Similar to data_buffer_heap for OpenSSL, provides heap allocation for large event structures. Accessed via get_gotls_event() helper.
Sources: kern/gotls_kern.c:67-72, kern/gotls_kern.c:74-87
OpenSSL Master Secret Maps
Event Output Maps
mastersecret_events
Type: BPF_MAP_TYPE_PERF_EVENT_ARRAY
Purpose: Capture OpenSSL/BoringSSL TLS master secrets
Key: CPU ID (u32)
Value: Reference to perf ring buffer (u32)
Max Entries: 1024
Outputs mastersecret_t structures from uprobe on SSL_write or configured master key extraction functions. Contains both TLS 1.2 master keys and TLS 1.3 traffic secrets.
Event Structure: mastersecret_t
- TLS 1.2 fields:
version- SSL/TLS version constantclient_random[SSL3_RANDOM_SIZE]- 32-byte client randommaster_key[MASTER_SECRET_MAX_LEN]- 48-byte master secret
- TLS 1.3 fields:
cipher_id- Cipher suite identifierearly_secret[EVP_MAX_MD_SIZE]- Early traffic secrethandshake_secret[EVP_MAX_MD_SIZE]- Handshake traffic secrethandshake_traffic_hash[EVP_MAX_MD_SIZE]- Handshake hashclient_app_traffic_secret[EVP_MAX_MD_SIZE]- Client application traffic secretserver_app_traffic_secret[EVP_MAX_MD_SIZE]- Server application traffic secretexporter_master_secret[EVP_MAX_MD_SIZE]- Exporter master secret
Sources: kern/openssl_masterkey.h:48-53, kern/openssl_masterkey.h:25-39, kern/openssl_masterkey.h:82-251
State Storage Maps
bpf_context
Type: BPF_MAP_TYPE_LRU_HASH
Purpose: Temporary storage for master secret structures during extraction
Key: PID/TID (u64)
Value: mastersecret_t structure
Max Entries: 2048
Used as an intermediate storage during the make_event() allocation pattern. The LRU eviction policy prevents memory leaks for processes that crash before cleaning up.
Sources: kern/openssl_masterkey.h:55-60
bpf_context_gen
Type: BPF_MAP_TYPE_ARRAY
Purpose: Template for master secret structure allocation
Key: Always 0 (u32)
Value: mastersecret_t structure
Max Entries: 1
Single-entry array serves as a template that is copied into bpf_context map. This two-stage allocation pattern circumvents the eBPF stack size limit.
// Pattern used for large structure allocation
static __always_inline struct mastersecret_t *make_event() {
u32 key_gen = 0;
// Get template from single-entry array
struct mastersecret_t *bpf_ctx = bpf_map_lookup_elem(&bpf_context_gen, &key_gen);
if (!bpf_ctx) return 0;
// Copy to per-thread entry in hash map
u64 id = bpf_get_current_pid_tgid();
bpf_map_update_elem(&bpf_context, &id, bpf_ctx, BPF_ANY);
// Return pointer to hash map entry for modification
return bpf_map_lookup_elem(&bpf_context, &id);
}Sources: kern/openssl_masterkey.h:62-68, kern/openssl_masterkey.h:71-78
Map Size Configuration
Map sizes are chosen based on expected workload:
| Map | Max Entries | Rationale |
|---|---|---|
tls_events | 1024 | One per CPU core for event output |
connect_events | 1024 | One per CPU core for event output |
active_ssl_*_args_map | 1024 | Supports ~1024 concurrent SSL operations |
ssl_st_fd | 10240 | Many persistent SSL connections |
tcp_fd_infos | 10240 | High connection churn during accept/connect |
network_map | 10240 | LRU handles long-lived server connections |
bpf_context | 2048 | Concurrent master secret extractions |
data_buffer_heap | 1 | Single per-CPU scratchpad |
Larger values increase memory usage but prevent event loss under heavy load. PERF_EVENT_ARRAY maps (1024 entries) match typical server CPU counts. LRU_HASH maps auto-evict entries to prevent unbounded growth.
Sources: kern/openssl.h:79-134, kern/tc.h:57-77
Memory Management Strategies
Per-CPU Heap Allocation Pattern
eBPF programs have a 512-byte stack limit, but many event structures exceed this (e.g., ssl_data_event_t is ~16KB with its data payload). eCapture uses PERCPU_ARRAY maps as per-CPU heaps:
Benefits:
- No contention: each CPU has its own buffer instance
- No locking overhead
- Exceeds stack size limitations
- Reusable across multiple events on same CPU
Usage Pattern:
- Lookup key
0from PERCPU_ARRAY map - BPF verifier returns per-CPU instance automatically
- Initialize common fields (timestamp, PID)
- Populate event-specific data
- Send to output map
- Buffer can be reused immediately by next event on same CPU
Sources: kern/openssl.h:113-118, kern/openssl.h:141-158, kern/tc.h:64-69, kern/gotls_kern.c:67-72
Entry/Exit Probe Context Storage
For two-stage probes (entry + return), HASH maps store context:
Key Design Points:
- Key is always
bpf_get_current_pid_tgid()for thread-local storage - Entry probe stores, return probe consumes
- Automatic cleanup via
bpf_map_delete_elem()prevents leaks - Max entries sized for concurrent operations
Examples: active_ssl_read_args_map, active_ssl_write_args_map, tcp_fd_infos
Sources: kern/openssl.h:97-109, kern/openssl.h:268-323, kern/openssl.h:354-393
LRU-Based Connection Tracking
network_map uses LRU_HASH to prevent unbounded growth:
Scenario: A web server handling millions of connections would exhaust memory with a regular HASH map. LRU_HASH automatically evicts least-recently-used entries when the map fills.
Trade-off: Evicted connections lose process context enrichment, but packets are still captured. Acceptable for long-running captures where recent connections matter most.
Sources: kern/tc.h:72-77, kern/tc.h:285-333
Global Variable Configuration
Starting from Linux kernel 5.2, eBPF supports global variables that can be set from userspace before program load. eCapture uses these for filtering:
Constants defined in kern/common.h:64-70:
less52- Kernel version flag (1 = <5.2, disables filtering)target_pid- Filter by process ID (0 = all processes)target_uid- Filter by user ID (0 = all users)target_errno- Bash module error code filter
These are set via ConstantEditor in userspace before loading eBPF bytecode:
// Example from user/module/probe_gotls.go:193-228
editor := []manager.ConstantEditor{
{Name: "target_pid", Value: g.conf.GetPid()},
{Name: "target_uid", Value: g.conf.GetUid()},
{Name: "less52", Value: kernelLess52},
}Filtering Functions:
passes_filter(ctx)- Checks PID/UID for uprobes/kprobes kern/ecapture.h:108-127filter_rejects(pid, uid)- Checks PID/UID for TC classifiers kern/ecapture.h:93-105
For kernels <5.2, global variables are not supported, so filtering is disabled (less52 = 1).
Sources: kern/common.h:64-70, kern/ecapture.h:93-127, user/module/probe_gotls.go:193-228
Userspace Map Access
User-space modules read from event output maps via:
- Perf Event Arrays (kernel <5.8) - Uses
cilium/ebpflibrary'sperfEventReader - Ring Buffers (kernel ≥5.8) - Uses
ringbufEventReaderfor better performance
Map registration in userspace:
// From user/module/probe_openssl_text.go:190-212
func (m *MOpenSSLProbe) initDecodeFunText() error {
// Get map handle
SSLDumpEventsMap, found, err := m.bpfManager.GetMap("tls_events")
if err != nil { return err }
// Register map with corresponding event decoder
m.eventMaps = append(m.eventMaps, SSLDumpEventsMap)
sslEvent := &event.SSLDataEvent{}
m.eventFuncMaps[SSLDumpEventsMap] = sslEvent
// Repeat for other maps (connect_events, etc.)
}Each module maintains:
eventMaps [](*ebpf.Map)- List of maps to polleventFuncMaps map[*ebpf.Map]event.IEventStruct- Map decoder functions
The event processing loop reads from all registered maps concurrently.
Sources: user/module/probe_openssl_text.go:190-234, user/module/probe_gotls.go:231-234
Summary Table: All Maps by Module
| Module | Map Name | Type | Key | Value | Purpose |
|---|---|---|---|---|---|
| OpenSSL/BoringSSL | tls_events | PERF_EVENT_ARRAY | CPU ID | - | SSL/TLS plaintext output |
connect_events | PERF_EVENT_ARRAY | CPU ID | - | Connection lifecycle events | |
active_ssl_read_args_map | HASH | TID | active_ssl_buf | SSL_read context storage | |
active_ssl_write_args_map | HASH | TID | active_ssl_buf | SSL_write context storage | |
data_buffer_heap | PERCPU_ARRAY | 0 | ssl_data_event_t | Large event allocation | |
ssl_st_fd | HASH | SSL ptr | FD | SSL structure to FD mapping | |
tcp_fd_infos | HASH | PID/TID | tcp_fd_info | Connect/accept FD tracking | |
mastersecret_events | PERF_EVENT_ARRAY | CPU ID | - | Master secret output | |
bpf_context | LRU_HASH | PID/TID | mastersecret_t | Master secret temp storage | |
bpf_context_gen | ARRAY | 0 | mastersecret_t | Master secret template | |
| Traffic Control | skb_events | PERF_EVENT_ARRAY | CPU ID | - | Packet metadata output |
skb_data_buffer_heap | PERCPU_ARRAY | 0 | skb_data_event_t | SKB event allocation | |
network_map | LRU_HASH | net_id_t | net_ctx_t | 5-tuple to process mapping | |
| Go TLS | events | PERF_EVENT_ARRAY | CPU ID | - | Go TLS plaintext output |
mastersecret_go_events | PERF_EVENT_ARRAY | CPU ID | - | Go master secret output | |
gte_context_gen | PERCPU_ARRAY | 0 | go_tls_event | Go TLS event allocation |
Sources: All files referenced throughout this document