Skip to main content

Overview

The eBPF Event Interceptor is built as a modular system with two primary components: tcpEvent and udpEvent. Each component operates as an independent library that attaches eBPF programs to kernel functions, streams events through perf buffers, and provides a C/C++ API for event consumption.
Both tcpEvent and udpEvent are compiled as shared objects (.so files) that can be loaded dynamically into applications for real-time network monitoring.

High-Level Architecture

The system follows a kernel-to-userspace event pipeline:

Core Components

tcpEvent Library

The TCP event interceptor monitors TCP state changes and enriches events with socket diagnostics. Key Files:
  • tcpEvent/event.cc - Main implementation (710 lines)
  • tcpEvent/event.h - Public API declarations
  • tcpEvent/common.h - Data structure definitions
Functionality:
  • Attaches to tcp_set_state kernel function
  • Uses netlink socket diagnostics for detailed TCP statistics
  • Dual event collection: kprobes + netlink polling
  • Attributes events to processes via /proc filesystem

TCP Event Flow

  1. Kprobe on tcp_set_state captures state changes
  2. Events pushed to tcpEvents perf buffer
  3. Parallel netlink thread polls socket diagnostics every 6.2s
  4. Events enriched with PID, UID, command name, and TCP stats
  5. Stored in deque for consumer retrieval

udpEvent Library

The UDP event interceptor tracks UDP send/receive operations across IPv4 and IPv6. Key Files:
  • udpEvent/udpTracer.cc - Main implementation (626 lines)
  • udpEvent/common.h - Data structure definitions
Kprobes Attached:
UDP tracking uses both entry kprobes and return kretprobes to capture actual bytes sent/received from function return values.

Perf Buffer Architecture

Buffer Configuration

Both libraries use BCC’s BPF_PERF_OUTPUT mechanism: TCP:
UDP:

Event Flow

  1. Kernel → Perf Buffer: eBPF programs call perf_submit() to push events
  2. Polling: bpf.poll_perf_buffer() runs in infinite loop
  3. Callback: handle_output() invoked for each event
  4. Queuing: Events pushed to std::deque<event_t*>
  5. Consumption: DequeuePerfEvent() retrieves events for applications

Queue Management

When event production exceeds consumption rate, the system automatically sheds the oldest events. Monitor for “Shedding” messages in logs.

Threading Model

Thread Architecture

Both libraries use POSIX threads for concurrent operation: tcpEvent threads:
Synchronization primitives:

Thread Lifecycle

Created in: setupBPF() function (event.cc:176)Initialization:
Termination: Cancelled in cleanup() via pthread_cancel(tid)

Consumer Thread

Applications call DequeuePerfEvent() which blocks until events are available:

Data Flow: Kernel to User Space

Event Capture Path

  1. Kernel Function Call
    • Application calls socket operation (e.g., connect(), send())
    • Kernel executes tcp_set_state, udp_sendmsg, etc.
  2. Kprobe Activation
    • eBPF program executes before/after kernel function
    • Reads kernel memory: struct sock, addresses, ports
    • Calls bpf_get_current_pid_tgid(), bpf_get_current_uid_gid()
  3. Perf Buffer Submit
  4. User Space Polling
    • bpf.poll_perf_buffer() retrieves events
    • Invokes handle_output() callback
  5. Event Enrichment
    • Timestamp adjustment: event->EventTime + notSoLongAgo
    • Address conversion: inet_ntop() for IP addresses
    • Process lookup: readCmdLine() from /proc
  6. Consumer Delivery
    • DequeuePerfEvent() returns structured event
    • Application processes network telemetry
TCP events get additional statistics via netlink socket diagnostics:
The custom anu_tcp_info struct (common.h:75-148) extends standard tcp_info to include tcpi_bytes_sent which is critical for bandwidth tracking.

Process Attribution Mechanism

Both libraries identify which process generated network events:

Inode-to-PID Mapping (TCP)

Reading Command Names

Process information is captured at event time. Short-lived processes may show PID but missing command names if they exit before enrichment.

Memory Management

Event Lifecycle

TCP: Uses pointer tracking map to prevent double-free
UDP: Simpler model, events deleted after consumption

Time Synchronization

Component Communication

Public API

Both libraries expose a minimal C-compatible API:

Initialization Sequence

AddProbe() returns immediately. Call getStatus() to verify initialization completed successfully before consuming events.

Cleanup and Shutdown

Proper teardown sequence:

Performance Characteristics

Event Latency

  • Kprobe execution: < 1μs
  • Perf buffer transfer: < 10μs
  • Queue processing: < 100μs
  • Total latency: ~100μs

Throughput

  • Max queue size: 1024 events
  • Shedding triggers at capacity
  • Typical rate: 1K-10K events/sec
  • Peak: ~50K events/sec

Next Steps

eBPF Overview

Learn how eBPF programs are loaded and verified

Event Collection

Understand event data structures and collection mechanics