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

# Two-box test

> Sender on one machine, receiver on the other, and how to tell the two ends agree.

The classic setup: one machine generates, the other counts. When both ends report the same number of packets, you know the path between them carried everything.

```mermaid theme={null}
flowchart LR
    subgraph TX ["Sender"]
      A["wireblast --mode imix"]
    end
    subgraph NET [" "]
      S["Switch"]
    end
    subgraph RX ["Receiver"]
      B["wireblast --mode receive<br/>--rx-mode udp-port --rx-port 9000"]
    end
    A -->|eth1| S
    S -->|eth1| B
```

<Warning>
  **Manage each box over a different interface than you test on.** Attaching XDP drops carrier on the test NIC for several seconds, and receive modes take packets away from the kernel. If you're SSH'd in over the interface you're testing, you'll lose the session. Wireblast warns you when it detects this, but the habit is better than the warning.
</Warning>

## Before you start

On both machines:

```bash theme={null}
wireblast --version
ip -br addr show
```

You need, on each box: the test interface name (the **physical** NIC, not a VLAN sub-interface), and on the receiver, its MAC address, which you'll hand to the sender so it doesn't have to resolve anything.

```bash theme={null}
# on the receiver
ip link show eth1 | awk '/link\/ether/ {print $2}'
```

## Start the receiver first

Always. If the sender starts first, its first several seconds go into a void and the totals won't match.

```bash theme={null}
sudo wireblast -i eth1 --mode receive \
  --rx-mode udp-port --rx-port 9000 -d 60s
```

That takes **only** UDP packets destined to port 9000 away from the kernel. Everything else on that interface, meaning ARP, your monitoring, anything else sharing the link, keeps flowing normally.

## Then the sender

Give it a duration shorter than the receiver's, so the receiver is definitely listening for the whole run.

```bash theme={null}
sudo wireblast -i eth1 --mode imix \
  --src-ip 192.0.2.99 --dst-ip 192.0.2.20 \
  --dst-mac 3c:ec:ef:b4:c2:dc \
  --dst-port 9000 --flows 64 --pps 200k -d 12s
```

A few choices worth explaining:

* **`--dst-mac` explicitly.** The receiver won't answer ARP for an address it doesn't own, and giving the MAC skips resolution entirely. Drop it if both boxes are properly addressed on the same subnet.
* **`--src-ip` doesn't have to be real.** Nothing needs to route back, because the receiver counts what arrives.
* **`--flows 64`** exercises hashing across the path. Add `--vary-dst-port` to spread wider, but then widen the receive filter to match.

Sending tagged frames? Add `--vlan`, and see [VLAN-tagged traffic](/guides/vlan) for the 68-byte minimum.

## Reading the result

Both ends steady at the same packets/sec and the same L1 bit rate during the overlap. That's the agreement you're looking for.

<Note>
  The receiver's *average* rate over its whole run will be much lower than the sender's, because it was idle before the sender started and after it stopped. Compare the **per-second lines during the overlap**, and the **packet totals**, not the run averages.
</Note>

## When the numbers don't match

<AccordionGroup>
  <Accordion title="Receiver counts zero">
    The filter doesn't match what's arriving. Check the destination port on both sides, and remember the filter matches the **destination** port only.

    Confirm packets are physically arriving at all:

    ```bash theme={null}
    sudo tcpdump -ni eth1 -c 10 udp port 9000
    ```

    If tcpdump sees nothing either, it's the path: VLAN, cabling, or switch config. If tcpdump sees traffic but Wireblast doesn't, it's the filter.
  </Accordion>

  <Accordion title="Receiver counts fewer packets">
    Something dropped them, and where matters:

    * **`Drops/errors` climbing on the receiver** means the receive rings filled up. The receiver can't keep up. Try more queues, or a lower send rate.
    * **Receiver clean, but short** means the loss is in the path: a switch, a policer, or a link that isn't as fast as you think.

    Per-queue detail appears under the dashboard:

    ```text theme={null}
    ! queue 3: rx ring full (1.2 k)
    ```
  </Accordion>

  <Accordion title="Sender reports fewer packets than you asked for">
    Check `Errors` on the TX side. If it's zero and the rate is simply below what you set, you've found the box's limit rather than a fault. [Finding your max rate](/guides/max-rate) covers what to do about it.
  </Accordion>

  <Accordion title="Bit rates differ slightly between the two ends">
    Expected if one end is tagging and the numbers are being read at different layers. [Reading the numbers](/concepts/numbers) explains the L1/L2/kernel-counter split.
  </Accordion>
</AccordionGroup>

## Running it repeatedly

In the TUI, press `r` to run again. The XDP program stays attached, so the second run starts in about two seconds instead of waiting out another link bounce. Press `e` to change a setting first.

To script the whole thing, see [scripting and automation](/guides/scripting), or grab [example 018](https://github.com/atoonk/wireblast/tree/main/examples/018-two-box-imix), which is exactly this test.
