Появления Роутер ОС 7 давно ждали. Новая система создавалась разумеется для более производительных устройств, имеющих новые процессоры и больше оперативной памяти. Новое ядро Linux, поддержка WireGuard и ZieroTier, новые возможности маршрутизации и BGP, новый users manager, обновление MPLS, запуск приложений в контейнерах далеко не полный список новинок.
Но в этой статье мы будем обсуждать нововведения только в скриптовом языке системы вплоть до актуальной beta версии 7.12.
Итак версия 7 (по состоянию на 7.12 beta 3) получила несколько новых команд:
:timestamp
Необходимость команды полностью очевидна. Вся работа со временем должна проводиться через вычисление универсального времени UNIX, равного числу секунд, прошедших с полуночи (00:00:00 UTC) 1 января 1970 года; этот момент называют «эпохой Unix». Ранее, в том числе во всех ветках Роутер ОС 6, приходилось програмно вычислять UNIX time с помощью весьма объемного скрипта. Теперь для этого достаточно всего одной команды:
которая вычисляет Unix time с учетом часового пояса пользователя (GMT offset) не считая секунды високосных лет.
Правда формат вывода мне не нравится. Не знаю зачем, то в Рос 7 изменился и сам формат времени. Разработчики РоутерОС зачем то поддерживают вычисление количества недель.
Команда, приведенная выше выдает:
2801w06:05:12.725909345
Ну и как это понимать?
Для читабельности можно воспользоваться ещё одной новинкой – командой :tonsec. Обратите внимание, именно :tonsec, а не :tosec. Команда преобразует аргумент в количество наносекунд. Таким образом, для вычислений можно использовать такое преобразование:
Получим такой результат:
1694066733047820422
По сути, без учета GMT
Следующее нововведение – команда :rndnum служит для генерации случайного числа. Без параметров использоваться не может и требует указания диапазона, из которого нужно выбрать случайное число.
:rndnum from=[num] to=[num]
Например:
Вывод:
17
Целесообразна для генерации ключей, паролей, выборки случайных значений из диапазона для чего угодно.
:rndstr from=[str] length=[num]
Команда генерации случайной строки. Может использоваться без параметра length, тогда длина строки устанавливается по умолчанию 16 символов.
e^&b^accaefcbf&b%^%e&ac%feda%&%ac
Символы для генерации берутся только из указанных в «from=». Команда также очень полезна для генерации ключей и паролей.
Например, генерация случайного МАК-адреса теперь может быть проще, чем в Роутер ОС 6 (примеры взяты из этого поста официального форума Микротик:
Или вообще скриптом в одну строку:
:retry command= delay=[num] max=[num] on-error=
Новая команда :retry призвана обеспечить выполнения инструкций в блоке «command» с максимальным количеством попыток, указанном в параметре max= с заданной задержкой между попытками delay=. При ошибке исполнения блока command выполняется блок on-error={}
Например:
# Mikrotik
Или:
# trying…
# trying…
# trying…
# I give up!
:jobname
Наконец-то появилась команда позволяющая без «танцев с бубнами» узнать имя исполняемого скрипта.
Ранее, в Роутер ОС версии 6, для этого можно было использовать такой трюк (автор Rextended, https://forum.mikrotik.com/viewtopic.php?t=197314#p1009493):
Скрипт искал своё имя по уникальной метке в собственном «теле».
Теперь, в Роутер ОС 7 можно так:
Или просто из кода скрипта
Подошли к самой сложной новой команде :convert from=[arg] to=[arg] transform=
Команда преобразует указанное значение из одного формата в другой. По умолчанию используется автоматически проанализированное значение, если формат «from» не указан (например, «001» становится «1», «10.1» становится «10.0.0.1» и т.д.). Опция transforme по умолчанию не используется, что эквивалентно transforme=none. При указании transforme=reverse преобразуемые данные переворачиваются.
from задает формат значения — base32, base64, hex, raw, rot13, uri.
to указывает формат выходного значения — base32, base64, hex, raw, rot13, uri.
Примеры:
31
MikroTik
# YWJjZA==
# abcd
# dcba
# 64636261
Часть новых команд коснулась только консоли.
Для упрощения ввода значений появилась новая инструкция
:terminal/ask preinput= prompt= , позволяющая вводить значения после выдаваемого в терминал preinput с приглашением из параметра prompt.
Например:
В данном случае preinput даётся без самого кодового слова, а prompt опущен.
Чтобы ввести строку из Терминала, в том числе в обоих ветках системы (6 и 7) конечно, можно написать небольшой скрипт с использованием :terminal inkey типа такого:
Эта небольшая локальная функция позволяет ввести строку длиной до 254 символов посимвольно. В этом примере ввод прекращается, если пользователь нажимает клавишу «Enter» (код клавиши Enter=$0D (13). Разумеется посимвольный ввод позволяет использовать для конца ввода любые другие ограничения (например другой символ окончания или количество вводимых символов), что позволяет наиболее гибко настроить ввод.
Её можно дополнить разными плюшками с моментальной проверкой вводимых символов, ограничивать длину формируемой строки и.т.д…
Но, если нужно проще и быстрее можно использовать такую фичу:
Работает это так:
Enter login
value: admin
Enter password
value: test
Login is [admin] and password is [test]
Фишка в том, что пустой :return из Терминала всегда предлагает ввести значение. Окончанием ввода обязательно служит клавиша «Enter».Единственным неудобством будет вывод слова «value:» в качестве приглашения перед вводом, но если это не раздражает, то всё нормально работает.
Удобно использовать из интерактивных скриптов настройки конфигураций и т.д…
В Роутер ОС 7, начиная с версии 7.11 появилась ещё одна возможность — использование :terminal ask. Эта новая команда лишена неудобства, связанного с выводом приглашения ко вводу значения :value. Окончанием ввода также обязательно служит клавиша «Enter».
Ну или как-то так (для примера):
Можно также задавать любое приглашение ко вводу, если использовать параметр «preinput»:
Очень полезная новая команда:
:console/inspect as-value request= path=
Инструкция позволяет запросить список команд и параметров дочернего меню.
Гуру официального форума Микротик Amm0 написал скрипт, выполняющий обход всего дерева команд Роутер ОС и получающий список всех команд, параметров и их типов:
add=.id=*2;name=add;node-type=cmd;type=child;comment=.id=*3;name=comment;node-type
=cmd;type=child;disable=.id=*4;name=disable;node-type=cmd;type=child;edit=.id=*5;n
ame=edit;node-type=cmd;type=child;enable=.id=*6;name=enable;node-type=cmd;type=chi
ld;export=.id=*7;name=export;node-type=cmd;type=child;find=.id=*8;name=find;node-t
ype=cmd;type=child;get=.id=*9;name=get;node-type=cmd;type=child;print=.id=*a;name=
print;node-type=cmd;type=child;remove=.id=*b;name=remove;node-type=cmd;type=child;
reset=.id=*c;name=reset;node-type=cmd;type=child;set=.id=*d;name=set;node-type=cmd
;type=child
У :console inspect есть и другие возможности (подробнее см. тут)
Ещё одна новая инструкция консоли :task по слухам аналогична инструкциям Linux jobs, fg и bg, позволяющими узнать какой процесс выполняется, переместить процесс в фон или наоборот выдвинуть на первый план и т д… Но пока точных данных как работает команда и какие параметры имеет у меня нет.
Некоторые изменения коснулись команды :execute. Она получила новый атрибут «as-string», которая делает исполнение команды синхронным (например, ожидает завершения скрипта, прежде чем вернуться с новым «as-string»).
Также в версии 7 введена опция "as-value" для "/tool /snmp-get", которая может получать значения из SNMP OID в скрипт без синтаксического анализа, требуемого в версии 6:
# oid=1.3.6.1.2.1.2.2.1.2.1;type=octet-string;value=ether1
# ether1
Наконец улучшена работа консоли при создании сложных массивов:
*) console — improved multi-argument property parsing into array;
Не знаю, что конкретно разработчики Микротик имели ввиду, но гуру форума Микиротик уверяют, что сложные массивы в РОС 7 перестали «рассыпаться на указатели», теперь при копировании массива происходит именно его копирование в памяти (мы ведь помним, что у новых устройств Микротик оперативной памяти теперь хватает !), а не создания указателя. То есть массивы — это копии в версии 7, а не «указатели». Можно говорить о («передаче по значению» в версии 7, вместо «передаче по ссылке» в версии 6).
Наглядно проблему иллюстрирует следующий скрипт:
На более простом примере, которым любезно поделился Amm0: если мы возьмем простой массив с дочерним массивом внутри. Наибольшее внутреннее значение, ca, начинается с «2», и мы создаем новый массив, используя часть первого, затем устанавливаем внутреннее значение подмассива равным 1:
В версии Роутер ОС 6 «mysubarray» фактически ссылается на родительский массив, поэтому при установке значения «mysubarray» родительское значение «myarray» также обновляется:
# true
В версии 7 это изменилось, поэтому mysubarray является копией исходного массива, поэтому обновления не влияют на myarray. Таким образом, ":set" устанавливает только тот, который находится в подмассиве. Таким образом, «родительский» массив остается с использованием его исходного значения 2, а не обновленного 1.
# true
Дополнительно хочу сообщить новость, касающуюся обоих веток системы и 6 и 7. Недавно пользователь fludorkin обнаружил новый (не документированный) тип данных Роутер ОС – op:
op
В последующем этот тип данных был проанализирован и высказано предположение, что «op» возможно означает «only pointer» (только указатель), а конструкция служит ярлыком для обращения к элементам сложных ассоциативных массивов, в том числе если их элементами являются функции. Подробнее об этом можно прочитать тут и тут.
На этом пока всё. Мы рады, что наконец-то разработчики Микротик снизошли до улучшений скриптового языка. Видимо раньше руки им сильно связывало недостаточное количество оперативной памяти у старых RouterBoard, что было преодолено с выходом новых устройств, таких как RB5009, HAP AX2 и HAP AX3, L009 и т д… Хотелось бы пожелать им успехов, пожелать вносить изменения и дополнения системно и аккуратно, чтобы не нарушить работу системы и, конечно, подробно документировать свои разработки. Излишне говорить, что описания изменений бета-версий обкатываются и не помещаются в официальные руководства до выхода stable-версий. Все желающие, прочитавшие данную статью, могут в коментариях оставить свои предложения по улучшению скриптового языка Микротик. Мы обязательно обсудим достойные внимания из них на официальном форуме.
Но в этой статье мы будем обсуждать нововведения только в скриптовом языке системы вплоть до актуальной beta версии 7.12.
Итак версия 7 (по состоянию на 7.12 beta 3) получила несколько новых команд:
:timestamp
Необходимость команды полностью очевидна. Вся работа со временем должна проводиться через вычисление универсального времени UNIX, равного числу секунд, прошедших с полуночи (00:00:00 UTC) 1 января 1970 года; этот момент называют «эпохой Unix». Ранее, в том числе во всех ветках Роутер ОС 6, приходилось програмно вычислять UNIX time с помощью весьма объемного скрипта. Теперь для этого достаточно всего одной команды:
:put [:timestamp]
которая вычисляет Unix time с учетом часового пояса пользователя (GMT offset) не считая секунды високосных лет.
Правда формат вывода мне не нравится. Не знаю зачем, то в Рос 7 изменился и сам формат времени. Разработчики РоутерОС зачем то поддерживают вычисление количества недель.
Команда, приведенная выше выдает:
2801w06:05:12.725909345
Ну и как это понимать?
Для читабельности можно воспользоваться ещё одной новинкой – командой :tonsec. Обратите внимание, именно :tonsec, а не :tosec. Команда преобразует аргумент в количество наносекунд. Таким образом, для вычислений можно использовать такое преобразование:
:put [:tonsec [:timestamp]]
Получим такой результат:
1694066733047820422
По сути, без учета GMT
[:tonsec [:timestamp] = [:tonsec ([:totime [/system clock get date]]+[/system clock get time])]
Следующее нововведение – команда :rndnum служит для генерации случайного числа. Без параметров использоваться не может и требует указания диапазона, из которого нужно выбрать случайное число.
:rndnum from=[num] to=[num]
Например:
:put [:rndnum from=1 to=99]
Вывод:
17
Целесообразна для генерации ключей, паролей, выборки случайных значений из диапазона для чего угодно.
:rndstr from=[str] length=[num]
Команда генерации случайной строки. Может использоваться без параметра length, тогда длина строки устанавливается по умолчанию 16 символов.
:put [:rndstr from="abcdef%^&" length=33]
e^&b^accaefcbf&b%^%e&ac%feda%&%ac
Символы для генерации берутся только из указанных в «from=». Команда также очень полезна для генерации ключей и паролей.
Например, генерация случайного МАК-адреса теперь может быть проще, чем в Роутер ОС 6 (примеры взяты из этого поста официального форума Микротик:
{ :local array { "c8:ea:f8"; "70:9f:2d"; "38:3b:26"; "5c:fa:fb"; "9c:7b:ef" } :local part1 ($array->[:rndnum from=0 to=([:len $array]-1)]) :local hex1 [:rndstr length=6 from="0123456789abcdef"] :local part2 ([:pick $hex1 0 2].":".[:pick $hex1 2 4].":".[:pick $hex1 4 6]) :local Mac ($part1.":".$part2) :put $Mac }
Или вообще скриптом в одну строку:
:put "$[:rndstr length=1 from="0123456789ABCDEF"]$[:rndstr length=1 from="048C"]$[:rndstr length=10 from="0123456789ABCDEF"]"
:retry command= delay=[num] max=[num] on-error=
Новая команда :retry призвана обеспечить выполнения инструкций в блоке «command» с максимальным количеством попыток, указанном в параметре max= с заданной задержкой между попытками delay=. При ошибке исполнения блока command выполняется блок on-error={}
Например:
:retry delay=1s max=3 on-error={:put "got an error"} command={:put [/system/identity/get name]}
# Mikrotik
Или:
:retry delay=1s max=3 on-error={:put "I give up!"} command={:put "trying..."; :error "cause error"}
# trying…
# trying…
# trying…
# I give up!
:jobname
Наконец-то появилась команда позволяющая без «танцев с бубнами» узнать имя исполняемого скрипта.
Ранее, в Роутер ОС версии 6, для этого можно было использовать такой трюк (автор Rextended, https://forum.mikrotik.com/viewtopic.php?t=197314#p1009493):
:local UniqueScriptID "QnJhdm8h" :local ThisScriptName [/system script get ([find where source~"$UniqueScriptID"]->0) name] :local AlreadyRunning "Script $ThisScriptName already running" :if ([:len [/system script job find where script=$ThisScriptName]] > 1) do={:log error $AlreadyRunning; :error $AlreadyRunning}
Скрипт искал своё имя по уникальной метке в собственном «теле».
Теперь, в Роутер ОС 7 можно так:
/system script add name=log-jobname source=\"/log info \"\$[:jobname]\""
Или просто из кода скрипта
:log info [:jobname]
Подошли к самой сложной новой команде :convert from=[arg] to=[arg] transform=
Команда преобразует указанное значение из одного формата в другой. По умолчанию используется автоматически проанализированное значение, если формат «from» не указан (например, «001» становится «1», «10.1» становится «10.0.0.1» и т.д.). Опция transforme по умолчанию не используется, что эквивалентно transforme=none. При указании transforme=reverse преобразуемые данные переворачиваются.
from задает формат значения — base32, base64, hex, raw, rot13, uri.
to указывает формат выходного значения — base32, base64, hex, raw, rot13, uri.
Примеры:
:put [:convert 001 to=hex ]
31
:put [:convert [/ip dhcp-client/option/get hostname raw-value] from=hex to=raw ]
MikroTik
:put [:convert "abcd" to=base64]
# YWJjZA==
:put [:convert from=base64 "YWJjZA==" ]
# abcd
:put [:convert from=base64 "YWJjZA==" transform=reverse]
# dcba
:put [:convert from=base64 "YWJjZA==" transform=reverse to=hex]
# 64636261
Часть новых команд коснулась только консоли.
Для упрощения ввода значений появилась новая инструкция
:terminal/ask preinput= prompt= , позволяющая вводить значения после выдаваемого в терминал preinput с приглашением из параметра prompt.
Например:
:put [:terminal/ask "Do you agree to use Router OS 7?"]
В данном случае preinput даётся без самого кодового слова, а prompt опущен.
Чтобы ввести строку из Терминала, в том числе в обоих ветках системы (6 и 7) конечно, можно написать небольшой скрипт с использованием :terminal inkey типа такого:
:local EnterString do={ :local cont; :local string :while ($cont!=13) do={ :if ([:len $string]<254) do={ :local key ([:terminal inkey]) :if ($key!=13) do={ :local char [[:parse "(\"\\$[:pick "0123456789ABCDEF" (($key >> 4) & 0xF)]$[:pick "0123456789ABCDEF" ($key & 0xF)]\")"]] :set string ("$string"."$char")} :set cont $key } } :return $string}
Эта небольшая локальная функция позволяет ввести строку длиной до 254 символов посимвольно. В этом примере ввод прекращается, если пользователь нажимает клавишу «Enter» (код клавиши Enter=$0D (13). Разумеется посимвольный ввод позволяет использовать для конца ввода любые другие ограничения (например другой символ окончания или количество вводимых символов), что позволяет наиболее гибко настроить ввод.
Её можно дополнить разными плюшками с моментальной проверкой вводимых символов, ограничивать длину формируемой строки и.т.д…
Но, если нужно проще и быстрее можно использовать такую фичу:
:local input do={:put $1; :return;} :local login [$input "Enter login:"] :local password [$input "Enter password:"] :put "Login is [$login] and password is [$password]"
Работает это так:
Enter login
value: admin
Enter password
value: test
Login is [admin] and password is [test]
Фишка в том, что пустой :return из Терминала всегда предлагает ввести значение. Окончанием ввода обязательно служит клавиша «Enter».Единственным неудобством будет вывод слова «value:» в качестве приглашения перед вводом, но если это не раздражает, то всё нормально работает.
Удобно использовать из интерактивных скриптов настройки конфигураций и т.д…
В Роутер ОС 7, начиная с версии 7.11 появилась ещё одна возможность — использование :terminal ask. Эта новая команда лишена неудобства, связанного с выводом приглашения ко вводу значения :value. Окончанием ввода также обязательно служит клавиша «Enter».
:global Answer [:terminal/ask "Do you agree to use Router OS 7?"] :put $Answer
Ну или как-то так (для примера):
{ :global Answer [] :while ($Answer!="yes") do={ :set Answer [:terminal/ask "Do you agree to use Router OS 7?"] } }
Можно также задавать любое приглашение ко вводу, если использовать параметр «preinput»:
:global userinput [/terminal/ask preinput="preinput>" prompt="Some text that in prompt"]
Очень полезная новая команда:
:console/inspect as-value request= path=
Инструкция позволяет запросить список команд и параметров дочернего меню.
Гуру официального форума Микротик Amm0 написал скрипт, выполняющий обход всего дерева команд Роутер ОС и получающий список всех команд, параметров и их типов:
:global ast [:toarray ""] :global mkast do={ :global mkast :global ast :local path "" :if ([:typeof $1] ~ "str|array") do={ :set path $1 } :local pchild [/console/inspect as-value request=child path=$path] :foreach k,v in=$pchild do={ :if (($v->"type") = "child") do={ :local astkey "" :local arrpath [:toarray $path] :foreach part in=$arrpath do={ :set astkey "$astkey/$part" } :set ($ast->$astkey->($v->"name")) $v :put "Processing: $astkey $($v->"name") $($v->"node-type")" :local newpath "$($path),$($v->"name")" # TODO use [/console/inspect as-value request=syntax path=$path] [$mkast $newpath] } } return $ast } # & this call start the recursion :put [$mkast]
:put ($ast->"/ip/address")
add=.id=*2;name=add;node-type=cmd;type=child;comment=.id=*3;name=comment;node-type
=cmd;type=child;disable=.id=*4;name=disable;node-type=cmd;type=child;edit=.id=*5;n
ame=edit;node-type=cmd;type=child;enable=.id=*6;name=enable;node-type=cmd;type=chi
ld;export=.id=*7;name=export;node-type=cmd;type=child;find=.id=*8;name=find;node-t
ype=cmd;type=child;get=.id=*9;name=get;node-type=cmd;type=child;print=.id=*a;name=
print;node-type=cmd;type=child;remove=.id=*b;name=remove;node-type=cmd;type=child;
reset=.id=*c;name=reset;node-type=cmd;type=child;set=.id=*d;name=set;node-type=cmd
;type=child
У :console inspect есть и другие возможности (подробнее см. тут)
Ещё одна новая инструкция консоли :task по слухам аналогична инструкциям Linux jobs, fg и bg, позволяющими узнать какой процесс выполняется, переместить процесс в фон или наоборот выдвинуть на первый план и т д… Но пока точных данных как работает команда и какие параметры имеет у меня нет.
Некоторые изменения коснулись команды :execute. Она получила новый атрибут «as-string», которая делает исполнение команды синхронным (например, ожидает завершения скрипта, прежде чем вернуться с новым «as-string»).
Также в версии 7 введена опция "as-value" для "/tool /snmp-get", которая может получать значения из SNMP OID в скрипт без синтаксического анализа, требуемого в версии 6:
{ :local interfaceOneName [/tool/snmp-get oid=.1.3.6.1.2.1.2.2.1.2.1 address=127.0.0.1 community=public as-value] :put $interfaceOneName :put ($interfaceOneName->"value") }
# oid=1.3.6.1.2.1.2.2.1.2.1;type=octet-string;value=ether1
# ether1
Наконец улучшена работа консоли при создании сложных массивов:
*) console — improved multi-argument property parsing into array;
Не знаю, что конкретно разработчики Микротик имели ввиду, но гуру форума Микиротик уверяют, что сложные массивы в РОС 7 перестали «рассыпаться на указатели», теперь при копировании массива происходит именно его копирование в памяти (мы ведь помним, что у новых устройств Микротик оперативной памяти теперь хватает !), а не создания указателя. То есть массивы — это копии в версии 7, а не «указатели». Можно говорить о («передаче по значению» в версии 7, вместо «передаче по ссылке» в версии 6).
Наглядно проблему иллюстрирует следующий скрипт:
# the mother array :global aGlobalArray ({}); # function to add a sub-array, defined locally, to the global array :global popData do={ :global aGlobalArray; :local subObj ({soname="soname-orig"; sodata="sodata-orig"}); :set ($aGlobalArray->"sub-obj-1") $subObj; :return "OK"; } :log info "Populate and log"; :local pop [$popData]; :foreach key,value in=$aGlobalArray do={ :log info ("[key:".$key."] soname:".($value->"soname")." | sodata:".($value->"sodata")); # result [key:sub-obj-1] soname:soname-orig | sodata:sodata-orig } :log info "Modify subjobj and log"; :foreach key,value in=$aGlobalArray do={ :set ($value->"sodata") "sodata-modified"; # logging the data here shows it is modified # Adding this line fixes the issue for v7 but is not needed in v6 # :set ($aGlobalArray->"$key") $value; } :foreach key,value in=$aGlobalArray do={ :log info ("[key:".$key."] soname:".($value->"soname")." | sodata:".($value->"sodata")); # v6 result [key:sub-obj-1] soname:soname-orig | sodata:sodata-modified # v7 result [key:sub-obj-1] soname:soname-orig | sodata:sodata-orig }
На более простом примере, которым любезно поделился Amm0: если мы возьмем простой массив с дочерним массивом внутри. Наибольшее внутреннее значение, ca, начинается с «2», и мы создаем новый массив, используя часть первого, затем устанавливаем внутреннее значение подмассива равным 1:
:global myarray {a=1;child={ca=2}} :global mysubarray ($myarray->"child") :set ($mysubarray->"ca") 1
В версии Роутер ОС 6 «mysubarray» фактически ссылается на родительский массив, поэтому при установке значения «mysubarray» родительское значение «myarray» также обновляется:
:put ( ($myarray->"child"->"ca") = 1)
# true
В версии 7 это изменилось, поэтому mysubarray является копией исходного массива, поэтому обновления не влияют на myarray. Таким образом, ":set" устанавливает только тот, который находится в подмассиве. Таким образом, «родительский» массив остается с использованием его исходного значения 2, а не обновленного 1.
:put ( ($myarray->"child"->"ca") = 2)
# true
Дополнительно хочу сообщить новость, касающуюся обоих веток системы и 6 и 7. Недавно пользователь fludorkin обнаружил новый (не документированный) тип данных Роутер ОС – op:
:put [:typeof (>[])]
op
В последующем этот тип данных был проанализирован и высказано предположение, что «op» возможно означает «only pointer» (только указатель), а конструкция служит ярлыком для обращения к элементам сложных ассоциативных массивов, в том числе если их элементами являются функции. Подробнее об этом можно прочитать тут и тут.
На этом пока всё. Мы рады, что наконец-то разработчики Микротик снизошли до улучшений скриптового языка. Видимо раньше руки им сильно связывало недостаточное количество оперативной памяти у старых RouterBoard, что было преодолено с выходом новых устройств, таких как RB5009, HAP AX2 и HAP AX3, L009 и т д… Хотелось бы пожелать им успехов, пожелать вносить изменения и дополнения системно и аккуратно, чтобы не нарушить работу системы и, конечно, подробно документировать свои разработки. Излишне говорить, что описания изменений бета-версий обкатываются и не помещаются в официальные руководства до выхода stable-версий. Все желающие, прочитавшие данную статью, могут в коментариях оставить свои предложения по улучшению скриптового языка Микротик. Мы обязательно обсудим достойные внимания из них на официальном форуме.
