Community discussions

MikroTik App
 
Yogo
just joined
Topic Author
Posts: 23
Joined: Fri Oct 18, 2013 12:58 pm
Location: Sydney, Australia

Interface Data Quota

Wed Jul 30, 2014 11:42 am

Hi All,

Was wondering if it possible to set up a quota for an outbound interface?

The situation:

Basically I have two connections set up in failover.. One is hardwired, the other is a 4G connection as backup.
The 4G connection has an 8GB/month ISP quota (additional data is charged per MB), and I really don't want to exceed it.
I want to set up an outbound interface quota and shaping on the 4G interface, where at 6GB it starts shaping traffic, and at 7.8GB (allowing for usage discrepancies) to deny traffic.
Then I need the quota to reset at the start of each month

Is this possible? Would I do it via queues? Scripting? I'm a bit lost...

Hardwired interface is named "LAN" via ethernet
4G Backup interface is named "BigPondBackup" via USB

let me know if you want any more info and I appreciate the help.. I'm still learning..
 
User avatar
cdiedrich
Forum Veteran
Forum Veteran
Posts: 997
Joined: Thu Feb 13, 2014 2:03 pm
Location: Basel, Switzerland // Bremen, Germany
Contact:

Re: Interface Data Quota

Wed Jul 30, 2014 6:20 pm

I am facing exactly this situation in the implementation of a dual-WAN config for a client of mine.

Since I never ever needed queues I went the scripting way, the outcome of which I like to share with you.
What you see is my initial very basic script, I'm sure there's much to improve, but I think it's pretty good for the start.
Some snipplets of this script are taken from other posts here in the forum and altered to my needs.

The first script is scheduled to run every 5 minutes. It collects the traffic of lte1 (sums up tx and rx bytes) and writes this to a file.
I prefer the file method over a global variable because it survives system reboots or interface losses.
As you can see it checks whether the actual data makes sense in context of the data read from the file. If current traffic on the interface is smaller, it gets added to the file content:

ros code

:local counter [/interface get lte1 rx-bytes]
:set $counter ($counter + [/interface get lte1 tx-bytes])
:local traffic
:if ([:len [/file find where name=counter.txt]] < 1 ) do={
/file print file=counter.txt where name=counter.txt;
/delay delay-time=2;
/file set counter.txt contents="0";
};
:local before value=[/file get counter.txt contents]

:if ($counter > $before) do={
/file set counter.txt contents=$counter
} else= {
:set $traffic ($counter+$before)
/file set counter.txt contents=$traffic
};
The second script is run every 15 minutes which checks the traffic usage and issues a warning email at 80% and triggers the stoplte script at 100%:

ros code

:local traffic ([/file get traffic.txt contents] / 1000 / 1000 / 1000)
#set the LTE quota in GB
:local limit 30
:local percent ($traffic*100 / $limit)

:if ([:len [/file find where name=warning.txt]] < 1 ) do={
/file print file=warning.txt where name=warning.txt;
/delay delay-time=2;
/file set warning.txt contents=$percent;

:if ($percent < 50) do={
#any action you like - maybe you want to issue daily reports, warnings at 50% or whatsoever
}

} else={
     :if ($percent < 79) do={
        /file set warning.txt contents=$percent;
                                :log info "Traffic at $percent%"
     } else={
        :if (($percent >=80) && ($traffic <$limit)) do={
                                  :if ([/file get warning.txt contents] <> "99") do={
                      /tool e-mail send to=<youremailaddress> subject="Traffic warning: $percent% reached at $[/system clock get date], $[/system clock get time]" body="The actual traffic amount is $traffic GB \r\nThis is $percent% of the monthly limit\r\n\"
          /file set warning.txt contents="99"
                      :log warning "Warning message sent at $percent%"};
        } else={
            :if ($percent >= 100) do={
                /system script run stoplte
                                } 
        }
    }
}
The stoplte script disables the interface and all related NAT-rules as well as the default route to lte1.
Then automatically the DSL backup kicks in since it still has an active default route (but with a higher distance).

Then I finally have another script, ran daily at midnight which checks if it's the first of the month and then enables lte1 and all rules/routes, resets the counters and warnings.

Hope that helps a little,
-Chris
 
Yogo
just joined
Topic Author
Posts: 23
Joined: Fri Oct 18, 2013 12:58 pm
Location: Sydney, Australia

Re: Interface Data Quota

Thu Jul 31, 2014 12:22 am

OMG wow!

Thanks Chris, you've saved my wallet!

Now time to test..
 
User avatar
cdiedrich
Forum Veteran
Forum Veteran
Posts: 997
Joined: Thu Feb 13, 2014 2:03 pm
Location: Basel, Switzerland // Bremen, Germany
Contact:

Re: Interface Data Quota

Thu Jul 31, 2014 8:40 am

Glad to hear this helps.
In case you modify the script and add new "features" I'd be very interested.

Cheers
-Chris ...and thanks for the Karma
 
gniers
just joined
Posts: 9
Joined: Fri Nov 15, 2013 3:37 pm

Re: Interface Data Quota

Thu Nov 12, 2015 10:43 am

Great posting,

I try to build this script on a RB912UAG-2HPnD witth ROS 6.25 and a sierra board as LTE interface.

Unfortunatly i'm not getting any usage data with ; [/interface get lte1 rx-bytes
This works on a normal ether1 interface not on an LTE

Any suggestion how to get rx-bytes tx-bytes in a script from the LTE interface ??

Thanks !
 
maikel
just joined
Posts: 8
Joined: Thu Jun 08, 2017 2:53 pm

Re: Interface Data Quota

Fri Jun 16, 2017 8:37 pm

Dear Chris,

First of all I would like to thank you, your script is the first introduction for me with RouterOS (6.38.5) and the language C
Your script was not directly usable at first because of many updates of ROS but helped me tremendously, thanks again for that.
I would like to share the script that I build the last couple of days, I tested it on my router (hEX routerboard);
<as this is firstly commercially sold I removed the information, I will add it later>
 
luidoltp
newbie
Posts: 31
Joined: Mon Feb 22, 2016 6:27 am
Location: Graz, Austria

Re: Interface Data Quota

Fri Dec 22, 2017 8:20 am

Dear Maikel,

<as this is firstly commercially sold I removed the information, I will add it later>
Can you already share your script. I would highly appreciate it!

Thanks & best regards,
Peter
 
chrisjc
just joined
Posts: 12
Joined: Wed Sep 30, 2015 12:28 pm

Re: Interface Data Quota

Mon Feb 12, 2018 1:11 pm

Hi maikel,

I would also be very interested in your new and improved script if you're willing!

Thanks,

Chris
 
maikel
just joined
Posts: 8
Joined: Thu Jun 08, 2017 2:53 pm

Re: Interface Data Quota

Tue Feb 13, 2018 9:47 am

Dear Maikel,

<as this is firstly commercially sold I removed the information, I will add it later>
Can you already share your script. I would highly appreciate it!

Thanks & best regards,
Peter
Hi maikel,

I would also be very interested in your new and improved script if you're willing!

Thanks,

Chris
Dear Peter and Chris,
In the end we never really implemented this scripts, but if I'm remembering correctly it should be working. If you would like to know which specifik routerBoard I was programming this for, please ask me.
The scripts are a buch of different ones, one main scripts is executing the other ones;
mainscript freedata-mikrotik.c reads data from interfaces and writes them to files
#This first script is scheduled to run every 5 minutes. It collects the traffic of lte1 (sums up tx and rx bytes)
#and writes different data to multiple files. Kudos to Christopher Diedrich: https://forum.mikrotik.com/viewtopic.php?t=87565#
#Creator: Maikel Egberink Robacomm.nl
#The following crontab rule is essential for the correct execution of this script:
#
#Please crontab as follow:   */5 * * * *   which lets cron starts this script every 5 min, e.g. 21:40,21:45,21:50,21:55
#
#Get newest tx- and rx-data from interface and put in var $newdata
:local interf "ether2"
:global newdata
:global tx [/interface get $interf tx-byte] 
:put "tx: $tx"
:global rx [/interface get $interf rx-byte] 
:put "rx: $rx"
:set $newdata ( $rx + $tx )
:put "Newdata value: $newdata"
#
#Check if freedata is applicable
:local curtime [/system clock get time]
:put "Current time value: $curtime"
#Example: freedata is from 0:00:00 until 6:00:00 (when changing times please change if-then's too
:local startfreedata 0:00:00
:local beforestartfreedata 23:59:59
:local stopfreedata 6:00:00
:local freedata
#Between freedata-times count freedata
:if ( $curtime >= $startfreedata && $curtime <= $stopfreedata ) do={
	:set $freedata true
	:put "Freedata applicable"
};
#Later than (latest) freedata-times count no freedata. Cannot look before 0:00:00, so always later than 0:00:00
:if ( $curtime > $stopfreedata && $curtime < $beforestartfreedata ) do={
	:set $freedata false
	:put "Freedata NOT applicable"
};
:put "Freedata is set to: $freedata"
#
#Check if files are already created;
:local fileref "refcount.txt"
:local filename "counter.txt"
:local filefree "freecount.txt"
#Check if file refcount.txt not exists, then do (1=exist, 0=not exist)
:if ([:len [/file find where name=$fileref]] < 1 ) do={
	#Create new file
	/file print file=$fileref where name=$fileref;
	#Wait 2 sec
	/delay delay-time=2;
	#Put value 0 in file contents
	/file set $fileref contents=0;
	:put "New file $fileref is created with content 0"
};
#Check if file counter.txt not exists, then do (1=exist, 0=not exist)
:if ([:len [/file find where name=$filename]] < 1 ) do={
	#Create new file
	/file print file=$filename where name=$filename;
	#Wait 2 sec
	/delay delay-time=2;
	#Put value 0 in file contents
	/file set $filename contents=0;
	:put "New file $filename is created with content 0"
}

