Pull to refresh

Mikrotik. QoS для дома

Reading time 5 min
Views 76K
Сегодня я хотел бы немного рассказать о приоритетах.
image

Статья не претендует на охват всей информации по QoS на Mikrotik. Это демонстрация набора правил, позволяющих настроить несложную схему приоритезации трафика и пополнять её по мере необходимости.

Надеюсь, коллеги помогут советами в комментариях.

Говоря о QoS, обычно подразумевают два направления — более или менее равномерное деление канала по количеству пользователей, либо приоритезацию трафика. Направления эти вполне дополняют друг-друга, но для дома, для семьи заниматься делением канала я смысла не вижу и, если вас интересует эта тема, сошлюсь на исчерпывающе раскрывающую тему статью «MikroTik QoS — развенчание мифов».

Я же сосредоточусь на приоретизации трафика, благо это несколько проще.

Ограничение скорости передачи данных может быть выполнено двумя способами:

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

Principles of rate limiting and equalizing

Как видно на иллюстрации, шейпер режет всё, что не влезло, а шедулер просто притормаживает.
Соответственно, именно шедулер нам и нужен.

Теперь необходимо поделить трафик на классы и задать каждому классу свой приоритет. Первый класс обслуживается в первую очередь, последний — в последнюю.

Самый простой вариант такого решения, который зачастую и используется — просто пустить приоритетом VoIP-трафик, а весь остальной по остаточному принципу, но я сделаю чуть сложнее.

Итак, план таков:

prio_1: DNS, ICMP, ACK — в первую очередь идёт служебный трафик. Установка и разрыв соединений, резолвинг имён и т.п.
prio_2: SIP — VoIP очень любит минимальные задержки.
prio_3: SSH и игры — удалённый доступ важен для работы. Игры — для отдыха.
prio_4: RDP и HTTP/HTTPS — веб, видео и т.п.
prio_5: всё, что не опознано выше — в принципе, можно принудительно загнать сюда торренты. Благо дома порты с которых работают клиенты вполне известны..

Маленькое лирическое отступление:

Если мы поищем информацию о QoS в Mikrotik, то найдём несколько вариантов скриптов, начиная от монструозного QOS script by Greg Sowell или явно основанного на нём The Mother of all QoS Trees, заканчивая Traffic Prioritization Script (кстати, советую отнестись к нему с большой осторожностью, автор явно довольно смутно понимает, что делает и поэтому скрипт делает явно не то, что было задумано). У всех этих скриптов есть одна общая проблема — они написаны довольно давно и в значительной степени устарели по одной простой причине — мир изменился.

Сегодня, благодаря всеобщему шифрованию трафика, мы не можем так запросто взять и с помощью L7-regexp отловить трафик youtube, например, или Skype. Поэтому, используя такие скрипты, внимательно отнеситесь к вопросу определения трафика. Это, на мой взгляд, единственная сложность в этом вопросе.

Теперь разметим трафик согласно плана выше. В коде я использую interfaceBandwidth, т.е. ширину канала. У меня он симметричный и равен 100М. Если у вас отличается ширина канала, то необходимо изменить значение interfaceBandwidth на необходимое. Если канал асинхронный, то скрипт будет сложнее за счёт необходимости отдельно маркировать пакеты для входящего и исходящего трафика. Это несложно, но значительно увеличит скрипт, ухудшив его читаемость и, в целом, выходит за рамки статьи.

В address-list я демонстрирую возможность массовой вставки адресов из FQDN (для примера взяты адреса кластеров из wiki Мира Танков). Разумеется, можно просто прописать необходимые IP вручную.

#Set bandwidth of the interface
:local interfaceBandwidth 100M

# address-lists
:for i from=1 to=10 do={/ip firewall address-list add list=WoT address=("login.p"."$i".".worldoftanks.net")}
#
/ip firewall mangle
# prio_1
    add chain=prerouting action=mark-packet new-packet-mark=prio_1 protocol=icmp
    add chain=prerouting action=mark-packet new-packet-mark=prio_1 protocol=tcp port=53
    add chain=prerouting action=mark-packet new-packet-mark=prio_1 protocol=udp port=53
    add chain=prerouting action=mark-packet new-packet-mark=prio_1 protocol=tcp tcp-flags=ack packet-size=0-123
