Technical Requirements Document (TRD): Aegis Packet Engine
1. System Architecture Overview
Aegis is composed of a multi-stage pipeline designed to minimize cache misses, eliminate dynamic memory allocations during packet processing, and run without lock contention.
Pipeline Stages:
[Ingestion / PCAP Reader]
│
▼ (SPSC Lock-Free Queue 1)
[Load Balancer]
/ │ \
/ │ \ (SPSC Lock-Free Queues 2..N)
▼ ▼ ▼
[FP0] [FP1] [FPk] (Fast Path Workers: Flow Track, DPI, Rules)
\ │ /
\ │ / (Individual SPSC Worker-to-Writer Queues)
▼ ▼ ▼
[Output / Exporter (Round-Robin Polling)]
2. Low-Latency Concurrency Design
2.1 Lock-Free Bounded Queues
- Single Producer Single Consumer (SPSC): The ingestion thread communicates with the Load Balancer via a dedicated SPSC queue. The Load Balancer communicates with each worker (Fast Path) thread using private SPSC queues.
- Worker-to-Writer SPSC Array: Instead of worker threads competing on a shared Multi-Producer Single-Consumer (MPSC) queue, each worker thread forwards accepted packets to the Output Writer via a private SPSC queue. The Output Writer polls these SPSC queues in a round-robin loop. This guarantees lock-freedom and eliminates producer-producer contention on the write path.
- Fallback Strategy: If lock-free structures are unsupported (rare on modern x86/ARM), compilation will fall back to using atomic flags or mutexes with diagnostic logs.
2.2 Thread Pinning & CPU Affinity
- To prevent OS context-switch overhead, threads are pinned to specific CPU cores.
- Configurable topology via a YAML/JSON file or CLI options (e.g., pin Ingestion to Core 0, Load Balancer to Core 1, Workers to Cores 2-7).
- Fallback to OS scheduler on platforms that do not support thread pinning (e.g., default Windows).
2.3 False Sharing Prevention
- All shared queues and thread-local status structures must be padded to the CPU cache line size (64 bytes on x86/x64).
- Use
alignas(64)for atomic pointers, write heads, and read heads.
3. Zero-Copy Packet Lifecycle
3.1 Pre-allocated Packet Pool
- Memory for packets is allocated once at startup.
- A
PacketBufferPoolmaintains a ring of pre-allocated buffers of fixed size (2048 bytes). - The PCAP Reader writes directly into the pre-allocated buffer.
- The packet metadata struct (
PacketJob) stores: - A raw pointer to the buffer:
const uint8_t* raw_data. - Offsets for headers:
eth_offset,ip_offset,tcp_offset,payload_offset. - Lengths:
packet_length,payload_length. - A reference-counting mechanism (atomic counter) to return the buffer to the pool once processed/written.
3.2 String Views
- IP addresses, MAC addresses, and domain names are never instantiated as
std::stringinside the critical path. - Use
std::string_viewfor SNI or Host sub-strings, referencing the packet payload memory directly. - IPs are represented as
uint32_t(IPv4) orstd::array<uint8_t, 16>(IPv6).
4. State Management (Connection Tracker)
4.1 Partitioned Flow Tables
- Each Fast Path worker thread owns a private flow table.
- Zero Contention: Because packets are dispatched using a consistent hash of their 5-tuple, all packets for a connection are guaranteed to go to the same worker. No locks or atomic synchronizations are needed to access or modify the flow table.
- Data Structure: Cache-efficient hash map with open addressing or closed hashing with pre-allocated nodes to avoid memory allocation.
4.2 TCP Stream Reassembly (Lightweight)
- Aegis tracks TCP sequence numbers for the handshake phase.
- Extracts the TLS Client Hello even if it is fragmented across two adjacent TCP segments by copying segments to a small flow-specific scratch buffer.
- Expired or terminated flows are reclaimed using a timer-based thread-local sweeper.
5. Optimized Rule Engine
5.1 Matching Algorithms
- IP / Subnet Matching: CIDR ranges are parsed into a Prefix Tree (Trie) or checked using bitmask checks sorted by subnet length (longest prefix match first).
- Domain / SNI Matching: Fast substring search or Aho-Corasick automaton for multiple string matching.
5.2 Hot-Reloading Rules
- Rules can be reloaded at runtime.
- Uses double-buffering (read-copy-update pattern) with a shared pointer or atomic swap. The worker threads swap to the new rule set atomically without blocking.
6. Build & Portability Requirements
- Target compiler support: GCC >= 8.1, Clang >= 7.0, MSVC >= 2019.
- Compile flags:
- Release:
-O3 -march=native -ffast-math -flto - Debug/Profiling:
-O2 -g -ggdb -fno-omit-frame-pointer - Static Analysis check: Integration with
clang-tidyand compile with-Wall -Wextra -Wpedantic -Werror.