#Check if file freecount.txt not exists, then do (1=exist, 0=not exist)
:if ([:len [/file find where name=$filefree]] < 1 ) do={
	#Create new file
	/file print file=$filefree where name=$filefree;
	#Wait 2 sec
	/delay delay-time=2;
	#Put value 0 in file contents
	/file set $filefree contents=0;
	:put "New file $filefree is created with content 0"
};
#
:local ref
#Reference file stores the $newdata value on 1st of the month at 0:00 after script 'resetfiles-mikrotik-x.x' ran 
#If there is no value (0) in refcount.txt then put contents to file from var newdata 
#If there is a value in refcount.txt then read it and put it in var ref
:set $ref [/file get $fileref contents]
:put "Reference value from $fileref: $ref"
:if ( $ref = 0 ) do={
	#Write var $newdata to file
	/file set $fileref contents=$newdata
	#Wait 2 sec
	/delay delay-time=2;
	:put "Reference data $newdata put in $fileref"
	:log info "Freedatascripts: Reference data $newdata put in $fileref"
};
#
#When freedata is applicable then count bytes during freedata (not total interface bytes) and write it to freecount.txt.
:local before
:local correct
:local free
#
#Freedata is applicable; write bytes to freecount.txt
#Check if freedata; >0:00 and < 6:00 do
:if ( $freedata = true ) do={
	#:put "if freecount true do"	
	#Read freecount.txt (last freedata)
	:set $free [/file get $filefree contents]
	:put "Previous Free value from $filefree: $free"
	#When newdata is lower than before (e.g. when interface reset) do
	:if ( $newdata < $free ) do={
		#:put "freedata true if newdata < before do"  
		#Correct reference file when counters did reset (to prevent reset value, this way we remember 'old' bytes)
		/file set $fileref contents=$newdata	
		#correct value written to freecount.txt (we suppose that 5 min before also was freedata)
		:set $correct ( $free + $newdata )
		#Write corrected value to freecount.txt
		/file set $filefree contents=$correct
		:put "Writen $correct to $filefree"
	} else={
		#:put "freedata true else newdata < before  do"
	:if ( $newdata >= $free ) do={
		#:put "freedata true if newdata >= before do"  
		#Read reference data and set freedata
		:set $ref [/file get $fileref contents]
		#The var $newdata is now only the actual bytes used from 01-mm-yyyy 0:00:00
		:set $newdata ( $newdata - $ref )
		:put "Variable newdata is now set to new value: $newdata"
		#Newest data from interface - content of counter.txt + contents of freecount.txt
		:set $free ( $newdata - $free )
		#Write updated data to freecount.txt
		/file set $filefree contents=$free
		:put "Written $free to $filefree"
		};
	};
};  
#
#Freedata is not applicable; write bytes to counter.txt
#Check if not freedata; > 6:00 and <23:59 do
:if ( $freedata = false ) do={
	#:put "if freedata false" 	
	#Read contents from file counter.txt (no freetime) and puts it in var $before
	:set $before [/file get $filename contents]
	:put "Previous Before value from $filename: $before"
	#When newdata is lower than before (e.g. when interface reset) do  
	:if ( $newdata < $before ) do={
		#:put "freedata false if newdata < before do"	  
		#Correct reference file
		/file set $fileref contents=$newdata
		#correct value written to counter.txt (to prevent reset value, this way we remember 'old' bytes)
		:set $correct ( $before + $newdata )
		#Write corrected value to counter.txt
		/file set $filename contents=$correct
		:put "Written $correct to $filename"
	} else={
	:if ( $newdata >= $before ) do={ 
		#:put "freedata false if newdata >= before do"
		#Read reference data and set counterdata
		:set $ref [/file get $fileref contents]
		#The var $newdata is now only the actual bytes used from 01-mm-yyyy 0:00:00
		:set $newdata ( $newdata - $ref )
		:put "Variable newdata is now set to new value: $newdata"
		#Write newdata value to counter.txt
		:set $correct ( $newdata - $free )
		/file set $filename contents=$correct
		:put "Written $newdata to $filename"
		}; 
	}; 
};
warning-mikrotik.c checks traffic usage
#This second script is scheduled to run every 15 minutes. It checks the traffic usage and issues a warning email at 80% 
#and triggers the stoplte script at 100%. Kudos to Christopher Diedrich: https://forum.mikrotik.com/viewtopic.php?t=87565#
#Creator: Maikel Egberink Robacomm.nl
#The following crontab rule is essential for the correct execution of this script:
#
#Please crontab as follow:   */15 * * * *   which lets cron starts this script every 15 min, e.g. 21:30,21:45,22:00,22:15
#
#Wait for script one; freedata-mikrotik0.2  for 5 seconds
:local interf "ether2"
:put "Wait for 5 seconds to finish first script"
/delay delay-time=5
:local filecount "counter.txt"
:local filewarn "warning.txt"
:local traffic ([/file get $filecount contents] / 1024 / 1024 / 1024)
:put "Registered amount of data is now: $traffic GB"
#Set the interface quota in GB;
:local limit 100
:put "Quota is set to: $limit GB"
#Calculate percents
:local percent ($traffic*100 / $limit)
:put "$percent % is now reached until set quota of $limit GB"
#
#Check if file is already created. Check if file warning.txt not exists, then do (1=exist, 0=not exist)
:if ([:len [/file find where name=$filewarn]] < 1 ) do={
	/file print file=$filewarn where name=$filewarn
	/delay delay-time=2
	/file set $filewarn contents=$percent
};
#Write precentage to file
/file set $filewarn contents=$percent
#
#Select action according to percentage reached until quota
:if ($percent < 50) do={
	#any action you like - maybe you want to issue daily reports, warnings at 50% or whatsoever
	:log info "Traffic on $interf at $percent %"
	:log info "Freedatascripts: Traffic on $interf at $percent%"
	/tool e-mail send to=maikel@robacomm.nl subject="Traffic warning: $percent% reached at $[/system clock get date], $[/system clock get time]" body="The actual traffic amount is $traffic GB \r\nThis is $percent% of the monthly limit of $limit GB\r\nThis email is automatically generated by Freedatascript on mikrotik router at CarpeDiem, please do not reply\r\n\"
} else={
     :if ($percent < 79) do={
		#Write percentage to file
        :set $percent [/file get $filewarn contents]
		:put "Traffic on $interf at $percent % (less than 79%)"
        #:log info "Freedatascripts: Traffic on $interf at $percent%"
     } else={
        :if (($percent >=80) && ($traffic < $limit)) do={
			#Send email one time when percentage is over 80% and traffic is not reached quota yet
			:if ([/file get $filewarn contents] <> 99) do={
				#/tool e-mail send to=<youremailaddress> subject="Traffic warning: $percent% reached at $[/system clock get date], $[/system clock get time]" body="The actual traffic amount is $traffic GB \r\nThis is $percent% of the monthly limit\r\n\"
				/file set $filewarn contents=99
				:put "Traffic on $interf at $percent % (80% and over) -99 in file and email sent-"
				:log warning "Freedatascripts: Warning message sent for $interf at $percent%"
				}
		} else={
			:if ($percent >= 100) do={
				/file set $filewarn contents=$percent
				:put "Traffic at $percent % (100% or over) -stop interface-"
				/system script run stoplte
				};
		};
	};
};
reset-files-mikrotik.c resets all counter files every first of the month
#This script ran daily at midnight which checks if it's the first of the month and then enables lte1 (and all rules/routes)
#and resets the counters and warnings. Kudos to Christopher Diedrich: https://forum.mikrotik.com/viewtopic.php?t=87565#
#Creator: Maikel Egberink Robacomm.nl
#The following crontab rule is essential for the correct execution of this script:
#
#Please crontab as follow:   0 0 * 1 *   which lets cron starts this script every 1st of every month
#
:local interf "ether2"
:local curdate [/system clock get date]
:put "Current date value: $curdate"
:local fileref "refcount.txt"
:local filename "counter.txt"
:local filefree "freecount.txt"
:local filewarn "warning.txt"
:local day [ :pick $curdate 4 6 ];
:put $day
:if ( $day = 1 ) do={
	:put "Today is 1th of the month, resetting all counters..."
	#RAM
	:put "Resetting counters on RAM..."
	:put "Resetting counter for regular data $filename ..."
	/file set $filename contents=0
	:put "Resetting counter for free data $filefree ..."
	/file set $filefree contents=0
	:put "Resetting counter for warnings $filewarn ..."
	/file set $filewarn contents=0
	:put "Resetting counter for reference data $fileref ..."
	/file set $fileref contents=0
	#enable interface, which might be disabled after reaching 100% data-usage
	:put "Enabling interface LTE..."
	#/interface ethernet set $interf disabled=no
	:put "The interface is enabled"
	:log info "Freedatascripts: All counters are reset to 0, interface $interf is enabled"
};
:if ( $day = 13 ) do={
    :log info "Freedatascripts: test 00:00:01 13th day"
};
stoplte.c stops the interface lte
#This script stops interface when the quota is reached (100%)
#Change the interfacename here;
:local interf "ether2"
#Uncomment the following rules for running scripts in production;
#/interface ethernet set $interf disabled=yes
#:put "The interface is disabled"
#:log warning "Interface $interf is DISABLED due to reached datalimit"
readfiles.c helpscript to run manually so you can read all files at once
:local filename counter.txt
:local fileref refcount.txt
:local filefree freecount.txt
:local filewarn warning.txt
#:put "-- Reference point made when the freedatascripts started running (1st of the month) --"
:put "-- Referentie/Ijkpunt gemaakt wanneer de freedatascripts zijn gestart (1ste vd maand) --"
:set $ref [/file get $fileref contents]
#:put "Reference value from $fileref: $ref in bytes"
:put "Referentie waarde vanuit $fileref: $ref in bytes"
#:put "-- Registered amount of data during NON-free data times --"
:put "-- Geregistreerde hoeveelheid data tijdens NIET-vrije data tijden --"
:set $before [/file get $filename contents]
#:put "Counted bytes value from $filename: $before"
:put "Getelde bytes waarde vanuit $filename: $before"
:local beforemb ( $before / 1024 / 1024 )
#:put "Counted Megabytes value from $filename: $beforemb"
:put "Getelde Megabytes waarde vanuit $filename: $beforemb"
:local beforegb ( $before / 1024 / 1024 / 1024 )
:put "Getelde Gigabytes waarde vanuit $filename: $beforegb"
#:put "-- Registered amount of data during FREE data times --"
:put "-- Geregistreerde hoeveelheid data tijdens VRIJE data tijden --"
:set $free [/file get $filefree contents]
#:put "Counted bytes value from $filefree: $free"
:put "Getelde bytes waarde vanuit $filefree: $free"
:local freemb ( $free / 1024 / 1024 )
#:put "Counted Megabytes value from $filename: $freemb"
:put "Getelde Megabytes waarde vanuit $filename: $freemb"
:local freegb ( $free / 1024 / 1024 / 1024 )
#:put "Counted Gigabytes value from $filename: $freegb"
:put "Getelde Gigabytes waarde vanuit $filename: $freegb"
#:put "-- Amount of GB when interface has to be switched off --"
:put "-- Waarde in GB wanneer de interface uitgeschakeld moet worden --"
#:put "The limit is set to: $limit GB"
:put "De limiet is ingesteld op: $limit GB"
:set $percent [/file get $filewarn contents]
#:put "Counted traffic data is now at $percent %"
:put "Getelde traffic data is nu op $percent %"
Hope it helps, it was a lot of fun program this, so thanks again Chris. If you have any questions please let me know
Maikel
 
luidoltp
newbie
Posts: 31
Joined: Mon Feb 22, 2016 6:27 am
Location: Graz, Austria

Re: Interface Data Quota

Tue Feb 13, 2018 11:13 pm

Hi Maikel,

thanks so much for sharing! :)
I will try to implement it in the wAP LTE kit counting LTE traffic.

Best regards,
Peter
 
maikel
just joined
Posts: 8
Joined: Thu Jun 08, 2017 2:53 pm

Re: Interface Data Quota

Thu Feb 15, 2018 12:56 pm

Hi Maikel,

thanks so much for sharing! :)
I will try to implement it in the wAP LTE kit counting LTE traffic.

Best regards,
Peter
Very welcome
 
mikrofunckryptar
just joined
Posts: 1
Joined: Fri Dec 28, 2018 10:06 pm

Re: Interface Data Quota

Fri Dec 28, 2018 10:21 pm

