Home / Alt manpages / tc-csum(8)

  • tc-csum(8)
  • Admin command
  • linux

Repair Packet Checksums After tc pedit Changes

Edit a packet's address with tc pedit and the receiving stack quietly drops it, because the checksum still describes the old bytes. The csum action fixes exactly that: it recalculates the checksums that a pedit edit invalidated. It does not decide which headers your edit affected, that is still your call, and the examples below use the installed iproute2 package, version 6.1.0-1ubuntu6.4, whose tc reports iproute2-6.1.0.

Allow about twenty minutes, plus time to test in a maintenance window.

  • Root access. Every state-changing command below needs it.
  • An interface carrying the packets you intend to change. Not a placeholder you guessed from an old script.
  • A rollback plan. Traffic control acts on live packets, so check the device, match, replacement address and existing ingress configuration before you paste the example against a production interface.

1. Check the installed contract

These are ordinary, read-only checks and do not need elevated privileges:

$ tc -V
tc utility, iproute2-6.1.0, libbpf 1.3.0
$ dpkg-query -W -f='${Package} ${Version}\n' iproute2
iproute2 6.1.0-1ubuntu6.4
$ man tc-csum

The action syntax is action csum UPDATE. The update names one or more targets:

  • ip4h for the IPv4 header checksum.
  • icmp, igmp, tcp, udp, udplite or sctp for the matching transport checksum.

The words and, or and + are accepted between targets as syntactic sugar; they do not change what the kernel updates.

Checkpoint

Confirm that your planned edit is an IPv4 edit and write down the transport protocol. An IPv4 destination change normally needs ip4h and the transport checksum target, such as udp. An IPv6 packet is not covered by this action's ip4h target.

2. Inspect the interface before changing it

Pick an explicit device and look for existing qdiscs and filters. This is read-only, but the output is host-specific:

$ ip -brief link show dev eth0
$ tc qdisc show dev eth0
$ tc filter show dev eth0 ingress

Replace eth0 with the real interface. Do not infer its name from an old command or a virtual machine image. If an ingress qdisc already exists, use its existing handle and document the filter priority you choose. Adding or deleting a qdisc can affect other filters, so treat that as a service change.

For a disposable test interface, create the ingress hook as root. The following command changes kernel state and may affect packet processing:

# tc qdisc add dev eth0 ingress handle ffff:

If this reports that the qdisc already exists, stop and inspect it. Do not replace it blindly. A failed add has not created this guide's qdisc, but it may indicate that another policy is already attached.

3. Add a narrowly matched pedit and csum filter

The manpage's representative example matches packets from 192.0.2.100, changes their destination to 198.51.100.1, and assumes UDP. The addresses are documentation ranges. Substitute values that are valid for your test network:

# tc filter add dev eth0 ingress pref 10 protocol ip \
    u32 match ip src 192.0.2.100/32 flowid :1 \
    action pedit munge ip dst set 198.51.100.1 pipe \
    action csum ip and udp

Run this with elevated privileges.

  • protocol ip selects IPv4 traffic.
  • The u32 expression limits the match.
  • pedit changes the destination. The csum action does not perform the address edit itself.
  • pipe lets processing continue to the next action, where csum recalculates the IPv4 and UDP checksums.

Use tcp instead of udp for a TCP flow. For a combined edit that affects an ICMP packet, use action csum ip and icmp. Include only headers that are present and affected by the edit. An incorrect target can produce an ineffective rule or corrupt processing for traffic that does not match your assumptions.

Checkpoint

Display the filter and confirm every value before sending traffic:

# tc filter show dev eth0 ingress pref 10

You should see a filter with the IPv4 source match, a destination edit, and csum updates for ip4h and UDP, although formatting varies by iproute2 release. If the filter is absent or attached to the wrong device, do not test it further.

4. Verify packets without trusting a successful install

A successful tc filter add proves that the kernel accepted the rule, not that the intended packets traverse it. Generate one controlled test flow from the matching source, then observe the packet on the relevant side of the device with your normal capture tooling. Check the destination and checksum status in the capture, and confirm that unrelated source addresses are unchanged.

For a counter-level check, ask tc for statistics:

# tc -s filter show dev eth0 ingress pref 10

Send the test flow again and run the command a second time. Packet and byte counters should increase for a matching flow. Exact counter fields and formatting are version-dependent. A counter that stays at zero points first to the interface direction, source address, protocol match or namespace, not to checksum arithmetic.

Warning

Do not use a successful ping as proof for this UDP example. Ping uses ICMP, so it does not exercise the UDP checksum target. Likewise, a packet that reaches an application does not prove that every checksum was recalculated as intended; inspect the traffic or use a receiver that reports validation failures.

5. Remove the filter when the test ends

Removing the filter is a state-changing operation requiring root. Use the same device and priority shown above:

# tc filter del dev eth0 ingress pref 10
# tc filter show dev eth0 ingress

The second command should no longer show the test filter. If the interface had no ingress qdisc before this exercise and you created one specifically for it, remove that qdisc only after confirming that no other policy uses it:

# tc qdisc show dev eth0
# tc qdisc del dev eth0 ingress

Warning

Deleting an ingress qdisc removes the filters attached to it. Do not run that command on a shared or production interface merely because this article used the same device name. If you accidentally remove a qdisc, restore the configuration from your recorded change plan rather than guessing at the old filters.

Common traps

  • Wrong checksum target. Changing an IPv4 address needs ip4h; changing or carrying a UDP flow needs udp. Choose the transport from the actual packets.
  • IPv4 and IPv6 confusion. protocol ip and ip4h describe IPv4. They do not make an IPv6 rule.
  • Testing the wrong direction. Ingress sees packets arriving at the device. Verify the interface and namespace before changing the match.
  • Assuming and is logic. In this action grammar it is only a separator accepted for readability.
  • Over-broad matching. A missing source mask or an incorrect protocol assumption can alter more traffic than intended. Start with one host and one priority.
  • Reusing a priority. Inspect existing filters first. A conflicting priority or an unexpected action order can make the observed result differ from the command you just entered.

Done means

  • Contract checked. You confirmed the installed iproute2 version and read the local tc-csum contract.
  • Interface inspected. You looked at the real interface, ingress qdisc and existing filters before changing state.
  • Filter is narrow and correct. It matches only the intended IPv4 traffic and names the affected transport checksum.
  • Counters moved. tc -s filter show counters increase for a controlled test, and packet inspection confirms the rewritten destination and checksums.
  • Cleanup done. You removed the test filter and left any shared ingress configuration intact.