Skip to content

Architecture Overview

OpenShield-XDP is an XDP eBPF firewall written in C (BPF) and Go (userspace). It attaches to a network interface at the earliest possible point in the Linux networking stack and makes drop/pass decisions before the kernel allocates an SKB.

Architecture Diagram

Key Concepts

ConceptDescription
16-stage pipelinePackets flow through ~16 ordered stages; any stage can drop the packet.
Bloom filter accelerationA 150K-entry Bloom filter does a fast negative-check before the HASH whitelist lookup, saving ~60-100ns per packet for non-whitelisted traffic.
freplace hot-patchingFive pipeline stages are declared as __attribute__((noinline)) global functions — they can be replaced at runtime without unloading the XDP program.
Dual-stackIPv4 and IPv6 are handled in separate paths with parallel map sets (ban_map / ban_map_v6, etc).
Per-CPU zero-lockglobal_stats_map, prof_map, and panic_bucket_map use BPF_MAP_TYPE_PERCPU_ARRAY — atomic increments without lock contention.
Map pinningAll maps are pinned to /sys/fs/bpf/openshield/ — they survive loader restarts.
Compile-time feature gatingOPENSHIELD_SYNPROXY, OPENSHIELD_L7_MULTISLOT, OPENSHIELD_GLOBAL_DETECT, and OPENSHIELD_ENTROPY are enabled based on kernel version detection in the Makefile.
Spinlock-protected global statenew_source_map uses struct bpf_spin_lock for safe concurrent access to the new-source flood counter.

Map Catalog

MapTypeMax EntriesPurpose
config_mapARRAY1Runtime configuration (written by userspace, read per-packet)
whitelist_mapHASH10KIPv4 whitelist with per-IP flags
whitelist_map_v6HASH10KIPv6 whitelist
ip_stats_mapLRU_HASH100KPer-IPv4 rate counters & suspicion scores
ip_stats_map_v6LRU_HASH100KPer-IPv6 rate counters
ban_mapLRU_HASH50KActive IPv4 bans with expiry
ban_map_v6LRU_HASH50KActive IPv6 bans
subnet_ban_mapLPM_TRIE1KIPv4 CIDR bans (longest-prefix match)
subnet_ban_map_v6LPM_TRIE512IPv6 CIDR bans
prefix_ban_mapLRU_HASH1KPer-/24 ban counter for auto-escalation
prefix_ban_map_v6LRU_HASH512Per-/64 ban counter for auto-escalation
new_source_mapARRAY1Spinlock-protected global new-source flood counter
global_stats_mapPERCPU_ARRAY1Global packet/byte counters (per-CPU)
baseline_mapARRAY1Dynamic mitigation baseline & attack state
prof_mapPERCPU_ARRAY27Profiling path counters (hot-path profiling)
panic_bucket_mapPERCPU_ARRAY1Per-CPU panic circuit breaker counters
events_mapRINGBUF256 KBEvent ring buffer for userspace alerts
syn_cookie_mapLRU_HASH100KSYNPROXY cookie store (kernel ≥ 5.15)
l7_sig_mapARRAY16L7 byte-pattern signature slots
bloom_mapARRAY150KBloom filter for fast whitelist membership test

Total memory footprint: ~37 MB (dominated by ip_stats_map + ip_stats_map_v6 at ~17 MB each for 100K LRU_HASH entries).

Fast-Path Flags

Two boolean flags in the config struct skip expensive lookups when maps are empty:

  • bans_empty — skip ban_map, subnet_ban_map, and prefix_ban_map lookups
  • whitelist_empty — skip whitelist_map and Bloom filter checks

These are set by the Go loader after reading current map sizes and reloaded on config changes.

Performance

MetricValue
Target PPS10M+ pps per core
Bloom filter overhead~60-100ns/pkt (saves 100-200ns when it skips HASH lookup)
HASH whitelist lookup~100-200ns
Per-CPU counter increment~10ns (no lock)
Pipeline stage count~16 stages

Further Reading