Hello
For LTE:
#   /$$    /$$$$$$$$/$$$$$$$$ /$$       /$$               /$$   /$$                        
#  | $$   |__  $$__/ $$_____/| $$      |__/              |__/  | $$                        
#  | $$      | $$  | $$      | $$       /$$ /$$$$$$/$$$$  /$$ /$$$$$$    /$$$$$$   /$$$$$$ 
#  | $$      | $$  | $$$$$   | $$      | $$| $$_  $$_  $$| $$|_  $$_/   /$$__  $$ /$$__  $$
#  | $$      | $$  | $$__/   | $$      | $$| $$ \ $$ \ $$| $$  | $$    | $$$$$$$$| $$  \__/
#  | $$      | $$  | $$      | $$      | $$| $$ | $$ | $$| $$  | $$ /$$| $$_____/| $$      
#  | $$$$$$$$| $$  | $$$$$$$$| $$$$$$$$| $$| $$ | $$ | $$| $$  |  $$$$/|  $$$$$$$| $$      
#  |________/|__/  |________/|________/|__/|__/ |__/ |__/|__/   \___/   \_______/|__/      
#  
#  Using: Set all var in User config section. Add scripts to schedule with onstart and interval 30 sek       
:do {              
#######################################################################################################
#                                              User config
#Set limit in MB                                                                                                                                                     
:local limit 12288 
#Set day to reset limit
:local dayresetlimit 1
#Set interface
:local interf "lte1"
#Set auto bring up interface 
:local autointon true
#######################################################################################################
:local filename "counter.txt"
:local filewarn "warning.txt"
:local fileref "refcount.txt"
:local reblock "reblock.txt"
:local status
:if ([:len [/file find where name=$filewarn]] < 1 ) do={
	/file print file=$filewarn where name=$filewarn
	/delay delay-time=2
	/file set $filewarn contents=$percent
};
:if ([:len [/file find where name=$filename]] < 1 ) do={
	/file print file=$filename where name=$filename
	/delay delay-time=2;
	/file set $filename contents=0
}
:if ([:len [/file find where name=$reblock]] < 1 ) do={
	/file print file=$reblock where name=$reblock
	/delay delay-time=2;
	/file set $reblock contents=1
}
:if ([:len [/file find where name=$fileref]] < 1 ) do={
	/file print file=$fileref where name=$fileref
	/delay delay-time=2;
	/file set $fileref contents=0
}
:local reblocker ([/file get $reblock contents])
:local curdate [/system clock get date]
:local day [ :pick $curdate 4 6 ]
:if ( $day = $dayresetlimit and $reblocker = 0) do={
	/file set $filename contents=0
	/file set $filewarn contents=0
	/file set $fileref contents=0
	/interface lte set $interf disabled=no
	/file set $reblock contents=1
	:log info "Limit reset, int $interf bring up" 
	/delay delay-time=5;
	:log info "Clear int counters - reboot"
	#TODO find another method for interf clear counters 
        /system reboot
} 
:if ( $day != $dayresetlimit ) do={
        /file set $reblock contents=0
}
:local before
:local correct
:local ref
:local newdata
:local tx [/interface get $interf tx-byte] 
:local rx [/interface get $interf rx-byte] 
:set $newdata (( $rx + $tx ) / 1024 / 1024 )
:set $before [/file get $filename contents]
:if ( $newdata < $before ) do={
		:set $ref [/file get $fileref contents]
		:set $correct ( $before + $newdata - $ref ) 
		/file set $fileref contents=$newdata
		/file set $filename contents=$correct
	} 
:if ( $newdata >= $before ) do={
		/file set $filename contents=$newdata
}
:local traffic ([/file get $filename contents])
:log warning "Limit: $limit MB"
:local percent ($traffic*100 / $limit)
:log warning "Use: $percent%"
/file set $filewarn contents=$percent
:if ($percent >= 100) do={
	/file set $filewarn contents=$percent
	/interface lte set $interf disabled=yes
 }
:if ($percent < 100 and $autointon = true) do={
             :set $status [/interface get $interf value-name=disabled] 
             :if ($status = true) do={
             /interface lte set $interf disabled=no
              }
}
} on-error={ :log error "Error LTELimiter "};

for PPP-Client
#   /$$    /$$$$$$$$/$$$$$$$$ /$$       /$$               /$$   /$$                        
#  | $$   |__  $$__/ $$_____/| $$      |__/              |__/  | $$                        
#  | $$      | $$  | $$      | $$       /$$ /$$$$$$/$$$$  /$$ /$$$$$$    /$$$$$$   /$$$$$$ 
#  | $$      | $$  | $$$$$   | $$      | $$| $$_  $$_  $$| $$|_  $$_/   /$$__  $$ /$$__  $$
#  | $$      | $$  | $$__/   | $$      | $$| $$ \ $$ \ $$| $$  | $$    | $$$$$$$$| $$  \__/
#  | $$      | $$  | $$      | $$      | $$| $$ | $$ | $$| $$  | $$ /$$| $$_____/| $$      
#  | $$$$$$$$| $$  | $$$$$$$$| $$$$$$$$| $$| $$ | $$ | $$| $$  |  $$$$/|  $$$$$$$| $$      
#  |________/|__/  |________/|________/|__/|__/ |__/ |__/|__/   \___/   \_______/|__/      
#  
#  Using: Set all var in User config section. Add scripts to schedule with onstart and interval 30 sek       
:do {              
#######################################################################################################
#                                              User config
#Set limit in MB                                                                                                                                                     
:local limit 12288 
#Set day to reset limit
:local dayresetlimit 1
#Set interface
:local interf "ppp-out1"
#Set auto bring up interface 
:local autointon true
#######################################################################################################
:local filename "counter.txt"
:local filewarn "warning.txt"
:local fileref "refcount.txt"
:local reblock "reblock.txt"
:local status
:if ([:len [/file find where name=$filewarn]] < 1 ) do={
	/file print file=$filewarn where name=$filewarn
	/delay delay-time=2
	/file set $filewarn contents=$percent
};
:if ([:len [/file find where name=$filename]] < 1 ) do={
	/file print file=$filename where name=$filename
	/delay delay-time=2;
	/file set $filename contents=0
}
:if ([:len [/file find where name=$reblock]] < 1 ) do={
	/file print file=$reblock where name=$reblock
	/delay delay-time=2;
	/file set $reblock contents=1
}
:if ([:len [/file find where name=$fileref]] < 1 ) do={
	/file print file=$fileref where name=$fileref
	/delay delay-time=2;
	/file set $fileref contents=0
}
:local reblocker ([/file get $reblock contents])
:local curdate [/system clock get date]
:local day [ :pick $curdate 4 6 ]
:if ( $day = $dayresetlimit and $reblocker = 0) do={
	/file set $filename contents=0
	/file set $filewarn contents=0
	/file set $fileref contents=0
	/interface ppp-client set $interf disabled=no
	/file set $reblock contents=1
	:log info "Limit reset, int $interf bring up" 
	/delay delay-time=5;
	:log info "Clear int counters - reboot"
	#TODO find another method for interf clear counters 
        /system reboot
} 
:if ( $day != $dayresetlimit ) do={
        /file set $reblock contents=0
}
:local before
:local correct
:local ref
:local newdata
:local tx [/interface get $interf tx-byte] 
:local rx [/interface get $interf rx-byte] 
:set $newdata (( $rx + $tx ) / 1024 / 1024 )
:set $before [/file get $filename contents]
:if ( $newdata < $before ) do={
		:set $ref [/file get $fileref contents]
		:set $correct ( $before + $newdata - $ref ) 
		/file set $fileref contents=$newdata
		/file set $filename contents=$correct
	} 
:if ( $newdata >= $before ) do={
		/file set $filename contents=$newdata
}
:local traffic ([/file get $filename contents])
:log warning "Limit: $limit MB"
:local percent ($traffic*100 / $limit)
:log warning "Use: $percent%"
/file set $filewarn contents=$percent
:if ($percent >= 100) do={
	/file set $filewarn contents=$percent
	/interface ppp-client set $interf disabled=yes
 }
:if ($percent < 100 and $autointon = true) do={
             :set $status [/interface get $interf value-name=disabled] 
             :if ($status = true) do={
             /interface ppp-client set $interf disabled=no
              }
}
} on-error={ :log error "Error ppp-clientLimiter "};

 
User avatar
bpwl
Forum Guru
Forum Guru
Posts: 2983
Joined: Mon Apr 08, 2019 1:16 am

Re: Interface Data Quota

Mon Apr 08, 2019 1:34 am

Hi, I used this excellent LTELimiter script for several weeks on 2 SXT's. Keeping an eye on the data volumes. It works excellent. Thanks for sharing!

I made it only run every 10 minutes not to damage the flash with too many write operations. The reset of the interface counters in an SXT LTE kit is also done when you disable/enable the interface (or switch between the SIM cards). Yesterday we had a power failure, and the counters that have been incremented over a long time, were reduced to some value of an earlier interface reset. The calculation of the "correct" counter value is mistakenly subtracting the "ref" value in the case of a counter reset.. Anything accumulated in this period is subtracted. So I modified the script to avoid this substraction of the accumulated value.

The script reads in that lower part now as:

:log info "Clear int counters - reboot"
#TODO find another method for interf clear counters
#/system reboot
#resetting interface will clear counters
/interface lte set $interf disabled=yes
/delay delay-time=2;
/interface lte set $interf disabled=no
/delay delay-time=2;

}
:if ( $day != $dayresetlimit ) do={
/file set $reblock contents=0
}
:local before
:local correct
:local ref
:local newdata
:local tx [/interface get $interf tx-byte]
:local rx [/interface get $interf rx-byte]
:set $newdata (( $rx + $tx ) / 1024 / 1024 )
:set $before [/file get $filename contents]
# delta count ?
:if ( $newdata < $before ) do={
:set $ref [/file get $fileref contents]
# BPWL by counter reset then zero out old ref value
:if ( $newdata < $ref ) do={
set $ref (0)
}

:set $correct ( $before + $newdata - $ref )
/file set $fileref contents=$newdata
/file set $filename contents=$correct
}
# regular count
:if ( $newdata >= $before ) do={
/file set $filename contents=$newdata
}
:local traffic ([/file get $filename contents])
:local percent ($traffic*100 / $limit)
:log warning "Limit: $limit MB Traffic: $traffic MB Used: $percent%"
/file set $filewarn contents=$percent
:if ($percent >= 100) do={
/file set $filewarn contents=$percent
/interface lte set $interf disabled=yes
}
:if ($percent < 100 and $autointon = true) do={
:set $status [/interface get $interf value-name=disabled]
:if ($status = true) do={
/interface lte set $interf disabled=no
}
}
} on-error={ :log error "Error LTELimiter "};
Last edited by bpwl on Sat Feb 05, 2022 11:49 pm, edited 2 times in total.
 
leon84
Member Candidate
Member Candidate
Posts: 201
Joined: Wed Dec 02, 2009 12:15 pm

Re: Interface Data Quota

Fri Aug 02, 2019 1:27 pm

Very good this script but it has a problem, I think.
If the router is powered off in the day of dayresetlimit the counter reset never happens. Is it right?
Hello
For LTE:
#   /$$    /$$$$$$$$/$$$$$$$$ /$$       /$$               /$$   /$$                        
#  | $$   |__  $$__/ $$_____/| $$      |__/              |__/  | $$                        
#  | $$      | $$  | $$      | $$       /$$ /$$$$$$/$$$$  /$$ /$$$$$$    /$$$$$$   /$$$$$$ 
#  | $$      | $$  | $$$$$   | $$      | $$| $$_  $$_  $$| $$|_  $$_/   /$$__  $$ /$$__  $$
#  | $$      | $$  | $$__/   | $$      | $$| $$ \ $$ \ $$| $$  | $$    | $$$$$$$$| $$  \__/
#  | $$      | $$  | $$      | $$      | $$| $$ | $$ | $$| $$  | $$ /$$| $$_____/| $$      
#  | $$$$$$$$| $$  | $$$$$$$$| $$$$$$$$| $$| $$ | $$ | $$| $$  |  $$$$/|  $$$$$$$| $$      
#  |________/|__/  |________/|________/|__/|__/ |__/ |__/|__/   \___/   \_______/|__/      
#  
#  Using: Set all var in User config section. Add scripts to schedule with onstart and interval 30 sek       
:do {              
#######################################################################################################
#                                              User config
#Set limit in MB                                                                                                                                                     
:local limit 12288 
#Set day to reset limit
:local dayresetlimit 1
#Set interface
:local interf "lte1"
#Set auto bring up interface 
:local autointon true
#######################################################################################################
:local filename "counter.txt"
:local filewarn "warning.txt"
:local fileref "refcount.txt"
:local reblock "reblock.txt"
:local status
:if ([:len [/file find where name=$filewarn]] < 1 ) do={
	/file print file=$filewarn where name=$filewarn
	/delay delay-time=2
	/file set $filewarn contents=$percent
};
:if ([:len [/file find where name=$filename]] < 1 ) do={
	/file print file=$filename where name=$filename
	/delay delay-time=2;
	/file set $filename contents=0
}
:if ([:len [/file find where name=$reblock]] < 1 ) do={
	/file print file=$reblock where name=$reblock
	/delay delay-time=2;
	/file set $reblock contents=1
}
:if ([:len [/file find where name=$fileref]] < 1 ) do={
	/file print file=$fileref where name=$fileref
	/delay delay-time=2;
	/file set $fileref contents=0
}
:local reblocker ([/file get $reblock contents])
:local curdate [/system clock get date]
:local day [ :pick $curdate 4 6 ]
:if ( $day = $dayresetlimit and $reblocker = 0) do={
	/file set $filename contents=0
	/file set $filewarn contents=0
	/file set $fileref contents=0
	/interface lte set $interf disabled=no
	/file set $reblock contents=1
	:log info "Limit reset, int $interf bring up" 
	/delay delay-time=5;
	:log info "Clear int counters - reboot"
	#TODO find another method for interf clear counters 
        /system reboot
} 
:if ( $day != $dayresetlimit ) do={
        /file set $reblock contents=0
}
:local before
:local correct
:local ref
:local newdata
:local tx [/interface get $interf tx-byte] 
:local rx [/interface get $interf rx-byte] 
:set $newdata (( $rx + $tx ) / 1024 / 1024 )
:set $before [/file get $filename contents]
:if ( $newdata < $before ) do={
		:set $ref [/file get $fileref contents]
		:set $correct ( $before + $newdata - $ref ) 
		/file set $fileref contents=$newdata
		/file set $filename contents=$correct
	} 
:if ( $newdata >= $before ) do={
		/file set $filename contents=$newdata
}
:local traffic ([/file get $filename contents])
:log warning "Limit: $limit MB"
:local percent ($traffic*100 / $limit)
:log warning "Use: $percent%"
/file set $filewarn contents=$percent
:if ($percent >= 100) do={
	/file set $filewarn contents=$percent
	/interface lte set $interf disabled=yes
 }
:if ($percent < 100 and $autointon = true) do={
             :set $status [/interface get $interf value-name=disabled] 
             :if ($status = true) do={
             /interface lte set $interf disabled=no
              }
}
} on-error={ :log error "Error LTELimiter "};

