Прежде чем объяснять саму суть, расскажу кейс, чтобы было понятнее где можно применять.

Мне необходимо было, при подключении vpn клиента PPP* создать QoS очереди, кто-то из вас наверное скажет "ПФ... это же делается в profile пользователя PPP" конечно он будет прав, но у меня был немного другой кейс.

Для каждого клиента выделялась своя максимальная полоса, и трафик необходимо было делить по приоритетам и должна использоваться прямая реализация HTB, а точнее Queue Tree.

Клиенты все динамические, порядка 300 пользователей.

В чём смысл!

Существует сеть филиалов, которые подключаются к VPN серверу с помощью PPP* туннеля и ширина канала клиента лимитированна и находиться в диапазоне 2-50Mbps. Необходимо сделать так, чтобы можно было выделять приоритет для определённого трафика.

Подготовка

Для начало необходимо подготовить очередь, так чтобы было понимание, что мы будет делать динамически.

Создадим очередь для одного из клиентов

/queue tree
add max-limit=20M name=B011-Global parent=l2tp-B011
add max-limit=20M name=B011-p1 packet-mark=p1 parent=B011-Global priority=1
add max-limit=20M name=B011-p2 packet-mark=p2 parent=B011-Global priority=2
add max-limit=20M name=B011-p3 packet-mark=p3 parent=B011-Global priority=3
add max-limit=20M name=B011-p4 packet-mark=p4 parent=B011-Global priority=4
add max-limit=20M name=B011-p5 packet-mark=p5 parent=B011-Global priority=5
add max-limit=20M name=B011-p6 packet-mark=p6 parent=B011-Global priority=6
add max-limit=20M name=B011-p7 packet-mark=p7 parent=B011-Global priority=7
add max-limit=20M name=B011-p8 packet-mark=p8,no-mark parent=B011-Global

Вроде нечего сложного, смысл такой. У нас есть родитель который смотрит непосредственно на interface нашего PPP* клиента, у очереди есть max-limit и у родителя есть наследники, непосредственно очереди которые работают с маркированная пакетами и последняя очередь работает как для маркированных пакетов, так и непосредственно для пакетов без маркировки (по умолчанию).

Теперь нам необходимо маркировать пакеты.

/ip firewall mangle
add chain=mrkPPP action=mark-packet new-packet-mark=p1 passthrough=no protocol=ospf
add chain=mrkPPP action=mark-packet dscp=26 new-packet-mark=p2 passthrough=no protocol=udp
add chain=mrkPPP action=mark-packet dscp=46 new-packet-mark=p2 passthrough=no protocol=udp
add chain=mrkPPP action=mark-packet new-packet-mark=p2 passthrough=no protocol=icmp
add chain=mrkPPP action=mark-packet dst-port=8291 new-packet-mark=p3 passthrough=no protocol=tcp
add chain=mrkPPP action=mark-packet dst-port=22 new-packet-mark=p3 passthrough=no protocol=tcp
add chain=mrkPPP action=mark-packet new-packet-mark=p5 passthrough=no protocol=tcp src-address=10.200.1.100 src-port=80,443

Вкратце, у нас есть некая кастомная цепочка mrkPPP в которой определяется какому пакету установить необходимую марку. Соответственно в очереди родитель будет учитывать данную марку и распределяться приоритет среди своих наследников.

Пояснение

add chain=mrkPPP action=mark-packet dscp=26 new-packet-mark=p2 passthrough=no protocol=udp
add chain=mrkPPP action=mark-packet dscp=46 new-packet-mark=p2 passthrough=no protocol=udp

Маркируем пакеты телефонии SIP сигнализация и медиа поток, и помечаем их как марка p2. Далее маркируем по необходимости. Например трафик tcp для WInBox и SSH и так далее по необходимости.

Автоматизация

Проблема как бы есть и как бы её нет. В чем собственно проблема, проблема в том, что мне не хочется делать всё руками, а хочется какой-то автоматизации, а также упрощённая настройка для тех кто будет настраивать.

