QoS FreeBSD

Материал из rrv-wiki
Перейти к навигации Перейти к поиску
FreeBSD QoS.

Автор статьи - Эдуард Афонцев

Введение

В связи с развитием интерактивных сервисов задача обеспечения качества обслуживания (QoS) в сетях передачи данных становится все более актуальной. Операционная система FreeBSD в базовой поставке содержит встроенный механизм поддержки QoS – DUMMYNET.

DUMMYNET

В общем случае DUMMYNET можно рассматривать как средство ограничения полосы пропускания (Bandwidth limiting – Shaper), обеспечения очередей (Queuing) и эмуляции канала ханизм Weighted Fair Queuing (WFQ).

Общая схема использования DUMMYNET.

1. Конфигурируется ядро с поддержкой DUMMYNET

options IPFIREWALL
options DUMMYNET
options HZ=1000 

Замечание: DUMMYNET неразрывно связан с файерволлом (IPFW), поэтому опция IPFIREWALL обязательна.

2. Устанавливаются системные переменные

  • sysctl net.inet.ip.fw.one_pass - данный параметр определяет прохождение пакета, выходящего из pipe: пакет будет обрабатываться следующим правилом файерволла (sysctl net.inet.ip.fw.one_pass=0) или игнорироваться всеми дальнейшими правилами (sysctl net.inet.ip.fw.one_pass=1).
  • net.inet.ip.dummynet.hash_size - число динамических объектов (pipes или queues).

3. В зависимости от задачи конфигурируются каналы и очереди с заданными свойствами

На практике для жесткого ограничения полосы пропускания (Bandwidth) используется pipe, а для распределения полосы пропускания (WFQ) – queue.

4. Средствами файерволла (Ipfw) производится классификация трафика на потоки (flows), которые направляются к соответствующим объектам (каналам или очередям).

Замечание:

Пакеты, посланные к конкретному pipe или queue далее могут классифицироваться на несколько потоков, каждый из которых далее посылается к отдельному dynamic pipe или queue. В данном случае flow идентификатор конструируется с помощью параметра mask. Для каждого отличающегося flow (разделение с помощью mask) создается новый pipe или queue с параметрами оригинального объекта и пакеты посылаются к новому pipe или queue.

Если есть много хостов и нужно ограничение для каждого, то: или много pipes (или queues) или используем masks (т.е. masks используется для отделения независимых pipes (или queues)) и получаем несколко pipes (или queues) с параметрами описанного с mask объекта.

5. Потоки (Flows) проходят через объекты (каналы или очереди), претерпевая заданные свойствами объектов изменения.

Ограничение полосы пропускания (Shaping).

1. Определение трубы (канала)

# ipfw pipe PIPE_NUMBER config bw BANDWIDTH queue QUEUE_SIZE 

Замечание:

Следует отметить, что pipe использует очередь внутри себя, причем ее параметры можно менять (queue QUEUE_SIZE), но это очередь внутри pipe, она отличается от объекта queue!

2. Классификация трафика

# ipfw add IPFW_NUMBER pipe PIPE_NUMBER tcp from IP_ADDR to IP_ADDR 

Замечание:

Классификатор является стандартным правилом файерволла (ipfw) и направляет пакеты в pipe.

3. Просмотр текущей конфигурации

# ipfw pipe show
# ipfw pipe list 

4. Удаление

# ipfw pipe PIPE_NUMBER delete
# ipfw pipe flush 

Распределение полосы пропускания (WFQ).

1. Определение общей трубы (канала)

# ipfw pipe PIPE_NUMBER config bw BANDWIDTH queue QUEUE_SIZE 

Замечание:

Размер очереди (queue QUEUE_SIZE) задается в так называемых слотах (пакетах) или байтах (по умолчанию 50 слотов). В некоторых случаях, например при небольшой ширине трубы BANDWIDTH, размер очереди по умолчанию может оказаться чрезмерно большим и приводить к неоправданным задержкам, что недопустимо.

