# Retis traces a packet through the Linux stack instead of only its wire bytes

> Retis is a Rust tool that attaches eBPF probes to the Linux networking stack, collects packet events with connection tracking, netfilter and namespace context attached, and can reconstruct a packet's journey after the fact with retis sort.

**retis-org/retis** — Tracing packets in the Linux networking stack & friends

- Repository: https://github.com/retis-org/retis
- Website: https://retis.readthedocs.io/en/stable/
- Stars: 543 · Forks: 39
- Language: Rust
- License: GPL-2.0
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/retis-org-retis

## eBPF probes on skb-enabled functions and tracepoints

Retis traces filtered packets in the Linux networking stack using eBPF probes, and it interfaces with control and data paths such as Open vSwitch or Netfilter. The key point about the mechanism is that it operates on skb-enabled functions and tracepoints, which is what lets it see a packet at the point where the kernel is working with it, rather than only at the wire.

The default run is deliberately small. Collectors for connection tracking, netfilter, device events, skb events, dropped skbs, skb tracking and namespaces are started, and with no probes given the tool falls back to two tracepoints, the receive and the transmit path, loading seven probes in total:

```bash
$ retis collect
Collector(s) started: ct, nft, dev, skb, skb-drop, skb-tracking, ns
No probe(s) given: using tp:net:netif_receive_skb, tp:net:net_dev_start_xmit
7 probe(s) loaded
```

The output then shows packets as they are seen, with the interface, the network namespace, the protocol and the socket or CPU context of the event. Retis also states that it does not require compilation on the target, which is the practical difference from writing your own probes for a machine you do not control.

## One packet produces many events, and tracking links them

The most important idea in the tool is that a packet is not one event. The same packet can be seen multiple times, modified along the way, and each sighting is a separate event with its own context.

That is why the tool offers both filtering and tracking, and why the output distinguishes event kinds with markers such as tp for a tracepoint and k for a kprobe. A packet leaving the host through the transmit path and the same packet arriving back on an interface are two events tied together, and following that pair is how you see a reply being handled differently from the original request.

The advanced run makes the difference visible. With a filter and the generic profile, the same UDP packet appears at the output path, at the device queue, at the transmit tracepoint, then in the receive path through the NAPI and GRO receive functions and the final receive tracepoint, with the connection tracking state changing between them:

```bash
$ retis -p generic collect -f 'udp port 53 and host 2606:4700:4700::1111'
L2+L3 packet filter(s) loaded
30 probe(s) loaded
```

Thirty probes instead of seven, and the same packet five or six times. That is the point of the tool, and it is why a plain capture utility is not a substitute.

## Context from conntrack, netfilter and namespaces

The second design goal is to retrieve more than the packet itself, with additional metadata and contextual information attached to each event. Three kinds of context show up in the output.

Connection tracking state appears as a line with the connection state, the status flags, and the original and reply tuples, along with the zone and the mark. In the advanced run the same packet shows ct_state NEW on the output path and ct_state REPLY when it comes back, and the status value changes as the entry matures. That single field often explains the behaviour you were trying to debug, because it tells you whether the kernel considered the flow new, established or related.

The namespace is another piece of context, shown as a namespace identifier and a network namespace value next to each event, which is what tells you a packet crossed a container boundary.

Netfilter is available through the nft collector, so firewall state can be seen in the same stream as the packets. The design is modular in what data is retrieved and where it is retrieved from, and that modularity is the point: you choose the collectors that answer your question instead of paying for a fixed capture format.

## retis sort rebuilds the journey after the run

Live output is only half of the story. When events are stored for later processing, the packets' journeys can be reconstructed, which the README shows by collecting with an output option and then running the sort command:

```bash
$ retis -p generic collect -f 'udp port 53 and host 2606:4700:4700::1111' -o \
      --cmd 'dig redhat.com @2606:4700:4700::1111'
$ retis sort
```

The sorted output uses an indented tree with arrow markers, and each event carries a sequence number, so a single packet is shown as one root event with its follow-up events nested beneath it. In the example, the root is the output path, and the nested entries are the device queue and the transmit tracepoint, so the order of a packet's life is legible at a glance rather than scattered across a flat list.

That is the post-processing ability the README advertises, and it changes how you work. A live trace tells you what is happening now, while a stored and sorted trace can be examined after the fact, filtered and compared, which is what makes the tool usable in a test or a CI script as well as in an interactive debugging session.

## Profiles and filters decide what you see

Two knobs shape a collection, and they sit on opposite ends of the pipeline.

Probes are selected by profile, and the generic profile, defined in retis/profiles/generic.yaml, defines a bigger set of probes than the default two. The generic run loads thirty probes against the default seven, which is what surfaces the kprobe-level events such as ip6_output and udp6_gro_receive alongside the tracepoint ones. The first example in the README is a two-probe trace of traffic in and out of a device, comparable to what the well-known AF_PACKET utilities do, and the generic profile is the step beyond that.

Filters are applied at the probe level, and the message when a filter loads says L2 plus L3 packet filters, which means the filtering happens in the kernel rather than on the displayed text. The filter syntax is the familiar tcpdump-style expression, for example a UDP port and host pair, and the README uses it to isolate a single DNS exchange.

