# packetdrill: scripting network stack behaviour in a test

> packetdrill is Google's tool for testing an entire network stack, from the system call layer down to the network card, by writing the scenario as a script with timestamps and letting the tool replay it against a live kernel. It runs on Linux and the BSDs, in a local mode with a virtual network device or a remote mode across a real LAN.

**google/packetdrill** — The official Google release of packetdrill

- Repository: https://github.com/google/packetdrill
- Stars: 978 · Forks: 240
- Language: C
- License: GPL-2.0
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/google-packetdrill

## The whole stack, from syscall to NIC

The scope is stated in one sentence and it is unusually wide.

The packetdrill scripting tool enables quick, precise tests for entire TCP, UDP, IPv4 and IPv6 network stacks, from the system call layer down to the NIC hardware. It currently works on Linux, FreeBSD, OpenBSD and NetBSD.

The word quick is doing real work in that sentence, because the alternative to this tool is not no testing, it is a socket-level test program written by hand that cannot easily assert on timing, on retransmissions or on what the peer actually received. A packetdrill script is a description of what the packets should look like and when they should arrive, and the tool checks the live stack against that description.

The reason the tool is worth a dedicated project rather than a test helper is the precision. A test that opens a socket and reads a response can tell you that the handshake worked. It cannot easily tell you that the retransmission timer was set to the right value, that the duplicate acknowledgement handling produced the right number of segments, or that the timestamps option was echoed correctly. Packetdrill sees the packets, so it can check all of that.

The project is the official Google release, licensed under GPLv2, and the source for the tool and a number of test scripts is in the git repository. The readme also says that more tests from the team's own Linux TCP test suite will continue to be posted as time permits, which is the closest thing here to a roadmap.

The surrounding material is substantial for a tool of this size: the USENIX paper from 2013 describing the tool and the team's experience with it, a follow-up article in the login magazine, a tutorial from the NetDev conference in March 2025, a mailing list, and a language syntax reference in the repository.

## The execution model: a script played back in real time

The design section explains how a script becomes a test, and the answer is the key idea.

Packetdrill parses an entire test script, and then executes each timestamped line in real time, at the pace described by the timestamps, to replay and verify the scenario. So a script is not a list of assertions, it is a timeline, and the tool sleeps until each line is due, then checks that reality matched.

That is what makes the tool able to test timing behaviour, and it is also what makes it sensitive to the machine it runs on. A test that expects a retransmission at a specific moment will fail on a loaded machine, which is the same fundamental problem every network test has and the reason the remote mode carries a warning about timing variation.

The interpreter has one thread for the main flow of events and another for executing any system calls that the script expects to block. The blocked call is the one that matters: when the script says the application will call poll and wait, the tool needs that call to be in flight while the main thread continues to advance the timeline and to handle the packets that arrive. Two threads is the minimum for that.

On top of the timeline there is a translation layer. For convenience, scripts use an abstracted notation for packets, and internally packetdrill models aspects of TCP and UDP behaviour, maintaining mappings between the values in the script and those in the live packet. The translation includes IP, UDP and TCP header fields, including TCP options such as SACK and timestamps. So packetdrill tracks each socket with its IP addresses, port numbers, TCP sequence numbers and TCP timestamps, and a script can say what it means in terms of those rather than in terms of raw bytes.

## Local mode and remote mode test different things

The two modes are not variations on the same thing. They cover different layers, and the readme is clear about which is which.

In local mode, packetdrill uses a single machine and a TUN virtual network device as a source and sink for packets. That tests the system call layer, sockets, TCP and IP. The readme gives the reason to prefer it: it is easier to use because there is less timing variation, and users need not coordinate access to multiple machines.

In remote mode, users run two packetdrill processes, one of which is on a remote machine and speaks to the system under test over a LAN. This tests the full networking system: system calls, sockets, TCP, IP, software and hardware offload mechanisms, the NIC driver, the NIC hardware, the wire and the switch. The readme is equally clear about the cost, because of the inherent variability in the many components under test, remote mode can produce larger timing variations, which can cause spurious test failures.

So the choice follows the question. If you are testing a kernel's TCP behaviour, local mode is both easier and more reliable. If you are testing a driver or the hardware path, only remote mode reaches the layers you care about.

The packet plumbing differs between them. To capture outgoing packets, packetdrill uses a packet socket on Linux or libpcap on the BSD derived systems. To inject packets locally it uses the TUN device, and to inject over the physical network in remote mode it again uses the packet socket or libpcap. To consume test packets in local mode it uses the TUN device, and remotely the packets travel over the physical network, with packetdrill setting up filtering rules to drop them before the layer 4 processing in the remote kernel sees them.

## Running a remote test means two processes and a wire server

The remote mode plumbing is described well enough to set up without reading the source.

On the machine under test, the client instance, you specify the wire server option with the DNS name or IP address of the remote server machine. Only the client instance takes a script argument, and it can be the path of any ordinary packetdrill test script:

```
client# ./packetdrill --wire_server_at=<server_name_or_ip> foo.pkt
```

On the remote machine, you run a packetdrill process as a wire server daemon that injects and sniffs packets on the wire:

```
server# ./packetdrill --wire_server
```

The client connects to the server over TCP and sends it the command line options and the contents of the script file, and then the two instances work in concert to execute the script against the client machine's network stack. So the script lives in one place and the server is a fairly dumb daemon once it has the script.

