Restore Conntrack Marks with tc connmark

The tc connmark action copies a connection mark from conntrack into a packet's firewall mark, nothing more, nothing less. This walks through adding that action, checking it exists, and removing it cleanly once you're done.

Allow about 15 minutes for the action itself, plus time to wire it into an existing filter. The examples use iproute2 6.1.0-1ubuntu6.4, installed here as tc 6.1.0. You need conntrack state already present before this action can restore anything, plus root privileges or the relevant network-administration capability to change traffic-control state; commands that only inspect local state can normally run without sudo. This guide does not create a qdisc, filter, firewall rule or conntrack entry for you.

1. Confirm the installed syntax

The action's job is narrow: look up the packet's connection and copy that connection's mark to the packet's fwmark. It doesn't set a connection mark, create conntrack state, or decide which packets should match, those jobs live elsewhere in the networking path.

$ tc actions help | sed -n '/connmark/,+4p'
Usage: ... connmark [zone ZONE] [CONTROL] [index <INDEX>]
where :
ZONE is the conntrack zone
CONTROL := reclassify | pipe | drop | continue | ok |
           goto chain <CHAIN_INDEX>

The local action help includes ok, while the installed tc-connmark(8) page describes the same normal control choices as reclassify, pipe, drop, continue and pass. Follow the help and manpage shipped with the exact iproute2 package on the host you're changing, don't assume a newer online example has identical parser details.

2. Choose the conntrack zone and action index

Use zone only when the connection belongs to a non-default conntrack zone. The value is an unsigned 16-bit decimal number, so the valid range is 0 through 65535. If the packet is tracked in zone 42, use zone 42; if your firewall uses the default zone, omit the option rather than guessing at a different value.

An index gives the action a stable 32-bit unsigned identifier, letting you list, replace or delete it later. It's an identifier, not the conntrack mark value and not a priority, so pick a number that isn't already in use on this host:

$ tc actions list action connmark
$ sudo tc actions add action connmark zone 42 pipe index 100

The first command is a read-only checkpoint. An empty result means no matching action is currently listed, it's not proof that no filter elsewhere uses connmark. The second changes kernel networking state and normally needs sudo, and it uses the default continuation behaviour explicitly as pipe, meaning continue with the next action.

Safety checkpoint: Don't run the add command on a production router until you've checked both the zone and the unused index. A standalone action isn't useful until a filter invokes it, but one added to the wrong shared configuration can still confuse later maintenance.

3. Check that the action was installed

List the action by type and inspect the result. Output is produced by the installed tc, so field ordering and counters can vary between releases:

$ sudo tc actions list action connmark
action order 1: connmark zone 42 pipe
 index 100 ref 1 bind 0

Look for the zone, control action and index you selected. If the list is empty after a successful add, check you used the same action type and ran the command in the same network namespace, traffic-control actions are namespace-local.

The action alone doesn't prove a packet's mark will actually change. You also need a filter attached to a qdisc, and the packet needs conntrack state in the selected zone. Before enabling a production filter, establish where the connection mark gets written and whether the packet path even reaches the filter. Restoring a mark from an empty or wrong-zone lookup won't give you the classification you expect.

4. Select the control behaviour deliberately

The manpage also documents pass as returning to the calling qdisc and ending classification, but the local parser help spells this control as ok. Check tc actions help on the target system before using either spelling in automation, and don't substitute drop for a spelling your host doesn't recognise:

$ sudo tc actions add action connmark zone 42 reclassify index 101
$ sudo tc actions add action connmark zone 42 continue index 102

These create additional actions and consume new indexes. They're syntax examples, not a recommendation to install all three controls. If you do run them, list the actions immediately and remove the test entries before attaching them to a live filter.

5. Attach and test it as part of a filter

The connmark action is normally referenced from a filter's action list. The exact filter depends on your interface, qdisc and match criteria, so don't copy a made-up device name or handle into a production command. The shape looks like this, but the classifier and parent must match your existing topology:

$ sudo tc filter add dev <INTERFACE> parent <PARENT> protocol ip \
    flower <MATCH-CRITERIA> action connmark zone 42 pipe index 100

Replace every angle-bracketed value with one already present in your configuration, this line is deliberately not runnable as written. Confirm the resulting filter with:

$ sudo tc filter show dev <INTERFACE> parent <PARENT>

To verify the data path, use counters or a controlled test flow whose conntrack mark you already know. Check the relevant filter and action statistics before and after one test packet. A counter increase shows the action ran, it doesn't by itself prove the mark value was the intended one. Keep a rollback command ready before generating traffic through a new production filter.

6. Remove test state and recover from a mistake

Warning: Deleting an action changes kernel networking state. First remove or replace any filter referencing it, then delete the action by its index. The delete is irreversible once the current configuration is lost, so save the existing tc configuration through your normal change process before touching a live host:

$ sudo tc filter del dev <INTERFACE> parent <PARENT> protocol ip \
    flower <MATCH-CRITERIA>
$ sudo tc actions delete action connmark index 100
$ sudo tc actions list action connmark

Use the exact filter identity from tc filter show, a broad deletion command can remove more policy than intended. If the add command reports RTNETLINK answers: Operation not permitted, you lack the required capability, or you're running in a namespace where the operation isn't allowed. Don't retry repeatedly on a production interface, check sudo, the network namespace and your change controls first.

Done means