How IBSR Works
Technical deep dive into IBSR’s architecture and data model.
Execution Model
XDP Hook Point
IBSR attaches at the XDP (eXpress Data Path) hook, the earliest point a packet can be processed in the Linux network stack:
Network Interface
|
v
+--------------+
| XDP Hook | <-- IBSR attaches here
| (kernel) |
+------+-------+
| XDP_PASS (always)
v
+--------------+
| tc ingress |
+------+-------+
v
+--------------+
| netfilter |
+------+-------+
v
Application
XDP runs before:
- Traffic control (tc)
- Netfilter/iptables
- Socket layer
- Any userspace
Per-Packet Processing
For each incoming TCP packet to a monitored port:
- Parse headers: Ethernet -> IP -> TCP
- Check destination port: Skip if not in monitored list
- Extract source IP: 32-bit IPv4 address
- Update counters: Increment appropriate metrics in BPF map
- Return
XDP_PASS: Packet continues to stack
All operations are O(1). No loops, no allocations, no blocking.
BPF Map Structure
IBSR uses a single LRU hash map to track per-source-IP counters:
+---------------------------------------------------------+
| BPF LRU Hash Map |
+---------------------------------------------------------+
| Key: (src_ip: u32, dst_port: u16) |
| Value: Counters { syn, ack, handshake_ack, rst, |
| packets, bytes } |
+---------------------------------------------------------+
| Max entries: --map-size (default 100,000) |
| Eviction: LRU (least recently updated) |
+---------------------------------------------------------+
Counter Semantics
| Counter | Incremented When |
|---|---|
syn | TCP SYN flag set (connection initiation) |
ack | TCP ACK flag set (includes data and handshake) |
handshake_ack | ACK with no payload and seq > 0 (handshake completion) |
rst | TCP RST flag set (connection reset) |
packets | Every matched TCP packet |
bytes | Every matched packet (IP total length) |
Important: Counters are cumulative within the map. They accumulate until the entry is evicted by LRU.
Userspace Collector
The userspace ibsr collect process:
- Attaches XDP program to network interface
- Polls BPF map at configurable intervals
- Emits snapshots with current counter values
- Writes status heartbeat for monitoring
- Handles signals for graceful shutdown
+-----------------------------------------+
| ibsr collect (userspace) |
| |
| +-----------------------------------+ |
| | Main Loop (every snapshot_sec) | |
| | | |
| | 1. Read BPF map entries | |
| | 2. Build Snapshot struct | |
| | 3. Serialize to JSONL | |
| | 4. Append to hourly file | |
| | 5. Update status.jsonl | |
| | 6. Rotate old files if needed | |
| +-----------------------------------+ |
| |
| Signal Handler: SIGINT/SIGTERM |
| - Write final snapshot |
| - Detach XDP program |
| - Exit cleanly |
+-----------------------------------------+
Snapshot Format
Schema Version 3
Each snapshot is a single JSON line (JSONL format):
{
"version": 3,
"ts_unix_sec": 1705312920,
"dst_ports": [8899, 8900],
"buckets": [
{
"key_type": "src_ip",
"key_value": 3232235777,
"dst_port": 8899,
"syn": 42,
"ack": 156,
"handshake_ack": 40,
"rst": 2,
"packets": 200,
"bytes": 45000
}
]
}
Field Reference
| Field | Type | Description |
|---|---|---|
version | u32 | Schema version (currently 3) |
ts_unix_sec | u64 | Unix timestamp (seconds since epoch) |
dst_ports | [u16] | List of monitored ports |
buckets | [Bucket] | Per-source counter entries |
Bucket Entry
| Field | Type | Description |
|---|---|---|
key_type | string | Key type: "src_ip" |
key_value | u32 | IPv4 address as 32-bit integer (MSB-first) |
dst_port | u16 | Destination port this entry tracks |
syn | u32 | SYN packets count |
ack | u32 | ACK packets count |
handshake_ack | u32 | Handshake-completing ACKs |
rst | u32 | RST packets count |
packets | u32 | Total packets count |
bytes | u64 | Total bytes count |
IP Address Encoding
The key_value field stores IPv4 addresses as 32-bit integers in network byte order (MSB-first):
IP: 192.168.1.1
Binary: 11000000.10101000.00000001.00000001
key_value: 3232235777 (decimal)
0xC0A80101 (hex)
To convert back:
ip = 3232235777
octets = [
(ip >> 24) & 0xFF, # 192
(ip >> 16) & 0xFF, # 168
(ip >> 8) & 0xFF, # 1
ip & 0xFF # 1
]
print(".".join(map(str, octets))) # "192.168.1.1"
Status File Format
The status.jsonl file records collection heartbeats:
{"timestamp":1705312800,"cycle":1,"ips_collected":15,"snapshots_written":1}
{"timestamp":1705312860,"cycle":2,"ips_collected":23,"snapshots_written":2}
| Field | Type | Description |
|---|---|---|
timestamp | u64 | Unix timestamp when cycle completed |
cycle | u64 | Collection cycle number (1-indexed) |
ips_collected | u64 | Unique source IPs in this cycle |
snapshots_written | u64 | Cumulative snapshots written |
File Naming
Snapshot Files
Pattern: snapshot_YYYYMMDDHH.jsonl
YYYY: Year (4 digits)MM: Month (01-12)DD: Day (01-31)HH: Hour (00-23) in UTC
Example: snapshot_2025011514.jsonl = January 15, 2025, 14:00-14:59 UTC
Multiple snapshots append to the same hourly file.
Deterministic Ordering
Within each snapshot, buckets are sorted by (key_type, key_value, dst_port) for:
- Reproducible output
- Stable diffs
- Easier testing
Failure Modes
IBSR is designed to be fail-open:
| Failure | Behavior |
|---|---|
| XDP program fails to load | Error at startup, no traffic impact |
| BPF verifier rejection | Error at startup, no traffic impact |
| Collector process crash | XDP detaches, traffic continues normally |
| Disk full | Snapshot write fails, traffic continues |
| Map overflow | LRU evicts oldest entries, traffic continues |
Graceful Shutdown
On SIGINT or SIGTERM:
- Stop collection loop
- Write final snapshot with current counters
- Detach XDP program from interface
- Exit with code 0
Data Flow Summary
+------------+ +-------------+ +--------------+
| Network |---->| XDP Program |---->| BPF LRU Map |
| Interface | | (kernel) | | (per-IP) |
+------------+ +-------------+ +------+-------+
| |
XDP_PASS Map read
(always) (userspace)
| |
v v
+---------+ +----------------+
| Network | | ibsr collect |
| Stack | | (serialize) |
+---------+ +-------+--------+
|
JSONL write
|
v
+---------------+
| Disk |
| (snapshots) |
+---------------+
Next Steps
- Safety Model - Safety guarantees and verification
- Reporting - Offline analysis
- FAQ - Common questions