Local mode is the default, and needs no special flags, just the path of the script:

```
./packetdrill foo.pkt
```

There is also a set of options for the addresses used by the test traffic, which is what you reach for when the default configuration does not fit the topology you are modelling. The local address for the machine under test, the netmask for IPv4, the gateway address and the remote endpoint address are all separately settable. By default, remote mode tests use the primary IP address of the client and server machines, where primary means the address the hostname resolves to.

Setting the addresses explicitly is what lets a test describe a topology the machine does not actually have, which is a large part of what a network test tool is for.

## Building it, and the optional PSP support

The build is a standard autotools style configure and make, and the dependency list is the useful part.

On a Debian or Ubuntu system, the dependencies are installed with apt, and the list names git, gcc, make, bison, flex, python3, net-tools and iptables.

```
sudo apt install git gcc make bison flex python3 net-tools iptables
```

The bison and flex packages are the parser and lexer generators the script parser is built with, and the Python is for the test runner script.

The build itself is clone, change into the packetdrill directory inside the tree, configure and make:

```
git clone https://github.com/google/packetdrill.git
cd packetdrill/gtests/net/packetdrill
./configure
make
```

The path is worth noting, because the tool is not at the root of the repository. The top level holds the licence, the readme, the syntax reference, a submodule file and a gtests directory, and the tool lives under the net subdirectory of that.

There is an optional feature, PSP support, which needs the OpenSSL development headers, a recursive clone so the ynl-c submodule comes along, and a make flag:

```
sudo apt install libssl-dev
git clone --recurse-submodules https://github.com/google/packetdrill.git
cd packetdrill/gtests/net/packetdrill
./configure
make ENABLE_PSP=1
```

And if you already have a checkout, the submodule can be pulled in afterwards with the submodule update command, recursively.

To run the whole suite on a machine with a recent Linux kernel, you become root and run the runner against the tcp directory, with the -S, -v, -L and -l flags and the tcp/ directory:

```
cd ..
./packetdrill/run_all.py -S -v -L -l tcp/
```

## The language reference, and what to expect from the project

Two practical points to close on.

The first is the script language, and the readme is upfront that it has a reference document in the repository. The syntax file is a first class part of the project, which tells you the language is stable enough to specify, and a language reference is a prerequisite for a tool that other people are supposed to write tests in. There is also an external link to a course exercise about using packetdrill for teaching TCP, which is a neat validation of the claim that the scripts are readable enough to be a teaching artefact.

The second is the maintenance picture. There are no GitHub releases, and the last push was on 2026-10-15 with the repository not archived. The tool is in daily use inside Google, and the readme says the team will keep posting more tests from their Linux TCP test suite as time permits, which is an honest description of how a test tool grows: slowly, in bursts, when someone has time to port a case.

The project is GPLv2, which matters if you want to contribute patches.

For an evaluator, the realistic first step is to build it in local mode, take one script from the tcp directory, and read it against the syntax reference. If the script reads as a description of a conversation between two endpoints, the tool is doing what the readme claims, and the question after that is only whether the behaviour you need to test lives in the layers that local mode reaches.

## Conclusion

packetdrill suits a kernel or driver team that needs reproducible tests for the parts of TCP behaviour that are hard to trigger by hand, such as sequence number edge cases and retransmission timing, and it is the tool the Linux TCP test suite grew out of. It is a poor fit for testing application level behaviour, and local mode will not tell you anything about the driver or the hardware. Before you set it up, read the syntax reference, decide which mode your question needs, since only remote mode exercises the NIC, and install the OpenSSL headers and the submodule up front if you intend to use the PSP support.

## FAQ

### What does packetdrill test?

Entire TCP, UDP, IPv4 and IPv6 network stacks, from the system call layer down to the NIC hardware. It works on Linux, FreeBSD, OpenBSD and NetBSD, and it runs a scripted scenario with timestamps against a live stack and verifies what actually happened.

### What is the difference between local and remote mode in packetdrill?

Local mode uses one machine and a TUN virtual network device, testing the system call layer, sockets, TCP and IP, with less timing variation. Remote mode runs two packetdrill processes over a LAN, testing the full system including offload mechanisms, the NIC driver, the hardware, the wire and the switch, at the cost of larger timing variations that can cause spurious failures.

### How do I build packetdrill?

Install the build dependencies, which on Debian and Ubuntu are git, gcc, make, bison, flex, python3, net-tools and iptables. Then clone the repository, change into the gtests/net/packetdrill directory, and run configure and make. The OpenSSL headers and a recursive clone are needed only if you want the optional PSP support, which also needs the ENABLE_PSP make flag.

### How do I run the whole packetdrill test suite?

On a machine with a recent Linux kernel, become root and run the bundled runner against the tcp directory, for example the run_all.py script with the -S, -v, -L and -l flags. The test scripts live in the tcp directory of the packetdrill tree and are written in the packetdrill script language documented in the syntax reference in the repository.

## Sources

- [google/packetdrill on GitHub](https://github.com/google/packetdrill)
- [Issues](https://github.com/google/packetdrill/issues)
- [License: GPL-2.0](https://github.com/google/packetdrill/blob/master/LICENSE)
- [README](https://github.com/google/packetdrill/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/google-packetdrill
