Вы здесь

Ограничение трафика на маршрутизаторе

Ограничение трафика на маршрутизаторе делается в два этапа:
1. Классификация пакетов с помощью netfilter или фильтров iproute2
2. Создание нескольких очередей пакетов с помощью iproute2

Пакеты распределяются в зависимости от класса на несколько очередей в которых ждут своей очереди на отправку. Каждая очередь имеет ограничения на полосу пропускания, приоритет и еще некоторые параметры. При переполнения очереди пакеты соответствующего класса начинают отбрасываться.
Очереди организованы в древовидную иерархию. Каждая очередь может быть разбита на более мелкие. Корневые очереди, связанные непосредственно с «хэндлером» интерфейса имеют абсолютные ограничения по пропускной способности. Дочерние очереди могут «заимствовать» друг у друга неиспользуемую полосу пропускания.

Классификация пакетов с iptables

Первый этап выполняется с помощью программы /sbin/iptables.

Маркируем пакеты в зависимости от каких либо параметров, например по размеру, номеру порта, ip адресу. Для специфических случаев можно дописывать свои модули для netfilter. Например модуль IP2P http://www.ipp2p.org позволяет выбирать пакеты p2p сетей.

Приписываем класс пакета в соответствии с проставленными меткам

Вообще говоря, можно было бы классифицировать пакеты сразу. Например выделим входящий HTTP трафик в отдельный класс

iptables -t mangle -A POSTROUTING -o eth0 -s 0/0 --source-port 80 -j CLASSIFY --set-class 1:10

Маркировка позволяет проверять только несколько первых пакетов в соединении. Для того, чтобы не исследовать каждый пакет используется модуль CONNMARK который позволяет маркировать все пакеты принадлежащие соединению.

Пример классификации P2P трафика. Классы для различных интерфейсов определяются независимо, что позволило использовать класс 1:20 для входящего и для исходящего трафика.

iptables -t mangle -A PREROUTING -p tcp -j CONNMARK --restore-mark
iptables -t mangle -A PREROUTING -p tcp -m mark ! --mark 0 -j ACCEPT
iptables -t mangle -A PREROUTING -p tcp -m ipp2p --ipp2p -j MARK --set-mark 1
iptables -t mangle -A PREROUTING -p tcp -m mark --mark 1 -j CONNMARK --save-mark

iptables -t mangle -A POSTROUTING -o eth0 -m mark --mark 1 -j CLASSIFY --set-class 1:20
iptables -t mangle -A POSTROUTING -o eth1 -m mark --mark 1 -j CLASSIFY --set-class 1:20

Создание очередей пакетов

Этап второй выполняется с помощью /sbin/tc.

Создаем связанную с интерфейсом очередь исходящих пакетов, указываем класс по умолчанию. Создаем корневой класс, назначаем лимит. Создаем дочерние классы, указываем лимиты для них (Обязательно должен быть создан класс используемый по умолчанию).

Теперь каждый пакет попадает в свою очередь. Если очередь переполняется, пакеты отбрасываются не доходя до аппаратного уровня.
Пример: Общая пропускная способность канала 10 Мбит/с. Внешний интерфейс eth0, внутренний eth1. Ограничиваем исходящий трафик P2P сетей из предыдущего примера полосой 32 Кбит/с, входящий 256 Кбит/с.

/sbin/tc qdisc add dev eth0 root handle 1: htb default 10
/sbin/tc class add dev eth0 parent 1: classid 1:1 htb rate 10mbit
/sbin/tc class add dev eth0 parent 1:1 classid 1:10 htb rate 10mbit
/sbin/tc class add dev eth0 parent 1:1 classid 1:20 htb rate 32kbit

/sbin/tc qdisc add dev eth1 root handle 1: htb default 10
/sbin/tc class add dev eth1 parent 1: classid 1:1 htb rate 10mbit
/sbin/tc class add dev eth1 parent 1:1 classid 1:10 htb rate 10mbit
/sbin/tc class add dev eth1 parent 1:1 classid 1:20 htb rate 256kbit

Пример стартового скрипта /etc/init.d/shaper (написан не мною и не связан с примером iptables)

#!/bin/sh
# init script written by shane at knowplace dot org
# this script only creates the qdiscs and classes required for shaping, it
# does NOT create the necessary filters

INTERFACE='eth0'
rc_done=" done"
rc_failed=" failed"

return=$rc_done

TC='/sbin/tc'

tc_reset ()
{
# Reset everything to a known state (cleared)
$TC qdisc del dev $INTERFACE root 2> /dev/null > /dev/null
}

tc_status ()
{
echo "[qdisc - $INTERFACE]"
$TC -s qdisc show dev $INTERFACE
echo "------------------------"
echo
echo "[class - $INTERFACE]"
$TC -s class show dev $INTERFACE
}

tc_showfilter ()
{
echo "[filter - $INTERFACE]"
$TC -s filter show dev $INTERFACE
}

case "$1" in

start)
echo -n "Starting traffic shaping"
tc_reset
U320="$TC filter add dev $INTERFACE protocol ip parent 1:0 prio 0 u32"
#
# dev eth0 - creating qdiscs & classes
#
$TC qdisc add dev $INTERFACE root handle 1: htb default 60
$TC class add dev $INTERFACE parent 1: classid 1:1 htb rate 116kbit
$TC class add dev $INTERFACE parent 1:1 classid 1:10 htb rate 32kbit ceil 116kbit prio 0
$TC class add dev $INTERFACE parent 1:1 classid 1:20 htb rate 22kbit ceil 116kbit prio 1
$TC class add dev $INTERFACE parent 1:1 classid 1:30 htb rate 22kbit ceil 116kbit prio 2
$TC class add dev $INTERFACE parent 1:1 classid 1:40 htb rate 20kbit ceil 116kbit prio 3
$TC class add dev $INTERFACE parent 1:1 classid 1:50 htb rate 18kbit ceil 116kbit prio 4
$TC class add dev $INTERFACE parent 1:1 classid 1:60 htb rate 2kbit ceil 116kbit prio 5
$TC qdisc add dev $INTERFACE parent 1:10 handle 10: sfq perturb 10
$TC qdisc add dev $INTERFACE parent 1:20 handle 20: sfq perturb 10
$TC qdisc add dev $INTERFACE parent 1:30 handle 30: sfq perturb 10
$TC qdisc add dev $INTERFACE parent 1:40 handle 40: sfq perturb 10
$TC qdisc add dev $INTERFACE parent 1:50 handle 50: sfq perturb 10
$TC qdisc add dev $INTERFACE parent 1:60 handle 60: sfq perturb 10
tc_status
;;

stop)
echo -n "Stopping traffic shaper"
tc_reset || return=$rc_failed
echo -e "$return"
;;

restart|reload)
$0 stop && $0 start || return=$rc_failed
;;

stats|status)
tc_status
;;

filter)
tc_showfilter
;;

*)
echo "Usage: $0 {start|stop|restart|stats|filter}"
exit 1

esac
test "$return" = "$rc_done" || exit 1
##################################

Примечания.

В параметрах iptables цель CLASSIFY в iptables может использоваться только в таблице mangle и только в цепочке POSTROUTING.

В параметрах tc встречаются сокращения:
qdisc – Classful Queuing Disciplines – базовый объект связанный с сетевым интерфейсом и обеспечивающий управление очередями
htb – Hierarchical Token Bucket – имя собственное одного из планировщиков очередей пакетов в ядре Linux

Имена классов имеют вид M:N. M: эквивалентно M:0 и используется для создания общего корня очередей (хэндлера) связанного напрямую с интерфейсом.