Mirror or Sample Every Packet with tc matchall
tc's matchall filter has no conditions at all: it grabs every packet at a hook, which makes it the tool for mirroring or sampling traffic wholesale. You'll finish with a repeatable way to attach the filter, inspect the rule tc installed, and remove it again. The examples cover ingress mirroring and packet sampling.
The route
Jump straight to the step you need, or tick off Done means at the end.
- Time. About fifteen minutes, plus a maintenance window if the interface carries production traffic.
- Tools.
tcfrom iproute2 6.1.0, a root shell orsudo, and two interface names if you're mirroring.
Read-only inspection needs no elevated privileges; adding qdiscs and filters normally does.
Checkpoint
This guide follows the installed tc-matchall(8) manpage, from iproute2 6.1.0-1ubuntu6.4. Current upstream documentation can use newer clsact examples, so keep the local syntax together when reproducing these commands.
1. Confirm the command and interfaces
Start with read-only checks. Replace the placeholder names only once you've identified the real devices:
$ tc -V
tc utility, iproute2-6.1.0, libbpf 1.3.0
$ ip -br link
$ tc qdisc show dev SOURCE_IFACE
Set SOURCE_IFACE to the interface whose packets you want to inspect and DEST_IFACE to a separate capture or monitoring interface. Do not choose either by pattern-matching a name, and never mirror a production interface to an untrusted port.
The last command shows whether the interface already has an ingress or root qdisc. Record that output before changing anything: a qdisc belongs to the interface, not to your shell session, and another administrator or service may already depend on it.
2. Create an ingress hook
An ingress qdisc with handle ffff: gives an ingress filter somewhere to attach:
$ sudo tc qdisc add dev SOURCE_IFACE handle ffff: ingress
$ sudo tc qdisc show dev SOURCE_IFACE
qdisc ingress ffff: dev SOURCE_IFACE parent ffff:fff1
Exact counters and formatting vary; seeing an ingress qdisc with handle ffff: is the check that matters. If the add command says the qdisc already exists, stop and inspect the existing setup rather than replacing it to make the example fit.
Warning
Adding traffic-control state changes packet handling immediately. Test on a spare interface or in a maintenance window first. If you created this ingress qdisc solely for the example, the recovery command is in step 6; it removes every ingress filter on that interface, so do not use it where the qdisc is shared.
3. Mirror every ingress packet
Attach the matchall filter with a generic mirred action. This copies matching traffic to the destination device; it does not move the original packet:
$ sudo tc filter add dev SOURCE_IFACE parent ffff: \
matchall skip_sw \
action mirred egress mirror \
dev DEST_IFACE
skip_swrequests hardware processing only. Fine when the interface and driver support traffic-control offload; the command fails if they don't.skip_hwforces software processing instead. Or omit both flags to lettcuse whatever path is available:
$ sudo tc filter add dev SOURCE_IFACE parent ffff: \
matchall skip_hw \
action mirred egress mirror \
dev DEST_IFACE
Do not install both examples: each adds another rule and can duplicate the mirrored traffic. A destination that feeds the source again creates a forwarding loop, so use a monitoring port or an isolated capture path.
Checkpoint
Inspect the filter rather than trusting a successful exit status:
$ sudo tc filter show dev SOURCE_IFACE parent ffff:
filter protocol all pref 49152 matchall
action order 1: mirred (Egress Mirror to device DEST_IFACE) stolen
Preference numbers, action details and counters can differ; the output should identify matchall and the intended destination.
4. Sample instead of mirroring
Sampling earns its keep when a full copy would swamp the capture path. The manpage's sample action sends one packet in every 100 to psample group 12:
$ sudo tc qdisc add dev SAMPLE_IFACE handle ffff: ingress
$ sudo tc filter add dev SAMPLE_IFACE parent ffff: \
matchall \
action sample rate 100 group 12
$ sudo tc filter show dev SAMPLE_IFACE parent ffff:
This needs a consumer for the psample group: installing the filter alone prints nothing in your terminal. The group number is an integration value, so pick one your monitoring software expects and do not assume group 12 is globally special.
If you add a sample rule after the mirror rule on the same parent, both actions can run. Give each test interface one purpose, or inspect the full filter list and remove rules you no longer need.
5. Understand classid and direction
An action is optional. Instead, classid CLASSID sends every matching packet into a class on the attached qdisc; the class must already exist and the value is parsed as hexadecimal. Do not add a classid to an ingress example unless you've deliberately built the matching classful qdisc.
Ingress and egress are different hooks; the commands above attach to ingress. For egress mirroring, the installed manpage uses a root prio qdisc and attaches the filter to its parent:
$ sudo tc qdisc add dev SOURCE_IFACE handle 1: root prio
$ sudo tc filter add dev SOURCE_IFACE parent 1: \
matchall skip_sw \
action mirred egress mirror \
dev DEST_IFACE
Warning
A root qdisc controls the interface's outgoing traffic. Adding this command can replace an existing root qdisc and disrupt shaping or queuing. Only use it after saving the current configuration and confirming this test owns the interface. Prefer a dedicated test device.
6. Verify and remove the test state
Generate a small amount of known traffic, then check counters or the capture consumer. For a read-only view of the current setup:
$ sudo tc -s filter show dev SOURCE_IFACE parent ffff:
$ sudo tc qdisc show dev SOURCE_IFACE
Rising counters confirm packets reached the filter. They don't prove a capture application decoded every copy, nor that hardware offload behaved exactly like software processing.
Remove the filter before removing its parent. If the interface has no other ingress filters and you created the qdisc for this test, remove the whole ingress qdisc:
$ sudo tc qdisc del dev SOURCE_IFACE ingress
$ sudo tc qdisc show dev SOURCE_IFACE
This is deliberately broad: it removes the ingress qdisc and every filter below it. If other rules exist, restore the configuration you recorded in step 1 instead of running a blind deletion. For the egress example, restore the previous root qdisc from your saved configuration; tc qdisc del dev SOURCE_IFACE root can remove more than this guide created.
7. Diagnose the common failures
- File exists: a qdisc or filter is already present. Show the qdisc and filters, then choose a dedicated parent or coordinate a change.
- Operation not supported with
skip_sw: hardware offload is unavailable or disabled. Remove that requirement only after deciding software processing is acceptable. - No mirrored packets: confirm the filter direction, destination interface, destination capture process and counters. A successful add command does not create a listener.
- Duplicate traffic: show all filters under the parent. Two matchall actions both match every packet; remove the extra rule or use separate test interfaces.
Done means
- Version and state recorded. You confirmed the installed iproute2 version and recorded the existing qdisc state.
- Filter attached correctly. A matchall rule sits on the intended ingress or egress hook.
- Offload flag matches reality. You selected
skip_sw,skip_hwor neither based on the actual offload requirement. - Output confirms it.
tc filter showidentifies the intended action and destination. - You know which mode you tested. Mirroring or psample, and how to restore the previous qdisc configuration.
- Cleanup is done or documented. Temporary filters and qdiscs are removed, or their persistent ownership is written down.