Проиллюстрируем это на примере. Для Ethernetа размер очереди по умолчанию равен QUEUE_TOTAL=MTU*QUEUE_SIZE=1500(bytes)*50=12000(bit)*50=600(kbit). Если сделать BANDWIDTH=56 (kbit/s), то данная очередь заполнится за QUEUE_TOTAL/ BANDWIDTH ~10 (s), то есть возникнет большая задержка. Поэтому нужно указывать размер очереди отличный от размера по умолчанию. Например, pipe 10 config bw 56Kbit/s queue 5kbytes. Данная очередь заполнится за 5000*8/56000~0.7 (s).

2. Определение очередей (с весами) внутри канала (трубы)

# ipfw queue QUEUE_NUMBER config pipe PIPE_NUMBER weight WEIGHT 

Queue ассоциирует с каждым потоком (flow) вес (WEIGHT) и соответствующий pipe (PIPE_NUMBER). Вес - это не приоритет, DUMMYNET queue предназначена только для WFQ. В соответствии с весом очереди выделяется часть пропускной способности.

Например:

# ipfw queue 1 config pipe 1 weight 50
# ipfw queue 2 config pipe 1 weight 30
# ipfw queue 3 config pipe 1 weight 20 

3. Классифицируем трафик (направляем в соответствующие очереди)

# ipfw add IPFW_NUMBER queue QUEUE_NUMBER ... from ... to ... via ... in/out 

Например:

Более приоритетный в очередь номер 1

# ipfw add 1000 queue 1 ... from ... to ... via ... in/out
# ipfw add 1000 queue 1 ... from ... to ... via ... in/out 

Менее приоритетный в очередь номер 2

# ipfw add 2000 queue 2 ... from ... to ...
# ipfw add 2000 queue 2 ... from ... to ... 

И так далее

# ipfw add 3000 queue 3 ... from ... to ...
# ipfw add 3000 queue 3 ... from ... to ... 

Замечание:

Классификатор является стандартным правилом файерволла (ipfw) и направляет пакеты в queue.

4. Просмотр текущей конфигурации

# ipfw queue show
# ipfw queue list 

5. Удаление

# ipfw queue QUEUE_NUMBER delete
# ipfw queue flush 

Примеры ограничения трафика.

1. Ограничение для всех ftp клиентов bw в 64 Kbyte/s (64*8=512 Kbit/s).

# ipfw pipe 1 config bw 512Kbits queue 10
# ipfw add 1000 pipe 1 tcp from me 20 to any 

Первый ftp клиент покажет скорость скачивания в 64 Kbyte/s. Следующий меньшую скорость, так как они поделят общую полосу в 64 Kbyte/s. И так далее.

2. Ограничение для каждого ftp клиента bw в 20 Kbyte/s (20*8=160 Kbit/s).

# ipfw pipe 1 config mask all bw 160Kbits queue 10
# ipfw add 1000 pipe 1 tcp from me 20 to any 

Каждый клиент покажет скорость скачивания в 20 Kbyte/s (Пока хватит общей полосы).

3. Канал в котором все делят одну полосу на прием и другую на передачу.

# ipfw add pipe 1 ip from A to B out
# ipfw add pipe 2 ip from B to A in
# ipfw pipe 1 config bw 1Mbit/s delay 80ms queue 10 
# ipfw pipe 2 config bw 128Kbit/s delay 300ms queue 10 

Для симуляции full-duplex делается два объекта pipe - in и out.

4. Канал в котором ограничивается трафик для каждого адреса в 100Kbit/s.

# ipfw pipe 10 config mask src-ip 0x000000ff bw 100Kbit/s queue 10Kbytes
# ipfw pipe 20 config mask dst-ip 0x000000ff bw 100Kbit/s queue 10Kbytes
# ipfw add 1000 add pipe 10 all from 192.168.0.0/16 to any out via fxp0
# ipfw add 2000 add pipe 20 all from 192.168.0.0/16 to any in via fxp0 