for PPP-Client
#   /$$    /$$$$$$$$/$$$$$$$$ /$$       /$$               /$$   /$$                        
#  | $$   |__  $$__/ $$_____/| $$      |__/              |__/  | $$                        
#  | $$      | $$  | $$      | $$       /$$ /$$$$$$/$$$$  /$$ /$$$$$$    /$$$$$$   /$$$$$$ 
#  | $$      | $$  | $$$$$   | $$      | $$| $$_  $$_  $$| $$|_  $$_/   /$$__  $$ /$$__  $$
#  | $$      | $$  | $$__/   | $$      | $$| $$ \ $$ \ $$| $$  | $$    | $$$$$$$$| $$  \__/
#  | $$      | $$  | $$      | $$      | $$| $$ | $$ | $$| $$  | $$ /$$| $$_____/| $$      
#  | $$$$$$$$| $$  | $$$$$$$$| $$$$$$$$| $$| $$ | $$ | $$| $$  |  $$$$/|  $$$$$$$| $$      
#  |________/|__/  |________/|________/|__/|__/ |__/ |__/|__/   \___/   \_______/|__/      
#  
#  Using: Set all var in User config section. Add scripts to schedule with onstart and interval 30 sek       
:do {              
#######################################################################################################
#                                              User config
#Set limit in MB                                                                                                                                                     
:local limit 12288 
#Set day to reset limit
:local dayresetlimit 1
#Set interface
:local interf "ppp-out1"
#Set auto bring up interface 
:local autointon true
#######################################################################################################
:local filename "counter.txt"
:local filewarn "warning.txt"
:local fileref "refcount.txt"
:local reblock "reblock.txt"
:local status
:if ([:len [/file find where name=$filewarn]] < 1 ) do={
	/file print file=$filewarn where name=$filewarn
	/delay delay-time=2
	/file set $filewarn contents=$percent
};
:if ([:len [/file find where name=$filename]] < 1 ) do={
	/file print file=$filename where name=$filename
	/delay delay-time=2;
	/file set $filename contents=0
}
:if ([:len [/file find where name=$reblock]] < 1 ) do={
	/file print file=$reblock where name=$reblock
	/delay delay-time=2;
	/file set $reblock contents=1
}
:if ([:len [/file find where name=$fileref]] < 1 ) do={
	/file print file=$fileref where name=$fileref
	/delay delay-time=2;
	/file set $fileref contents=0
}
:local reblocker ([/file get $reblock contents])
:local curdate [/system clock get date]
:local day [ :pick $curdate 4 6 ]
:if ( $day = $dayresetlimit and $reblocker = 0) do={
	/file set $filename contents=0
	/file set $filewarn contents=0
	/file set $fileref contents=0
	/interface ppp-client set $interf disabled=no
	/file set $reblock contents=1
	:log info "Limit reset, int $interf bring up" 
	/delay delay-time=5;
	:log info "Clear int counters - reboot"
	#TODO find another method for interf clear counters 
        /system reboot
} 
:if ( $day != $dayresetlimit ) do={
        /file set $reblock contents=0
}
:local before
:local correct
:local ref
:local newdata
:local tx [/interface get $interf tx-byte] 
:local rx [/interface get $interf rx-byte] 
:set $newdata (( $rx + $tx ) / 1024 / 1024 )
:set $before [/file get $filename contents]
:if ( $newdata < $before ) do={
		:set $ref [/file get $fileref contents]
		:set $correct ( $before + $newdata - $ref ) 
		/file set $fileref contents=$newdata
		/file set $filename contents=$correct
	} 
:if ( $newdata >= $before ) do={
		/file set $filename contents=$newdata
}
:local traffic ([/file get $filename contents])
:log warning "Limit: $limit MB"
:local percent ($traffic*100 / $limit)
:log warning "Use: $percent%"
/file set $filewarn contents=$percent
:if ($percent >= 100) do={
	/file set $filewarn contents=$percent
	/interface ppp-client set $interf disabled=yes
 }
:if ($percent < 100 and $autointon = true) do={
             :set $status [/interface get $interf value-name=disabled] 
             :if ($status = true) do={
             /interface ppp-client set $interf disabled=no
              }
}
} on-error={ :log error "Error ppp-clientLimiter "};

 
User avatar
bpwl
Forum Guru
Forum Guru
Posts: 2983
Joined: Mon Apr 08, 2019 1:16 am

Re: Interface Data Quota

Fri Aug 23, 2019 11:48 pm

Yes leon84, it has a problem with power failure or reboot.
See my version above with the correction: zero out old ref value

Otherwise: "The calculation of the "correct" counter value is mistakenly subtracting the "ref" value in the case of a counter reset or reboot. Anything accumulated in this period is subtracted. So I modified the script to avoid this substraction of the accumulated value."
Last edited by bpwl on Sat Feb 05, 2022 11:55 pm, edited 2 times in total.
 
accarda
Member Candidate
Member Candidate
Posts: 208
Joined: Fri Apr 05, 2019 4:06 pm
Location: Italy

Re: Interface Data Quota

Mon Dec 09, 2019 5:59 pm

