Skip to main content
RunBook Academy

OPNsenseXLVII · Capacity PlanningCapacity planning

IDS/IPS throughput budget — what Suricata costs and how to budget for it

Advanced⏱ ~14 minsuricatasysctlvmstattopprometheus

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

Not yet marked complete on this device.

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:

RulesetPer-packet costSingle-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.
ModeCPU costFailure mode
IDS (alert-only)~50% of IPS costSuricata saturation drops alerts, not traffic
IPS (inline)Full per-packet evaluationSuricata 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_drops rising. The kernel dropped packets before Suricata could read them. Non-zero is the canary.
  • alert_queue.dropped rising. 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:

  1. suricata --build-info shows Hyperscan enabled — the build is correct.
  2. capture.kernel_drops and alert_queue.dropped are zero at production load — saturation is not happening.
  3. Suricata CPU usage is below 70% on the busiest worker thread — headroom remains.
  4. Throughput with IDS enabled meets the deployment target — the sizing is correct.
  5. pfctl -s state shows 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

  1. 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?

  2. 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.

  3. Q3. Which of the following are tuning levers for Suricata performance? Select all that apply.

  4. 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.