#!/bin/sh -x # # Tomato STM Monitor v1.12 # Written by tievolu # http://www.tievolu.co.uk/stm/stm-monitor.html # # This script is for use on routers running Tomato, connected to the # Internet through a Virgin Media UK cable connection. VM's cable # connections implement Subscriber Traffic Management (STM) i.e. the # WAN bandwidth is limited for a set time (typically five hours) when # a predefined amount of data is transferred between certain hours of # the day. # # It allows the WAN bandwidth usage to be automatically monitored and # suitable QOS settings applied. There are three modes of operation: # # 1. STM Mitigation # # This is the default mode. If an STM limit is exceeded, QOS limits # are applied in accordance with the bandwidth limits imposed by STM. # # 2. STM Prevention # # If bandwidth usage is on target to exceed an STM limit, QOS limits # are applied to prevent that from happening. Activated by the "-p" # option (see below), and controlled by the STM Prevention Threshold # (default 80% of STM limit). # # 3. Intelligent STM Prevention/Mitigation # # If bandwidth usage is on target to exceed an STM limit, the script # analyses the two available options to see which is better - i.e. # either applying STM Prevention, or allowing STM to be triggered and # mitigating it. It makes the decision by calculating which option # will allow more data to be transferred in the long term. # # Add the following to your "WAN Up" script to download the script and # set it to run every two minutes: # # wget -O /tmp/stm-monitor.sh http://www.tievolu.co.uk/stm/stm-monitor.sh # chmod 755 /tmp/stm-monitor.sh # cru a STM-Monitor "1-59/2 * * * * /tmp/stm-monitor.sh [broadband type] [-p|-i]" # logger -t STM-Monitor "Downloaded `head /tmp/stm-monitor.sh | grep \"STM Monitor\" | sed 's/# //g'`" # # Where [broadband type] = "S5", "M", "L", "XL", "ML20", "L30", "XL30", "XXL", "XL60" or "XXL100" (no quotes) # [-p] = Activates STM prevention # [-i] = Activates Intelligent STM Prevention/Mitigation # # Note: Default tier settings assume that your upload speed has been upgraded # to the latest 2012 levels, as described here: # # http://help.virginmedia.com/system/...E=Cable&CMD=VIEW_ARTICLE&ARTICLE_ID=2781#tier # # You can also add the following code to your WAN up script, which allows you # to customise some of the settings: # # echo "STM_PERIOD_BW_LIMIT_1=" >> /tmp/stm-monitor.cfg # echo "STM_PERIOD_BW_LIMIT_2=" >> /tmp/stm-monitor.cfg # echo "STM_PERIOD_BW_LIMIT_3=" >> /tmp/stm-monitor.cfg # echo "STM_PREVENTION_THRESHOLD=" >> /tmp/stm-monitor.cfg # echo "STM_INBOUND_BANDWIDTH_WITHOUT_STM=" >> /tmp/stm-monitor.cfg # echo "STM_INBOUND_BANDWIDTH_WITH_STM=" >> /tmp/stm-monitor.cfg # echo "STM_OUTBOUND_BANDWIDTH_WITHOUT_STM=" >> /tmp/stm-monitor.cfg # echo "STM_OUTBOUND_BANDWIDTH_WITH_STM=" >> /tmp/stm-monitor.cfg # # For example, to set the STM prevention threshold to 50%: # # echo "STM_PREVENTION_THRESHOLD=50" >> /tmp/stm-monitor.cfg # # Events are recorded in the system log, and details are displayed in a # small web page located at: # # http://[router IP address]/ext/stm-monitor.htm # # The script assumes that the time on your router is accurate to within # a minute or so, so make sure your NTP settings are correct! It also only # works correcly if your router is left on throughout each STM period, # because rebooting destroys the Tomato bandwidth stats this script relies on. # Logging command LOGGER="logger -t STM-Monitor" # STM Monitor version stm_monitor_version=`head /tmp/stm-monitor.sh | grep "STM Monitor" | sed 's/# //g'` # Check command line arguments if [[ "$1" != "S5" && "$1" != "M" && "$1" != "L" && "$1" != "XL" && "$1" != "ML20" && "$1" != "L30" && "$1" != "XL30" && "$1" != "XXL" && "$1" != "XL60" && "$1" != "XXL100" ]] then $LOGGER "Usage: stm-monitor.sh [S5|M|L|XL|ML20|L30|XL30|XXL|XL60|XXL100] [-p|-i]" exit fi if [[ "$#" -eq 2 && "$2" != "-p" && "$2" != "-i" ]] then $LOGGER "Usage: stm-monitor.sh [S|M|M+|L|L+|XL|XL+|XXL] [-p|-i]" exit fi # Enable STM prevention if specified if [[ "$2" = "-p" ]] then stm_prevention=1 else stm_prevention=0 fi # Enable Intelligent STM Prevention/Mitigation if specified if [[ "$2" = "-i" ]] then stm_prevention=1 intelligent=1 else stm_prevention=0 intelligent=0 fi # The upload QOS bandwidth values are set at ~91% of the cable modem # bandwidth limiter (download set at 100%), which works well for my # connection. Cable connections tend to be pretty stable so they should work # ok for most users. The STM related variables are based on the information # published by VM here: http://allyours.virginmedia.com/html/internet/traffic.html # STM period definitions (time values are hours of the day e.g. 16 = 16:00 = 4pm) stm_period_name_1="Daytime Downstream" stm_period_start_1=10 stm_period_end_1=15 stm_period_direction_1="RX" stm_period_name_2="Evening Downstream" stm_period_start_2=16 stm_period_end_2=21 stm_period_direction_2="RX" stm_period_name_3="Evening Upstream" stm_period_start_3=15 stm_period_end_3=20 stm_period_direction_3="TX" # STM sentence length (i.e. how long STM lasts for once it's triggered) stm_sentence_length_hours=5 stm_sentence_length_seconds=`expr $stm_sentence_length_hours \* 3600` # Settings specific to XXL100 (100Mb down, 10Mb up) if [[ $1 = "XXL100" ]] then # STM limits (values in MB) stm_period_bw_limit_mb_1=20000 stm_period_bw_limit_mb_2=10000 stm_period_bw_limit_mb_3=12000 # QOS settings (values in Kbits/s) inbound_bandwidth_without_stm=102400 # Not sure if this is accurate inbound_bandwidth_with_stm=51200 outbound_bandwidth_without_stm=9318 # 10240 * 0.91 outbound_bandwidth_with_stm=2330 # 9318 * 0.25 fi # Settings specific to XL60 (60Mb down, 6Mb up) if [[ $1 = "XL60" ]] then # STM limits (values in MB) stm_period_bw_limit_mb_1=10000 stm_period_bw_limit_mb_2=5000 stm_period_bw_limit_mb_3=7000 # QOS settings (values in Kbits/s) inbound_bandwidth_without_stm=64453 # 66000000 bps inbound_bandwidth_with_stm=30720 outbound_bandwidth_without_stm=5591 # 6144 * 0.91 outbound_bandwidth_with_stm=1398 # 5591 * 0.25 fi # Settings specific to XXL (50Mb down, 5Mb up) if [[ $1 = "XXL" ]] then # STM limits (values in MB) stm_period_bw_limit_mb_1=10000 stm_period_bw_limit_mb_2=5000 stm_period_bw_limit_mb_3=6000 # QOS settings (values in Kbits/s) inbound_bandwidth_without_stm=51757 # 53000000 bps inbound_bandwidth_with_stm=25879 outbound_bandwidth_without_stm=4659 # 5120 * 0.91 outbound_bandwidth_with_stm=1630 # 4659 * 0.25 fi # Settings specific to XL30 (30Mb down, 3Mb up) if [[ $1 = "XL30" ]] then # STM limits (values in MB) stm_period_bw_limit_mb_1=7000 stm_period_bw_limit_mb_2=3500 stm_period_bw_limit_mb_3=4200 # QOS settings (values in Kbits/s) inbound_bandwidth_without_stm=32548 # 33330000 b/s inbound_bandwidth_with_stm=16274 outbound_bandwidth_without_stm=2962 # 3333000 b/s * 0.91 outbound_bandwidth_with_stm=740 # 2962 * 0.25 fi # Settings specific to L30 (30Mb down, 3Mb up) if [[ $1 = "L30" ]] then # STM limits (values in MB) stm_period_bw_limit_mb_1=7000 stm_period_bw_limit_mb_2=3500 stm_period_bw_limit_mb_3=4200 # QOS settings (values in Kbits/s) inbound_bandwidth_without_stm=32548 # 33330000 b/s inbound_bandwidth_with_stm=16274 outbound_bandwidth_without_stm=2962 # 3333000 b/s * 0.91 outbound_bandwidth_with_stm=740 # 2962 * 0.25 fi # Settings specific to ML20 (20Mb down, 2Mb up) if [[ $1 = "ML20" ]] then # STM limits (values in MB) stm_period_bw_limit_mb_1=7000 stm_period_bw_limit_mb_2=3500 stm_period_bw_limit_mb_3=3000 # QOS settings (values in Kbits/s) inbound_bandwidth_without_stm=20480 inbound_bandwidth_with_stm=5120 outbound_bandwidth_without_stm=1864 # 2048 * 0.91 outbound_bandwidth_with_stm=466 # 1864 * 0.25 fi # Settings specific to XL (20Mb down, 2Mb up) if [[ $1 = "XL" ]] then # STM limits (values in MB) stm_period_bw_limit_mb_1=7000 stm_period_bw_limit_mb_2=3500 stm_period_bw_limit_mb_3=3000 # QOS settings (values in Kbits/s) inbound_bandwidth_without_stm=20480 inbound_bandwidth_with_stm=5120 outbound_bandwidth_without_stm=1864 # 2048 * 0.91 outbound_bandwidth_with_stm=466 # 1864 * 0.25 fi # Settings specific to L (10Mb down, 1Mb up) if [[ $1 = "L" ]] then # STM limits (values in MB) stm_period_bw_limit_mb_1=3000 stm_period_bw_limit_mb_2=1500 stm_period_bw_limit_mb_3=1500 # QOS settings (values in Kbits/s) inbound_bandwidth_without_stm=10240 inbound_bandwidth_with_stm=2560 outbound_bandwidth_without_stm=932 # 1024 * 0.91 outbound_bandwidth_with_stm=233 # 932 * 0.25 fi # Settings specific to M (10Mb down, 1Mb up) if [[ $1 = "M" ]] then # STM limits (values in MB) stm_period_bw_limit_mb_1=1500 stm_period_bw_limit_mb_2=750 stm_period_bw_limit_mb_3=750 # QOS settings (values in Kbits/s) inbound_bandwidth_without_stm=10240 inbound_bandwidth_with_stm=2560 outbound_bandwidth_without_stm=932 # 1024 * 0.91 outbound_bandwidth_with_stm=233 # 932 * 0.25 fi # Settings specific to S5 (5Mb down, 512Kb up) if [[ $1 = "S5" ]] then # STM limits (values in MB) stm_period_bw_limit_mb_1=500 stm_period_bw_limit_mb_2=250 stm_period_bw_limit_mb_3=200 # QOS settings (values in Kbits/s) inbound_bandwidth_without_stm=10240 inbound_bandwidth_with_stm=2560 outbound_bandwidth_without_stm=932 # 1024 * 0.91 outbound_bandwidth_with_stm=233 # 932 * 0.25 fi # STM prevention threshold. STM prevention only becomes active once # this percentage of the STM bandwidth limit has been transferred. # Default for STM Prevention is 80%. stm_prevention_threshold=80 # Override settings with user-defined values if valid values were specified if [[ -e /jffs/stm-monitor.cfg ]] then source /jffs/stm-monitor.cfg fi if [[ -e /tmp/stm-monitor.cfg ]] then source /tmp/stm-monitor.cfg fi if [[ "$STM_PERIOD_BW_LIMIT_1" != "" ]] then invalid_value=`echo "" | awk '{ if (value < 0) {print(1)} }' value=$STM_PERIOD_BW_LIMIT_1` if [[ "$invalid_value" = 1 ]] then $LOGGER "Invalid STM_PERIOD_BW_LIMIT_1 (${STM_PERIOD_BW_LIMIT_1} MB). Reverting to default value (${stm_period_bw_limit_mb_1} MB)." else stm_period_bw_limit_mb_1=$STM_PERIOD_BW_LIMIT_1 fi fi if [[ "$STM_PERIOD_BW_LIMIT_2" != "" ]] then invalid_value=`echo "" | awk '{ if (value < 0) {print(1)} }' value=$STM_PERIOD_BW_LIMIT_2` if [[ "$invalid_value" = 1 ]] then $LOGGER "Invalid STM_PERIOD_BW_LIMIT_2 (${STM_PERIOD_BW_LIMIT_2} MB). Reverting to default value (${stm_period_bw_limit_mb_2} MB)." else stm_period_bw_limit_mb_2=$STM_PERIOD_BW_LIMIT_2 fi fi if [[ "$STM_PERIOD_BW_LIMIT_3" != "" ]] then invalid_value=`echo "" | awk '{ if (value < 0) {print(1)} }' value=$STM_PERIOD_BW_LIMIT_3` if [[ "$invalid_value" = 1 ]] then $LOGGER "Invalid STM_PERIOD_BW_LIMIT_3 (${STM_PERIOD_BW_LIMIT_3} MB). Reverting to default value (${stm_period_bw_limit_mb_3} MB)." else stm_period_bw_limit_mb_3=$STM_PERIOD_BW_LIMIT_3 fi fi if [[ "$STM_PREVENTION_THRESHOLD" != "" ]] then invalid_value=`echo "" | awk '{ if (value > 100 || value < 0) {print(1)} }' value=$STM_PREVENTION_THRESHOLD` if [[ "$invalid_value" = 1 ]] then $LOGGER "Invalid STM_PREVENTION_THRESHOLD (${STM_PREVENTION_THRESHOLD}%). Reverting to default value (${stm_prevention_threshold}%)." else stm_prevention_threshold=$STM_PREVENTION_THRESHOLD fi fi if [[ "$STM_INBOUND_BANDWIDTH_WITHOUT_STM" != "" ]] then invalid_value=`echo "" | awk '{ if (value < 0) {print(1)} }' value=$STM_INBOUND_BANDWIDTH_WITHOUT_STM` if [[ "$invalid_value" = 1 ]] then $LOGGER "Invalid STM_INBOUND_BANDWIDTH_WITHOUT_STM (${STM_INBOUND_BANDWIDTH_WITHOUT_STM} kb/s). Reverting to default value (${inbound_bandwidth_without_stm} kb/s)." else inbound_bandwidth_without_stm=$STM_INBOUND_BANDWIDTH_WITHOUT_STM fi fi if [[ "$STM_INBOUND_BANDWIDTH_WITH_STM" != "" ]] then invalid_value=`echo "" | awk '{ if (value < 0) {print(1)} }' value=$STM_INBOUND_BANDWIDTH_WITH_STM` if [[ "$invalid_value" = 1 ]] then $LOGGER "Invalid STM_INBOUND_BANDWIDTH_WITH_STM (${STM_INBOUND_BANDWIDTH_WITH_STM} kb/s). Reverting to default value (${inbound_bandwidth_with_stm} kb/s)." else inbound_bandwidth_with_stm=$STM_INBOUND_BANDWIDTH_WITH_STM fi fi if [[ "$STM_OUTBOUND_BANDWIDTH_WITHOUT_STM" != "" ]] then invalid_value=`echo "" | awk '{ if (value < 0) {print(1)} }' value=$STM_OUTBOUND_BANDWIDTH_WITHOUT_STM` if [[ "$invalid_value" = 1 ]] then $LOGGER "Invalid STM_OUTBOUND_BANDWIDTH_WITHOUT_STM (${STM_OUTBOUND_BANDWIDTH_WITHOUT_STM} kb/s). Reverting to default value (${outbound_bandwidth_without_stm} kb/s)." else outbound_bandwidth_without_stm=$STM_OUTBOUND_BANDWIDTH_WITHOUT_STM fi fi if [[ "$STM_OUTBOUND_BANDWIDTH_WITH_STM" != "" ]] then invalid_value=`echo "" | awk '{ if (value < 0) {print(1)} }' value=$STM_OUTBOUND_BANDWIDTH_WITH_STM` if [[ "$invalid_value" = 1 ]] then $LOGGER "Invalid STM_OUTBOUND_BANDWIDTH_WITH_STM (${STM_OUTBOUND_BANDWIDTH_WITH_STM} kb/s). Reverting to default value (${outbound_bandwidth_with_stm} kb/s)." else outbound_bandwidth_with_stm=$STM_OUTBOUND_BANDWIDTH_WITH_STM fi fi # Grab the current time current_hours=`date +%H` current_minutes=`date +%M` current_unix_time=`date +%s` # Set up web page. Use a string to store web page content and pipe # it to /var/wwwext/stm-monitor.htm when the script exits if [[ ! -e "/var/wwwext" ]] then mkdir /var/wwwext fi web_page="
STM Description | Start | End | Bandwidth Limit | Bandwidth Used | Average Rate | ||
---|---|---|---|---|---|---|---|
${stm_period_name} (${1}) | ${stm_period_start}:00 | ${stm_period_end}:00 | ${stm_period_bw_limit_mb} MB | " # Setup a few RX/TX dependent variables if [[ $stm_period_direction = "RX" ]] then data=$rx_data stm_period_rx_active=1 stm_sentence_active=`nvram get rx_stm_sentence_active` last_stm_sentence_end_unix_time=`nvram get rx_last_stm_sentence_end_unix_time` else data=$tx_data stm_period_tx_active=1 stm_sentence_active=`nvram get tx_stm_sentence_active` last_stm_sentence_end_unix_time=`nvram get tx_last_stm_sentence_end_unix_time` fi # Calculate the number of minutes since the STM period started, or since the last STM sentence # ended (whichever happened more recently). # Then calculate the number of values to take from the rstats data (each value covers two minutes) minutes_since_stm_period_started=`echo "" | awk '{ printf("%0.f", (((hours - stm_start) * 60) + minutes)); }' hours=$current_hours minutes=$current_minutes stm_start=${stm_period_start}` if [[ "$last_stm_sentence_end_unix_time" != "" ]] then minutes_since_last_stm_sentence_ended=`echo "" | awk '{ printf("%0.f", (current - sentence_end) / 60); }' current=$current_unix_time sentence_end=$last_stm_sentence_end_unix_time` if [[ $minutes_since_last_stm_sentence_ended -lt $minutes_since_stm_period_started ]] then # Need to calculate the number of seconds to subtract from the length of the # STM period when we do the maximum average rate calculation later on max_rate_adjustment=`echo "" | awk '{ print((mins_since_stm_start - mins_since_sentence_end) * 60); }' mins_since_stm_start=$minutes_since_stm_period_started mins_since_sentence_end=$minutes_since_last_stm_sentence_ended` number_of_values=`expr $minutes_since_last_stm_sentence_ended / 2` else # Don't need to adjust the rate calculation max_rate_adjustment=0 number_of_values=`expr $minutes_since_stm_period_started / 2` fi else # Don't need to adjust the rate calculation max_rate_adjustment=0 number_of_values=`expr $minutes_since_stm_period_started / 2` fi # Extract the useful numbers from the rstats data if [[ $number_of_values != 0 ]] then # Sum the last XXX values of the 720 in the rstats data to get the # total bytes transferred since the STM period started (or since the last # STM sentence ended) total_transferred_bytes=`echo $data | awk ' { values_string = substr($0, index($0, "[") + 1, index($0, "]") - 6); split(values_string, values_array, ","); for (i=(721-number_of_values); i<=720; i++) { total += values_array[i]; } printf("%0.f" total); }' number_of_values=$number_of_values total=0` total_transferred_mb=`echo "" | awk '{ printf("%.2f", bytes / 1048576) }' bytes=$total_transferred_bytes` average_rate=`echo "" | awk '{ printf("%.2f", bytes / (number_of_values * 2 * 60 * 1024)) }' number_of_values=$number_of_values bytes=$total_transferred_bytes` average_rate_kilobits=`echo "" | awk '{printf("%.2f", rate_kilobytes * 8)}' rate_kilobytes=$average_rate` else total_transferred_bytes="0" total_transferred_mb="0.00" average_rate="0.00" average_rate_kilobits="0.00" fi # Calculate maximum average rate (i.e. rate required to trigger STM), # then compare this to our actual rate. If the actual rate is equal or # higher, we paint the cell red, if it's greater than 90% of the max # we paint it amber, and if it's anything else we paint it green. stm_period_max_ave_rate=`echo "" | awk '{printf((limit * 1024) / (((end - start)*3600) - adjustment))}' limit=$stm_period_bw_limit_mb start=$stm_period_start end=$stm_period_end adjustment=$max_rate_adjustment` cell_color=`echo | awk '{ if (rate >= max) {print("FF6633")} else if (rate > (0.9 * max)) {print("FFCC33")} else {print("66FF33")}}' rate=$average_rate max=$stm_period_max_ave_rate` # STM Prevention code if [[ $stm_prevention = 1 && "$stm_sentence_active" != 1 ]] then exceeded_stm_prevention_threshold=`echo "" | awk '{ if (transferred > (limit * (threshold/100))) {print("1")} else {print("0")} }' transferred=$total_transferred_mb limit=$stm_period_bw_limit_mb threshold=$stm_prevention_threshold` if [[ $cell_color = "FF6633" && $exceeded_stm_prevention_threshold = 1 && "$stm_sentence_active" != 1 ]] then # Cell is red => calculate preventative QOS limit # Calculate the number of kilobits we have left before we trigger STM total_kilobits_remaining=`echo "" | awk '{print(((limit*1048576)-total)/128)}' limit=$stm_period_bw_limit_mb total=$total_transferred_bytes` # Calculate time remaining until end of STM period seconds_remaining=`echo "" | awk '{print(((end_hour - current_hour - 1) * 3600) + (3600 - (60 * current_minute)))}' end_hour=$stm_period_end current_hour=$current_hours current_minute=$current_minutes` # Calculate a QOS limit such that we'll transfer a maximum of 90% (TX) or 50% (RX) of the remaining allowance in the remaining time # It has to be as harsh as 50% to work properly for RX. If it's set any higher it won't work because VM counts all the data that # arrives at the router before QOS throws it away in accordance with the temporary limit we've imposed. I've done extensive testing # and 50-55% is about as high as you can go. if [[ $stm_period_direction = RX ]] then preventative_qos_limit=`echo "" | awk '{printf("%.0f", 0.5*(kilobits/secs))}' kilobits=$total_kilobits_remaining secs=$seconds_remaining` else preventative_qos_limit=`echo "" | awk '{printf("%.0f", 0.9*(kilobits/secs))}' kilobits=$total_kilobits_remaining secs=$seconds_remaining` fi if [[ $intelligent = 1 ]] then # Check whether we're actually better off NOT preventing STM seconds_until_stm_is_triggered=`echo "" | awk '{ printf("%0.f", kilobits / rate) }' kilobits=$total_kilobits_remaining rate=$average_rate_kilobits` total_assessment_time=`echo "" | awk '{printf("%0.f", seconds_until_stm + sentence_length)}' seconds_until_stm=$seconds_until_stm_is_triggered sentence_length=$stm_sentence_length_seconds` if [[ $stm_period_direction = "RX" ]] then potential_kilobits_transferred_without_stm_prevention=`echo "" | awk '{ print((no_stm_rate * seconds_until_stm) + (stm_rate * sentence_length)) }' no_stm_rate=$inbound_bandwidth_without_stm stm_rate=$inbound_bandwidth_with_stm sentence_length=$stm_sentence_length_seconds seconds_until_stm=$seconds_until_stm_is_triggered` potential_kilobits_transferred_with_stm_prevention=`echo "" | awk '{ print((seconds_remaining * proposed_limit) + ((total_assessment_time - seconds_remaining) * no_stm_rate)) }' seconds_remaining=$seconds_remaining total_assessment_time=$total_assessment_time proposed_limit=$preventative_qos_limit no_stm_rate=$inbound_bandwidth_without_stm` else potential_kilobits_transferred_without_stm_prevention=`echo "" | awk '{ print((no_stm_rate * seconds_until_stm) + (stm_rate * sentence_length)) }' no_stm_rate=$outbound_bandwidth_without_stm stm_rate=$outbound_bandwidth_with_stm sentence_length=$stm_sentence_length_seconds seconds_until_stm=$seconds_until_stm_is_triggered` potential_kilobits_transferred_with_stm_prevention=`echo "" | awk '{ print((seconds_remaining * proposed_limit) + ((total_assessment_time - seconds_remaining) * no_stm_rate)) }' seconds_remaining=$seconds_remaining total_assessment_time=$total_assessment_time proposed_limit=$preventative_qos_limit no_stm_rate=$outbound_bandwidth_without_stm` fi stm_prevention_is_beneficial=`echo "" | awk '{if (with_prevention > without_prevention) {print(1)} else {print(0)}}' with_prevention=$potential_kilobits_transferred_with_stm_prevention without_prevention=$potential_kilobits_transferred_without_stm_prevention` # Compile detailed information total_mb_remaining=`echo "" | awk '{ printf("%.2f", bits / 8192) }' bits=$total_kilobits_remaining` potential_mb_transferred_without_stm_prevention=`echo "" | awk '{ printf("%.0f", bits / 8192) }' bits=$potential_kilobits_transferred_without_stm_prevention` potential_mb_transferred_with_stm_prevention=`echo "" | awk '{ printf("%.0f", bits / 8192) }' bits=$potential_kilobits_transferred_with_stm_prevention` else # Assume STM prevention is *always* beneficial stm_prevention_is_beneficial=1 fi if [[ $stm_period_direction = "RX" && "`nvram get qos_ibw`" -gt $preventative_qos_limit ]] then if [[ $stm_prevention_is_beneficial = 1 ]] then $LOGGER "STM (RX) will trigger in `date -ud 00:00:${seconds_until_stm_is_triggered} +%Hh%Mm%Ss`. Potential ${stm_period_direction} over `date -ud 00:00:${total_assessment_time} +%Hh%Mm%Ss` with/without STM Prevention: ${potential_mb_transferred_with_stm_prevention} MB / ${potential_mb_transferred_without_stm_prevention} MB => STM Prevention is beneficial." $LOGGER "Setting preventative inbound QOS limit of $preventative_qos_limit kbits/s" nvram set qos_ibw=$preventative_qos_limit # We must set the inbound rate limits to 100% or less for this to work ("None" will not work # because the rate will not be limited). To make sure this does work, we'll change the # settings to 100% across the board and restore the old settings when we remove the # temporary QOS limit. nvram set qos_irates_old=`nvram get qos_irates` nvram set qos_irates=100,100,100,100,100,100,100,100,100,100 service qos restart else $LOGGER "STM (RX) will trigger in `date -ud 00:00:${seconds_until_stm_is_triggered} +%Hh%Mm%Ss`. Potential ${stm_period_direction} over `date -ud 00:00:${total_assessment_time} +%Hh%Mm%Ss` with/without STM Prevention: ${potential_mb_transferred_with_stm_prevention} MB / ${potential_mb_transferred_without_stm_prevention} MB => STM Prevention is not beneficial." fi fi if [[ $stm_period_direction = "TX" && "`nvram get qos_obw`" -gt $preventative_qos_limit ]] then if [[ $stm_prevention_is_beneficial = 1 ]] then $LOGGER "STM (TX) will trigger in `date -ud 00:00:${seconds_until_stm_is_triggered} +%Hh%Mm%Ss`. Potential ${stm_period_direction} over `date -ud 00:00:${total_assessment_time} +%Hh%Mm%Ss` with/without STM Prevention: ${potential_mb_transferred_with_stm_prevention} MB / ${potential_mb_transferred_without_stm_prevention} MB => STM Prevention is beneficial." $LOGGER "Setting preventative outbound QOS limit of $preventative_qos_limit kbits/s" nvram set qos_obw=$preventative_qos_limit service qos restart else $LOGGER "STM (TX) will trigger in `date -ud 00:00:${seconds_until_stm_is_triggered} +%Hh%Mm%Ss`. Potential ${stm_period_direction} over `date -ud 00:00:${total_assessment_time} +%Hh%Mm%Ss` with/without STM Prevention: ${potential_mb_transferred_with_stm_prevention} MB / ${potential_mb_transferred_without_stm_prevention} MB => STM Prevention is not beneficial." fi fi fi # Remove STM Prevention QOS settings if the cell is green if [[ $cell_color = "66FF33" && "$stm_sentence_active" != 1 ]] then if [[ $stm_period_direction = "RX" && "`nvram get qos_ibw`" != $inbound_bandwidth_without_stm ]] then $LOGGER "Removing preventative inbound QOS limit" nvram set qos_ibw=$inbound_bandwidth_without_stm nvram set qos_irates=`nvram get qos_irates_old` nvram unset qos_irates_old service qos restart fi if [[ $stm_period_direction = "TX" && "`nvram get qos_obw`" != $outbound_bandwidth_without_stm ]] then $LOGGER "Removing preventative outbound QOS limit" nvram set qos_obw=$outbound_bandwidth_without_stm service qos restart fi fi fi # End of STM prevention code # Add data to web page total_transferred_mb_percent=`echo "" | awk '{ printf("%.0f", (transferred / limit) * 100) }' transferred=$total_transferred_mb limit=$stm_period_bw_limit_mb` if [[ $max_rate_adjustment != 0 ]] then # Add link to note explaining adjusted figures web_page="${web_page}${total_transferred_mb} MB (${total_transferred_mb_percent}%) * | ${average_rate} KB/s (${average_rate_kilobits} kb/s) * | " add_adjustment_note=1 else web_page="${web_page}${total_transferred_mb} MB (${total_transferred_mb_percent}%) | ${average_rate} KB/s (${average_rate_kilobits} kb/s) | " fi # Check whether STM limit has been exceeded stm_period_bw_limit_bytes=`expr $stm_period_bw_limit_mb \* 1048576` result=`echo "" | awk '{ if (total > limit) {print(1)} else {print(0)}}' total=$total_transferred_bytes limit=$stm_period_bw_limit_bytes` if [[ $result = 1 && "$stm_sentence_active" != 1 ]] then if [[ $stm_period_direction = "RX" ]] then rx_stm_sentence_triggered=1 nvram set rx_stm_sentence_active=1 else tx_stm_sentence_triggered=1 nvram set tx_stm_sentence_active=1 fi $LOGGER "STM (${stm_period_direction}) triggered: ${stm_period_name} (${stm_period_start}:00 -> ${stm_period_end}:00, ${stm_period_bw_limit_mb} MB)" fi else # This STM period is not currently active web_page="${web_page}
${stm_period_name} (${1}) | ${stm_period_start}:00 | ${stm_period_end}:00 | ${stm_period_bw_limit_mb} MB | N/A | N/A | " fi web_page="${web_page}
* This data was calculated from the end of the last STM sentence, rather than from the beginning of the STM period.
" fi # Remove RX/TX STM Prevention QOS limits if necessary. This code makes sure the temporary limits # are removed when they are not relevant (i.e. when we're not in an STM period and STM has not # been triggered) if [[ $stm_prevention = 1 ]] then if [[ "`nvram get rx_stm_sentence_active`" != 1 && "$stm_period_rx_active" != 1 && "`nvram get qos_ibw`" != $inbound_bandwidth_without_stm ]] then $LOGGER "Removing preventative inbound QOS limit" nvram set qos_ibw=$inbound_bandwidth_without_stm nvram set qos_irates=`nvram get qos_irates_old` nvram unset qos_irates_old service qos restart fi if [[ "`nvram get tx_stm_sentence_active`" != 1 && "$stm_period_tx_active" != 1 && "`nvram get qos_obw`" != $outbound_bandwidth_without_stm ]] then $LOGGER "Removing preventative outbound QOS limit" nvram set qos_obw=$outbound_bandwidth_without_stm service qos restart fi fi # If STM is active, check whether QOS is set accordingly # Upstream if [[ "`nvram get tx_stm_sentence_active`" = 1 && "`nvram get qos_obw`" != $outbound_bandwidth_with_stm ]] then if [[ $tx_stm_sentence_triggered = 1 ]] then # We must have triggered an STM sentence on this run. # Work out the hour component of the time the STM sentence will end # (for logging purposes only - we will use unix time to track the # STM sentence accurately) tx_stm_end_hour=`expr $current_hours + $stm_sentence_length_hours` if [[ $tx_stm_end_hour -gt 23 ]] then tx_stm_end_hour="0`expr $stm_end_hour - 24`" fi # Set NVRAM variables to describe the STM sentence being served nvram set tx_stm_sentence_end_time="$stm_end_hour:$current_minutes" nvram set tx_stm_sentence_end_unix_time=`expr $current_unix_time + $stm_sentence_length_seconds` $LOGGER "STM (TX) sentence started: applying STM outbound QOS configuration (until $stm_end_hour:$current_minutes)" else # An STM sentence is active and we didn't trigger it on this run, # but the QOS settings are wrong. We must have rebooted, or someone # messed with the QOS settings. So we want to set the QOS settings # to deal with the STM, but we don't want to overwrite our NVRAM # variables. $LOGGER "STM (TX) sentence resumed: applying STM outbound QOS configuration (until `nvram get tx_stm_sentence_end_time`)" fi # Apply STM QOS settings nvram set qos_obw=$outbound_bandwidth_with_stm service qos restart fi # Downstream if [[ "`nvram get rx_stm_sentence_active`" = 1 && "`nvram get qos_ibw`" != $inbound_bandwidth_with_stm ]] then if [[ $rx_stm_sentence_triggered = 1 ]] then # We must have triggered an STM sentence on this run. # Work out the hour component of the time the STM sentence will end # (for logging purposes only - we will use unix time to track the # STM sentence accurately) rx_stm_end_hour=`expr $current_hours + $stm_sentence_length_hours` if [[ $rx_stm_end_hour -gt 23 ]] then rx_stm_end_hour="0`expr $stm_end_hour - 24`" fi # Set NVRAM variables to describe the STM sentence being served nvram set rx_stm_sentence_end_time="$stm_end_hour:$current_minutes" nvram set rx_stm_sentence_end_unix_time=`expr $current_unix_time + $stm_sentence_length_seconds` $LOGGER "STM (RX) sentence started: applying STM inbound QOS configuration (until $stm_end_hour:$current_minutes)" else # An STM sentence is active and we didn't trigger it on this run, # but the QOS settings are wrong. We must have rebooted, or someone # messed with the QOS settings. So we want to set the QOS settings # to deal with the STM, but we don't want to overwrite our NVRAM # variables. $LOGGER "STM (RX) sentence resumed: applying STM inbound QOS configuration (until `nvram get rx_stm_sentence_end_time`)" fi # Apply STM QOS settings nvram set qos_ibw=$inbound_bandwidth_with_stm service qos restart fi # Add status to the web page if [[ $intelligent = 1 ]] then web_page="${web_page}