Внутри pipe несколько dynamic pipes (по одному 100Kbit/s на каждый хост в данном случае).

5. Ограничение нежелательного трафика.

Организуем следующую топологию: маршрутизатор ROUTER связывает CLIENT и SERVER, причем интерфейс fxp0 на ROUTERе имеет скорость 100 Mbit/s, а интерфейс fxp1 - 10 mbit/s. Таким образом организуется узкое место по пропускной способности в сети.

CLIENT---[fxp0 100mbit] ROUTER [fxp1 10mbit]---SERVER Каким-либо образом загружаем канал CLIENT-SERVER udp пакетами, например, используя iperf:

SERVER# iperf -s -u 
CLIENT# iperf -c SERVER_IP -N -P 20 -u -V -t 1000 

Наблюдаем, что tcp пакеты от CLIENTа до SERVERа не проходят (ping, ssh). Это означает перегрузку канала по пропускной способности (участок 10 mbit).

Включаем на ROUTERе ограничение полосы для udp:

ROUTER# ipfw pipe 1 config bw 512Kbits queue 10
ROUTER# ipfw add 1000 pipe 1 udp from any to any 

После этого tcp пакеты от CLIENTа до SERVERа успешно проходят, то есть ограничивается нежелательный трафик udp.

Примеры приоритезации трафика.

1. Общая полоса 512Kbits с приоритезацией (WFQ).

# ipfw pipe 1 config bw 512Kbits queue 10 

# ipfw queue 1 config pipe 1 weight 50 
# ipfw queue 2 config pipe 1 weight 30
# ipfw queue 3 config pipe 1 weight 20 

# ipfw add 1000 queue 1 ip from ... to ... 
# ipfw add 2000 queue 1 ip from ... to ... 

# ipfw add 3000 queue 2 ip from ... to ...
# ipfw add 4000 queue 2 ip from ... to ... 

# ipfw add 5000 queue 3 ip from ... to ...
# ipfw add 6000 queue 3 ip from ... to ... 

В данном примере организуется канал шириной 512 Kbits в котором организуются очереди, обрабатывающиеся в соответствии с весом (из очереди с большим весом проходит больше пакетов в единицу времени). Это не Priority Queuing (PQ), а WFQ, то есть всем очередям гарантируется прохождение пакетов.

2. Предотвращение перегрузки канала.

Организуем следующую топологию: маршрутизатор ROUTER связывает CLIENT и SERVER, причем интерфейс fxp0 на ROUTERе имеет скорость 100 Mbit, а интерфейс fxp1 - 10 mbit. Таким образом организуется узкое место по пропускной способности в сети.

CLIENT---[fxp0 100mbit] ROUTER [fxp1 10mbit]---SERVER Каким-либо образом загружаем канал CLIENT-SERVER udp пакетами, например, используя iperf:

SERVER# iperf -s -u 
CLIENT# iperf -c SERVER_IP -N -P 20 -u -V -t 1000 

Наблюдаем, что tcp пакеты от CLIENTа до SERVERа не проходят (ping, ssh). Это означает перегрузку канала по пропускной способности (участок 10 mbit).

Включаем на ROUTERе приоритезацию:

ROUTER# ipfw pipe 1 config bw 1Mbits queue 10
ROUTER# ipfw queue 1 config pipe 1 weight 80
ROUTER# ipfw queue 2 config pipe 1 weight 20 

ROUTER# ipfw add 1000 queue 1 icmp from any to any
ROUTER# ipfw add 1000 queue 1 tcp from any to any
ROUTER# ipfw add 2000 queue 2 udp from any to any 

После этого tcp пакеты от CLIENTа до SERVERа успешно проходят, то есть работает приоритезация (очереди).