> ## Documentation Index
> Fetch the complete documentation index at: https://wireblast.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Performance

> What Wireblast does on real hardware: 100G line rate at every frame size, measured.

Short version: on a 100G Mellanox link, Wireblast fills the pipe at every frame size, from 1518-byte frames down to the smallest tagged frame there is.

All the numbers on this page are measured, not modelled. Every one is a real run you can reproduce.

## The test rig

|           |                                                   |
| --------- | ------------------------------------------------- |
| NIC       | NVIDIA/Mellanox ConnectX, `mlx5_core`, 100 Gbit/s |
| Attach    | native XDP, zero-copy, 48 queues                  |
| CPU       | 48 cores                                          |
| Kernel    | 6.8                                               |
| Framing   | 802.1Q tagged, VLAN 2043                          |
| Wireblast | one process, one interface                        |

Two identical boxes back to back, one sending and one receiving.

## Line rate at every frame size

Each row is an unlimited-rate run held for 12 seconds. **L1 is link utilisation**, so \~98 Gbit/s L1 is a full 100G link once you account for the preamble, start-frame delimiter and interframe gap that the wire carries but the frame doesn't.

| Frame (tagged) | Packets/sec    | L1          | L2          |
| -------------- | -------------- | ----------- | ----------- |
| 68 B           | **138.2 Mpps** | 97.3 Gbit/s | 75.2 Gbit/s |
| 128 B          | 82.9 Mpps      | 98.2 Gbit/s | 84.9 Gbit/s |
| 256 B          | 44.5 Mpps      | 98.2 Gbit/s | 91.1 Gbit/s |
| 512 B          | 23.0 Mpps      | 98.0 Gbit/s | 94.3 Gbit/s |
| 1024 B         | 11.8 Mpps      | 98.5 Gbit/s | 96.6 Gbit/s |
| 1518 B         | 8.0 Mpps       | 98.5 Gbit/s | 97.2 Gbit/s |
| IMIX (364 B)   | 32.0 Mpps      | 98.3 Gbit/s | 93.2 Gbit/s |

The small-frame number is the one that matters, because small frames are the hardest thing a NIC does. **138 million packets a second** of 68-byte frames is 97% of tagged line rate, from a single process.

<Note>
  68 bytes, not 64, because these frames are VLAN-tagged and a tagged frame can't be smaller than 68. On an untagged link the smallest frame is 64 bytes and the packet rate is correspondingly a touch higher. See [reading the numbers](/concepts/numbers).
</Note>

## It doesn't take many cores

Queue count is your parallelism budget, and it turns out you don't need much of it. Same 1518-byte frames, unlimited rate, varying the queue count:

| Queues | L1           |
| ------ | ------------ |
| 1      | 83.0 Gbit/s  |
| 2      | 95.4 Gbit/s  |
| 4      | 95.8 Gbit/s  |
| 8      | 97.5 Gbit/s  |
| 32     | 100.0 Gbit/s |

**A single queue already does 83 Gbit/s.** Two queues nearly saturate 100G. This is what zero-copy native XDP buys you: the NIC reads the frames straight out of the UMEM, so there's very little per-packet work left for the CPU to do.

## The receive side is real too

Sending is only half a test. Running a receiver on the far end, 1518-byte frames at 8 Mpps:

```text theme={null}
sender    tx: 122.1 M packets
receiver  rx: 122.09 M packets
```

Every packet accounted for. Lossless at 8 Mpps through a real switch fabric.

<Warning>
  **High-rate receive needs many flows.** A single flow is one 5-tuple, which the NIC steers to one receive queue, which is one core. That core tops out around 7 Mpps here, so a single-flow 138 Mpps blast overruns it and most frames are dropped in hardware before Wireblast ever sees them.

  The fix is flows: `--flows 1000` spreads the traffic across receive queues so the work parallelises. This is a property of how NICs steer traffic, not of Wireblast, and it's the same reason real high-rate capture setups fan out across queues.
</Warning>

## The attach is quick on Mellanox

The link bounce that native XDP causes depends entirely on the driver. On this `mlx5` NIC it's barely there:

```text theme={null}
link came back after 0.8s
```

For comparison, a 10G Intel `ixgbe` NIC takes 8 to 11 seconds for the same thing. Either way the run clock doesn't start until the link is back, and reruns reuse the attachment. See [how it works](/concepts/how-it-works#why-the-link-drops-on-the-first-run).

## For reference: 10 Gigabit

Not everyone has a 100G rig. On a 10G Intel `ixgbe` link, Wireblast saturates the pipe at every size too, and the aggregate rate limiter holds steady regardless of queue count. Measured at `--pps 1M`:

| Queues | Achieved    |
| ------ | ----------- |
| 1      | 999.34 kpps |
| 4      | 999.35 kpps |
| 12     | 999.44 kpps |

You can reproduce the shape of any of this on a `veth` pair with no NIC at all, at whatever rate your CPU manages. See the [namespace lab](/guides/namespace-lab).

## Reproducing these numbers

Nothing here is special-cased. The frame-size sweep is just this, once per size:

```bash theme={null}
sudo wireblast --no-tui -i eno2 --vlan 2043 \
  --src-ip 192.168.43.1 --dst-ip 192.168.43.2 --dst-mac <receiver-mac> \
  --dst-port 9000 --packet-size 1518 --pps unlimited -d 12s -y
```

The queue sweep adds `--queues N`. The receive side is a plain [receiver](/guides/two-box). Runnable versions are in the [examples directory](https://github.com/atoonk/wireblast/tree/main/examples).

## Why it's fast

None of this is Wireblast being clever. The speed comes from AF\_XDP and the zero-copy path, which live in [go-afxdp](https://github.com/atoonk/go-afxdp), the library Wireblast is built on. Wireblast's job is to make that reachable without knowing any of it. If you want to build your own line-rate tool in Go, [go-afxdp](https://github.com/atoonk/go-afxdp) is the foundation.