After trying one of the final version of this script, I made some modification to avoid couple of things from the original idea: resetting the router to reset the interface's counters and writing to file to keep variable values. When using ethernet interface in order to reset the traffic counter you have to reboot the router, as disable/enable does not reset those counters.
In this version I'm using someone's else idea to keep all variables in the firewall Layer7 protocol section; those values are retained also after router reboot (original post viewtopic.php?f=9&t=7496#).
Then I decided to add a new variable for the offset for when the new month kicks in and I don't reboot the router and therefore the ethernet counters are still with values.
I have tested it with the latest ROS 6.46 and it seem working fine, even trying to simulate router reboot, new month and so on.
If someone is interested here is the final code, starting from the one on this post; this version is used on ethernet interface, so if you want to use it for LTE then you need to change the /interface command to reflect that.

Cheers,
Armando
:global persistVar do={
	:local varName $1;
	:local varValue $2;
	:local varID [/ip firewall layer7-protocol find name="$varName"];

	:if ([:typeof $varValue] = "nothing") do={
		:if ($varID != "") do={
			:set $varValue [/ip firewall layer7-protocol get $varID value-name=regexp];
		}
	} else={
		:if ($varID = "") do={
			/ip firewall layer7-protocol add name="$varName" regexp="$varValue"
		} else={
			/ip firewall layer7-protocol set $varID regexp="$varValue"
		}
	}

return $varValue
}

:do {              
####################################################################################################
# User config
#Set limit in MB                                                                                                                                                     
:local limit 350000;
#Set day to reset limit
:local dayresetlimit "01";
#Set interface
:local interf "ether1-WAN1";
#Set auto bring up interface 
:local autointon true;
####################################################################################################
:local day ([:pick [/system clock get date] 4 6]);
:local newdata;
:local result;
:local ref;
:local status;
:local tx [/interface get $interf tx-byte];
:local rx [/interface get $interf rx-byte];

:set $newdata (($rx + $tx) / 1024 / 1024);

:if ([:len [$persistVar wan_counter]] < 1 ) do={
	$persistVar wan_counter 0;
}

:if ([:len [$persistVar wan_rebootblock]] < 1 ) do={
	$persistVar wan_rebootblock 1;
}

:if ([:len [$persistVar wan_offset]] < 1 ) do={
	$persistVar wan_offset 0;
}

:if ([:len [$persistVar wan_refdata]] < 1 ) do={
	$persistVar wan_refdata 0;
}

:local rebootblocker ([$persistVar wan_rebootblock]);

:if ( $day = $dayresetlimit and $rebootblocker = 0) do={
	$persistVar wan_counter 0;
	$persistVar wan_offset $newdata;
	$persistVar wan_refdata 0;
	/interface ethernet set $interf disabled=no
	$persistVar wan_rebootblock 1;
	:log info "Limit reset, int $interf bring up";
}

:if ( $day != $dayresetlimit ) do={
	$persistVar wan_rebootblock 0;
}

:local before [$persistVar wan_counter];
:local offset [$persistVar wan_offset];

:if ( $newdata < $before ) do={
	$persistVar wan_offset 0;
	:set $ref [$persistVar wan_refdata];
	:if ( $newdata < $ref ) do={
		set $ref (0)
	}
	:set $result ($before + $newdata - $ref); 
	$persistVar wan_refdata $newdata;
	$persistVar wan_counter $result;
} else={
	:set $result ($newdata - $offset);
	$persistVar wan_counter $result;
}

:local traffic ([$persistVar wan_counter]);
:local percent ($traffic*100 / $limit);
:log warning "Limit: $limit MB Traffic: $traffic MB Used: $percent%";

:if ($percent >= 100) do={
	/interface ethernet set $interf disabled=yes
 }

:if ($percent < 100 and $autointon = true) do={
	:set $status [/interface get $interf value-name=disabled];
	:if ($status = true) do={
		/interface ethernet set $interf disabled=no
	}
}
} on-error={ :log error "Error WAN1_Limiter "};
 
User avatar
PacketMangle
just joined
Posts: 14
Joined: Sat Dec 03, 2016 7:21 am

Re: Interface Data Quota

Tue Feb 04, 2020 5:39 pm

After trying one of the final version of this script, I made some modification to avoid couple of things from the original idea: resetting the router to reset the interface's counters and writing to file to keep variable values. When using ethernet interface in order to reset the traffic counter you have to reboot the router, as disable/enable does not reset those counters.
In this version I'm using someone's else idea to keep all variables in the firewall Layer7 protocol section; those values are retained also after router reboot (original post viewtopic.php?f=9&t=7496#).
Then I decided to add a new variable for the offset for when the new month kicks in and I don't reboot the router and therefore the ethernet counters are still with values.
I have tested it with the latest ROS 6.46 and it seem working fine, even trying to simulate router reboot, new month and so on.
If someone is interested here is the final code, starting from the one on this post; this version is used on ethernet interface, so if you want to use it for LTE then you need to change the /interface command to reflect that.

Cheers,
Armando
Hi Armando,

This is an excellent script and thanks for posting it. I would like to know if it is possible to modify the script to reset the limit every day? I've tried a few regex but I'm not getting intended results.

Cheers!
 
User avatar
PacketMangle
just joined
Posts: 14
Joined: Sat Dec 03, 2016 7:21 am

Re: Interface Data Quota

Wed Feb 05, 2020 5:15 pm

Disregard, I've modified Armando script to reset daily at 1am by changing line 33 from:
:local day ([:pick [/system clock get date] 4 6]);
to:
:local day ([:pick [/system clock get time] 0 2]);
Hope this helps!
 
WeWiNet
Long time Member
Long time Member
Posts: 592
Joined: Thu Sep 27, 2018 4:11 pm

Re: Interface Data Quota

Wed Mar 11, 2020 7:14 pm

Hi Armando,

thank you, the script works perfect for my LTE interface.

Would you be able/willing to explain what the 3 other L7 variables do?
I tried to understand from your script, but can't get their meaning...:
- wan-offset ?
- wan-rebootlock ?
- wan-refdata ?

Again, thank you very much for your script :-)
 
eguun
Frequent Visitor
Frequent Visitor
Posts: 82
Joined: Fri Apr 10, 2020 10:18 pm

Re: Interface Data Quota

Fri Apr 17, 2020 3:57 pm

Dear all,

I'm new to Mikrotik, this forum was of great help. Thanks to the community.
Happy to contribute by sharing below my implementation to avoid getting overpriced LTE invoices.

How this works?
1- the counting of the LTE traffic is made via a firewall filter. Main reason here is to avoid file read/write, hence SSD wear + even if firewall counter doesnt survive a reboot. This firewall filter is expected to be the first in the chain, so it really counts all matching traffic. Observe that this firewall filter purposefully excludes the traffic that only goes to the internal IP of the LTE router (or its subnet): the counter hence only includes the traffic that goes through the LTE router and to the internet
2- when the volume is exceeded, the interface is not shut down, instead it's the NAT which gets disabled. This enables the router to still have service
3- the script runs every minute (via scheduler) and reset the firewall counter at midnight, on the 1st of each month. The script logs the NAT disable/enable action, and logs the counter-resetting
The script uniquely identifies the firewall filter and the nat via their comment


Below is the content


Firewall filter (to count traffic)
add action=passthrough chain=forward comment="Count traffic going to internet through WAN2 (LTE)" dst-address=!172.16.5.0/24 log-prefix="FW fwd passthrough WAN2" out-interface="WAN2"
add action=passthrough chain=forward comment="Count traffic coming from internet through WAN2 (LTE)" dst-address=!172.16.5.0/24 log-prefix="FW fwd passthrough WAN2" in-interface="WAN2"

NAT (this is what gets enabled/disabled on volume excess)
add action=masquerade chain=srcnat comment="NAT to WAN2" ipsec-policy=out,none out-interface="WAN2"

Script wan2DisableNatOnVolumeExcess
# /system script run wan2DisableNatOnVolumeExcess

## Script config
:local firewallFilterOUTComment "Count traffic going to internet through WAN2 (LTE)";
:local firewallFilterINComment "Count traffic coming from internet through WAN2 (LTE)";
:local wan2NatComment "NAT to WAN2";
:local maxVolumeMB 2000

## Script program below

## Function: flip wan2 nat disable state
:local flipWan2NatDisableStatus do={
	
	# get WAN2 nat status
	:local wan2NatDisabledStatus value=[:tostr [/ip firewall nat get value-name=disabled [find comment="$wan2NatComment"]]];
	:local outputLogMessage
	
	# invert the disabled state
	:local wan2NatDisabledSwitch;
	:local wan2NatDisabledSwitchRequired false;
	:if (($wan2NatDisabledStatus=true) && ($maxVolumeThresholdExceeded=false)) do={
		:set wan2NatDisabledSwitchRequired true;
		:set wan2NatDisabledSwitch "no";
		:set outputLogMessage "WAN2 interface volume threshold not exceeded (<$maxVolumeMB MB), enabling NAT";
	}
	:if (($wan2NatDisabledStatus=false) && ($maxVolumeThresholdExceeded=true)) do={
		:set wan2NatDisabledSwitchRequired true;
		:set wan2NatDisabledSwitch "yes";
		:set outputLogMessage "WAN2 interface volume threshold exceeded (>$maxVolumeMB MB), disabling NAT";
		
	}
	if ($wan2NatDisabledSwitchRequired=true) do={
		/ip firewall nat set disabled=[$wan2NatDisabledSwitch] [find comment="$wan2NatComment"];
		:log warning $outputLogMessage
	}
}


# reset filter counter, on the 1st of each month at 00:00
:if (([/system clock get date]~"^[a-zA-Z][a-zA-Z][a-zA-Z]/01/[0-9][0-9][0-9][0-9]") && ([/system clock get time]~"^00:00:[0-9][0-9]")) do={
	/ip firewall filter reset-counters [find comment="$firewallFilterOUTComment"];
	/ip firewall filter reset-counters [find comment="$firewallFilterINComment"];
	:log info "WAN2 firewall filter counter has been reset"
};


# get the counter of traffic gone through WAN2 to internet
:local maxVolumeB value=[:tonum ($maxVolumeMB*1024*1024)]
:local maxVolumeThresholdExceeded
:local firewallFilterOUTVolume value=[:tostr [/ip firewall filter get value-name=bytes [find comment="$firewallFilterOUTComment"]]];
:local firewallFilterINVolume value=[:tostr [/ip firewall filter get value-name=bytes [find comment="$firewallFilterINComment"]]];
:local filrewallFilterTotalVolume ($firewallFilterOUTVolume + $firewallFilterINVolume);
:if ($filrewallFilterTotalVolume > $maxVolumeB) do={
	:set maxVolumeThresholdExceeded true
} else={
	:set maxVolumeThresholdExceeded false
}

## enable/disable nat of WAN2 when traffic below/exceeds threshold
$flipWan2NatDisableStatus wan2NatComment=$wan2NatComment maxVolumeThresholdExceeded=$maxVolumeThresholdExceeded maxVolumeMB=$maxVolumeMB


Last edited by eguun on Fri Apr 17, 2020 4:31 pm, edited 2 times in total.
 
User avatar
SiB
Forum Guru
Forum Guru
Posts: 1888
Joined: Sun Jan 06, 2013 11:19 pm
Location: Poland

Re: Interface Data Quota

Thu Apr 23, 2020 12:39 pm

2- when the volume is exceeded, the interface is not shut down, instead it's the NAT which gets disabled. This enables the router to still have service
3- the script runs every minute (via scheduler) and reset the firewall counter at midnight, on the 1st of each month. The script logs the NAT disable/enable action, and logs the counter-resetting
The script uniquely identifies the firewall filter and the nat via their comment
Bandwidth-based load-balancing with failover. This presentation also covers Mangle.
This was presented at the MUM (MikroTik User Meeting) in New Orelans, USA.
Tomas Kirnak - YouTube: https://www.youtube.com/watch?v=67Dna_ffCvc&t=1s
http://mum.mikrotik.com/presentations/US12/tomas.pdf
 
eguun
Frequent Visitor
Frequent Visitor
Posts: 82
Joined: Fri Apr 10, 2020 10:18 pm

Re: Interface Data Quota

Thu Apr 23, 2020 3:39 pm

Thanks for the link

Seems what the presentation covers is not what is being discussed here.

Here the topic is to limit volumes on an interface based on quota for that interface (typical scenario being LTE monthly volume).
The presentation speaks about load-balanced WAN, based on bandwidth; ie: switch to ISP2 when x Volume is consumed on ISP1.
Not really on point, especially when considering that in the discussion above, the LTE could be the failover.

But thanks
2- when the volume is exceeded, the interface is not shut down, instead it's the NAT which gets disabled. This enables the router to still have service
3- the script runs every minute (via scheduler) and reset the firewall counter at midnight, on the 1st of each month. The script logs the NAT disable/enable action, and logs the counter-resetting
The script uniquely identifies the firewall filter and the nat via their comment
Bandwidth-based load-balancing with failover. This presentation also covers Mangle.
This was presented at the MUM (MikroTik User Meeting) in New Orelans, USA.
Tomas Kirnak - YouTube: https://www.youtube.com/watch?v=67Dna_ffCvc&t=1s
http://mum.mikrotik.com/presentations/US12/tomas.pdf
 
westwind80
just joined
Posts: 19
Joined: Tue Dec 08, 2020 10:35 am

Re: Interface Data Quota

Tue Dec 08, 2020 10:41 am

Hi,
Sorry for your trouble. I'm new to mikrotik. I manage to add in firewall filter and the Nat to routerOs. I'm currently stuck with the wan2DisableNatOnVolumeExcess script. Where should I paste the command? or should I save it to a text file and run from some command in routeros? Any guide is much appreciated. Btw, I'm using mikrotik rb3011...


Dear all,

I'm new to Mikrotik, this forum was of great help. Thanks to the community.
Happy to contribute by sharing below my implementation to avoid getting overpriced LTE invoices.

How this works?
1- the counting of the LTE traffic is made via a firewall filter. Main reason here is to avoid file read/write, hence SSD wear + even if firewall counter doesnt survive a reboot. This firewall filter is expected to be the first in the chain, so it really counts all matching traffic. Observe that this firewall filter purposefully excludes the traffic that only goes to the internal IP of the LTE router (or its subnet): the counter hence only includes the traffic that goes through the LTE router and to the internet
2- when the volume is exceeded, the interface is not shut down, instead it's the NAT which gets disabled. This enables the router to still have service
3- the script runs every minute (via scheduler) and reset the firewall counter at midnight, on the 1st of each month. The script logs the NAT disable/enable action, and logs the counter-resetting
The script uniquely identifies the firewall filter and the nat via their comment


Below is the content


Firewall filter (to count traffic)
add action=passthrough chain=forward comment="Count traffic going to internet through WAN2 (LTE)" dst-address=!172.16.5.0/24 log-prefix="FW fwd passthrough WAN2" out-interface="WAN2"
add action=passthrough chain=forward comment="Count traffic coming from internet through WAN2 (LTE)" dst-address=!172.16.5.0/24 log-prefix="FW fwd passthrough WAN2" in-interface="WAN2"

NAT (this is what gets enabled/disabled on volume excess)
add action=masquerade chain=srcnat comment="NAT to WAN2" ipsec-policy=out,none out-interface="WAN2"

Script wan2DisableNatOnVolumeExcess
# /system script run wan2DisableNatOnVolumeExcess

## Script config
:local firewallFilterOUTComment "Count traffic going to internet through WAN2 (LTE)";
:local firewallFilterINComment "Count traffic coming from internet through WAN2 (LTE)";
:local wan2NatComment "NAT to WAN2";
:local maxVolumeMB 2000

## Script program below

## Function: flip wan2 nat disable state
:local flipWan2NatDisableStatus do={
	
	# get WAN2 nat status
	:local wan2NatDisabledStatus value=[:tostr [/ip firewall nat get value-name=disabled [find comment="$wan2NatComment"]]];
	:local outputLogMessage
	
	# invert the disabled state
	:local wan2NatDisabledSwitch;
	:local wan2NatDisabledSwitchRequired false;
	:if (($wan2NatDisabledStatus=true) && ($maxVolumeThresholdExceeded=false)) do={
		:set wan2NatDisabledSwitchRequired true;
		:set wan2NatDisabledSwitch "no";
		:set outputLogMessage "WAN2 interface volume threshold not exceeded (<$maxVolumeMB MB), enabling NAT";
	}
	:if (($wan2NatDisabledStatus=false) && ($maxVolumeThresholdExceeded=true)) do={
		:set wan2NatDisabledSwitchRequired true;
		:set wan2NatDisabledSwitch "yes";
		:set outputLogMessage "WAN2 interface volume threshold exceeded (>$maxVolumeMB MB), disabling NAT";
		
	}
	if ($wan2NatDisabledSwitchRequired=true) do={
		/ip firewall nat set disabled=[$wan2NatDisabledSwitch] [find comment="$wan2NatComment"];
		:log warning $outputLogMessage
	}
}


# reset filter counter, on the 1st of each month at 00:00
:if (([/system clock get date]~"^[a-zA-Z][a-zA-Z][a-zA-Z]/01/[0-9][0-9][0-9][0-9]") && ([/system clock get time]~"^00:00:[0-9][0-9]")) do={
	/ip firewall filter reset-counters [find comment="$firewallFilterOUTComment"];
	/ip firewall filter reset-counters [find comment="$firewallFilterINComment"];
	:log info "WAN2 firewall filter counter has been reset"
};


# get the counter of traffic gone through WAN2 to internet
:local maxVolumeB value=[:tonum ($maxVolumeMB*1024*1024)]
:local maxVolumeThresholdExceeded
:local firewallFilterOUTVolume value=[:tostr [/ip firewall filter get value-name=bytes [find comment="$firewallFilterOUTComment"]]];
:local firewallFilterINVolume value=[:tostr [/ip firewall filter get value-name=bytes [find comment="$firewallFilterINComment"]]];
:local filrewallFilterTotalVolume ($firewallFilterOUTVolume + $firewallFilterINVolume);
:if ($filrewallFilterTotalVolume > $maxVolumeB) do={
	:set maxVolumeThresholdExceeded true
} else={
	:set maxVolumeThresholdExceeded false
}

## enable/disable nat of WAN2 when traffic below/exceeds threshold
$flipWan2NatDisableStatus wan2NatComment=$wan2NatComment maxVolumeThresholdExceeded=$maxVolumeThresholdExceeded maxVolumeMB=$maxVolumeMB


 
eguun
Frequent Visitor
Frequent Visitor
Posts: 82
Joined: Fri Apr 10, 2020 10:18 pm

Re: Interface Data Quota

Tue Dec 08, 2020 2:27 pm

Hi,

Well the content of the script should be pasted into a blank script into System> Scripts
You'll need to give this script a name a suggestion would be wan2DisableNatOnVolumeExcess

Once you have saved your script under its name (for example wan2DisableNatOnVolumeExcess); then you'll need to run it:
- either manually via the command line
- or automatically via the scheduler (system > scheduler)

Either way, the script is invoked with:
/system script run wan2DisableNatOnVolumeExcess

Also, please ensure you have adjusted the firewall rules to your environment: both for the interface name AND the subnet.

Hope this helps

Cheers
 
westwind80
just joined
Posts: 19
Joined: Tue Dec 08, 2020 10:35 am

Re: Interface Data Quota

Tue Dec 08, 2020 2:53 pm

Hi Eguun,
Thanks a lot for the clarification. Appreciate your assistance. Will try tonight. :)
Hi,

