Hi everyone,
INFRASTRUCTURE
OS: Debian Linux (Kernel 6.16) as a virsh guest on SUSE host with PCI pass-thru for
Suricata Version: 8.0.6 (Built from source, installed under /opt)
Mode: AF_PACKET IPS inline copy-mode
NICs: 03:00.0 Ethernet controller: Intel Corporation 82576 Gigabit Network Connection (rev 01)
03:00.1 Ethernet controller: Intel Corporation 82576 Gigabit Network Connection (rev 01)
I’m setting up Suricata 8.0.6 in IPS mode using AF_PACKET with xdp-mode: driver on a 2-port inline bridge (enp9s0 <==> enp10s0). The eBPF driver program compiles, loads into the kernel without verifier errors, and links successfully. However, the BPF flow tables (flow_table_v4) remain completely empty ([]), and suricatasc -c ebpf-bypassed-stat reports 0 bypassed flows across both interfaces. Post suricata start my Internet in Debian VM and SUSE host goes down.
I’m trying to understand why Suricata’s engine is not populating the eBPF maps when a flow reaches stream.reassembly.depth or when stream.bypass: true is set.
The BPF object loads clean into kernel 6.16, and bpftool shows the XDP filter running:
# bpftool prog list name xdp_hashfilter
55: xdp name xdp_hashfilter tag baa10127dca180f2 gpl
loaded_at 2026-08-12T18:08:10+0530 uid 0
xlated 3040B jited 1642B memlock 4096B map_ids 75,71,77,76,72,74,73
btf_id 118
However, inspecting Map ID 71 (flow_table_v4) shows it is completely empty:
# bpftool map dump id 71
[]
And suricatasc confirms 0 bypassed flows:
# suricatasc -c ebpf-bypassed-stat
{
"message": {
"enp9s0": { "ipv4_maps_count": 0, "ipv4_success": 0, "ipv4_fail": 0 },
"enp10s0": { "ipv4_maps_count": 0, "ipv4_success": 0, "ipv4_fail": 0 }
},
"return": "OK"
}
Configuration Snippets
ips-xdp.yaml:
af-packet:
- interface: enp9s0
threads: auto
cluster-id: 99
cluster-type: cluster_qm
defrag: yes
copy-mode: ips
copy-iface: enp10s0
xdp-mode: driver
xdp-filter-file: /opt/libexec/suricata/ebpf/xdp_filter.bpf
bypass: yes
use-mmap: yes
ring-size: 200000
buffer-size: 64535
- interface: enp10s0
threads: auto
cluster-id: 100
cluster-type: cluster_qm
defrag: yes
copy-mode: ips
copy-iface: enp9s0
xdp-mode: driver
xdp-filter-file: /opt/libexec/suricata/ebpf/xdp_filter.bpf
bypass: yes
use-mmap: yes
ring-size: 200000
buffer-size: 64535
suricata-ips.yaml (Stream section):
stream:
memcap: 64 MiB
bypass: true
checksum-validation: yes
midstream: false
midstream-policy: bypass
inline: auto
reassembly:
memcap: 256 MiB
depth: 1 MiB
Additional information :stdout
Is stream.reassembly.depth + stream.bypass: true expected to automatically call EBPFBypassSetFlow() and insert flow tuples into flow_table_v4 in modern Suricata releases, or does kernel eBPF map insertion strictly require an explicit signature with a pass / bypass action?
Are there specific capture: or flow: configuration directives required in Suricata 8 to bridge user-space stream bypasses with AF_PACKET eBPF map population?
Any insight on what triggers the eBPF map insertion callback in standard AF_PACKET IPS mode would be greatly appreciated!