From: Донченко Евгений <donchenko@tecon.org.ua.> Попов Александр <popov2al@gmail.com.>
Newsgroups: email
Date: Mon, 2 Sep 2009 17:02:14 +0000 (UTC)
Subject: Шейпер ADSL для домовой сети
Хотим предоставить на суд общественности реально работающий шейпер,
который применяю для справедливой раздачи инета в домовой сети.
Признаемся честно, источником вдохновения стала статья Anton Shuko
Управление трафиком на роутере небольшой сети под Linux
Итак:
В нашем доме и парочке соседних прокинута локалка. Всего в сети 22 машины, находящиеся
в общей подсети 192.168.100.0
Имеется модем ADSL, обеспечивающий 8 Мбит/с входящий, около 850кбит/с исходящий скорости.
Задача: Обеспечить пользователям собственную гарантированную полосу
пропускания трафика и возможность заимствования неиспользуемой полосы у соседей.
При этом требуется:
- Обеспечить низкую задержку отклика при Web серфинге.
- Обеспечить низкие пинги и отсутствие лагов в on-line играх, причем порты могут меняться произвольно.
- Обеспечить работу torrenta для всех пользователей.
Для этого мы используем NAT на IPTABLES.
Все это работает под Redhat Linux Fedora 11.
За подробными пояснениями по работе шейпера и дополнительными ссылками отсылаю к оригиналу,
Управление трафиком на роутере небольшой сети под Linux
моя задача предоставить реально _работающую_ программу.
ВАРИАНТ 1.
Дальше идет текст adsl_qos.
#!/bin/bash
#запускается как
#adsl_qos {start|stop|status} ppp_интерфейс адрес_интерфейса.
DEV_OUT=$2
IP=$3
QLEN_OUT=10.
RATE_OUT=650 # Ограничиваю исходящую скорость
MTU_OUT=1492
DEV_IN=eth0 # Это интерфейс внутренней сети
RATE_IN=7000 # Ограничиваю входящую скорость
QLEN_IN=1000
RATE_LOCAL=100mbit
IP_LOCAL=192.168.100.1 # Это адрес моего сервера в локальной сети
ICMP="match ip protocol 1 0xff"
TCP="match ip protocol 6 0xff"
UDP="match ip protocol 17 0xff"
DPORT="match ip dport"
SPORT="match ip sport"
SRC="match ip src"
DST="match ip dst"
MRK="match mark"
U32="protocol ip u32"
# Сделано это для запуска из ip-up/ip-down скрипта ppp..
# xxx_OUT - относится к adsl интерфейсу, исходящему потоку.
# xxx_IN - относится к интерфейсу локальной сети, но входящему на adsl модем потоку :)
# Количество полос
NNN=24+3
# Количество пользователей + специальные полосы
#Ставлю ограничение 650kbit для исходящего потока и 6000kbit для входящего.
status(){
# Это если интересно посмотреть на работу шейпера
echo "[qdisc out]"
tc -s -d qdisc show dev $DEV_OUT
echo
echo "[class out]"
tc -s -d class show dev $DEV_OUT
echo
echo "[filter out]"
tc -s filter show dev $DEV_OUT
echo
echo "-----------------------------------------------------------------"
echo "[qdisc in]"
tc -s -d qdisc show dev $DEV_IN
echo
echo "[class in]"
tc -s -d class show dev $DEV_IN
echo
echo "[filter in]"
tc -s filter show dev $DEV_IN
exit
}
stop(){
# Если больше ненужен и для перезапуска
tc qdisc del dev $DEV_OUT ingress 2> /dev/null > /dev/null
tc qdisc del dev $DEV_OUT root 2> /dev/null > /dev/null
tc qdisc del dev $DEV_IN ingress 2> /dev/null > /dev/null
tc qdisc del dev $DEV_IN root 2> /dev/null > /dev/null
}
start_out(){
# Старт исходящего интерфейса. Например ppp0.
#ip link set dev $DEV_OUT qlen $QLEN_OUT mtu $MTU_OUT
# В оригинале правили MTU. Я не стал - и так все в порядке!
#добавляем особый тип очереди - ingress, которая пропускает трафик не выше.
#заданной скорости, при этом заметьте, что очередь
#не имеет размещения (всегда root), что позволяет добавлять к интерфейсу.
#очередь ingress не мешая htb (или любой другой очереди), подключенной к
#этому же интерфейсу:
# (На самом деле это просто очередь на входе, что бы не писали переводчики.
# Но реально ограничивает количество соединений в секунду )
tc qdisc add dev $DEV_OUT handle ffff: ingress
tc filter add dev $DEV_OUT parent ffff: protocol ip prio 0 handle 1 fw police rate 100kbit burst 1500 mtu 9k drop flowid :1
#Мы установили лимит SYN пакетов до 320 пакетов в секунду (пакет с SYN
#флагом занимает 320 бит, но 320 пакетов в секунду несколько многовато, хотя
#точно должно обеспечить обработку всех запросов на соединение).
tc qdisc add dev $DEV_OUT root handle 1: htb default 17
# Весь неклассифицированный трафик пойдет на очередь 17
tc class add dev $DEV_OUT parent 1: classid 1:1 htb rate $[$RATE_OUT]kbit
tc class add dev $DEV_OUT parent 1:1 classid 1:10 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/30]kbit prio 1
tc class add dev $DEV_OUT parent 1:1 classid 1:12 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/3]kbit prio 2
#Полоса для неопределенного трафика
tc class add dev $DEV_OUT parent 1:1 classid 1:17 htb rate $[$RATE_OUT/$NNN]kbit ceil ${RATE_OUT/3}kbit prio 7
# Полосы для моих машин. Приоритет чуть повыше, я же себя не обижу :-)
tc class add dev $DEV_OUT parent 1:1 classid 1:21 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/2]kbit prio 4
tc class add dev $DEV_OUT parent 1:1 classid 1:22 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/2]kbit prio 4
# Полосы для остальных машин
tc class add dev $DEV_OUT parent 1:1 classid 1:23 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/2]kbit prio 5
tc class add dev $DEV_OUT parent 1:1 classid 1:24 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/2]kbit prio 5
tc class add dev $DEV_OUT parent 1:1 classid 1:25 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/2]kbit prio 5
tc class add dev $DEV_OUT parent 1:1 classid 1:26 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/2]kbit prio 5
tc class add dev $DEV_OUT parent 1:1 classid 1:27 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/2]kbit prio 5
tc class add dev $DEV_OUT parent 1:1 classid 1:28 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/2]kbit prio 5
tc class add dev $DEV_OUT parent 1:1 classid 1:29 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/2]kbit prio 5
tc class add dev $DEV_OUT parent 1:1 classid 1:30 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/2]kbit prio 5
tc class add dev $DEV_OUT parent 1:1 classid 1:31 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/2]kbit prio 5
tc class add dev $DEV_OUT parent 1:1 classid 1:32 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/2]kbit prio 5
tc class add dev $DEV_OUT parent 1:1 classid 1:33 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/2]kbit prio 5
tc class add dev $DEV_OUT parent 1:1 classid 1:34 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/2]kbit prio 5
tc class add dev $DEV_OUT parent 1:1 classid 1:35 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/2]kbit prio 5
tc class add dev $DEV_OUT parent 1:1 classid 1:36 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/2]kbit prio 5
tc class add dev $DEV_OUT parent 1:1 classid 1:37 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/2]kbit prio 5
tc class add dev $DEV_OUT parent 1:1 classid 1:38 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/2]kbit prio 5
tc class add dev $DEV_OUT parent 1:1 classid 1:39 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/2]kbit prio 5
tc class add dev $DEV_OUT parent 1:1 classid 1:40 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/2]kbit prio 5
tc class add dev $DEV_OUT parent 1:1 classid 1:41 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/2]kbit prio 5
tc class add dev $DEV_OUT parent 1:1 classid 1:42 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/2]kbit prio 5
tc class add dev $DEV_OUT parent 1:1 classid 1:43 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/2]kbit prio 5
tc class add dev $DEV_OUT parent 1:1 classid 1:44 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/2]kbit prio 5
#rate - гарантированная полоса пропускания.
#ceil - максимальная, если очереди с более высоким приоритетом незагружены
#prio - приоритет полосы. 0 - максимальный
#Ниже будут заданы фильтры, которые направляют пакеты в нужные полосы (классы).
#Прошу обратить внимание на prio. Чем меньше, тем выше. Это не имеет отношения
#к приоритету полос. Это приоритет для выборки пакета фильтром.
# DNS запросы самые приоритетные
tc filter add dev $DEV_OUT parent 1:0 prio 1 $U32 $SPORT 53 0xffff classid 1:10
tc filter add dev $DEV_OUT parent 1:0 prio 1 $U32 $DPORT 53 0xffff classid 1:10
#Все прочие udp пакеты. Возможно, некоторые пиринговые сети будут жить в этой полосе.
#Но в основном для игрушек, которые не попали в более приоритетную полосу.
tc filter add dev $DEV_OUT parent 1:0 prio 3 $U32 $UDP classid 1:12
# Фильруем все машины моей сети в попытке выбраться в модем по полосам
tc filter add dev $DEV_OUT parent 1:0 protocol ip prio 21 handle 21 fw flowid 1:21
tc filter add dev $DEV_OUT parent 1:0 protocol ip prio 22 handle 22 fw flowid 1:22
tc filter add dev $DEV_OUT parent 1:0 protocol ip prio 23 handle 23 fw flowid 1:23
tc filter add dev $DEV_OUT parent 1:0 protocol ip prio 24 handle 24 fw flowid 1:24
tc filter add dev $DEV_OUT parent 1:0 protocol ip prio 25 handle 25 fw flowid 1:25
tc filter add dev $DEV_OUT parent 1:0 protocol ip prio 26 handle 26 fw flowid 1:26
tc filter add dev $DEV_OUT parent 1:0 protocol ip prio 27 handle 27 fw flowid 1:27
tc filter add dev $DEV_OUT parent 1:0 protocol ip prio 28 handle 28 fw flowid 1:28
tc filter add dev $DEV_OUT parent 1:0 protocol ip prio 29 handle 29 fw flowid 1:29
tc filter add dev $DEV_OUT parent 1:0 protocol ip prio 30 handle 30 fw flowid 1:30
tc filter add dev $DEV_OUT parent 1:0 protocol ip prio 31 handle 31 fw flowid 1:31
tc filter add dev $DEV_OUT parent 1:0 protocol ip prio 32 handle 32 fw flowid 1:32
tc filter add dev $DEV_OUT parent 1:0 protocol ip prio 33 handle 33 fw flowid 1:33
tc filter add dev $DEV_OUT parent 1:0 protocol ip prio 34 handle 34 fw flowid 1:34
tc filter add dev $DEV_OUT parent 1:0 protocol ip prio 35 handle 35 fw flowid 1:35
tc filter add dev $DEV_OUT parent 1:0 protocol ip prio 36 handle 36 fw flowid 1:36
tc filter add dev $DEV_OUT parent 1:0 protocol ip prio 37 handle 37 fw flowid 1:37
tc filter add dev $DEV_OUT parent 1:0 protocol ip prio 38 handle 38 fw flowid 1:38
tc filter add dev $DEV_OUT parent 1:0 protocol ip prio 39 handle 39 fw flowid 1:39
tc filter add dev $DEV_OUT parent 1:0 protocol ip prio 40 handle 40 fw flowid 1:40
tc filter add dev $DEV_OUT parent 1:0 protocol ip prio 41 handle 41 fw flowid 1:41
tc filter add dev $DEV_OUT parent 1:0 protocol ip prio 42 handle 42 fw flowid 1:42
tc filter add dev $DEV_OUT parent 1:0 protocol ip prio 43 handle 43 fw flowid 1:43
tc filter add dev $DEV_OUT parent 1:0 protocol ip prio 44 handle 44 fw flowid 1:44
# Этот фильтр использует маркировку пакетов в IPTABLES.
# Напряжно конечно, зато работает!
#Ну, и наконец, организуем очереди
# Это прочий трафик.
tc qdisc add dev $DEV_OUT parent 1:17 handle 17: sfq perturb 10
# Это машины сети. Лучше конечно esfq, но у меня не заработало.
# Но ничего, пусть каждый делит свой трафик сам.
# Если кого задалбывают вирусы, то это так и остается его персональной
# проблемой! А без шейпера - это было проблемой всех.
tc qdisc add dev $DEV_OUT parent 1:21 handle 21: sfq perturb 5
tc qdisc add dev $DEV_OUT parent 1:22 handle 22: sfq perturb 5
tc qdisc add dev $DEV_OUT parent 1:23 handle 23: sfq perturb 5
tc qdisc add dev $DEV_OUT parent 1:24 handle 24: sfq perturb 5
tc qdisc add dev $DEV_OUT parent 1:25 handle 25: sfq perturb 5
tc qdisc add dev $DEV_OUT parent 1:26 handle 26: sfq perturb 5
tc qdisc add dev $DEV_OUT parent 1:27 handle 27: sfq perturb 5
tc qdisc add dev $DEV_OUT parent 1:28 handle 28: sfq perturb 5
tc qdisc add dev $DEV_OUT parent 1:29 handle 29: sfq perturb 5
tc qdisc add dev $DEV_OUT parent 1:30 handle 30: sfq perturb 5
tc qdisc add dev $DEV_OUT parent 1:31 handle 31: sfq perturb 5
tc qdisc add dev $DEV_OUT parent 1:32 handle 32: sfq perturb 5
tc qdisc add dev $DEV_OUT parent 1:33 handle 33: sfq perturb 5
tc qdisc add dev $DEV_OUT parent 1:34 handle 34: sfq perturb 5
tc qdisc add dev $DEV_OUT parent 1:35 handle 35: sfq perturb 5
tc qdisc add dev $DEV_OUT parent 1:36 handle 36: sfq perturb 5
tc qdisc add dev $DEV_OUT parent 1:37 handle 37: sfq perturb 5
tc qdisc add dev $DEV_OUT parent 1:38 handle 38: sfq perturb 5
tc qdisc add dev $DEV_OUT parent 1:39 handle 39: sfq perturb 5
tc qdisc add dev $DEV_OUT parent 1:40 handle 40: sfq perturb 5
tc qdisc add dev $DEV_OUT parent 1:41 handle 41: sfq perturb 5
tc qdisc add dev $DEV_OUT parent 1:42 handle 42: sfq perturb 5
tc qdisc add dev $DEV_OUT parent 1:43 handle 43: sfq perturb 5
tc qdisc add dev $DEV_OUT parent 1:44 handle 44: sfq perturb 5
echo "Outbound shaping added to $DEV_OUT. Rate: ${RATE_OUT}Kbit/sec."
}
start_in(){
# Это шейпер на внутреннюю сеть, то есть на входящий трафик
ip link set dev $DEV_IN qlen $QLEN_IN
#добавляем особый тип очереди - ingress, что сидин на входе.
# Собственно, ограничиваем количество коннектов в секунду.
tc qdisc add dev $DEV_IN handle ffff: ingress
tc filter add dev $DEV_IN parent ffff: protocol ip prio 0 handle 1 fw police rate 200kbit burst 1500 mtu 9k drop flowid :1
#Мы установили лимит SYN пакетов до 620 пакетов в секунду (пакет с SYN
#флагом занимает 320 бит, но 620 пакетов в секунду несколько многовато, хотя
#точно должно обеспечить обработку всех запросов на соединение).
tc qdisc add dev $DEV_IN root handle 1: htb default 17
tc class add dev $DEV_IN parent 1: classid 1:1 htb rate ${RATE_IN}kbit
tc class add dev $DEV_IN parent 1:1 classid 1:10 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/30]kbit prio 0
tc class add dev $DEV_IN parent 1:1 classid 1:12 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/3]kbit prio 2
#Полоса для неопределенного трафика
tc class add dev $DEV_IN parent 1:1 classid 1:17 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/3]kbit prio 7
# Полосы для моих машин
tc class add dev $DEV_IN parent 1:1 classid 1:21 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/2]kbit prio 4
tc class add dev $DEV_IN parent 1:1 classid 1:22 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/2]kbit prio 4
# Полосы для остальных машин
tc class add dev $DEV_IN parent 1:1 classid 1:23 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/2]kbit prio 5
tc class add dev $DEV_IN parent 1:1 classid 1:24 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/2]kbit prio 5
tc class add dev $DEV_IN parent 1:1 classid 1:25 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/2]kbit prio 5
tc class add dev $DEV_IN parent 1:1 classid 1:26 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/2]kbit prio 5
tc class add dev $DEV_IN parent 1:1 classid 1:27 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/2]kbit prio 5
tc class add dev $DEV_IN parent 1:1 classid 1:28 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/2]kbit prio 5
tc class add dev $DEV_IN parent 1:1 classid 1:29 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/2]kbit prio 5
tc class add dev $DEV_IN parent 1:1 classid 1:30 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/2]kbit prio 5
tc class add dev $DEV_IN parent 1:1 classid 1:31 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/2]kbit prio 5
tc class add dev $DEV_IN parent 1:1 classid 1:32 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/2]kbit prio 5
tc class add dev $DEV_IN parent 1:1 classid 1:33 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/2]kbit prio 5
tc class add dev $DEV_IN parent 1:1 classid 1:34 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/2]kbit prio 5
tc class add dev $DEV_IN parent 1:1 classid 1:35 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/2]kbit prio 5
tc class add dev $DEV_IN parent 1:1 classid 1:36 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/2]kbit prio 5
tc class add dev $DEV_IN parent 1:1 classid 1:37 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/2]kbit prio 5
tc class add dev $DEV_IN parent 1:1 classid 1:38 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/2]kbit prio 5
tc class add dev $DEV_IN parent 1:1 classid 1:39 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/2]kbit prio 5
tc class add dev $DEV_IN parent 1:1 classid 1:40 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/2]kbit prio 5
tc class add dev $DEV_IN parent 1:1 classid 1:41 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/2]kbit prio 5
tc class add dev $DEV_IN parent 1:1 classid 1:42 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/2]kbit prio 5
tc class add dev $DEV_IN parent 1:1 classid 1:43 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/2]kbit prio 5
tc class add dev $DEV_IN parent 1:1 classid 1:44 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/2]kbit prio 5
#Примерно тоже самое, только этот интерфейс работает с локальной сетью.
tc class add dev $DEV_IN parent 1: classid 1:2 htb rate $RATE_LOCAL prio 7
#Через этот класс пропускается не транзитный с adsl модема трафик, а исходящий
#с роутера, поэтому используется другой, более высокий rate
tc filter add dev $DEV_IN parent 1:0 prio 1 $U32 $SRC $IP_LOCAL classid 1:2
#а это фильтр для него
tc filter add dev $DEV_IN parent 1:0 prio 2 $U32 $SPORT 53 0xffff classid 1:10
tc filter add dev $DEV_IN parent 1:0 prio 3 $U32 $UDP classid 1:12
tc filter add dev $DEV_IN parent 1:0 prio 4 $U32 $DST $ADR01 classid 1:21
tc filter add dev $DEV_IN parent 1:0 prio 4 $U32 $DST $ADR02 classid 1:22
tc filter add dev $DEV_IN parent 1:0 prio 4 $U32 $DST $ADR03 classid 1:23
tc filter add dev $DEV_IN parent 1:0 prio 4 $U32 $DST $ADR04 classid 1:24
tc filter add dev $DEV_IN parent 1:0 prio 5 $U32 $DST $ADR05 classid 1:25
tc filter add dev $DEV_IN parent 1:0 prio 5 $U32 $DST $ADR06 classid 1:26
tc filter add dev $DEV_IN parent 1:0 prio 5 $U32 $DST $ADR07 classid 1:27
tc filter add dev $DEV_IN parent 1:0 prio 5 $U32 $DST $ADR08 classid 1:28
tc filter add dev $DEV_IN parent 1:0 prio 5 $U32 $DST $ADR09 classid 1:29
tc filter add dev $DEV_IN parent 1:0 prio 5 $U32 $DST $ADR10 classid 1:30
tc filter add dev $DEV_IN parent 1:0 prio 5 $U32 $DST $ADR11 classid 1:31
tc filter add dev $DEV_IN parent 1:0 prio 5 $U32 $DST $ADR12 classid 1:32
tc filter add dev $DEV_IN parent 1:0 prio 5 $U32 $DST $ADR13 classid 1:33
tc filter add dev $DEV_IN parent 1:0 prio 5 $U32 $DST $ADR14 classid 1:34
tc filter add dev $DEV_IN parent 1:0 prio 5 $U32 $DST $ADR15 classid 1:35
tc filter add dev $DEV_IN parent 1:0 prio 5 $U32 $DST $ADR16 classid 1:36
tc filter add dev $DEV_IN parent 1:0 prio 5 $U32 $DST $ADR17 classid 1:37
tc filter add dev $DEV_IN parent 1:0 prio 5 $U32 $DST $ADR18 classid 1:38
tc filter add dev $DEV_IN parent 1:0 prio 5 $U32 $DST $ADR19 classid 1:39
tc filter add dev $DEV_IN parent 1:0 prio 5 $U32 $DST $ADR20 classid 1:40
tc filter add dev $DEV_IN parent 1:0 prio 5 $U32 $DST $ADR21 classid 1:41
tc filter add dev $DEV_IN parent 1:0 prio 5 $U32 $DST $ADR22 classid 1:42
tc filter add dev $DEV_IN parent 1:0 prio 5 $U32 $DST $ADR23 classid 1:43
tc filter add dev $DEV_IN parent 1:0 prio 5 $U32 $DST $ADR24 classid 1:44
# Тут все просто. Фильтруем по адресу машины-получателя в сети.
# Можно было маркировать в IPTABLES, как и для DEV_OUT, но я не стал.
# Но Вам не мешаю!
tc qdisc add dev $DEV_IN parent 1:2 handle 2: pfifo
#Использую самую простую и легкую для процессора очередь pfifo для исходящего
#с роутера трафика (не транзитный!)
Очереди для DNS и UDP
tc qdisc add dev $DEV_IN parent 1:10 handle 10: sfq perturb 10
tc qdisc add dev $DEV_IN parent 1:12 handle 12: sfq perturb 5
# Это прочий неклассифицированный трафик
tc qdisc add dev $DEV_IN parent 1:17 handle 17: sfq perturb 15
iptables -L -n -v -t mangle
# Это полюбоваться на маркирование пакетов
status
;;
*)
echo "Usage: $0 {start|stop|status} ppp_interface ip"
esac
# Это конец программы
Для запуска использую:
adsl_qos start ppp0
Разумеется, ppp0 должен быть поднят.
Почему ppp0? Сознательно использую бридж, т.к. при большом числе соединений
даже Zyxel 660HT2 в режиме роутера начинает тормозить и лагать.
А так - установил на сервере 512Мб памяти, и желающие пользователи
спокойно пользуют torrent.
Все входящие вызовы на 63737 порт автоматом переадресовываются на машину Юры.
Естественно, что в его торренте тоже настроен порт 63737.
Только количество соединений в IPTABLES лучше все-таки ограничить.
А то вирусы часто теряют всякую наглость!
Для чего уместно добавить в файл iptables:
# Максимум 105 одновременных соединений c одного IP eth0 (ЛВС)
-A FORWARD -p tcp -m connlimit -i eth0 -j DROP --syn --connlimit-above 105
Продолжая тему вирусов в сети, замечу, что разумно заблокировать и 25 порт, что бы Вас не
внесли в список массовых спамеров. Это конечно полумера, но:
# Максимум 1 одновременное соединение c одного IP eth0 для smtp
-A FORWARD -p tcp -m connlimit -i eth0 --dport smtp -j DROP --syn --connlimit-above 1
И может быть интересным ограничение числа пингов во входящей цепочке (ЛВС):
# Защита от пинга смерти
-A FORWARD_IN -p icmp -m limit --icmp-type echo-request --limit 10/s -j ACCEPT
Теперь о впечатлениях от работы.
Думаю, лучшей рекомендацией для шейпера является ОДНОВРЕМЕННАЯ игра в on-line игры
до 10 пользователей сети без ЛАГОВ и тормозов с высоким пингом!
ВАРИАНТ 2 Шейпера для ADSL
Приведенный выше скрипт предназначен прежде всего для понимания работы многополосного шейпера для раздачи
интернета в домовой сети, хотя и полностью функционален.
Благодаря Александру Попову, удалось сократить размер скрипта, одновременно повысив его
функциональность и облегчить настройку для пользователей.
Внесены дополнительные комментарии, облегчающие понимание причин выбора отдельных настроек.
Дальше идет текст adsl_qos.
#!/bin/bash
# vim: sw=4 ts=4 expandtab ai
TC="/sbin/tc"
IPT="/sbin/iptables"
IPROUTE="/sbin/ip"
USAGE="Usage: $0 {start|stop|restart|status} output_interface"
# Это сделано для запуска из ip-up/ip-down скрипта ppp.
# Если скрипт запустили вручную то нужно проверить наличие параметров DEV_OUT.
if [ -z "$2" ] ; then
# Интерфейс, для подкоючения к интернету, указываем обязательно.
echo "Not present output_interface"
echo $USAGE
exit 1
else
DEV_OUT=$2
fi
################################################################################
# Настройки шейпинга
#
# xxx_OUT - относится к adsl интерфейсу, исходящему потоку.
# xxx_IN - относится к интерфейсу локальной сети, но входящему
# на adsl модем потоку :).
# Длина очереди fifo на выходном интерфейсе.
QLEN_OUT=10
# Ограничение исходящей скорости, кбит/с.
# Рассчитывается на основании фактической исходящей скорости минус 15-20% в
# зависимости от того, как плавает скорость при ADSL соединении.
# Если скорость постоянна, можно снижать от фактической на 10%.
RATE_OUT=650
# Размер MTU на выходном интерфейсе. В настройке указано для ADSL.
MTU_OUT=1492
# Интерфейс внутренней сети.
DEV_IN=eth0
# Ограничение входящей скорости.
# Рассчитывается на основании фактической входящей скорости минус 10-15%.
RATE_IN=7000
# Длина очереди fifo на входном интерфейсе
# (сетевой карте сервера, обращенной в локалку).
QLEN_IN=1000
# Скорость внутреннего интерфейса (сетевой карты сервера, обращенной в локалку).
RATE_LOCAL=100mbit
# Адрес самого сервера в локальной сети.
IP_LOCAL="192.168.100.1"
# Переменные, сокращающие длины команд и облегчающие их понимание.
# Может используются не очень часто :) - но вдруг кому пригодится.
TCP="match ip protocol 6 0xff"
UDP="match ip protocol 17 0xff"
DPORT="match ip dport"
SPORT="match ip sport"
SRC="match ip src"
DST="match ip dst"
MRK="match mark"
U32="protocol ip u32"
################################################################################
################################################################################
# Настройки пользователей
# Массив содержит информацию о пользователях сервера из локальной сети
# Адреса пользователей принадлежат локальной сети. Формат записи:
# [Порядк_ном]="IP Приоритет Мин_канала Макс_канала", где
# Порядк_ном - Номер строки по порядку. Повторение не допускается;
# IP - IP адрес пользователя;
# Приоритет - Приоритет пользователя, чем меньше значение тем лучше;
# Мин_канала - Число обозначающее сколько частей пропускной способности
# канала нужно гарантировано выделить пользователю, например
# есть Вася с 2, Петя с 1 и Коля с 1, тогда канал распреде-
# литься так - Васе достанется 2/(2+1+1)=0,5 канала,
# Пете - 1/(2+1+1)=0,25 и Коле тоже 0,25;
# Макс_канала - Число от 1 до 100, показывающее какую часть общего канала
# можно выделить пользователю, если канал свободен. Значение
# 1 будет равно 0,01 канала, 100 соответствует каналу целиком;
# Для временного отключения клиентов допускается комментировать строки.
LOCAL_IPS=(
[1]="192.168.100.10 4 1 80"
[2]="192.168.100.20 4 1 70"
[3]="192.168.100.25 4 1 50"
[4]="192.168.100.35 5 1 50"
[5]="192.168.100.2 5 1 50"
[6]="192.168.100.11 5 1 50"
[7]="192.168.100.17 5 1 50"
[8]="192.168.100.33 5 1 50"
[9]="192.168.100.36 5 1 50"
[10]="192.168.100.48 5 1 50"
[11]="192.168.100.51 5 1 50"
[12]="192.168.100.55 5 1 50"
[13]="192.168.100.15 5 1 50"
[14]="192.168.100.39 5 1 50"
[15]="192.168.100.18 5 1 50"
[16]="192.168.100.7 5 1 50"
[17]="192.168.100.133 5 1 50"
[18]="192.168.100.9 5 1 50"
[19]="192.168.100.52 5 1 50"
[20]="192.168.100.45 5 1 50"
[21]="192.168.100.4 5 1 50"
[22]="192.168.100.26 5 1 50"
[23]="192.168.100.8 5 1 50"
#[24]="192.168.100.4 5 1 50"
#[25]="192.168.100.254 5 1 50"
)
################################################################################
# Шейпер подразумевает разбиение выделенной полосы пропускания на конечное
# число полос. Каждая полоса обеспечивает гарантированный трафик в выделенных
# пределах. Чем больше полос, тем меньший гарантированный трафик приходится на
# одну. Расчет общего количества полос производится так:
# Количество полоc = Cпециальные полосы + Общее количество полос пользователей
# Спец полосы - по ним пойдет общий для всех пользователей трафик по UDP и ASK
# пакеты, но с наивысшим приоритетом, а так же прочий неклассифицированный
# трафик, с низким приоритетом.
# Число меняется только при изменении в программе.
NNN=3
# Общее количество полос.
# Получается сложением полос для всех пользователей, и спец полос.
for client in "${LOCAL_IPS[@]}"; do
if [ -z "$client" ]; then continue; fi
let "NNN += `echo $client | awk '{print $3}'`"
done
ShaperStatus(){
# Показываем настройки шэйпера.
echo "SHAPER SETTINGS"
echo
echo "[qdisc out]"
$TC -s -d qdisc show dev $DEV_OUT
echo
echo "[class out]"
$TC -s -d class show dev $DEV_OUT
echo
echo "[filter out]"
$TC -s filter show dev $DEV_OUT
echo
echo "-----------------------------------------------------------------"
echo "[qdisc in]"
$TC -s -d qdisc show dev $DEV_IN
echo
echo "[class in]"
$TC -s -d class show dev $DEV_IN
echo
echo "[filter in]"
$TC -s filter show dev $DEV_IN
echo
}
ShaperStopAll(){
# Удаляем все настройки шэйпинга. Используется для остановки
# или перезапуска.
$TC qdisc del dev $DEV_OUT ingress 2> /dev/null > /dev/null
$TC qdisc del dev $DEV_OUT root 2> /dev/null > /dev/null
$TC qdisc del dev $DEV_IN ingress 2> /dev/null > /dev/null
$TC qdisc del dev $DEV_IN root 2> /dev/null > /dev/null
echo "Shaping removed on $DEV_OUT/$DEV_IN."
}
ShaperStartOut(){
############################################################################
# Ограничение скорости для SYN пакетов. Закомментировать если не требуется
# ограничить скорость создания новых подключений.
# На входном интерфейсе используется для защиты от SYN-атаки из интернета.
# Актуально, если разрешены любые входящие подключения из интернета.
$TC qdisc add dev $DEV_OUT handle ffff: ingress
$TC filter add dev $DEV_OUT parent ffff: protocol ip prio 0 handle 1 fw police rate 100kbit burst 1500 mtu 9k drop flowid :1
############################################################################
$TC class add dev $DEV_OUT parent 1: classid 1:1 htb rate $[$RATE_OUT]kbit
# Специальным видам трафика выделяем по одной полосе.
$TC class add dev $DEV_OUT parent 1:1 classid 1:10 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/20]kbit prio 1
$TC class add dev $DEV_OUT parent 1:1 classid 1:12 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/4]kbit prio 2
$TC class add dev $DEV_OUT parent 1:1 classid 1:17 htb rate $[$RATE_OUT/$NNN]kbit ceil $[$RATE_OUT/4]kbit prio 7
# DNS запросы самые приоритетные.
$TC filter add dev $DEV_OUT parent 1:0 prio 1 $U32 $SPORT 53 0xffff classid 1:10
$TC filter add dev $DEV_OUT parent 1:0 prio 2 $U32 $DPORT 53 0xffff classid 1:10
############################################################################
# Короткие SYN пакеты, для установки соединения, отправляем в ту же полосу.
# Это увеличит скорость установления новых соединий, что при сильной загрузке
# канала обеспечит сохранение минимальной паузы при открытии новой Web страницы.
# Закоментировать, если используется очередь ingress на входном интерфейсе
# и Вы не доверяете локальной сети.
$TC filter add dev $DEV_OUT parent 1:0 protocol ip prio 3 handle 1 fw flowid 1:10
############################################################################
# Все прочие udp пакеты. Возможно, некоторые пиринговые сети будут жить в
# этой полосе. Но в основном для игрушек, которые не попали в более
# приоритетную полосу.
$TC filter add dev $DEV_OUT parent 1:0 prio 4 $U32 $UDP classid 1:12
#Организуем очереди для специальных полос.
$TC qdisc add dev $DEV_OUT parent 1:10 handle 10: sfq perturb 5
$TC qdisc add dev $DEV_OUT parent 1:12 handle 12: sfq perturb 5
# Это прочий (неклассифицированный) трафик.
$TC qdisc add dev $DEV_OUT parent 1:17 handle 17: sfq perturb 10
# Классы клиентов.
j=21
for client in "${LOCAL_IPS[@]}"; do
if [ -z "$client" ]; then continue; fi
# Это определяются переменные для выражения.
prio=`echo $client | awk '{print $2}'`
let "rate= $RATE_OUT / $NNN * `echo $client | awk '{print $3}'`"
let "cell= $RATE_OUT / 100 * `echo $client | awk '{print $4}'`"
# Создаем полосы для клиентов.
$TC class add dev $DEV_OUT parent 1:1 classid 1:$j htb rate $[$rate]kbit ceil $[cell]kbit prio $prio
# Создаем фильтры для машин сети.
$TC filter add dev $DEV_OUT parent 1:0 protocol ip prio $j handle $j fw flowid 1:$j
# Теперь создаем очереди для машин сети.
$TC qdisc add dev $DEV_OUT parent 1:$j handle $j: sfq perturb 5
let "j += 1"
done
echo "Outbound shaping added to $DEV_OUT. Rate: ${RATE_OUT}Kbit/sec."
}
ShaperStartIn(){
# Это шейпер на внутреннюю сеть, то есть на входящий трафик.
$IPROUTE link set dev $DEV_IN qlen $QLEN_IN
############################################################################
# Добавляем особый тип очереди - ingress, что контролирует вход интерфейса.
# Собственно, ограничиваем количество входящих! коннектов в секунду.
# Раскомментировать, если Вы не доверяете локальной сети.
#$TC qdisc add dev $DEV_IN handle ffff: ingress
#$TC filter add dev $DEV_IN parent ffff: protocol ip prio 0 handle 1 fw police rate 200kbit burst 1500 mtu 9k drop flowid :1
############################################################################
$TC qdisc add dev $DEV_IN root handle 1: htb default 17
$TC class add dev $DEV_IN parent 1: classid 1:1 htb rate ${RATE_IN}kbit
$TC class add dev $DEV_IN parent 1:1 classid 1:10 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/20]kbit prio 0
$TC class add dev $DEV_IN parent 1:1 classid 1:12 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/4]kbit prio 2
# Полоса для неопределенного трафика.
$TC class add dev $DEV_IN parent 1:1 classid 1:17 htb rate $[$RATE_IN/$NNN]kbit ceil $[$RATE_IN/4]kbit prio 7
# Примерно тоже самое, только этот интерфейс работает с локальной сетью.
$TC class add dev $DEV_IN parent 1: classid 1:2 htb rate $RATE_LOCAL prio 7
# Через этот класс пропускается не транзитный с adsl модема трафик, а
# исходящий с роутера, поэтому используется другой, более высокий rate,
# а это фильтр для него.
$TC filter add dev $DEV_IN parent 1:0 prio 1 $U32 $SRC $IP_LOCAL classid 1:2
# это фильтр для DNS.
$TC filter add dev $DEV_IN parent 1:0 prio 2 $U32 $SPORT 53 0xffff classid 1:10
$TC filter add dev $DEV_IN parent 1:0 prio 3 $U32 $DPORT 53 0xffff classid 1:10
############################################################################
# Короткие SYN пакеты, для установки соединения, отправляем в ту же полосу.
# Раскоментировать, если не используется (закоментирована) очередь ingress
# на исходящем интерфейсе.
#$TC filter add dev $DEV_IN parent 1:0 protocol ip prio 4 handle 1 fw flowid 1:10
############################################################################
# Это фильтр для прочих UDP соединений.
$TC filter add dev $DEV_IN parent 1:0 prio 5 $U32 $UDP classid 1:12
# Использую самую простую и легкую для процессора очередь pfifo для
# исходящего с роутера трафика (не транзитный!).
$TC qdisc add dev $DEV_IN parent 1:2 handle 2: pfifo
# Очереди для DNS и UDP.
$TC qdisc add dev $DEV_IN parent 1:10 handle 10: sfq perturb 5
$TC qdisc add dev $DEV_IN parent 1:12 handle 12: sfq perturb 5
# Это прочий неклассифицированный трафик.
$TC qdisc add dev $DEV_IN parent 1:17 handle 17: sfq perturb 15
# Полосы для клиентских машин.
j=21
for client in "${LOCAL_IPS[@]}"; do
if [ -z "$client" ]; then continue; fi
# Это определяются переменные для выражения.
ip=`echo $client | awk '{print $1}'`
prio=`echo $client | awk '{print $2}'`
let "rate= $RATE_IN / $NNN * `echo $client | awk '{print $3}'`"
let "cell= $RATE_IN / 100 * `echo $client | awk '{print $4}'`"
# Создаем полосы для клиентов.
$TC class add dev $DEV_IN parent 1:1 classid 1:$j htb rate $[$rate]kbit ceil $[cell]kbit prio $prio
# Фильтры для них же.
$TC filter add dev $DEV_IN parent 1:0 prio $j $U32 $DST $ip classid 1:$j
# Очереди.
$TC qdisc add dev $DEV_IN parent 1:$j handle $j: sfq perturb 5
let "j += 1"
done
echo "Outbound shaping added to $DEV_IN. Rate: ${RATE_IN}Kbit/sec."
}
Marking(){
action=$1
j=21
for client in "${LOCAL_IPS[@]}"; do
if [ -z "$client" ]; then continue; fi
ip=`echo $client | awk '{print $1}'`
# Маркируем пакеты для клиентов.
# Это действие требуется для распределения клиентов по полосам.
$IPT $action PREROUTING -t mangle -s $ip -j MARK --set-mark $j
let "j += 1"
done
# Маркируем syn пакеты.
$IPT $action PREROUTING -t mangle -p tcp --syn -j MARK --set-mark 1
# Назначаем одинаковое время жизни для пакетов.
$IPT $action PREROUTING -t mangle -i $DEV_IN -j TTL --ttl-set 64
}
Опытная эксплуатация второго варианта скрипта подтвердила его отличные характеристики (разумеется,
в связке с соответствующе настроенным фаерволом).
Дальнейшая наша разработка (скрипт фаервол+шейпер+проброс DNS), будет приведен
в последующей статье.
935 Прочтений • [Шейпер ADSL для домовой сети (shaper traffic adsl bandwidth linux fedora)] [08.05.2012] [Комментариев: 0]