OPNsenseXLVII · Capacity PlanningCapacity planning
IDS/IPS throughput budget — what Suricata costs and how to budget for it
What you'll learn
- Calculate the IDS/IPS throughput the firewall can sustain based on ruleset and mode
- Compare IDS mode (alert-only) and IPS mode (inline) performance characteristics
- Identify the ruleset factors that determine per-packet IDS cost — rule count, rule complexity, flowbits
- Tune Suricata threading and confirm Hyperscan is built in
- Recognise the symptoms of IDS saturation — kernel_drops, alert queue, throughput plateau
Prerequisites
Verified against OPNsense 25.x · FreeBSD 14.x · PF (FreeBSD packet filter) FreeBSD 14.x · Unbound 1.20+ · Kea DHCP OPNsense 25.x plugin · WireGuard in-kernel + OPNsense plugin · strongSwan (IPsec plugin) OPNsense 25.x plugin · OpenVPN 2.6.x · Suricata 7.x · 2026-08-14
Suricata IDS on OPNsense is the most expensive optional feature. Every packet that traverses the firewall is mirrored to Suricata; Suricata runs a ruleset of tens of thousands of signatures against each packet; matched packets generate alerts or trigger drop actions. The cost can dominate the firewall’s CPU budget, drop packets at high traffic rates, and produce a queue of unprocessed packets that grows until the firewall itself becomes the bottleneck.
This lesson covers the IDS/IPS throughput budget — the CPU cost, the ruleset factors, the IDS versus IPS performance difference, the threading model, the canary metrics, and the discipline of sizing the firewall for the workload with IDS enabled.
The CPU cost of Suricata
Suricata’s per-packet CPU cost depends on:
- Ruleset size. Every rule is evaluated per packet (with some short-circuiting when earlier rules match). A ruleset of 30,000 rules is typical; 50,000 is large; 100,000 is the upper limit before performance collapses.
- Rule complexity. Simple IP/port matches are fast; multi-pattern content matches with modifiers are slower.
- Flowbits. Rules that set or check flowbits create dependencies; a rule that sets a flowbit that 50 other rules check forces those 50 rules to evaluate even when the flowbit is not set.
- Preprocessor activity. HTTP, TLS, DNS, SMB protocol parsers reconstruct streams and may buffer data; high protocol diversity costs more.
The per-packet CPU cost on a modern x86 with Hyperscan:
| Ruleset | Per-packet cost | Single-core throughput |
|---|---|---|
| 1,000 rules (small) | ~1 μs | ~1 Mpps |
| 10,000 rules (medium) | ~5 μs | ~200 Kpps |
| 30,000 rules (ETOpen) | ~10 μs | ~100 Kpps |
| 50,000 rules (ETPro) | ~20 μs | ~50 Kpps |
| 100,000 rules (large) | ~50 μs | ~20 Kpps |
The numbers are approximate; actual cost depends on the ruleset’s complexity and the packet mix. A deployment with mostly small HTTP packets (where HTTP parsing is expensive) sees higher per-packet cost than a deployment with mostly large non-HTTP packets.
IDS mode versus IPS mode
The two modes have different throughput characteristics:
- IDS mode (alert-only). Suricata receives mirrored packets via netmap; PF forwards packets independently. Suricata’s CPU cost does not directly affect PF throughput. The two run in parallel; the firewall’s effective throughput is
min(PF throughput, Suricata throughput)— the slower of the two is the bottleneck. - IPS mode (inline). Suricata sits inline in the packet path; PF sends packets to Suricata; Suricata decides to forward or drop. Suricata’s CPU cost directly affects PF throughput. The firewall’s effective throughput is
Suricata throughput— Suricata is the bottleneck.
| Mode | CPU cost | Failure mode |
|---|---|---|
| IDS (alert-only) | ~50% of IPS cost | Suricata saturation drops alerts, not traffic |
| IPS (inline) | Full per-packet evaluation | Suricata saturation drops traffic |
For a deployment with 500 Mbps of traffic and Suricata delivering 400 Mbps in IDS mode:
- IDS mode: 400 Mbps alerts, 500 Mbps traffic (Suricata cannot keep up but traffic continues; alerts are missed).
- IPS mode: 400 Mbps total (Suricata is the bottleneck; the firewall cannot forward more than Suricata processes).
The capacity plan must account for the mode. A deployment that needs IDS-mode performance for 1 Gbps of traffic needs IPS-mode performance for 1 Gbps of traffic, which requires twice the Suricata capacity.
The threading model
Suricata uses multiple threads:
- Management thread. Configuration, counters.
- Packet acquisition threads. Read packets from netmap (one per interface).
- Worker threads. Run the detection engine — evaluate rules against each packet.
- Flow worker threads. Track flow state across packets.
- Output threads. Write alerts, logs, stats.
The number of worker threads is threading.detect-thread-ratio (typically 1.5x the core count). On a 4-core firewall, that’s 6 worker threads. The operator tunes the ratio up or down based on the workload.
# Confirm Suricata's build configuration.
suricata --build-info | grep -E 'Threads|Detect|Netmap|Hyperscan'
# Hyperscan: yes <-- 5-10x faster pattern matching
# Netmap: yes <-- the OPNsense fast path
# Detect thread ratio: 1.5
The discipline: confirm Hyperscan is built in. Without Hyperscan, pattern matching is 5-10x slower; the deployment’s effective Suricata throughput drops dramatically. If Hyperscan is not built in, the operator should either rebuild Suricata with Hyperscan or reduce the ruleset to compensate.
Symptoms of IDS saturation
The signatures of Suricata saturation:
capture.kernel_dropsrising. The kernel dropped packets before Suricata could read them. Non-zero is the canary.alert_queue.droppedrising. The alert queue is full; alerts are dropped before being written. Non-zero indicates output is not keeping up.- High CPU on Suricata threads. The worker threads are at 100% in
top. - Latency in IPS mode. Packets queue while Suricata processes; latency rises.
- Lower-than-expected throughput in IPS mode. The firewall’s pps is well below the expected rate.
# Suricata stats — the canary metrics.
curl -s http://127.0.0.1:9911/ | grep -E 'kernel_drops|alert_queue'
# "capture.kernel_drops": 12345, <-- non-zero is bad
# "alert_queue.dropped": 0 <-- non-zero is bad
The discipline: monitor capture.kernel_drops and alert_queue.dropped as canary metrics; alert on non-zero values; investigate immediately.
Sizing for IDS
The IDS sizing calculation:
ids_throughput = single_core_throughput × worker_threads × efficiency_factor
For a deployment with:
- 30,000 ETOpen rules: ~100 Kpps per worker thread
- 4-core firewall, 1.5x ratio: 6 worker threads
- 0.7 efficiency factor (memory bandwidth, contention, etc.)
ids_throughput = 100 Kpps × 6 × 0.7 = 420 Kpps
At 1500-byte packets, 420 Kpps is 5 Gbps of throughput. At 64-byte packets, 420 Kpps is 215 Mbps of throughput. The discipline: account for the actual packet mix, not the theoretical maximum.
Tuning for IDS performance
The tuning levers:
- Reduce the ruleset. Disable unused categories. The ETOpen ruleset has categories; the operator should disable categories irrelevant to the deployment.
- Tune
detect-thread-ratio. More threads = more parallelism but more memory. Tune up for higher packet rates; tune down for lower memory. - Confirm Hyperscan is built in. 5-10x faster pattern matching. The single biggest performance win.
- Reduce logging. Every alert is written to disk; verbose logging on a busy network saturates disk I/O. Tune to log only what the operator will read.
- Tune flow timeouts. Short flow timeouts reduce memory pressure; long timeouts increase state.
The discipline: tune systematically. Change one variable at a time; measure the impact; keep the changes that improve performance.
IPS sizing — when blocking is required
IPS mode has the throughput cost of IDS mode plus the inline-blocking cost. The capacity plan must account for:
- Inline evaluation. Every packet is evaluated inline; Suricata’s decision time is on the packet’s critical path.
- Failure mode. A Suricata hang in IPS mode means traffic stops. The deployment needs a fallback (IDS mode, fail-open) for Suricata outages.
The discipline: use IPS mode only when inline blocking is required; have a tested rollback to IDS mode; size the firewall for the IPS-mode workload, not the IDS-mode workload.
Verification
After deploying the sized firewall with IDS, verify:
suricata --build-infoshows Hyperscan enabled — the build is correct.capture.kernel_dropsandalert_queue.droppedare zero at production load — saturation is not happening.- Suricata CPU usage is below 70% on the busiest worker thread — headroom remains.
- Throughput with IDS enabled meets the deployment target — the sizing is correct.
pfctl -s stateshows the firewall is forwarding packets normally — IDS in alert-only mode is not affecting PF.
An IDS sizing that meets 1-2 but fails 3-5 has the build correct but the workload exceeds capacity. The operator reduces the ruleset, tunes threading, or upgrades the hardware.
Knowledge check · 4 questions
Q1. A deployment has Suricata in IDS mode with 30,000 ETOpen rules on a 4-core firewall. The capture.kernel_drops counter is rising. What is the most likely diagnosis?
Q2. The CPU cost of IPS mode relative to IDS mode depends on the deployment and has to be measured; it is not a fixed multiple.
Q3. Which of the following are tuning levers for Suricata performance? Select all that apply.
Q4. A deployment runs Suricata with Hyperscan. A single signature uses PCRE with backreferences. What happens to the ruleset performance?
Passing score: 75%. Answers are checked in this browser.