Нам необходимо подготовить профили для пользователей.

/ppp profile
add interface-list=vpn-tun local-address=172.29.201.1 name=vpn-tun-2M only-one=yes remote-address=pool-vpn use-compression=no use-encryption=no use-mpls=no use-upnp=no

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

/ip firewall mangle
add action=jump chain=postrouting jump-target=mrkPPP out-interface-list=vpn-tun

Все пакеты, которые уходят (postrouting) в сторону любого из интерфейса в листе vpn-tun будут обрабатываться в кастомной цепочке mrkPPP и на пакеты будут устанавливаться необходимые маркировки. (p1,p2,p3....)

Отлично, нам нет необходимости городить кучу правил, одна цепочка на все туннели, но что делать с пропускной способностью, у всех туннелей она разная.

Подготовим скрипт.

Нам необходимо создать скрипт и поместить его в в стандартный раздел скриптов дайте ему имя qtreevpn

/queue tree
remove [find comment=$user]
add comment=$user parent=$interface max-limit=$limit name="$user-Global"
add comment=$user parent="$user-Global" max-limit=$limit name="$user-p1" packet-mark=p1 priority=1
add comment=$user parent="$user-Global" max-limit=$limit name="$user-p2" packet-mark=p2 priority=2
add comment=$user parent="$user-Global" max-limit=$limit name="$user-p3" packet-mark=p3 priority=3
add comment=$user parent="$user-Global" max-limit=$limit name="$user-p4" packet-mark=p4 priority=4
add comment=$user parent="$user-Global" max-limit=$limit name="$user-p5" packet-mark=p5 priority=5
add comment=$user parent="$user-Global" max-limit=$limit name="$user-p6" packet-mark=p6 priority=6
add comment=$user parent="$user-Global" max-limit=$limit name="$user-p7" packet-mark=p7 priority=7
add comment=$user parent="$user-Global" max-limit=$limit name="$user-p8" packet-mark=p8,no-mark priority=8
}

Ну а теперь самый смак.

Профиль

Данный функционал расписан на wiki, но не очевиден. Мы можем обратиться к скрипту как к функции и передать её аргументы. В каждом профиле согласно его имени в разделе on-up будет выполнен скрипт, при успешном соединении.

Зададим переменную в которой хранится скорость нашего клиента, для каждого профиля значение переменной будет уникальное.

:local limit "5M"

Далее нам необходимо получить содержимое скрипта в переменную.

:local qtree [:parse [/system script get "qtreevpn" source]];

А дальше нам необходимо выполнить скрип с переданными аргументами

$qtree limit=$limit user=$interface

Что в итоге

Каждому пользователю назначен свой профиль, где в разделе "выполнить скрипт при подключении" указанная примерно следующее, меняется только значение переменной limit.

:local limit "5M"
:local qtree [:parse [/system script get "qtreevpn" source]];
$qtree limit=$limit user=$interface

Выполняется скрипт, который создаёт необходимые очереди. Интерфейс клиента добавляется в interface-list и правило mangle устанавливает необходимую маркировку на трафик.

Ответы на вопросы)))

  • Нет эта не вся настройка, естественно со стороны клиента тоже были очереди.
  • Естественно файрвол был настроен, но статья не об этом.
  • Да в скрипте стоит "удалять все очереди", что может приводить к износу флешки, вы можете переписать скрипт, так чтобы он проверял наличие очередей, проверял их актуальность и не изменяло в случае необходимости.
  • Нет не обязательно маркировать соединения, в данном кейсе вообще connection-tracker был отключен.
  • Типы трафика которые маркируется приведён как пример, вы самостоятельно должны определить для себя какой трафик и как должен маркироваться.
  • Да будут оставаться "мёртвые очереди", можете их удалять каким-нибудь другим скриптом.

Рассказать друзьям

Чатик телеграм

@mikrotikme