суббота, 18 января 2014 г.

Шейпинг трафика в Ubuntu 12.04 LTS

Задача: разделить небольшой интернет-канал между большим количеством пользователей с  приоритизацией трафика.

Использованные источники:
1. http://www.opennet.ru/docs/RUS/LARTC/index.html
2. http://habrahabr.ru/post/133076/

Проблема была в том, что 100 пользователям интернет (10 Мбит/с) раздавал обычный Wi-Fi роутер. Среди этих пользователей были те, кто пользовался интернетом мало, те, кто весь день подключен к удаленному серверу Windows 2008 через RDP, и те, кому в течение дня требуется быстро качать файлы размером 30-300 Мб. Во-первых, когда кто-нибудь начинал усиленно качать какой-нибудь торрент, то у остальных все начинало тормозить. Во-вторых, даже если никто торренты не качал, а, к примеру, несколько человек просто копировали большие файлы с удаленного корпоративного файлового сервера, то страдали программисты 1С, которым всегда нужна высокая скорость соединения с Windows 2008 через RDP.

Итак, было выявлено 2 подзадачи:
1) Сделать равномерное распределение интернет-канала между пользователями. Нужно было исключить ситуацию, при которой один пользователь забирал большую часть скорости.
2) Установить RDP-трафику программистов 1С высокий приоритет.

Прокси-сервер squid не позволял решить вышеозначенные задачи, т.к. не умел контролировать HTTPS-трафик. Во-вторых, для контроля скорости другого трафика все равно нужно было использовать что-то другое.
Поэтому основным инструментом была выбрана утилита tc (traffic control). TC может ограничивать только исходящую скорость, поэтому все правила будем настраивать для сетевого интерфейса, смотрящего в локальную сеть.

Итак, схема распределения скорости выглядит так.



Реализация:
1) Пишем shell-скрипт

#!/bin/sh
tc=/sbin/tc
ipt=/sbin/iptables

#----Интерфейс, смотрящий в локальную сеть----
local_iface=eth0

# RDP использует TCP потр 3389
RDP_port=3389

#----Общая скорость Интернет-канала (10 Мбит/c или 1250Кбайт/c)----
channel_sp=1250kbps

#----Максимальные и минимальные скорости----
#__скорость для всего RDP-трафика__
sp_rdp=400kbps
m_sp_rdp=500kbps
#_скорость для RDP-трафика программистов 1С_
sp_rdp_progr=150kbps
m_sp_rdp_progr=500kbps
#_скорость для RDP-трафика всех остальных сотрудников_
sp_rdp_every=350kbps
m_sp_rdp_every=500kbps

#__скорость для остального (не RDP) трафика__
sp_oth_tr=850kbps
m_sp_oth_tr=1250kbps
#_минимальная и максимальная скорость на один IP_
sp_every=25kbps
m_sp_every=300kbps

# --IP-адреса программистов 1С
progr_ip1=192.168.0.10/32
progr_ip2=192.168.0.11/32
#----Диапазон IP-адресов локальной сети----
first_localnet_ip=2
last_localnet_ip=254
localnet_pr=192.168.0

#------------Маркируем пакеты средствами iptables--------------

# Маркируем пакеты RDP-трафика, а именно пакеты, идущие с порта 3389, меткой 22
$ipt -t mangle -A POSTROUTING -o $local_iface -p tcp --sport $RDP_port -j MARK --set-mark 0x0022

# Маркируем пакеты RDP-трафика программистов 1С
$ipt -t mangle -A POSTROUTING -o $local_iface -p tcp --sport $RDP_port -d $progr_ip1 -j MARK --set-mark 0x0021
$ipt -t mangle -A POSTROUTING -o $local_iface -p tcp --sport $RDP_port -d $progr_ip2 -j MARK --set-mark 0x0021

# Настройка TC для сетевого интерфейса, смотрящего в локальную сеть.

# Удаляем корневую дисциплину
$tc qdisc del dev $local_iface root

