In this lesson, you will learn how to use iptables marking to apply granular traffic shaping to specific processes, allowing you to prioritize or throttle application-level traffic before it leaves your network stack.
The Problem with Port-Based Shaping
Standard traffic shaping often relies on port numbers (e.g., shaping port 80 for web traffic). However, modern applications often use ephemeral ports or share protocols, making port-based rules imprecise. To control traffic at the process level, we use socket marking.
The Mechanism: Marking and Shaping
We treat the packet as a vessel that carries a "mark"—a numerical identifier—assigned by the kernel. The workflow involves two steps:
- Marking (Netfilter): We use the
iptablesMARKtarget to flag packets originating from a specific process or user ID. This metadata stays with the packet as it traverses the kernel stack. - Shaping (tc): We use the
tc(Traffic Control) utility to create aclassthat filters for that specific mark and applies a rate limit (token bucket filter or hierarchical token bucket).
Practical Example
Suppose you want to throttle a backup script (Process ID 1234) to ensure it doesn't saturate your link:
First, mark the packets:
iptables -t mangle -A OUTPUT -m owner --pid-owner 1234 -j MARK --set-mark 10
Next, use tc to create a class that recognizes this mark:
tc filter add dev eth0 protocol ip parent 1:0 handle 10 fw police rate 1mbit burst 10k
By tagging the traffic at the OUTPUT hook of the Netfilter chain, you ensure that the packet enters the queueing discipline (qdisc) with the metadata required for the kernel to make a shaping decision. This process is highly efficient because the filtering happens entirely within the kernel, avoiding the latency overhead of user-space packet inspection.
When configuring this, ensure your tc rules are placed on the egress interface of the network namespace where the application is running, as the mark is locally significant to the kernel instance managing that specific stack.
Key Takeaway: By using iptables to inject a persistent mark onto packets and tc to read that mark, you can enforce precise bandwidth limits on individual applications regardless of the ports or protocols they use.