`AF_PACKET` XDP Driver Bypass: BPF maps remain empty (`ipv4_maps_count: 0`) despite `stream.bypass: true` (Suricata 8.0.6, Kernel 6.16)

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!