Community discussions

MikroTik App
 
User avatar
lapsio
Long time Member
Long time Member
Topic Author
Posts: 514
Joined: Wed Feb 24, 2016 5:19 pm

Script "fixing" slow CRS3xx LEDs

Mon Apr 01, 2019 1:36 am

So I asked MikroTik support why LEDs in CRS3xx are so slow and if they're gonna do anything about it. They said that LEDs are controlled by CPU thus they're so slow and that newer CRS3xx devices will have LEDs controlled by switch chips itself so LEDs won't be slow but won't be programmable either.

When I heard that they're gonna make LEDs non-programmable I was like HELL NO. And decided to do what MikroTik probably should do from very beginning - simulate faster LEDs in software to keep best of both worlds - programmable LEDs AND fast blinking LEDs. I'm aware it's not really "correct" solution because it kinda... makes up data basing on 1s interval read but I hope many people will still find it useful. Current implementation of LEDs in CRS3xx switches blinks like once every 2 seconds so sometimes it's really hard to tell whether there's actually any traffic since it's easy to miss that 1 blink every 2 seconds lol...

So here's code. LED blinker for sfp ports (CRS317, CRS326)

add name=ledblinkersfp source="/interface ethernet\
    \n\
    \n:local cycletime 1000\
    \n:local cyclenum 2\
    \n:local blinkpercycle 8\
    \n:local blinkparts 3\
    \n:local ifmatch \"sfp-sfpplus\"\
    \n:local instance \"ledblinkersfp\"\
    \n:local ledsuffix \"-led1\"\
    \n\
    \n######\
    \n\
    \n\
    \n:local pstat ({})\
    \n\
    \n:while ([:len [/system script job find script=\$instance]] = 1) do={\
    \n\
    \n    :local iflst [find name~(\$ifmatch) running=yes]\
    \n    :local ledlst ({})\
    \n\
    \n    :local blinkshort (\$cycletime / \$blinkpercycle)\
    \n    :local blinkshortoff (\$blinkshort / \$blinkparts)\
    \n    :local blinkshorton (\$blinkshortoff * (\$blinkparts -1))\
    \n\
    \n    :local realblinkshorton (\$blinkshorton - 50)\
    \n    :if (\$realblinkshorton < 0) do={\
    \n        :set realblinkshorton 0\
    \n    }\
    \n\
    \n    /system leds set [find name~(\$ifmatch) running=no] type=interface-activity\
    \n    :if ([:len \$iflst] != [:len \$pstat]) do={\
    \n        :set pstat ({})\
    \n        :foreach counter=i in=\$iflst do={\
    \n            :set pstat (\$pstat,\"0/0\")\
    \n        }\
    \n    }\
    \n\
    \n    :foreach counter=k,i in=\$iflst do={\
    \n        :local iname [get \$i name]    \
    \n        :local iled [/system leds find leds=(\$iname.\$ledsuffix)]\
    \n        :set ledlst (\$ledlst, \$iled)\
    \n    }\
    \n\
    \n\
    \n    :for counter=loop from=1 to=\$cyclenum do={        \
    \n        :local cstat ({})\
    \n        :local blinklst ({})\
    \n\
    \n        :foreach counter=k,i in=\$iflst do={\
    \n            :local istat ([get \$i rx-bytes].\"/\".[get \$i tx-bytes])\
    \n            :local iled (\$ledlst->\$k)\
    \n            :set cstat (\$cstat, \$istat)\
    \n            :if (\$istat != (\$pstat->\$k)) do={\
    \n                :set blinklst (\$blinklst, (\$iled))\
    \n            }\
    \n        }\
    \n        :for counter=i from=0 to=(\$cycletime / \$blinkshort - 1) do={\
    \n            :if (\$i = 0) do={\
    \n                :delay delay-time=((\$realblinkshorton).\"ms\")\
    \n            } else={\
    \n                :delay delay-time=((\$blinkshorton).\"ms\")\
    \n            }\
    \n\
    \n            :foreach counter=j in=\$blinklst do={\
    \n                /system leds set \$j type=off\
    \n            }\
    \n            :delay delay-time=((\$blinkshortoff).\"ms\")\
    \n            :foreach counter=j in=\$blinklst do={\
    \n                /system leds set \$j type=on\
    \n            }\
    \n        }\
    \n        :set pstat \$cstat\
    \n    }\
    \n}"
    

For LED blinker for ether ports (CRS326 only) you only need to change script name to "ledblinkereth" and change variables on top of script to:


    \n:local ifmatch \"ether\"\
    \n:local instance \"ledblinkereth\"\
    \n:local ledsuffix \"-led\"\
    

Here's script to reset all LEDs back to "interface-activity" type if someone doesn't want to use script anymore:


add name=ledreset source="/interface ethernet\
    \n\
    \n:local ledsuffix \"-led1\"\
    \n:local iflst [find name~\"sfp-sfpplus\"]\
    \n\
    \n:foreach counter=k,i in=\$iflst do={\
    \n    :local iname [get \$i name]\
    \n    :local iled [/system leds find leds=(\$iname.\$ledsuffix)]\
    \n    :put (\"Reset: \".[/system leds get \$iled leds])\
    \n    /system leds set \$iled type=interface-activity\
    \n}\
    \n"
    
You can change top variable accordingly for ether ports. In order to use script add it to /system scheduler. Interval doesn't really matter since it'll only affect restart delay in case script crashes for some reason but I use 1s personally.

Script comes with some defaults I found reasonable but if you want, blinking speed and behavior is configurable. How to configure it:
  • :local cycletime 1000 <- time between interface stats probing. By default 1000ms since CRS3xx chip reports rx and tx bytes only once every second
  • :local cyclenum 2 <- how many probe cycles will be performed before interface details will be refreshed (number of cycles before eg. interface down will be noticed. By default 2 seconds)
  • :local blinkpercycle 8 <- how many times LED will blink during single cycle (during 1 second by default)
  • :local blinkparts 3 <- ratio of LED on / LED off for each blink. By default 1/3 time LED is off and 2/3 time it's on
  • :local ifmatch "sfp-sfpplus" <- pattern for interface match
  • :local instance "ledblinkersfp" <- name of script as you added it in /system script (script uses it to determine whether script is already running as job. Each instance of blinker has to use unique name eg. ledblinkersfp and ledblinkereth for CRS326)
  • :local ledsuffix "-led1" <- suffix that has to be added to interface name to find matching LED.

Who is online

Users browsing this forum: No registered users and 22 guests