Hi guys, I tried to do two kind of speed booster on my broadband home internet service without disconnecting active users. Please advise me how to better this script. I have a PowerRouter2282 with FreeRadius server and about 500 active, 1000 total PPPoE users.
Priority1. On demand single speed booster
Priority2. Night speed booster for all users (speedx4)
1. ROS PPPoE server doesn`t support Radius CoA (Change of Authorization) yet. But when we try to send CoA request from FreeRadius, ROS shows log included username and some attributes. So I tried to use this log.
#add logging action to catch this log
/system logging add topics=radius,debug,packet prefix="" action=memory
When user purchase 10Mbps booster for 4 hours. Radius server will change "Rate-Limit=10Mbps, Framed-Pool=boosted" on it`s database and will send CoA request to ROS. As you see, after user name 1 more character "#". It will be used for simple queue comment and also identifies that started on demand speed booster for user1. When purchase speed booster if user account is off-line, we can not change comment of simple queue. Because there is no dynamic queue yet. In this case new boosted user will get address from pool "boosted". Now we can change comment of simple queue, if IP address is from "boosted".
/ip pool add name=boosted ranges=172.16.28.1-172.16.28.254
FreeRadius sends users requests one by one and always retries 3 times. Because some time ROS losses request.
echo "User-Name := '<pppoe-user1>#', Mikrotik-Rate-Limit := 10240k" | radclient -x -r 3 192.168.100.5:1700 coa Secret
After 4 hours FreeRadius will change back his database information and will send booster-off request. Now the additional character will be single space. It will replace comment of simple queue.
echo "User-Name := '<pppoe-user1> ', Mikrotik-Rate-Limit := 2048k" | radclient -x -r 3 192.168.100.5:1700 coa Secret
On the ROS log section, log will be show as below. We can see 3rd row is included Username, 4th row is included speed information.
02:20:38 radius,debug,packet received CoA-Request with id 168 from 192.168.100.1:41649
02:20:38 radius,debug,packet Signature = 0x3fddd04e7ceb222901d1e7329836f4f3
02:20:38 radius,debug,packet User-Name = "<pppoe-user1>#"
02:20:38 radius,debug,packet MT-Rate-Limit = "10240k"
# After 4 hours, on demand booster will be off.
02:23:03 radius,debug,packet received CoA-Request with id 187 from 192.168.100.1:46705
02:23:03 radius,debug,packet Signature = 0x8ffdbe8c36cef5d433ef64df6e7cbed6
02:23:03 radius,debug,packet User-Name = "<pppoe-user1> "
02:23:03 radius,debug,packet MT-Rate-Limit = "2048k"
Then I added script that runs every second.
#In the log section, to find internal ID of rows which include CoA request log. Script runs every second and looks logs of only that moment.
:foreach i in=[/log find where message~"received CoA-Request with id" time=[/system clock get time]] do={ \
#Internal ID will be *72a15 (* and hex number). So need to convert it to ROS friendly hex format (0x72a15)
:local idcoa ("0x".[:pick $i 1 [:len [$i]]]);
#Username of CoA request is third row for this log. So need to add 2 hex number. The result will be converted to dec number. #Because ROS not able to get result in hex numbers.
:local iduser1 [($idcoa+0x2)];
#Need to convert back this number from dec to hex (This dec to hex converter done by Petrn)
:local hexdigit 32
:local nibble
:local hex ""
:for i from=1 to=$hexdigit step=1 do={ \
:set nibble ($iduser1&0xf)
:set hex ([:pick "0123456789ABCDEF" $nibble ($nibble+1)].$hex)
:set iduser1 ($iduser1>>4)}
#Now the result is ready in hex numbers. So we need to convert it to format of ROS internal ID
:local iduser ("*"."$hex");
#The rate limit value will be in the fourth row for CoA request log. Same way to calculate and find internal ID of rate limit.
:local idboost1 [($idcoa+0x3)];
:local nibble
:local hex ""
:for i from=1 to=$hexdigit step=1 do={ \
:set nibble ($idboost1&0xf)
:set hex ([:pick "0123456789ABCDEF" $nibble ($nibble+1)].$hex)
:set idboost1 ($idboost1>>4)}
:local idboost ("*"."$hex");
#Now we already have log internal ID of Username and Rate-Limit. So need to pick clear value from text.
:local user [:pick [/log get $iduser message] 17 ([:len [/log get $iduser message]]-2)];
:local boost [:pick [/log get $idboost message] 21 ([:len [/log get $idboost message]]-1)];
#As radius request, next character of Username identifies that booster start request or booster stop request.
:local note [:pick [/log get $iduser message] ([:len [/log get $iduser message]]-2) ([:len [/log get $iduser message]]-1)];
#We have 3 variable Username, RateLimit and booster identification. So we will find queue of user and change speed and will do comment.
#If booster is started, comment will be "#", If booster is stopped there will be no comment.
/queue simple set [/queue simple find where name=$user] limit-at="$boost/$boost" max-limit="$boost/$boost" comment="$note";
#and the last command writes log that which user speed has changed. (Note: That will not exactly that user speed changed or not)
:log warning message="Single_Booster: $user changed speed to $boost $note";}
It works not bad. I have tested few times.
II. Now the second night booster for all users. But if user purchased on demand speed booster, we will not increase his speed again. My FreeRadius and ROS have same NTP server. Their clock is same. So the scripts can run separately on each other. Every day at 21:00 FreeRadius changes it`s database of all customers Rate-Limit="existing_speed x 4" excluding if Framed-Pool=boosted. At that moment, RouterOS runs below script.
#Need to add comment for all users, which are using On-Demand speed booster. Because we don`t want to increase their speed again x4.
#So find interface names of users, which got ip addresses from pool PPPoE_Baganuur. Because for PPPoE, interface and queue simple names are same.
:foreach a in=[ip address find where address~"172.22.28."] do={ \
:local intname [/ip address get $a interface];
#Using interface name, need to find dynamic simple queue and change comment.
/queue simple set [/queue simple find where name="$intname"] comment="#";}
:delay 1s;
#Now we commented all users, who are using On-Demand speed booster. Now we will multiplicate all simple queues without comment "#"
/queue simple; :foreach q in=[find where comment!="#"] do={ \
#Get value of Limit-At and pick only digits. Then need to multiplicate by 4000. Because my format is 1024k,512k,5120k etc. #$speed will be 2048000 if user existing rate was 512k.
:local speed [(([:pick [get $q limit-at] 0 [(([:len [get $q limit-at]]/2)-1)]])*4000)];
/queue simple set $q limit-at="$speed/$speed" max-limit="$speed/$speed";
:local userner [get $q name];
:log warning message="Night_Booster: speed of $userner has grown x4";}
I have tested it for 330 active users. Works no problem yet. Every morning at 09:00, FreeRadius and RouterOS will change all speed to normal case, using same scripts.