That distinction matters for performance and for what you see. A filter that runs on the probes avoids the cost of collecting everything and discarding it later, and it means the events you get are the events you asked for rather than a sample.

## A Rust workspace with its own eBPF build

The repository is a Rust workspace whose manifest lists four members, the retis binary, retis-derive, retis-events and retis-pnet, with the workspace version at 1.8.0 and the edition at 2021.

The build is not a plain cargo build, and the Makefile shows why. There is a separate set of variables for compiling the eBPF programs, with the target set to bpf and the architecture chosen from the host or the cross-compilation target, mapping x86 to x86, aarch64 to arm64, powerpc64 to powerpc and s390x to s390. The Makefile also carries a release version helper that reads a local version tool and a release name from the package metadata, and it uses a container runtime, podman, for some of the steps.

Installation is offered in three ways, as a container image, on supported distributions, or built from sources, with the details in the online documentation at retis.readthedocs.io. The repository also holds a Containerfile, a Vagrantfile for local development, a makefile fragment for the eBPF objects, the documentation sources with an mkdocs configuration, a pcap file used for tests, and a demo animation.

## Where Retis is the wrong tool

The scope is a single host, and the README says so: Retis aims at providing better visibility on complex single-host topologies and linking useful context. Anything that needs a view across machines is out of reach, so a flow analysis of a whole network or a cross-host latency question is not what this tool answers.

The second constraint is the kernel itself. The probes attach to skb-enabled functions and tracepoints, which means the kernel has to expose them, and the set of usable probes changes between kernel versions. The tool also needs enough privilege to attach eBPF programs, so a hardened kernel with the relevant lockdown settings, or an environment where BPF is not permitted, will simply refuse to work.

The third is the cost of breadth. The generic profile loads thirty probes, and each event is a line of text with packet bytes and context. Collecting on a busy host without a filter produces a lot of output, and the tool is at its best when you already have a specific question about one host.

There is a smaller point about the workflow. The reconstructed journey comes from a stored run, so if you only watch the live stream you have the events but not the sorted view, and going back to a moment in the trace means re-running the collection.

## Licence, releases and how the project is packaged

Retis is licensed under GPL-2.0, with the licence declared in the workspace manifest as GPL-2.0-only and the LICENSE file at the root of the repository.

The release history is v1.7.0 on 2026-08-10, v1.6.4 on 2026-02-17 and v1.6.3 on 2025-10-07, and the last push to the repository was on 2026-10-14, with the repository not archived. The workspace manifest carries version 1.8.0, which is ahead of the latest tagged release, so the development branch is working towards a version that has not shipped yet.

The documentation is published on readthedocs with a stable badge, and the README points to the online documentation as well as to the built-in help, where retis --help and retis <command> --help describe the commands. The project also carries a RELEASE.md for the release process, a codecov configuration, a flake8 configuration for the Python parts of the tooling, and a set of test directories including one for pcap handling.

Because the tool attaches to kernel internals, the version of the kernel you run is a real constraint on which events you get, and the release notes are where that shows up.

## Conclusion

Retis fits a network engineer debugging a single host where the interesting question is how a packet moved through the stack rather than what it contained, and where the connection tracking table explains the behaviour better than a capture file would. It is the wrong tool for a multi-host traffic analysis, since it observes one machine at a time, and it needs eBPF and root level privileges, so it will not run in a locked-down environment. Before you use it, check three things: that the kernel exposes the skb-enabled functions and tracepoints you need, since the collector set is chosen per run, that the run captures events to a file with the output option if you intend to sort them later, since the live view cannot be reconstructed after the fact, and that your filter is applied at collection time, because the L2 and L3 filter runs on the probes rather than on the displayed text. The licence is GPL-2.0, the latest release is v1.7.0 from 2026-08-10, and the last push was on 2026-10-14.

## FAQ

### What is Retis used for?

Retis traces filtered packets in the Linux networking stack using eBPF probes, and interfaces with control and data paths such as Open vSwitch and Netfilter. It is aimed at debugging networking issues, exploring the Linux networking stack, or testing features such as in a CI script.

### What does a basic Retis collection look like?

Running `retis collect` starts the ct, nft, dev, skb, skb-drop, skb-tracking and ns collectors, loads two default tracepoints, netif_receive_skb and net_dev_start_xmit, and loads seven probes in total, printing each packet event with its interface, namespace and protocol.

### How do I see more events for the same packet in Retis?

Use the generic profile with the -p option, which defines a bigger set of probes, thirty against the default seven, and add a filter with -f. The same packet then appears at several points of the stack, with connection tracking state shown at each one.

### What does retis sort do?

When events are stored for later processing, `retis sort` reconstructs the packets' journeys and prints them as an indented tree, with each follow-up event nested under the event that produced it.

### Does Retis need to be compiled on the target machine?

No. The README states that Retis does not require compilation on the target, and it can be installed as a container image, on supported distributions, or built from sources, with the installation details in the online documentation.

## Sources

- [License: GPL-2.0](https://github.com/retis-org/retis/blob/main/LICENSE)
- [Project website](https://retis.readthedocs.io/en/stable/)
- [README](https://github.com/retis-org/retis/blob/main/README.md)
- [Releases](https://github.com/retis-org/retis/releases)
- [retis-org/retis on GitHub](https://github.com/retis-org/retis)

---

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