Еще один пост про управление трафиком с помощью tc в Linux

Во многих дистрибутивах, ориентированных на роутеры (openwrt, dd-wrt, ipcop & etc) есть встроенная поддержка QoS. Однако, такой QoS «из коробки» не гибок и адаптирован под интернет-тарифы «цивилизованных» стран, с постоянной скоростью доступа. В нашей же социалистической реальности скорость ночью может быть в 2 раза больше чем днем и терять этот бонус жалко.

В этой записи я попробую привести пример рабочего решения для управления приоритетами трафика в Linux с помощью tc и iptables.

В первую очередь определимся с переменными:

LAN_IFACE="eth0"
WAN_IFACE="eth1"

GLOB_RATE="1000mbit"
LAN_RATE="100mbit"

H=`/bin/date +%H`

if [ $H -gt 2 ] && [ $H -lt 8 ]; then
    WAN_RATE="11060kbit"
    WAN_BW="1024kbit"
else
    WAN_RATE="2765kbit"
    WAN_BW="512kbit"
fi

LAN_NET="192.168.0.0/24"
LOCAL_NETS="10.0.0.0/8 172.16.0.0/16"

В данной секции показан пример увеличения скорости доступа в интернет с 2-х ночи до 8-ми утра. Переменные:
LAN_IFACE — сетевой интерфейс смотрящий в локальную сеть
WAN_IFACE — сетевой интерфейс смотрящий в интернет
LAN_RATE — скорость локальной сети
H — текущий час суток
WAN_RATE — скорость подключения к сети интернет (для того чтобы QoS работал, -10% от реальной скорости)
WAN_BW — минимальная гарантированная скорость для того или иного класса трафика.
LAN_NET — локальная сеть.
LOCAL_NETS — диапазоны адресов провайдера, ограничение скорости на которые не распространяется.

Создаем основные планировщики пакетов и классы для входящего трафика:

# Root qdsc
tc qdisc del dev $LAN_IFACE root 2> /dev/null > /dev/null
tc qdisc add dev $LAN_IFACE root handle 1:0 htb default 106
tc class add dev $LAN_IFACE parent 1:0 classid 1:1 htb rate $GLOB_RATE \
 burst 20k

# Speed for lan traffic
tc class add dev $LAN_IFACE parent 1:1 classid 1:2 htb rate $LAN_RATE \
 burst 10k prio 6
tc qdisc add dev $LAN_IFACE parent 1:2 handle 2: sfq perturb 10
tc filter add dev $LAN_IFACE parent 1:0 prio 6 protocol ip handle 2 fw \
 classid 1:2

# Speed for inet traffic
tc class add dev $LAN_IFACE parent 1:1 classid 1:10 htb rate $WAN_RATE \
 burst 6k prio 3

Настал черед для исходящего трафика:

# Root qdsc
tc qdisc del dev $WAN_IFACE root 2> /dev/null > /dev/null
tc qdisc add dev $WAN_IFACE root handle 1:0 htb default 106
tc class add dev $WAN_IFACE parent 1:0 classid 1:1 htb rate $GLOB_RATE \
 burst 20k

# Speed for lan traffic
tc class add dev $WAN_IFACE parent 1:1 classid 1:2 htb rate $LAN_RATE \
 burst 10k prio 6
tc qdisc add dev $WAN_IFACE parent 1:2 handle 2: sfq perturb 10
tc filter add dev $WAN_IFACE parent 1:0 prio 6 protocol ip handle 2 fw \
 classid 1:2

# Speed for inet traffic
tc class add dev $WAN_IFACE parent 1:1 classid 1:10 htb rate $WAN_RATE \
 burst 6k prio 3

Теперь создаем 6 классов трафика разного приоритета:

### Prio 1
# Incoming
tc class add dev $LAN_IFACE parent 1:10 classid 1:101 htb rate $WAN_BW \
 ceil $WAN_RATE burst 2k prio 1
tc qdisc add dev $LAN_IFACE parent 1:101 handle 101: sfq perturb 10
tc filter add dev $LAN_IFACE parent 1:0 prio 1 protocol ip handle 101 fw \
 classid 1:101
# Outgoing
tc class add dev $WAN_IFACE parent 1:10 classid 1:101 htb rate $WAN_BW \
 ceil $WAN_RATE burst 2k prio 1