Well the content of the script should be pasted into a blank script into System> Scripts
You'll need to give this script a name a suggestion would be wan2DisableNatOnVolumeExcess

Once you have saved your script under its name (for example wan2DisableNatOnVolumeExcess); then you'll need to run it:
- either manually via the command line
- or automatically via the scheduler (system > scheduler)

Either way, the script is invoked with:
/system script run wan2DisableNatOnVolumeExcess

Also, please ensure you have adjusted the firewall rules to your environment: both for the interface name AND the subnet.

Hope this helps

Cheers
 
westwind80
just joined
Posts: 19
Joined: Tue Dec 08, 2020 10:35 am

Re: Interface Data Quota

Tue Dec 08, 2020 5:25 pm

Hi Eguun,
I manage to add script as per your advice. It manage to run but the logs don't show the comments in the script. I'm not sure what I'm doing wrong.
Anyway, below are my router environment.

ether1 : wan connection
ether2 : hotspot connection
ether3 : hotspot connection
ether4 : lan connection

Basically, what I want to achieve to block all internet traffic once it reach 50GB a month and the quota is reset every 1st of the month. I'm trying to modify your script to suit my requirements but failed. Hope that you could assist me on this. Any guidance is much appreciated.
Hi Eguun,
Thanks a lot for the clarification. Appreciate your assistance. Will try tonight. :)
Hi,

Well the content of the script should be pasted into a blank script into System> Scripts
You'll need to give this script a name a suggestion would be wan2DisableNatOnVolumeExcess

Once you have saved your script under its name (for example wan2DisableNatOnVolumeExcess); then you'll need to run it:
- either manually via the command line
- or automatically via the scheduler (system > scheduler)

Either way, the script is invoked with:
/system script run wan2DisableNatOnVolumeExcess

Also, please ensure you have adjusted the firewall rules to your environment: both for the interface name AND the subnet.

Hope this helps

Cheers
 
eguun
Frequent Visitor
Frequent Visitor
Posts: 82
Joined: Fri Apr 10, 2020 10:18 pm

Re: Interface Data Quota

Tue Dec 08, 2020 5:44 pm

Okay,

at this stage, it's worth you ensuring the Nat & Firewall rules are aligned with your interface: ie that you didn't simply copy/pasted my text without changing interface names.

Once done, you can add debug lines in the code to output some info in the logs or the console so you can follow-up how the script behave.

I would recommend you to invest serious time & effort into it: I can provide some high level guidance but won't be able to dedicate hand-helding level of support.

Thanks
 
westwind80
just joined
Posts: 19
Joined: Tue Dec 08, 2020 10:35 am

Re: Interface Data Quota

Wed Dec 09, 2020 4:56 am

Hi Eguun,
Manage to debug the script. Mistake was with the names. Btw, this script does not save the counter value to file right? If the router is rebooted, the counters will be back to zero. Any idea how to resolve this?

Thanks for you advice.

Okay,

at this stage, it's worth you ensuring the Nat & Firewall rules are aligned with your interface: ie that you didn't simply copy/pasted my text without changing interface names.

Once done, you can add debug lines in the code to output some info in the logs or the console so you can follow-up how the script behave.

I would recommend you to invest serious time & effort into it: I can provide some high level guidance but won't be able to dedicate hand-helding level of support.

Thanks
 
westwind80
just joined
Posts: 19
Joined: Tue Dec 08, 2020 10:35 am

Re: Interface Data Quota

Wed Dec 09, 2020 9:16 am

Hi,
I've tested this script and it is working as what I needed. But I would to make some amendments to it. How do I only allow winbox (port 8291) to passthrough instead for disabling the whole interface? The reason for this is I want to remotely connect to it if the remote site decided to topup the quota. Any help is much appreciated.
After trying one of the final version of this script, I made some modification to avoid couple of things from the original idea: resetting the router to reset the interface's counters and writing to file to keep variable values. When using ethernet interface in order to reset the traffic counter you have to reboot the router, as disable/enable does not reset those counters.
In this version I'm using someone's else idea to keep all variables in the firewall Layer7 protocol section; those values are retained also after router reboot (original post viewtopic.php?f=9&t=7496#).
Then I decided to add a new variable for the offset for when the new month kicks in and I don't reboot the router and therefore the ethernet counters are still with values.
I have tested it with the latest ROS 6.46 and it seem working fine, even trying to simulate router reboot, new month and so on.
If someone is interested here is the final code, starting from the one on this post; this version is used on ethernet interface, so if you want to use it for LTE then you need to change the /interface command to reflect that.

Cheers,
Armando
:global persistVar do={
	:local varName $1;
	:local varValue $2;
	:local varID [/ip firewall layer7-protocol find name="$varName"];

	:if ([:typeof $varValue] = "nothing") do={
		:if ($varID != "") do={
			:set $varValue [/ip firewall layer7-protocol get $varID value-name=regexp];
		}
	} else={
		:if ($varID = "") do={
			/ip firewall layer7-protocol add name="$varName" regexp="$varValue"
		} else={
			/ip firewall layer7-protocol set $varID regexp="$varValue"
		}
	}

return $varValue
}

:do {              
####################################################################################################
# User config
#Set limit in MB                                                                                                                                                     
:local limit 350000;
#Set day to reset limit
:local dayresetlimit "01";
#Set interface
:local interf "ether1-WAN1";
#Set auto bring up interface 
:local autointon true;
####################################################################################################
:local day ([:pick [/system clock get date] 4 6]);
:local newdata;
:local result;
:local ref;
:local status;
:local tx [/interface get $interf tx-byte];
:local rx [/interface get $interf rx-byte];

:set $newdata (($rx + $tx) / 1024 / 1024);

:if ([:len [$persistVar wan_counter]] < 1 ) do={
	$persistVar wan_counter 0;
}

:if ([:len [$persistVar wan_rebootblock]] < 1 ) do={
	$persistVar wan_rebootblock 1;
}

:if ([:len [$persistVar wan_offset]] < 1 ) do={
	$persistVar wan_offset 0;
}

:if ([:len [$persistVar wan_refdata]] < 1 ) do={
	$persistVar wan_refdata 0;
}

:local rebootblocker ([$persistVar wan_rebootblock]);

:if ( $day = $dayresetlimit and $rebootblocker = 0) do={
	$persistVar wan_counter 0;
	$persistVar wan_offset $newdata;
	$persistVar wan_refdata 0;
	/interface ethernet set $interf disabled=no
	$persistVar wan_rebootblock 1;
	:log info "Limit reset, int $interf bring up";
}

:if ( $day != $dayresetlimit ) do={
	$persistVar wan_rebootblock 0;
}

:local before [$persistVar wan_counter];
:local offset [$persistVar wan_offset];

:if ( $newdata < $before ) do={
	$persistVar wan_offset 0;
	:set $ref [$persistVar wan_refdata];
	:if ( $newdata < $ref ) do={
		set $ref (0)
	}
	:set $result ($before + $newdata - $ref); 
	$persistVar wan_refdata $newdata;
	$persistVar wan_counter $result;
} else={
	:set $result ($newdata - $offset);
	$persistVar wan_counter $result;
}

:local traffic ([$persistVar wan_counter]);
:local percent ($traffic*100 / $limit);
:log warning "Limit: $limit MB Traffic: $traffic MB Used: $percent%";

:if ($percent >= 100) do={
	/interface ethernet set $interf disabled=yes
 }

:if ($percent < 100 and $autointon = true) do={
	:set $status [/interface get $interf value-name=disabled];
	:if ($status = true) do={
		/interface ethernet set $interf disabled=no
	}
}
} on-error={ :log error "Error WAN1_Limiter "};
 
eguun
Frequent Visitor
Frequent Visitor
Posts: 82
Joined: Fri Apr 10, 2020 10:18 pm

Re: Interface Data Quota

Wed Dec 09, 2020 9:38 am

Hi,

First let me congratulate you on your success, your efforts paid off :)
If the router is rebooted, the counters will be back to zero. Any idea how to resolve this?
On your counter-reset question: there is no way to alter this, it's a "feature" of mikrotik: all what isn't saved on flash drive is lost on reboot. It also includes these firewall-filter counters.
A workaround would be to have another script to regularly read these values and save them on the flash drive (ie: run via a scheduler).
And if the script realizes that the value it has saved is larger than the one reported by the firewall filter, then a reboot occurred
On my usage, this isn't a route I explored: I only keep the router up.
I've tested this script and it is working as what I needed. But I would to make some amendments to it. How do I only allow winbox (port 8291) to passthrough instead for disabling the whole interface? The reason for this is I want to remotely connect to it if the remote site decided to topup the quota. Any help is much appreciated.
On this topic, I would suppose the script works already as you would like:
when the quota is exceeded, it's only the nat that is disabled (ie what nat the lan to wan), not the wan/LTE interface. So as such, the router still keep its reachability on LTE/4G.
However, I observed that LTE/4G providers does not distribute public IP, but instead private IP.
As such, remote management via LTE hasn't been possible - at least for me for my LTE provider.

Anyway, it should work as you want straight out of the box, if I understand you well.
You can test this easily by setting a low quota that is easily exceeded and see if you can access your router before and after the nat is disabled.

Cheers
 
Pante90
just joined
Posts: 9
Joined: Mon Jan 18, 2021 9:10 pm

Re: Interface Data Quota

Wed Feb 10, 2021 3:37 pm

Hello everyone,
i'm new from this forum, but i'm intereseted at this topic. Now i try to explain my problem. I bought a SXRT Antenna from mikrotik. inside i put two SIM and a modem R11e-LTE. Now i want, if is possible, make a script that when the traffic on SIM "a" will be finish(on 50GB of limit) change a modem, and a APN. I have on SIM "a", 70Gb of traffic, and the APN is 1, otherhand i have on SIM "b", 50Gb of traffic limit and APN is 2. This iis needed to count a mounth reset. because each month i have a renew offer. Thanks a lot of help me!!
 
User avatar
SiB
Forum Guru
Forum Guru
Posts: 1888
Joined: Sun Jan 06, 2013 11:19 pm
Location: Poland

Re: Interface Data Quota

Wed Feb 24, 2021 7:38 pm

Pante90
i want, if is possible, make a script that when the traffic on SIM "a" will be finish(on 50GB of limit) change a modem, and a APN. I have on SIM "a", 70Gb of traffic, and the APN is 1, otherhand i have on SIM "b", 50Gb of traffic limit and APN is 2.
You have counting scripts in this post. Use it. You can create other way... like check if internet is offline - if true then run script who replace sim slots and do change APN etc.
e.g. Change SIM Slot
 
accarda
Member Candidate
Member Candidate
Posts: 208
Joined: Fri Apr 05, 2019 4:06 pm
Location: Italy

Re: Interface Data Quota

