15.10. Example of a full nat solution with QoS
Here I'm describing a common set up where we have lots of users in a private network connected to the Internet trough a Linux router with a public ip address that is doing network address translation (NAT). I use this QoS setup to give access to the Internet to 198 users in a university dorm, in which I live and I'm netadmin of. The users here do heavy use of peer to peer programs, so proper traffic control is a must. I hope this serves as a practical example for all interested lartc readers.
At first I make a practical approach with step by step configuration, and in the end I explain how to make the process automatic at bootime. The network to which this example applies is a private LAN connected to the Internet through a Linux router which has one public ip address. Extending it to several public ip address should be very easy, a couple of iptables rules should be added.
In order to get things working we need:
- Linux 2.4.18 or higher kernel version installed
-
If you use 2.4.18 you will have to apply HTB patch available here.
- iproute
-
Also ensure the "tc" binary is HTB ready, a precompiled binary is distributed with HTB.
- iptables
Let's begin optimizing that scarce bandwidth
First we set up some qdiscs in which we will classify the traffic. We create a htb qdisc with 6 classes with ascending priority. Then we have classes that will always get allocated rate, but can use the unused bandwidth that other classes don't need. Recall that classes with higher priority ( i.e with a lower prio number ) will get excess of bandwith allocated first. Our connection is 2Mb down 300kbits/s up Adsl. I use 240kbit/s as ceil rate just because it's the higher I can set it before latency starts to grow, due to buffer filling in whatever place between us and remote hosts. This parameter should be timed experimentally, raising and lowering it while observing latency between some near hosts.
CEIL=240 tc qdisc add dev eth0 root handle 1: htb default 15 tc class add dev eth0 parent 1: classid 1:1 htb rate ${CEIL}kbit ceil ${CEIL}kbit tc class add dev eth0 parent 1:1 classid 1:10 htb rate 80kbit ceil 80kbit prio 0 tc class add dev eth0 parent 1:1 classid 1:11 htb rate 80kbit ceil ${CEIL}kbit prio 1 tc class add dev eth0 parent 1:1 classid 1:12 htb rate 20kbit ceil ${CEIL}kbit prio 2 tc class add dev eth0 parent 1:1 classid 1:13 htb rate 20kbit ceil ${CEIL}kbit prio 2 tc class add dev eth0 parent 1:1 classid 1:14 htb rate 10kbit ceil ${CEIL}kbit prio 3 tc class add dev eth0 parent 1:1 classid 1:15 htb rate 30kbit ceil ${CEIL}kbit prio 3 tc qdisc add dev eth0 parent 1:12 handle 120: sfq perturb 10 tc qdisc add dev eth0 parent 1:13 handle 130: sfq perturb 10 tc qdisc add dev eth0 parent 1:14 handle 140: sfq perturb 10 tc qdisc add dev eth0 parent 1:15 handle 150: sfq perturb 10
We have just created a htb tree with one level depth. Something like this:
+---------+ | root 1: | +---------+ | +---------------------------------------+ | class 1:1 | +---------------------------------------+ | | | | | | +----+ +----+ +----+ +----+ +----+ +----+ |1:10| |1:11| |1:12| |1:13| |1:14| |1:15| +----+ +----+ +----+ +----+ +----+ +----+
- classid 1:10 htb rate 80kbit ceil 80kbit prio 0
- classid 1:11 htb rate 80kbit ceil ${CEIL}kbit prio 1
- classid 1:12 htb rate 20kbit ceil ${CEIL}kbit prio 2
- classid 1:13 htb rate 20kbit ceil ${CEIL}kbit prio 2
- classid 1:14 htb rate 10kbit ceil ${CEIL}kbit prio 3
-
Here goes mail traffic (SMTP,pop3...) and packets with Minimize-Cost TOS bit set.
- classid 1:15 htb rate 30kbit ceil ${CEIL}kbit prio 3
15.10.2. Classifying packets
tc filter add dev eth0 parent 1:0 protocol ip prio 1 handle 1 fw classid 1:10 tc filter add dev eth0 parent 1:0 protocol ip prio 2 handle 2 fw classid 1:11 tc filter add dev eth0 parent 1:0 protocol ip prio 3 handle 3 fw classid 1:12 tc filter add dev eth0 parent 1:0 protocol ip prio 4 handle 4 fw classid 1:13 tc filter add dev eth0 parent 1:0 protocol ip prio 5 handle 5 fw classid 1:14 tc filter add dev eth0 parent 1:0 protocol ip prio 6 handle 6 fw classid 1:15
First you have to understand how packet traverse the filters with iptables:
+------------+ +---------+ +-------------+ Packet -| PREROUTING |--- routing-----| FORWARD |-------+-------| POSTROUTING |- Packets input +------------+ decision +-Â-------+ | +-------------+ out | | +-------+ +--------+ | INPUT |---- Local process -| OUTPUT | +-------+ +--------+
echo 1 > /proc/sys/net/ipv4/ip_forward iptables -t nat -A POSTROUTING -s 172.17.0.0/255.255.0.0 -o eth0 -j SNAT --to-source 212.170.21.172
Now check that packets are flowing through 1:15:
tc -s class show dev eth0
You can start marking packets adding rules to the PREROUTING chain in the mangle table.
iptables -t mangle -A PREROUTING -p icmp -j MARK --set-mark 0x1 iptables -t mangle -A PREROUTING -p icmp -j RETURN
tc -s class show dev eth0
iptables -t mangle -A PREROUTING -m tos --tos Minimize-Delay -j MARK --set-mark 0x1 iptables -t mangle -A PREROUTING -m tos --tos Minimize-Delay -j RETURN iptables -t mangle -A PREROUTING -m tos --tos Minimize-Cost -j MARK --set-mark 0x5 iptables -t mangle -A PREROUTING -m tos --tos Minimize-Cost -j RETURN iptables -t mangle -A PREROUTING -m tos --tos Maximize-Throughput -j MARK --set-mark 0x6 iptables -t mangle -A PREROUTING -m tos --tos Maximize-Throughput -j RETURN
iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 22 -j MARK --set-mark 0x1 iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 22 -j RETURN
A good idea is to prioritize packets to begin tcp connections, those with SYN flag set:
iptables -t mangle -I PREROUTING -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN -j MARK --set-mark 0x1 iptables -t mangle -I PREROUTING -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN -j RETURN
When we are done adding rules to PREROUTING in mangle, we terminate the PREROUTING table with:
iptables -t mangle -A PREROUTING -j MARK --set-mark 0x6
15.10.3. Improving our setup
tc qdisc add dev eth0 parent 1:13 handle 130: sfq perturb 10 tc qdisc add dev eth0 parent 1:14 handle 140: sfq perturb 10 tc qdisc add dev eth0 parent 1:15 handle 150: sfq perturb 10