tc qdisc add dev $WAN_IFACE parent 1:101 handle 101: sfq perturb 10
tc filter add dev $WAN_IFACE parent 1:0 prio 1 protocol ip handle 101 fw \
 classid 1:101

### Prio 2
# Incoming
tc class add dev $LAN_IFACE parent 1:10 classid 1:102 htb rate $WAN_BW \
 ceil $WAN_RATE burst 2k prio 2
tc qdisc add dev $LAN_IFACE parent 1:102 handle 102: sfq perturb 10
tc filter add dev $LAN_IFACE parent 1:0 prio 2 protocol ip handle 102 fw \
 classid 1:102
# Outgoing
tc class add dev $WAN_IFACE parent 1:10 classid 1:102 htb rate $WAN_BW \
 ceil $WAN_RATE burst 2k prio 2
tc qdisc add dev $WAN_IFACE parent 1:102 handle 102: sfq perturb 10
tc filter add dev $WAN_IFACE parent 1:0 prio 2 protocol ip handle 102 fw \
 classid 1:102

### Prio 3
# Incoming
tc class add dev $LAN_IFACE parent 1:10 classid 1:103 htb rate $WAN_BW \
 ceil $WAN_RATE burst 2k prio 3
tc qdisc add dev $LAN_IFACE parent 1:103 handle 103: sfq perturb 10
tc filter add dev $LAN_IFACE parent 1:0 prio 3 protocol ip handle 103 fw \
 classid 1:103
# Outgoing
tc class add dev $WAN_IFACE parent 1:10 classid 1:103 htb rate $WAN_BW \
 ceil $WAN_RATE burst 2k prio 3
tc qdisc add dev $WAN_IFACE parent 1:103 handle 103: sfq perturb 10
tc filter add dev $WAN_IFACE parent 1:0 prio 3 protocol ip handle 103 fw \
 classid 1:103

### Prio 4
# Incoming
tc class add dev $LAN_IFACE parent 1:10 classid 1:104 htb rate $WAN_BW \
 ceil $WAN_RATE burst 2k prio 4
tc qdisc add dev $LAN_IFACE parent 1:104 handle 104: sfq perturb 10
tc filter add dev $LAN_IFACE parent 1:0 prio 4 protocol ip handle 104 fw \
 classid 1:104
# Outgoing
tc class add dev $WAN_IFACE parent 1:10 classid 1:104 htb rate $WAN_BW \
 ceil $WAN_RATE burst 2k prio 4
tc qdisc add dev $WAN_IFACE parent 1:104 handle 104: sfq perturb 10
tc filter add dev $WAN_IFACE parent 1:0 prio 1 protocol ip handle 104 fw \
 classid 1:104

### Prio 5
# Incoming
tc class add dev $LAN_IFACE parent 1:10 classid 1:105 htb rate $WAN_BW \
 ceil $WAN_RATE burst 2k prio 5
tc qdisc add dev $LAN_IFACE parent 1:105 handle 105: sfq perturb 10
tc filter add dev $LAN_IFACE parent 1:0 prio 5 protocol ip handle 105 fw \
 classid 1:105
# Outgoing
tc class add dev $WAN_IFACE parent 1:10 classid 1:105 htb rate $WAN_BW \
 ceil $WAN_RATE burst 2k prio 5
tc qdisc add dev $WAN_IFACE parent 1:105 handle 105: sfq perturb 10
tc filter add dev $WAN_IFACE parent 1:0 prio 5 protocol ip handle 105 fw \
 classid 1:105

### Prio 6
# Incoming
tc class add dev $LAN_IFACE parent 1:10 classid 1:106 htb rate $WAN_BW \
 ceil $WAN_RATE burst 2k prio 6
tc qdisc add dev $LAN_IFACE parent 1:106 handle 106: sfq perturb 10
tc filter add dev $LAN_IFACE parent 1:0 prio 6 protocol ip handle 106 fw \
 classid 1:106
# Outgoing
tc class add dev $WAN_IFACE parent 1:10 classid 1:106 htb rate $WAN_BW \
 ceil $WAN_RATE burst 2k prio 6
tc qdisc add dev $WAN_IFACE parent 1:106 handle 106: sfq perturb 10
tc filter add dev $WAN_IFACE parent 1:0 prio 6 protocol ip handle 106 fw \
 classid 1:106

Итак, мы имеем 6 классов трафика, от 1 (максимальный приоритет) до 6 (минимальный приоритет). По-умолчанию весь трафик имеет 6-ой, минимальный приоритет.

