# How XDP filtering works

> How OpenShield-XDP drops attack traffic at the NIC driver hook: the packet path, baseline spike detection, the eBPF maps, and why false positives stay low.
>
> Canonical: https://xdp.network/docs/attack-mitigation/how-xdp-filtering-works · Updated 2026-08-09

OpenShield-XDP drops attack traffic inside your server's network card path, before the
kernel spends any real work on it. This page walks the packet path, how detection fires,
and why legitimate traffic rarely gets caught.

## The path of a packet

Without OpenShield, every arriving packet travels the full Linux network stack: the kernel
allocates a socket buffer, parses headers, runs netfilter, and only then can anything drop
it. A flood large enough to exhaust that pipeline takes the whole server down with it.

With OpenShield, an eBPF program attaches to the XDP hook in the NIC driver — the earliest
point a packet can be handled. Verdicts happen there, and attack packets are dropped
(`XDP_DROP`) before a socket buffer is ever allocated. That is why mitigation runs at line
rate with sub-millisecond overhead.

```text title="Packet path with OpenShield"
NIC
 │
 ▼
XDP hook (eBPF program — earliest point in the stack)
 │─ source on whitelist map ─────────────► pass
 │─ source on ban map ───────────────────► XDP_DROP
 │─ attack active and packet offending ──► XDP_DROP
 │
 ▼ pass
kernel network stack ──► socket buffer ──► your application
```

The console reports which mode the program runs in (`system.xdp_mode` — native driver or
generic fallback) and which interface it guards (`system.interface`).

## How detection fires

The agent continuously learns a traffic baseline (`attack.baseline_pps`). When the current
packet rate (`attack.current_pps`) exceeds baseline × a spike factor
(`attack.spike_factor`), the agent flips into mitigation (`attack.state`) and starts
dropping offending packets. The threshold it crossed is reported as
`attack.spike_pps_threshold`.

During mitigation, offending sources are banned with an expiry (`bans.active_count`,
`bans.recent`), and brand-new sources can be refused outright
(`attack.new_sources_blocked`).

## Where the state lives

All state sits in eBPF maps; the metrics payload reports entry counts per map.

| Map | Holds |
| --- | --- |
| `config` | The active mitigation settings |
| `whitelist` | Sources that always pass |
| `ip_stats` | Per-source packet counters |
| `ban` | Banned sources and their expiry |
| `global_stats` | Global packet and drop counters |
| `baseline` | The learned traffic baseline |
| `events` | The recent event ring buffer |

## Why false positives stay low

Two mechanisms protect real users. The whitelist map is checked first, so sources you
trust always pass. And on game profiles, per-player buckets track each source against its
own budget, so one busy player doesn't look like a flood. Tune this per workload — see
[Tuning profiles](/docs/openshield-xdp/tuning-profiles).

## Next steps

- [Attack types explained](/docs/attack-mitigation/attack-types)
- [Reading attack logs and forensics](/docs/attack-mitigation/reading-attack-logs)
- [Tuning profiles](/docs/openshield-xdp/tuning-profiles)