# prio_2
    add chain=prerouting action=mark-packet new-packet-mark=prio_2 dscp=40                                     
    add chain=prerouting action=mark-packet new-packet-mark=prio_2 dscp=46
    add chain=prerouting action=mark-packet new-packet-mark=prio_2 protocol=udp port=5060,5061,10000-20000 src-address=192.168.100.110
    add chain=prerouting action=mark-packet new-packet-mark=prio_2 protocol=udp port=5060,5061,10000-20000 dst-address=192.168.100.110
# prio_3
    add chain=prerouting action=mark-packet new-packet-mark=prio_3 protocol=tcp port=22
    add chain=prerouting action=mark-packet new-packet-mark=prio_3 src-address-list=WoT
    add chain=prerouting action=mark-packet new-packet-mark=prio_3 dst-address-list=WoT
# prio_4
    add chain=prerouting action=mark-packet new-packet-mark=prio_4 protocol=tcp port=3389
    add chain=prerouting action=mark-packet new-packet-mark=prio_4 protocol=tcp port=80,443
Аккуратно уложим размеченный трафик в очередь:

<source>queue tree add max-limit=$interfaceBandwidth name=QoS_global parent=global priority=1
:for indexA from=1 to=4 do={
   /queue tree add \ 
      name=( "prio_" . "$indexA" ) \
      parent=QoS_global \
      priority=($indexA) \
      queue=ethernet-default \
      packet-mark=("prio_" . $indexA) \
      comment=("Priority " . $indexA . " traffic")
}
/queue tree add name="prio_5" parent=QoS_global priority=5 \
    queue=ethernet-default packet-mark=no-mark comment="Priority 5 traffic"

И последнее, коль скоро Mikrotik поддерживает WMM, было бы логично разметить трафик и для него.

Делается это тем же mangle-ом с помощью команды set_priority. Согласно wiki Mikrotik'а, таблица приоритетов WMM выглядит довольно причудливо:

1,2 — background
0,3 — best effort
4,5 — video
6,7 — voice.

Разметим приоритеты, используя те же правила, что и для маркировки пакетов:

/ip firewall mangle
# prio_1
    add chain=prerouting action=set-priority new-priority=7 protocol=icmp
    add chain=prerouting action=set-priority new-priority=7 protocol=tcp port=53
    add chain=prerouting action=set-priority new-priority=7 protocol=udp port=53
    add chain=prerouting action=set-priority new-priority=7 protocol=tcp tcp-flags=ack packet-size=0-123
# prio_2
    add chain=prerouting action=set-priority new-priority=6 dscp=40                                     
    add chain=prerouting action=set-priority new-priority=6 dscp=46
    add chain=prerouting action=set-priority new-priority=6 protocol=udp port=5060,5061,10000-20000 src-address=192.168.100.110
    add chain=prerouting action=set-priority new-priority=6 protocol=udp port=5060,5061,10000-20000 dst-address=192.168.100.110
# prio_3
    add chain=prerouting action=set-priority new-priority=5 protocol=tcp port=22
    add chain=prerouting action=mark-packet new-packet-mark=prio_3 src-address-list=WoT
    add chain=prerouting action=mark-packet new-packet-mark=prio_3 dst-address-list=WoT
# prio_4
    add chain=prerouting action=set-priority new-priority=3 protocol=tcp port=3389

В принципе, на этом всё.

В будущем, при необходимости, можно подумать о формировании динамических адресных листов, периодически формируемых из кэша DNS скриптами типа:

:foreach i in=[/ip dns cache all find where (name~"youtube" || name~"facebook" || name~".googlevideo")]
    do={:put [/ip dns cache get $i address]}

для отбора онлайнового видео.

Или детектить Skype с помощью поиска upnp-правил:

:foreach i in=[/ip firewall nat find dynamic and comment~"Skype"]
    do={:put [/ip firewall nat get $i dst-port]}

Но пока у меня такой необходимости нет.

Скрипты из статьи доступны на GitHub'е. Если у вас что-то не заработало, есть идеи или комментарии — пишите.

Спасибо за внимание!

UPD: В исходной версии статьи в скриптах была ошибка (неверно выбранная цепочка). Скрипты исправлены.
Tags:
Hubs:
+15
Comments 27
Comments Comments 27

Articles