С помощью iptables разложим трафик по классам, для этого создадим специальную цепочку — qos_tc:

# Delete Chains
iptables -t mangle -D POSTROUTING -o $LAN_IFACE -j qos_tc
iptables -t mangle -D PREROUTING -i $LAN_IFACE -j qos_tc
iptables -t mangle -F qos_tc
iptables -t mangle -X qos_tc
iptables -t mangle -F
iptables -t mangle -X
# Create Chain
iptables -t mangle -N qos_tc
iptables -t mangle -I POSTROUTING -o $LAN_IFACE -d $LAN_NET  -j qos_tc
iptables -t mangle -I PREROUTING -i $LAN_IFACE -s $LAN_NET -j qos_tc
# ICMP 
iptables -t mangle -A qos_tc -s $LAN_NET ! -d $LAN_NET -p icmp -j MARK \
 --set-mark 101
iptables -t mangle -A qos_tc -d $LAN_NET ! -s $LAN_NET -p icmp -j MARK \
 --set-mark 101
# ACK & Other small packets
iptables -t mangle -A qos_tc -s $LAN_NET ! -d $LAN_NET -p tcp -m length \
 --length :64 -j MARK --set-mark 101
iptables -t mangle -A qos_tc -d $LAN_NET ! -s $LAN_NET -p tcp -m length \
 --length :64 -j MARK --set-mark 101
# DNS
iptables -t mangle -A qos_tc -s $LAN_NET ! -d $LAN_NET -p tcp --dport 53 \
 -j MARK --set-mark 101
iptables -t mangle -A qos_tc -d $LAN_NET ! -s $LAN_NET -p tcp --sport 53 \
 -j MARK --set-mark 101
iptables -t mangle -A qos_tc -s $LAN_NET ! -d $LAN_NET -p udp --dport 53 \
 -j MARK --set-mark 101
iptables -t mangle -A qos_tc -d $LAN_NET ! -s $LAN_NET -p udp --sport 53 \
 -j MARK --set-mark 101
# Web-client
iptables -t mangle -A qos_tc -s $LAN_NET ! -d $LAN_NET -m multiport -p tcp \
 --dports 80,443 -j MARK --set-mark 104
iptables -t mangle -A qos_tc -d $LAN_NET ! -s $LAN_NET -m multiport -p tcp \
 --sports 80,443 -j MARK --set-mark 104
# IM-client && SSH-Client
iptables -t mangle -A qos_tc -s $LAN_NET ! -d $LAN_NET -m multiport -p tcp \
 --dports 22,5190,5222,5223 -j MARK --set-mark 103
iptables -t mangle -A qos_tc -d $LAN_NET ! -s $LAN_NET -m multiport -p tcp \
 --sports 22,5190,5222,5223 -j MARK --set-mark 103
# LAN-to-LAN
iptables -t mangle -A qos_tc -s $LAN_NET -d $LAN_NET -j MARK --set-mark 1
iptables -t mangle -A qos_tc -d $LAN_NET -s $LAN_NET -j MARK --set-mark 1
# Poviders nets 
for net in $LOCAL_NETS;
do
    iptables -t mangle -A qos_tc -s $net -d $LAN_NET -j MARK --set-mark 2
    iptables -t mangle -A qos_tc -d $net -s $LAN_NET -j MARK --set-mark 2
done

С таким шейпированием трафика можно безболезненно пользоваться IM, SSH и серфить в интернете имея при этом десятки активных торрентов. Полоса пропускания будет автоматически выделяться под более приоритетные классы трафика по мере необходимости.

В некоторых Embedded-дистрибутивах (например openwrt) для работоспособности скрипта может потребоваться вручную загрузить соответствующие модули ядра:

insmod ip_queue 2> /dev/null > /dev/null
insmod sch_htb 2> /dev/null > /dev/null
insmod sch_sfq 2> /dev/null > /dev/null
insmod cls_u32 2> /dev/null > /dev/null
insmod sch_ingress 2> /dev/null > /dev/null
insmod cls_fw 2> /dev/null > /dev/null
insmod ipt_TOS 2> /dev/null > /dev/null
insmod sch_prio 2> /dev/null > /dev/null

Скачать скрипт целиком: qos_tc.sh

5 комментариев “Еще один пост про управление трафиком с помощью tc в Linux”

Комментирование закрыто.