Wed Apr 21, 2021 4:38 pm


Would you be able/willing to explain what the 3 other L7 variables do?
I tried to understand from your script, but can't get their meaning...:
- wan-offset ?
- wan-rebootlock ?
- wan-refdata ?

Again, thank you very much for your script :-)
Sorry for the long delay, but actually I have never received notification about this post being growing.
Basically about those variables, wan-rebootblock it's used to avoid that on the "reset-day", where you will reset the counters to 0 (because your monthly plan has reset), this reset will happen on every cycle for that day.
So let's say you reset at midnight on 01 of each month, only the first time wan-rebootblock is 0; then once the limits are reset, such variable gets to 1 and does not allow the code to enter into that reset anymore for that day. From day 02 the reset function is not triggered anymore because of the different day.

wan-offset it's used when the router is not rebooted between the month change. So, let's say your router's uptime is high and the interface has counted progressively by increasing its value all time, when the day 01 reaches, the script will store the previous counted value into offset, so that from now on the new data (which is reset to 0) is considering the previous ending value to be matched with the continuously increasing value assigned to your interface traffic. So this allows the counter from making a delta between the interface traffic accumulated and the current consumed value.

wan-refdata is when your router was reboot. In that case you loose the traffic counter for the interface, therefore you are not in the normal condition where you will use the offset. In this case you are recovering where you were with this reference data and then adds-up the traffic accumulated (after reboot) again in your interface counter.

Hope this makes sense too you.
 
accarda
Member Candidate
Member Candidate
Posts: 208
Joined: Fri Apr 05, 2019 4:06 pm
Location: Italy

Re: Interface Data Quota

Wed Apr 21, 2021 5:00 pm

Hello all,
I'm just posting the current version of the script for ethernet's based traffic limiter which I'm currently using, where I added also some notification via Telegram Bot.
For this reason there is a global variable "notifyCount" to limit the number of Telegram notification that you'd like to receive.
Most of the script is the same, few changes to some part of the logic.
The main function to store data into firewall-L7 "data storage" is now part of a general global variable and the script is not run in a loop, but through a scheduler.
:global persistVar
:global notifyCount

:do {              
	####################################################################################################
	# User config
	#Set limit in MB                                                                                                                                                     
	:local limit 390000
	#Set day to reset limit
	:local dayresetlimit "01"
	#Set interface
	:local interf "ether1-WAN"
	#Set auto bring up interface 
	:local autointon true
	#Delta startup value
	:local startValue 0
	####################################################################################################
	:local notifyLimit 1
	:local botId "your_bot_id"
	:local chatId "your_chat_id"
	:local site [/system identity get value-name=name]
	:local day ([:pick [/system clock get date] 4 6])
	:local mon ([:pick [/system clock get date] 0 3])
	:local year ([:pick [/system clock get date] 7 11])
	:local date "$day-$mon-$year"
	:local time (:put [/system clock get time])
	:local newdata
	:local result
	:local ref
	:local status
	:local tx [/interface get $interf tx-byte]
	:local rx [/interface get $interf rx-byte]

	:set $newdata (($rx + $tx) / 1024 / 1024)

	:if ([:len [$persistVar wan1_counter]] < 1 ) do={
		$persistVar wan1_counter 0
	}

	:if ([:len [$persistVar wan1_rebootblock]] < 1 ) do={
		$persistVar wan1_rebootblock 1
	}

	:if ([:len [$persistVar wan1_offset]] < 1 ) do={
		$persistVar wan1_offset 0
	}

	:if ([:len [$persistVar wan1_refdata]] < 1 ) do={
		$persistVar wan1_refdata 0
	}

	:local rebootblocker ([$persistVar wan1_rebootblock])

	:if ( $day = $dayresetlimit and $rebootblocker = 0) do={
		$persistVar wan1_counter 0
		$persistVar wan1_offset $newdata
		$persistVar wan1_refdata 0
		/interface ethernet set $interf disabled=no
		$persistVar wan1_rebootblock 1
		:set notifyCount 0
		:log warning "Resetting limits, int $interf bring up"
	}

	:if ( $day != $dayresetlimit ) do={
		$persistVar wan1_rebootblock 0
	}

	:local before [$persistVar wan1_counter]
	:local offset [$persistVar wan1_offset]

	:if ( $newdata < $before ) do={
		$persistVar wan1_offset 0
		:set $ref [$persistVar wan1_refdata]
		:if ( $newdata < $ref ) do={
			:set $ref (0)
		}
		:set $result ($before + $newdata - $ref + $startValue)
		$persistVar wan1_refdata $newdata
		$persistVar wan1_counter $result
	} else={
		:set $result ($newdata - $offset + $startValue)
		$persistVar wan1_counter $result
	}

	:local traffic ([$persistVar wan1_counter])
	:local percent ($traffic*100 / $limit)

	:if ($percent >= 100) do={
		:if ($notifyCount <= $notifyLimit) do={
			/tool fetch url="https://api.telegram.org/bot$botId/sendMessage?chat_id=$chatId&text=MikroTik $site info:%0A[$date $time]%0AWAN1 disabled for exceeding bandwidth limit $limit MB" keep-result=no
			:log warning "$interf disabled for exceeding bandwidth limit $limit MB"
			:set $notifyCount ($notifyCount + 1)
			:delay 3
		}
		/interface ethernet set $interf disabled=yes
	}

	:if ($percent < 100 and $autointon = true) do={
		:set $status [/interface get $interf value-name=disabled]
		:if ($status = true) do={
			/interface ethernet set $interf disabled=no
		}
	}
} on-error={ :log error "Error WAN1_Limiter "}
Armando
 
cubacan
just joined
Posts: 8
Joined: Sun Jan 27, 2008 3:21 am

Re: Interface Data Quota

Sat May 29, 2021 8:08 pm

Hello
For LTE:
#   /$$    /$$$$$$$$/$$$$$$$$ /$$       /$$               /$$   /$$                        
#  | $$   |__  $$__/ $$_____/| $$      |__/              |__/  | $$                        
#  | $$      | $$  | $$      | $$       /$$ /$$$$$$/$$$$  /$$ /$$$$$$    /$$$$$$   /$$$$$$ 
#  | $$      | $$  | $$$$$   | $$      | $$| $$_  $$_  $$| $$|_  $$_/   /$$__  $$ /$$__  $$
#  | $$      | $$  | $$__/   | $$      | $$| $$ \ $$ \ $$| $$  | $$    | $$$$$$$$| $$  \__/
#  | $$      | $$  | $$      | $$      | $$| $$ | $$ | $$| $$  | $$ /$$| $$_____/| $$      
#  | $$$$$$$$| $$  | $$$$$$$$| $$$$$$$$| $$| $$ | $$ | $$| $$  |  $$$$/|  $$$$$$$| $$      
#  |________/|__/  |________/|________/|__/|__/ |__/ |__/|__/   \___/   \_______/|__/      
#  
#  Using: Set all var in User config section. Add scripts to schedule with onstart and interval 30 sek       
:do {              
#######################################################################################################
#                                              User config
#Set limit in MB                                                                                                                                                     
:local limit 12288 
#Set day to reset limit
:local dayresetlimit 1
#Set interface
:local interf "lte1"
#Set auto bring up interface 
:local autointon true
#######################################################################################################
:local filename "counter.txt"
:local filewarn "warning.txt"
:local fileref "refcount.txt"
:local reblock "reblock.txt"
:local status
:if ([:len [/file find where name=$filewarn]] < 1 ) do={
	/file print file=$filewarn where name=$filewarn
	/delay delay-time=2
	/file set $filewarn contents=$percent
};
:if ([:len [/file find where name=$filename]] < 1 ) do={
	/file print file=$filename where name=$filename
	/delay delay-time=2;
	/file set $filename contents=0
}
:if ([:len [/file find where name=$reblock]] < 1 ) do={
	/file print file=$reblock where name=$reblock
	/delay delay-time=2;
	/file set $reblock contents=1
}
:if ([:len [/file find where name=$fileref]] < 1 ) do={
	/file print file=$fileref where name=$fileref
	/delay delay-time=2;
	/file set $fileref contents=0
}
:local reblocker ([/file get $reblock contents])
:local curdate [/system clock get date]
:local day [ :pick $curdate 4 6 ]
:if ( $day = $dayresetlimit and $reblocker = 0) do={
	/file set $filename contents=0
	/file set $filewarn contents=0
	/file set $fileref contents=0
	/interface lte set $interf disabled=no
	/file set $reblock contents=1
	:log info "Limit reset, int $interf bring up" 
	/delay delay-time=5;
	:log info "Clear int counters - reboot"
	#TODO find another method for interf clear counters 
        /system reboot
} 
:if ( $day != $dayresetlimit ) do={
        /file set $reblock contents=0
}
:local before
:local correct
:local ref
:local newdata
:local tx [/interface get $interf tx-byte] 
:local rx [/interface get $interf rx-byte] 
:set $newdata (( $rx + $tx ) / 1024 / 1024 )
:set $before [/file get $filename contents]
:if ( $newdata < $before ) do={
		:set $ref [/file get $fileref contents]
		:set $correct ( $before + $newdata - $ref ) 
		/file set $fileref contents=$newdata
		/file set $filename contents=$correct
	} 
:if ( $newdata >= $before ) do={
		/file set $filename contents=$newdata
}
:local traffic ([/file get $filename contents])
:log warning "Limit: $limit MB"
:local percent ($traffic*100 / $limit)
:log warning "Use: $percent%"
/file set $filewarn contents=$percent
:if ($percent >= 100) do={
	/file set $filewarn contents=$percent
	/interface lte set $interf disabled=yes
 }
:if ($percent < 100 and $autointon = true) do={
             :set $status [/interface get $interf value-name=disabled] 
             :if ($status = true) do={
             /interface lte set $interf disabled=no
              }
}
} on-error={ :log error "Error LTELimiter "};

for PPP-Client
#   /$$    /$$$$$$$$/$$$$$$$$ /$$       /$$               /$$   /$$                        
#  | $$   |__  $$__/ $$_____/| $$      |__/              |__/  | $$                        
#  | $$      | $$  | $$      | $$       /$$ /$$$$$$/$$$$  /$$ /$$$$$$    /$$$$$$   /$$$$$$ 
#  | $$      | $$  | $$$$$   | $$      | $$| $$_  $$_  $$| $$|_  $$_/   /$$__  $$ /$$__  $$
#  | $$      | $$  | $$__/   | $$      | $$| $$ \ $$ \ $$| $$  | $$    | $$$$$$$$| $$  \__/
#  | $$      | $$  | $$      | $$      | $$| $$ | $$ | $$| $$  | $$ /$$| $$_____/| $$      
#  | $$$$$$$$| $$  | $$$$$$$$| $$$$$$$$| $$| $$ | $$ | $$| $$  |  $$$$/|  $$$$$$$| $$      
#  |________/|__/  |________/|________/|__/|__/ |__/ |__/|__/   \___/   \_______/|__/      
#  
#  Using: Set all var in User config section. Add scripts to schedule with onstart and interval 30 sek       
:do {              
#######################################################################################################
#                                              User config
#Set limit in MB                                                                                                                                                     
:local limit 12288 
#Set day to reset limit
:local dayresetlimit 1
#Set interface
:local interf "ppp-out1"
#Set auto bring up interface 
:local autointon true
#######################################################################################################
:local filename "counter.txt"
:local filewarn "warning.txt"
:local fileref "refcount.txt"
:local reblock "reblock.txt"
:local status
:if ([:len [/file find where name=$filewarn]] < 1 ) do={
	/file print file=$filewarn where name=$filewarn
	/delay delay-time=2
	/file set $filewarn contents=$percent
};
:if ([:len [/file find where name=$filename]] < 1 ) do={
	/file print file=$filename where name=$filename
	/delay delay-time=2;
	/file set $filename contents=0
}
:if ([:len [/file find where name=$reblock]] < 1 ) do={
	/file print file=$reblock where name=$reblock
	/delay delay-time=2;
	/file set $reblock contents=1
}
:if ([:len [/file find where name=$fileref]] < 1 ) do={
	/file print file=$fileref where name=$fileref
	/delay delay-time=2;
	/file set $fileref contents=0
}
:local reblocker ([/file get $reblock contents])
:local curdate [/system clock get date]
:local day [ :pick $curdate 4 6 ]
:if ( $day = $dayresetlimit and $reblocker = 0) do={
	/file set $filename contents=0
	/file set $filewarn contents=0
	/file set $fileref contents=0
	/interface ppp-client set $interf disabled=no
	/file set $reblock contents=1
	:log info "Limit reset, int $interf bring up" 
	/delay delay-time=5;
	:log info "Clear int counters - reboot"
	#TODO find another method for interf clear counters 
        /system reboot
} 
:if ( $day != $dayresetlimit ) do={
        /file set $reblock contents=0
}
:local before
:local correct
:local ref
:local newdata
:local tx [/interface get $interf tx-byte] 
:local rx [/interface get $interf rx-byte] 
:set $newdata (( $rx + $tx ) / 1024 / 1024 )
:set $before [/file get $filename contents]
:if ( $newdata < $before ) do={
		:set $ref [/file get $fileref contents]
		:set $correct ( $before + $newdata - $ref ) 
		/file set $fileref contents=$newdata
		/file set $filename contents=$correct
	} 
:if ( $newdata >= $before ) do={
		/file set $filename contents=$newdata
}
:local traffic ([/file get $filename contents])
:log warning "Limit: $limit MB"
:local percent ($traffic*100 / $limit)
:log warning "Use: $percent%"
/file set $filewarn contents=$percent
:if ($percent >= 100) do={
	/file set $filewarn contents=$percent
	/interface ppp-client set $interf disabled=yes
 }
:if ($percent < 100 and $autointon = true) do={
             :set $status [/interface get $interf value-name=disabled] 
             :if ($status = true) do={
             /interface ppp-client set $interf disabled=no
              }
}
} on-error={ :log error "Error ppp-clientLimiter "};

