QoS FreeBSD
Автор статьи - Эдуард Афонцев
Содержание
Введение
В связи с развитием интерактивных сервисов задача обеспечения качества обслуживания (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а успешно проходят, то есть работает приоритезация (очереди).