# Определяем корневую дисциплину с префиксом 1 и планировщиком htb. Трафик, не отфильтрованный фильтрами, будет попадать в класс 1:15
$tc qdisc add dev $local_iface root handle 1: htb default 15

# Определяем корневой класс 1:1 с планировщиком htb и задаем общую скорость Интернет-канала (1250 Кбайт/c)
$tc class add dev $local_iface parent 1: classid 1:1 htb rate $channel_sp

# Определяем дочерний для класса 1:1 класс 1:15 с планировщиком htb для трафика, не отфильтрованного фильтрами, т.е. для не RDP-трафика, и задаем гарантированную (минимальную) (850 Кбайт/c) и максимальную скорость (1250 Кбайт/c).
$tc class add dev $local_iface parent 1:1 classid 1:15 htb prio 3 rate $sp_oth_tr ceil $m_sp_oth_tr

# Определяем дочерний для класса 1:1 класс 1:11 с планировщиком htb для всего RDP-трафика и задаем гарантированную (минимальную) (400 Кбайт/c) и максимальную скорость (500 Кбайт/c).
$tc class add dev $local_iface parent 1:1 classid 1:11 htb prio 1 rate $sp_rdp ceil $m_sp_rdp

# Определяем дочерний для класса 1:11 класс 1:12 с планировщиком htb для RDP-трафика программистов 1С и задаем гарантированную (минимальную) (150 Кбайт/c) и максимальную скорость (500 Кбайт/c).
$tc class add dev $local_iface parent 1:11 classid 1:12 htb prio 1 rate $sp_rdp_progr ceil $m_sp_rdp_progr

# Определяем дочерний для класса 1:11 класс 1:13 с планировщиком htb для RDP-трафика всех остальных и задаем гарантированную (минимальную) (350 Кбайт/c) и максимальную скорость (500 Кбайт/c).
$tc class add dev $local_iface parent 1:11 classid 1:13 htb prio 2 rate $sp_rdp_every ceil $m_sp_rdp_every

# Задаем фильтр для фильтрования RDP-трафика программистов 1С (метка 21). Фильтр будет привязан к дисциплине 1: . Отфильтрованный трафик будет направлен в класс 1:12
$tc filter add dev $local_iface prio 1 protocol ip parent 1: u32 match mark 0x0021 0xffff flowid 1:12

# Задаем фильтр для фильтрования всего RDP-трафика всех остальных (метка 22). Фильтр будет привязан к дисциплине 1: . Отфильтрованный трафик будет направлен в класс 1:13
$tc filter add dev $local_iface prio 1 protocol ip parent 1: u32 match mark 0x0022 0xffff flowid 1:13

# Определяем правила TC для каждого IP-адреса локальной сети
net="$localnet_pr"
i=$first_localnet_ip
while [ "$i" -ne "$last_localnet_ip" ]
do

# Определяем дочерний для класса 1:15 (не RDP-трафик) класс 1:$((${i}+15)) с планировщиком htb для IP-адреса локальной сети и задаем гарантированную (минимальную) (25 Кбайт/c) и максимальную скорость (300 Кбайт/c).
$tc class add dev $local_iface parent 1:15 classid 1:$((${i}+15)) htb prio 3 rate $sp_every ceil $m_sp_every
# Задаем фильтр для фильтрования трафика, идущего на IP-адрес локальной сети. Фильтр будет привязан к дисциплине 1: . Отфильтрованный трафик будет направлен в класс 1:$((${i}+15))
$tc filter add dev $local_iface prio 3 protocol ip parent 1: u32 match ip dst ${net}.${i} flowid 1:$((${i}+15))
# Определяем дисциплину с планировщиком sfq для класса 1:$((${i}+15)) IP-адреса локальной сети. Эта дисциплина будет равномерно распределять не RDP-трафик каждого IP-адреса локальной сети
$tc qdisc add dev $local_iface parent 1:$((${i}+15)) handle $((${i}+15)): sfq perturb 10

i=$((${i}+1))
done

Если данная инструкция оказалась полезной для вас, напишите, пожалуйста, об этом в комментарии.