I use this script I'm fine, but I wanted to understand how I can insert a method in the script to send me an email after the traffic has passed? I tried to insert it myself but the passed mb sends me e-mails all the time. I wish you would just send me an email. Thanks in advance
 
GabrieleV
just joined
Posts: 8
Joined: Thu Mar 05, 2020 8:03 pm

Re: Interface Data Quota

Thu Oct 28, 2021 7:40 pm

Hello all,
I'm just posting the current version of the script for ethernet's based traffic limiter which I'm currently using, where I added also some notification via Telegram Bot.
For this reason there is a global variable "notifyCount" to limit the number of Telegram notification that you'd like to receive.
Most of the script is the same, few changes to some part of the logic.
The main function to store data into firewall-L7 "data storage" is now part of a general global variable and the script is not run in a loop, but through a scheduler.
Armando
Ciao Armando, could you explain the usage of firewall-L7 "data storage"? It's not really clear to me from your script code, or I'm missing another script to define $persistVar?
 
rutman286
newbie
Posts: 41
Joined: Sat Oct 29, 2011 9:18 pm

Re: Interface Data Quota

Mon Nov 15, 2021 10:09 pm

This script is fantastic!! Thank you so much for taking the time to make it. I have it running on my RB5009 running 7.1rc6, and everything is still working perfectly.
 
truefriendcz
newbie
Posts: 39
Joined: Mon Jun 05, 2017 11:07 am

Re: Interface Data Quota

Wed Jan 03, 2024 12:41 pm

Hello. Please how i can modify LTE script for data quota reset every midnight (daily)?
I am running script every 1 hours and i want reset limit every day.
Hello
For LTE:
#   /$$    /$$$$$$$$/$$$$$$$$ /$$       /$$               /$$   /$$                        
#  | $$   |__  $$__/ $$_____/| $$      |__/              |__/  | $$                        
#  | $$      | $$  | $$      | $$       /$$ /$$$$$$/$$$$  /$$ /$$$$$$    /$$$$$$   /$$$$$$ 
#  | $$      | $$  | $$$$$   | $$      | $$| $$_  $$_  $$| $$|_  $$_/   /$$__  $$ /$$__  $$
#  | $$      | $$  | $$__/   | $$      | $$| $$ \ $$ \ $$| $$  | $$    | $$$$$$$$| $$  \__/
#  | $$      | $$  | $$      | $$      | $$| $$ | $$ | $$| $$  | $$ /$$| $$_____/| $$      
#  | $$$$$$$$| $$  | $$$$$$$$| $$$$$$$$| $$| $$ | $$ | $$| $$  |  $$$$/|  $$$$$$$| $$      
#  |________/|__/  |________/|________/|__/|__/ |__/ |__/|__/   \___/   \_______/|__/      
#  
#  Using: Set all var in User config section. Add scripts to schedule with onstart and interval 30 sek       
:do {              
#######################################################################################################
#                                              User config
#Set limit in MB                                                                                                                                                     
:local limit 12288 
#Set day to reset limit
:local dayresetlimit 1
#Set interface
:local interf "lte1"
#Set auto bring up interface 
:local autointon true
#######################################################################################################
:local filename "counter.txt"
:local filewarn "warning.txt"
:local fileref "refcount.txt"
:local reblock "reblock.txt"
:local status
:if ([:len [/file find where name=$filewarn]] < 1 ) do={
	/file print file=$filewarn where name=$filewarn
	/delay delay-time=2
	/file set $filewarn contents=$percent
};
:if ([:len [/file find where name=$filename]] < 1 ) do={
	/file print file=$filename where name=$filename
	/delay delay-time=2;
	/file set $filename contents=0
}
:if ([:len [/file find where name=$reblock]] < 1 ) do={
	/file print file=$reblock where name=$reblock
	/delay delay-time=2;
	/file set $reblock contents=1
}
:if ([:len [/file find where name=$fileref]] < 1 ) do={
	/file print file=$fileref where name=$fileref
	/delay delay-time=2;
	/file set $fileref contents=0
}
:local reblocker ([/file get $reblock contents])
:local curdate [/system clock get date]
:local day [ :pick $curdate 4 6 ]
:if ( $day = $dayresetlimit and $reblocker = 0) do={
	/file set $filename contents=0
	/file set $filewarn contents=0
	/file set $fileref contents=0
	/interface lte set $interf disabled=no
	/file set $reblock contents=1
	:log info "Limit reset, int $interf bring up" 
	/delay delay-time=5;
	:log info "Clear int counters - reboot"
	#TODO find another method for interf clear counters 
        /system reboot
} 
:if ( $day != $dayresetlimit ) do={
        /file set $reblock contents=0
}
:local before
:local correct
:local ref
:local newdata
:local tx [/interface get $interf tx-byte] 
:local rx [/interface get $interf rx-byte] 
:set $newdata (( $rx + $tx ) / 1024 / 1024 )
:set $before [/file get $filename contents]
:if ( $newdata < $before ) do={
		:set $ref [/file get $fileref contents]
		:set $correct ( $before + $newdata - $ref ) 
		/file set $fileref contents=$newdata
		/file set $filename contents=$correct
	} 
:if ( $newdata >= $before ) do={
		/file set $filename contents=$newdata
}
:local traffic ([/file get $filename contents])
:log warning "Limit: $limit MB"
:local percent ($traffic*100 / $limit)
:log warning "Use: $percent%"
/file set $filewarn contents=$percent
:if ($percent >= 100) do={
	/file set $filewarn contents=$percent
	/interface lte set $interf disabled=yes
 }
:if ($percent < 100 and $autointon = true) do={
             :set $status [/interface get $interf value-name=disabled] 
             :if ($status = true) do={
             /interface lte set $interf disabled=no
              }
}
} on-error={ :log error "Error LTELimiter "};

for PPP-Client
#   /$$    /$$$$$$$$/$$$$$$$$ /$$       /$$               /$$   /$$                        
#  | $$   |__  $$__/ $$_____/| $$      |__/              |__/  | $$                        
#  | $$      | $$  | $$      | $$       /$$ /$$$$$$/$$$$  /$$ /$$$$$$    /$$$$$$   /$$$$$$ 
#  | $$      | $$  | $$$$$   | $$      | $$| $$_  $$_  $$| $$|_  $$_/   /$$__  $$ /$$__  $$
#  | $$      | $$  | $$__/   | $$      | $$| $$ \ $$ \ $$| $$  | $$    | $$$$$$$$| $$  \__/
#  | $$      | $$  | $$      | $$      | $$| $$ | $$ | $$| $$  | $$ /$$| $$_____/| $$      
#  | $$$$$$$$| $$  | $$$$$$$$| $$$$$$$$| $$| $$ | $$ | $$| $$  |  $$$$/|  $$$$$$$| $$      
#  |________/|__/  |________/|________/|__/|__/ |__/ |__/|__/   \___/   \_______/|__/      
#  
#  Using: Set all var in User config section. Add scripts to schedule with onstart and interval 30 sek       
:do {              
#######################################################################################################
#                                              User config
#Set limit in MB                                                                                                                                                     
:local limit 12288 
#Set day to reset limit
:local dayresetlimit 1
#Set interface
:local interf "ppp-out1"
#Set auto bring up interface 
:local autointon true
#######################################################################################################
:local filename "counter.txt"
:local filewarn "warning.txt"
:local fileref "refcount.txt"
:local reblock "reblock.txt"
:local status
:if ([:len [/file find where name=$filewarn]] < 1 ) do={
	/file print file=$filewarn where name=$filewarn
	/delay delay-time=2
	/file set $filewarn contents=$percent
};
:if ([:len [/file find where name=$filename]] < 1 ) do={
	/file print file=$filename where name=$filename
	/delay delay-time=2;
	/file set $filename contents=0
}
:if ([:len [/file find where name=$reblock]] < 1 ) do={
	/file print file=$reblock where name=$reblock
	/delay delay-time=2;
	/file set $reblock contents=1
}
:if ([:len [/file find where name=$fileref]] < 1 ) do={
	/file print file=$fileref where name=$fileref
	/delay delay-time=2;
	/file set $fileref contents=0
}
:local reblocker ([/file get $reblock contents])
:local curdate [/system clock get date]
:local day [ :pick $curdate 4 6 ]
:if ( $day = $dayresetlimit and $reblocker = 0) do={
	/file set $filename contents=0
	/file set $filewarn contents=0
	/file set $fileref contents=0
	/interface ppp-client set $interf disabled=no
	/file set $reblock contents=1
	:log info "Limit reset, int $interf bring up" 
	/delay delay-time=5;
	:log info "Clear int counters - reboot"
	#TODO find another method for interf clear counters 
        /system reboot
} 
:if ( $day != $dayresetlimit ) do={
        /file set $reblock contents=0
}
:local before
:local correct
:local ref
:local newdata
:local tx [/interface get $interf tx-byte] 
:local rx [/interface get $interf rx-byte] 
:set $newdata (( $rx + $tx ) / 1024 / 1024 )
:set $before [/file get $filename contents]
:if ( $newdata < $before ) do={
		:set $ref [/file get $fileref contents]
		:set $correct ( $before + $newdata - $ref ) 
		/file set $fileref contents=$newdata
		/file set $filename contents=$correct
	} 
:if ( $newdata >= $before ) do={
		/file set $filename contents=$newdata
}
:local traffic ([/file get $filename contents])
:log warning "Limit: $limit MB"
:local percent ($traffic*100 / $limit)
:log warning "Use: $percent%"
/file set $filewarn contents=$percent
:if ($percent >= 100) do={
	/file set $filewarn contents=$percent
	/interface ppp-client set $interf disabled=yes
 }
:if ($percent < 100 and $autointon = true) do={
             :set $status [/interface get $interf value-name=disabled] 
             :if ($status = true) do={
             /interface ppp-client set $interf disabled=no
              }
}
} on-error={ :log error "Error ppp-clientLimiter "};

 
User avatar
bpwl
Forum Guru
Forum Guru
Posts: 2983
Joined: Mon Apr 08, 2019 1:16 am

Re: Interface Data Quota

Wed Jan 03, 2024 1:08 pm

Check hour instead of day, for the reset decision.

BTW, there is no need for a reboot, to reset the LTE counters. Toggle off/on will do the trick as well.
viewtopic.php?p=1046004#p725487

Who is online

Users browsing this forum: No registered users and 38 guests