mirror of
				https://github.com/Ysurac/openmptcprouter-feeds.git
				synced 2025-03-09 15:40:03 +00:00 
			
		
		
		
	Update SQM autorate
This commit is contained in:
		
							parent
							
								
									a3fc59f80e
								
							
						
					
					
						commit
						063a468465
					
				
					 11 changed files with 2526 additions and 695 deletions
				
			
		|  | @ -260,6 +260,10 @@ return view.extend({ | |||
| 		o.default = false; | ||||
| 		o.depends("autorate","1"); | ||||
| 
 | ||||
| 		o = s.taboption("tab_autorate", form.Flag, "sss_compensation", _("Starlink support")); | ||||
| 		o.default = false; | ||||
| 		o.depends("autorate","1"); | ||||
| 
 | ||||
| 		o = s.taboption("tab_autorate", form.Value, "reflector_ping_interval_s", _("Reflector ping interval in seconds:")); | ||||
| 		o.default = "0.2"; | ||||
| 		o.depends("autorate","1"); | ||||
|  |  | |||
|  | @ -14,8 +14,8 @@ | |||
| . /usr/lib/unbound/iptools.sh | ||||
| . /lib/functions/network.sh | ||||
| 
 | ||||
| _launch_autorate() { | ||||
| 	logger -t "SQM-autorate" "Launch on $1" | ||||
| _config_autorate() { | ||||
| 	logger -t "SQM-autorate" "Set config for $1" | ||||
| 	config_get enabled "$1" enabled | ||||
| 	[ "${enabled}" != "1" ] && return | ||||
| 	config_get autorate "$1" autorate | ||||
|  | @ -29,20 +29,36 @@ _launch_autorate() { | |||
| 	config_get upload "$1" upload | ||||
| 	config_get max_upload "$1" max_upload | ||||
| 	[ "${min_upload}" == "0" ] || [ "${max_upload}" == "0" ] || [ "${upload}" == "0" ] && return | ||||
| 	config_get interface "$1" interface | ||||
| 	cp /usr/share/sqm-autorate/cake-autorate_template.sh /usr/share/sqm-autorate/cake-autorate_config.${interface}.sh | ||||
| } | ||||
| 
 | ||||
| _launch_autorate() { | ||||
| 	logger -t "SQM-autorate" "Launch..." | ||||
| 	procd_open_instance | ||||
| 	# shellcheck disable=SC2086 | ||||
| 	procd_set_param command /usr/share/sqm-autorate/CAKE-autorate.sh "$1" | ||||
| #	procd_append_param env "OMR_TRACKER_SERVER_HTTP_TEST=$server_http_test" | ||||
| 	procd_set_param command /usr/share/sqm-autorate/cake-autorate_launcher.sh | ||||
| 	procd_set_param limits nofile="51200 51200" | ||||
| 	procd_set_param respawn 0 10 0 | ||||
| 	procd_set_param stderr 1 | ||||
| 	procd_close_instance | ||||
| 	sleep 2 | ||||
| } | ||||
| 
 | ||||
| start_service() { | ||||
| 	config_load sqm | ||||
| 	config_foreach _launch_autorate queue | ||||
| 	config_foreach _config_autorate queue | ||||
| 	_launch_autorate | ||||
| } | ||||
| 
 | ||||
| stop_service() { | ||||
| 	rm -f /usr/share/sqm-autorate/cake-autorate_config.*.sh | ||||
| } | ||||
| 
 | ||||
| reload_service() { | ||||
| 	stop | ||||
| 	start | ||||
| } | ||||
| 
 | ||||
| service_triggers() { | ||||
| 	procd_add_reload_trigger sqm | ||||
| } | ||||
							
								
								
									
										1
									
								
								luci-app-sqm-autorate/root/root/cake-autorate
									
										
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								luci-app-sqm-autorate/root/root/cake-autorate
									
										
									
									
									
										Symbolic link
									
								
							|  | @ -0,0 +1 @@ | |||
| ../usr/share/sqm-autorate | ||||
|  | @ -1,658 +0,0 @@ | |||
| #!/bin/bash | ||||
| 
 | ||||
| # CAKE-autorate automatically adjusts bandwidth for CAKE in dependence on detected load and OWD/RTT | ||||
| # requires packages: bash; and iputils-ping | ||||
| 
 | ||||
| # Author: @Lynx (OpenWrt forum) | ||||
| # Inspiration taken from: @moeller0 (OpenWrt forum) | ||||
| # Modified by Ycarus (Yannick Chabanois) for OpenMPTCProuter: | ||||
| #  * Add multiples interfaces support | ||||
| 
 | ||||
| # Possible performance improvement | ||||
| export LC_ALL=C | ||||
| export TZ=UTC | ||||
| 
 | ||||
| trap cleanup_and_killall INT TERM EXIT | ||||
| 
 | ||||
| cleanup_and_killall() | ||||
| { | ||||
| 	echo "Killing all background processes and cleaning up /tmp files." | ||||
| 	trap - INT TERM EXIT | ||||
| 	kill $monitor_achieved_rates_pid 2> /dev/null | ||||
| 	# Initiate termination of ping processes and wait until complete | ||||
| 	kill $maintain_pingers_pid 2> /dev/null | ||||
| 	wait $maintain_pingers_pid | ||||
| 	[[ -d /tmp/CAKE-autorate-${dl_if} ]] && rm -r /tmp/CAKE-autorate-${dl_if} | ||||
| 	exit | ||||
| } | ||||
| 
 | ||||
| install_dir="/usr/share/sqm-autorate/" | ||||
| 
 | ||||
| . $install_dir"config.sh" "$1" | ||||
| 
 | ||||
| # test if stdout is a tty (terminal) | ||||
| [[ ! -t 1 ]] &&	exec &> /tmp/cake-autorate-${dl_if}.log | ||||
| 
 | ||||
| get_next_shaper_rate()  | ||||
| { | ||||
| 	local min_shaper_rate_kbps=$1 | ||||
| 	local base_shaper_rate_kbps=$2 | ||||
| 	local max_shaper_rate_kbps=$3 | ||||
| 	local achieved_rate_kbps=$4 | ||||
| 	local load_condition=$5 | ||||
| 	local t_next_rate_us=$6 | ||||
| 	local -n t_last_bufferbloat_us=$7 | ||||
| 	local -n t_last_decay_us=$8 | ||||
|     	local -n shaper_rate_kbps=$9 | ||||
| 
 | ||||
| 	case $load_condition in | ||||
| 
 | ||||
| 		# upload Starlink satelite switching compensation, so drop down to minimum rate for upload through switching period | ||||
| 		ul*sss) | ||||
| 				shaper_rate_kbps=$min_shaper_rate_kbps | ||||
| 			;; | ||||
| 		# download Starlink satelite switching compensation, so drop down to base rate for download through switching period | ||||
| 		dl*sss) | ||||
| 				shaper_rate_kbps=$base_shaper_rate_kbps | ||||
| 			;; | ||||
| 		# bufferbloat detected, so decrease the rate providing not inside bufferbloat refractory period | ||||
| 		*bb*) | ||||
| 			if (( $t_next_rate_us > ($t_last_bufferbloat_us+$bufferbloat_refractory_period_us) )); then | ||||
| 				adjusted_achieved_rate_kbps=$(( ($achieved_rate_kbps*$achieved_rate_adjust_down_bufferbloat)/1000 ))  | ||||
| 				adjusted_shaper_rate_kbps=$(( ($shaper_rate_kbps*$shaper_rate_adjust_down_bufferbloat)/1000 ))  | ||||
| 				shaper_rate_kbps=$(( $adjusted_achieved_rate_kbps < $adjusted_shaper_rate_kbps ? $adjusted_achieved_rate_kbps : $adjusted_shaper_rate_kbps )) | ||||
| 				t_last_bufferbloat_us=${EPOCHREALTIME/./} | ||||
| 			fi | ||||
| 			;; | ||||
|             	# high load, so increase rate providing not inside bufferbloat refractory period  | ||||
| 		*high*)	 | ||||
| 			if (( $t_next_rate_us > ($t_last_bufferbloat_us+$bufferbloat_refractory_period_us) )); then | ||||
| 				shaper_rate_kbps=$(( ($shaper_rate_kbps*$shaper_rate_adjust_up_load_high)/1000 )) | ||||
| 			fi | ||||
| 			;; | ||||
| 		# medium load, so just maintain rate as is, i.e. do nothing | ||||
| 		*med*) | ||||
| 			: | ||||
| 			;; | ||||
| 		# low or idle load, so determine whether to decay down towards base rate, decay up towards base rate, or set as base rate | ||||
| 		*low*|*idle*) | ||||
| 			if (($t_next_rate_us > ($t_last_decay_us+$decay_refractory_period_us) )); then | ||||
| 
 | ||||
| 	                	if (($shaper_rate_kbps > $base_shaper_rate_kbps)); then | ||||
| 					decayed_shaper_rate_kbps=$(( ($shaper_rate_kbps*$shaper_rate_adjust_down_load_low)/1000 )) | ||||
| 					shaper_rate_kbps=$(( $decayed_shaper_rate_kbps > $base_shaper_rate_kbps ? $decayed_shaper_rate_kbps : $base_shaper_rate_kbps)) | ||||
| 				elif (($shaper_rate_kbps < $base_shaper_rate_kbps)); then | ||||
|         			        decayed_shaper_rate_kbps=$(( ($shaper_rate_kbps*$shaper_rate_adjust_up_load_low)/1000 )) | ||||
| 					shaper_rate_kbps=$(( $decayed_shaper_rate_kbps < $base_shaper_rate_kbps ? $decayed_shaper_rate_kbps : $base_shaper_rate_kbps)) | ||||
|                 		fi | ||||
| 
 | ||||
| 				t_last_decay_us=${EPOCHREALTIME/./} | ||||
| 			fi | ||||
| 			;; | ||||
| 	esac | ||||
|         # make sure to only return rates between cur_min_rate and cur_max_rate | ||||
|         (($shaper_rate_kbps < $min_shaper_rate_kbps)) && shaper_rate_kbps=$min_shaper_rate_kbps; | ||||
|         (($shaper_rate_kbps > $max_shaper_rate_kbps)) && shaper_rate_kbps=$max_shaper_rate_kbps; | ||||
| } | ||||
| 
 | ||||
| monitor_achieved_rates() | ||||
| { | ||||
| 	# track rx and tx bytes transfered and divide by time since last update | ||||
| 	# to determine achieved dl and ul transfer rates | ||||
| 
 | ||||
| 	local rx_bytes_path=$1 | ||||
| 	local tx_bytes_path=$2 | ||||
| 	local monitor_achieved_rates_interval_us=$3 # (microseconds) | ||||
| 
 | ||||
| 	compensated_monitor_achieved_rates_interval_us=$monitor_achieved_rates_interval_us | ||||
| 
 | ||||
| 	[[ -f $rx_bytes_path ]] && { read -r prev_rx_bytes < $rx_bytes_path; } 2> /dev/null || prev_rx_bytes=0 | ||||
|         [[ -f $tx_bytes_path ]] && { read -r prev_tx_bytes < $tx_bytes_path; } 2> /dev/null || prev_tx_bytes=0 | ||||
| 
 | ||||
| 	while true | ||||
| 	do | ||||
|         	t_start_us=${EPOCHREALTIME/./} | ||||
| 
 | ||||
| 		# If rx/tx bytes file exists, read it in, otherwise set to prev_bytes | ||||
| 		# This addresses interfaces going down and back up | ||||
|        		[[ -f $rx_bytes_path ]] && { read -r rx_bytes < $rx_bytes_path; } 2> /dev/null || rx_bytes=$prev_rx_bytes | ||||
|        		[[ -f $tx_bytes_path ]] && { read -r tx_bytes < $tx_bytes_path; } 2> /dev/null || tx_bytes=$prev_tx_bytes | ||||
| 
 | ||||
|         	dl_achieved_rate_kbps=$(( ((8000*($rx_bytes - $prev_rx_bytes)) / $compensated_monitor_achieved_rates_interval_us ) )) | ||||
|        		ul_achieved_rate_kbps=$(( ((8000*($tx_bytes - $prev_tx_bytes)) / $compensated_monitor_achieved_rates_interval_us ) )) | ||||
| 		 | ||||
| 		(($dl_achieved_rate_kbps<0)) && dl_achieved_rate_kbps=0 | ||||
| 		(($ul_achieved_rate_kbps<0)) && ul_achieved_rate_kbps=0 | ||||
| 	 | ||||
| 		printf '%s' "$dl_achieved_rate_kbps" > /tmp/CAKE-autorate-${dl_if}/dl_achieved_rate_kbps | ||||
| 		printf '%s' "$ul_achieved_rate_kbps" > /tmp/CAKE-autorate-${dl_if}/ul_achieved_rate_kbps | ||||
| 
 | ||||
| 		prev_rx_bytes=$rx_bytes | ||||
| 		prev_tx_bytes=$tx_bytes | ||||
| 
 | ||||
| 		# read in the max_wire_packet_rtt_us | ||||
| 		concurrent_read_positive_integer max_wire_packet_rtt_us /tmp/CAKE-autorate-${dl_if}/max_wire_packet_rtt_us | ||||
| 
 | ||||
| 		compensated_monitor_achieved_rates_interval_us=$(( (($monitor_achieved_rates_interval_us>(10*$max_wire_packet_rtt_us) )) ? $monitor_achieved_rates_interval_us : $((10*$max_wire_packet_rtt_us)) )) | ||||
| 
 | ||||
| 		sleep_remaining_tick_time $t_start_us $compensated_monitor_achieved_rates_interval_us		 | ||||
| 	done | ||||
| } | ||||
| 
 | ||||
| get_loads() | ||||
| { | ||||
| 	# read in the dl/ul achived rates and determine the loads | ||||
| 
 | ||||
| 	concurrent_read_positive_integer dl_achieved_rate_kbps /tmp/CAKE-autorate-${dl_if}/dl_achieved_rate_kbps  | ||||
| 	concurrent_read_positive_integer ul_achieved_rate_kbps /tmp/CAKE-autorate-${dl_if}/ul_achieved_rate_kbps  | ||||
| 
 | ||||
| 	dl_load_percent=$(((100*10#${dl_achieved_rate_kbps})/$dl_shaper_rate_kbps)) | ||||
| 	ul_load_percent=$(((100*10#${ul_achieved_rate_kbps})/$ul_shaper_rate_kbps)) | ||||
| } | ||||
| 
 | ||||
| classify_load() | ||||
| { | ||||
| 	# classify the load according to high/low/medium/idle and add _delayed if delayed | ||||
| 	# thus ending up with high_delayed, low_delayed, etc. | ||||
| 	local load_percent=$1 | ||||
| 	local achieved_rate_kbps=$2 | ||||
| 	local -n load_condition=$3 | ||||
| 	 | ||||
| 	if (( $load_percent > $high_load_thr_percent )); then | ||||
| 		load_condition="high"   | ||||
| 	elif (( $load_percent > $medium_load_thr_percent )); then | ||||
| 		load_condition="med" | ||||
| 	elif (( $achieved_rate_kbps > $connection_active_thr_kbps )); then | ||||
| 		load_condition="low" | ||||
| 	else  | ||||
| 		load_condition="idle" | ||||
| 	fi | ||||
| 	 | ||||
| 	(($bufferbloat_detected)) && load_condition=$load_condition"_bb" | ||||
| 		 | ||||
| 	if ((sss_compensation)); then | ||||
| 		for sss_time_us in "${sss_times_us[@]}" | ||||
| 		do | ||||
| 			((timestamp_usecs_past_minute=${EPOCHREALTIME/./}%60000000)) | ||||
| 			if (( ($timestamp_usecs_past_minute > ($sss_time_us-$sss_compensation_pre_duration_us)) && ($timestamp_usecs_past_minute < ($sss_time_us+$sss_compensation_post_duration_us)) )); then | ||||
| 				load_condition=$load_condition"_sss" | ||||
| 				break | ||||
| 			fi | ||||
| 		done			 | ||||
| 	fi | ||||
| } | ||||
| 
 | ||||
| monitor_reflector_responses()  | ||||
| { | ||||
| 	# ping reflector, maintain baseline and output deltas to a common fifo | ||||
| 
 | ||||
| 	local pinger=$1 | ||||
| 	local rtt_baseline_us=$2 | ||||
| 
 | ||||
| 	while read -r  timestamp _ _ _ reflector seq_rtt | ||||
| 	do | ||||
| 		# If no match then skip onto the next one | ||||
| 		[[ $seq_rtt =~ icmp_[s|r]eq=([0-9]+).*time=([0-9]+)\.?([0-9]+)?[[:space:]]ms ]] || continue | ||||
| 
 | ||||
| 		seq=${BASH_REMATCH[1]} | ||||
| 
 | ||||
| 		rtt_us=${BASH_REMATCH[3]}000 | ||||
| 		rtt_us=$((${BASH_REMATCH[2]}000+10#${rtt_us:0:3})) | ||||
| 
 | ||||
| 		reflector=${reflector//:/} | ||||
| 
 | ||||
| 		rtt_delta_us=$(( $rtt_us-$rtt_baseline_us )) | ||||
| 
 | ||||
| 		alpha=$(( (( $rtt_delta_us >=0 )) ? $alpha_baseline_increase : $alpha_baseline_decrease )) | ||||
| 
 | ||||
| 		rtt_baseline_us=$(( ( (1000-$alpha)*$rtt_baseline_us+$alpha*$rtt_us )/1000 )) | ||||
| 
 | ||||
| 		printf '%s %s %s %s %s %s\n' "$timestamp" "$reflector" "$seq" "$rtt_baseline_us" "$rtt_us" "$rtt_delta_us" > /tmp/CAKE-autorate-${dl_if}/ping_fifo | ||||
| 	 | ||||
| 		printf '%s' "${timestamp//[[\[\].]}" > /tmp/CAKE-autorate-${dl_if}/reflector_${pinger}_last_timestamp_us | ||||
| 
 | ||||
| 	done</tmp/CAKE-autorate-${dl_if}/pinger_${pinger}_fifo | ||||
| } | ||||
| 
 | ||||
| kill_pingers() | ||||
| { | ||||
| 	for (( pinger=0; pinger<$no_pingers; pinger++)) | ||||
| 	do | ||||
| 		kill ${pinger_pids[$pinger]} 2> /dev/null | ||||
| 		[[ -p /tmp/CAKE-autorate-${dl_if}/pinger_${pinger}_fifo ]] && rm /tmp/CAKE-autorate-${dl_if}/pinger_${pinger}_fifo | ||||
| 	done | ||||
| 	exit | ||||
| } | ||||
| 
 | ||||
| maintain_pingers() | ||||
| { | ||||
| 	# this initiates the pingers and monitors reflector health, rotating reflectors as necessary | ||||
| 
 | ||||
|  	trap kill_pingers TERM | ||||
| 
 | ||||
| 	declare -A pinger_pids | ||||
| 	declare -A rtt_baselines_us | ||||
| 
 | ||||
| 	reflector_offences_idx=0 | ||||
| 
 | ||||
| 	# For each pinger: create fifos, get baselines and initialize record of offences | ||||
| 	for ((pinger=0; pinger<$no_pingers; pinger++)) | ||||
| 	do | ||||
| 		mkfifo /tmp/CAKE-autorate-${dl_if}/pinger_${pinger}_fifo | ||||
| 		[[ $(ping -B -I ${dl_if} -q -c 5 -i 0.1 ${reflectors[$pinger]} | tail -1) =~ ([0-9.]+)/ ]] && printf -v rtt_baselines_us[$pinger] %.0f\\n "${BASH_REMATCH[1]}e3" || rtt_baselines_us[$pinger]=0 | ||||
| 	 | ||||
| 		declare -n reflector_offences="reflector_${pinger}_offences" | ||||
| 		for ((i=0; i<$reflector_misbehaving_detection_window; i++)) do reflector_offences[i]=0; done | ||||
| 
 | ||||
| 		sum_reflector_offences[$pinger]=0 | ||||
| 	done | ||||
| 
 | ||||
| 	pingers_t_start_us=${EPOCHREALTIME/./} | ||||
| 
 | ||||
| 	# Initiate pingers | ||||
| 	for ((pinger=0; pinger<$no_pingers; pinger++)) | ||||
| 	do | ||||
| 		printf '%s' "$pingers_t_start_us" > /tmp/CAKE-autorate-${dl_if}/reflector_${pinger}_last_timestamp_us | ||||
| 		start_pinger_next_pinger_time_slot $pinger pid | ||||
| 		pinger_pids[$pinger]=$pid | ||||
| 	done | ||||
| 
 | ||||
| 	# Reflector health check loop - verifies reflectors have not gone stale and rotates reflectors as necessary | ||||
| 	while true | ||||
| 	do | ||||
| 		sleep_s $reflector_health_check_interval_s | ||||
| 
 | ||||
| 		for ((pinger=0; pinger<$no_pingers; pinger++)) | ||||
| 		do | ||||
| 			reflector_check_time_us=${EPOCHREALTIME/./} | ||||
| 			concurrent_read_positive_integer reflector_last_timestamp_us /tmp/CAKE-autorate-${dl_if}/reflector_${pinger}_last_timestamp_us | ||||
| 			declare -n reflector_offences="reflector_${pinger}_offences" | ||||
| 
 | ||||
| 			(( ${reflector_offences[$reflector_offences_idx]} )) && ((sum_reflector_offences[$pinger]--)) | ||||
| 			reflector_offences[$reflector_offences_idx]=$(( (((${EPOCHREALTIME/./}-$reflector_last_timestamp_us) > $reflector_response_deadline_us)) ? 1 : 0 )) | ||||
| 			((reflector_offences[$reflector_offences_idx])) && ((sum_reflector_offences[$pinger]++)) | ||||
| 
 | ||||
| 			if ((sum_reflector_offences[$pinger]>=$reflector_misbehaving_detection_thr)); then | ||||
| 
 | ||||
| 				(($debug)) && echo "DEBUG: Warning: reflector: "${reflectors[$pinger]}" seems to be misbehaving." | ||||
| 				 | ||||
| 				if(($no_reflectors>$no_pingers)); then | ||||
| 
 | ||||
| 					# pingers always use reflectors[0]..[$no_pingers-1] as the initial set | ||||
| 					# and the additional reflectors are spare reflectors should any from initial set go stale | ||||
| 					# a bad reflector in the initial set is replaced with $reflectors[$no_pingers] | ||||
| 					# $reflectors[$no_pingers] is then unset | ||||
| 					# and the the bad reflector moved to the back of the queue (last element in $reflectors[]) | ||||
| 					# and finally the indices for $reflectors are updated to reflect the new order | ||||
| 	 | ||||
| 					(($debug)) && echo "DEBUG: Replacing reflector: "${reflectors[$pinger]}" with "${reflectors[$no_pingers]}"." | ||||
| 					kill ${pinger_pids[$pinger]} 2> /dev/null | ||||
| 					bad_reflector=${reflectors[$pinger]} | ||||
| 					# overwrite the bad reflector with the reflector that is next in the queue (the one after 0..$no_pingers-1) | ||||
| 					reflectors[$pinger]=${reflectors[$no_pingers]} | ||||
| 					# remove the new reflector from the list of additional reflectors beginning from $reflectors[$no_pingers] | ||||
| 					unset reflectors[$no_pingers] | ||||
| 					# bad reflector goes to the back of the queue | ||||
| 					reflectors+=($bad_reflector) | ||||
| 					# reset array indices | ||||
| 					reflectors=(${reflectors[*]}) | ||||
| 					# set up the new pinger with the new reflector and retain pid | ||||
| 					start_pinger_next_pinger_time_slot $pinger pid | ||||
| 					pinger_pids[$pinger]=$pid | ||||
| 					 | ||||
| 				else | ||||
| 					(($debug)) && echo "DEBUG: No additional reflectors specified so just retaining: "${reflectors[$pinger]}"." | ||||
| 					reflector_offences[$pinger]=0 | ||||
| 				fi | ||||
| 
 | ||||
| 				for ((i=0; i<$reflector_misbehaving_detection_window; i++)) do reflector_offences[i]=0; done | ||||
| 				sum_reflector_offences[$pinger]=0 | ||||
| 			fi		 | ||||
| 		done | ||||
| 		((reflector_offences_idx=(reflector_offences_idx+1)%$reflector_misbehaving_detection_window)) | ||||
| 	done | ||||
| } | ||||
| 
 | ||||
| start_pinger_next_pinger_time_slot() | ||||
| { | ||||
| 	# wait until next pinger time slot and start pinger in its slot | ||||
| 	# this allows pingers to be stopped and started (e.g. during sleep or reflector rotation) | ||||
| 	# whilst ensuring pings will remain spaced out appropriately to maintain granularity | ||||
| 
 | ||||
| 	local pinger=$1 | ||||
| 	local -n pinger_pid=$2 | ||||
| 	t_start_us=${EPOCHREALTIME/./} | ||||
| 	time_to_next_time_slot_us=$(( ($reflector_ping_interval_us-($t_start_us-$pingers_t_start_us)%$reflector_ping_interval_us) + $pinger*$ping_response_interval_us )) | ||||
| 	sleep_remaining_tick_time $t_start_us $time_to_next_time_slot_us | ||||
| 	if (($debug)); then | ||||
| 		ping -B -I ${dl_if} -D -i $reflector_ping_interval_s ${reflectors[$pinger]} > /tmp/CAKE-autorate-${dl_if}/pinger_${pinger}_fifo & | ||||
| 		pinger_pid=$! | ||||
| 	else | ||||
| 		ping -B -I ${dl_if} -D -i $reflector_ping_interval_s ${reflectors[$pinger]} > /tmp/CAKE-autorate-${dl_if}/pinger_${pinger}_fifo 2> /dev/null & | ||||
| 		pinger_pid=$! | ||||
| 	fi | ||||
| 	monitor_reflector_responses $pinger ${rtt_baselines_us[$pinger]} & | ||||
| } | ||||
| 
 | ||||
| set_cake_rate() | ||||
| { | ||||
| 	local interface=$1 | ||||
| 	local shaper_rate_kbps=$2 | ||||
| 	local -n time_rate_set_us=$3 | ||||
| 	 | ||||
| 	(($output_cake_changes)) && echo "tc qdisc change root dev ${interface} cake bandwidth ${shaper_rate_kbps}Kbit" | ||||
| 	 | ||||
| 	if (($debug)); then | ||||
| 		tc qdisc change root dev $interface cake bandwidth ${shaper_rate_kbps}Kbit | ||||
| 	else | ||||
| 		tc qdisc change root dev $interface cake bandwidth ${shaper_rate_kbps}Kbit 2> /dev/null | ||||
| 	fi | ||||
| 
 | ||||
| 	time_rate_set_us=${EPOCHREALTIME/./} | ||||
| } | ||||
| 
 | ||||
| set_shaper_rates() | ||||
| { | ||||
| 	if (( $dl_shaper_rate_kbps != $last_dl_shaper_rate_kbps || $ul_shaper_rate_kbps != $last_ul_shaper_rate_kbps )); then  | ||||
|      	 | ||||
| 		# fire up tc in each direction if there are rates to change, and if rates change in either direction then update max wire calcs | ||||
| 		(( $dl_shaper_rate_kbps != $last_dl_shaper_rate_kbps )) && { set_cake_rate $dl_if $dl_shaper_rate_kbps t_prev_dl_rate_set_us; last_dl_shaper_rate_kbps=$dl_shaper_rate_kbps; }  | ||||
| 		(( $ul_shaper_rate_kbps != $last_ul_shaper_rate_kbps )) && { set_cake_rate $ul_if $ul_shaper_rate_kbps t_prev_ul_rate_set_us; last_ul_shaper_rate_kbps=$ul_shaper_rate_kbps; }  | ||||
| 
 | ||||
| 		update_max_wire_packet_compensation | ||||
| 	fi | ||||
| } | ||||
| 
 | ||||
| get_max_wire_packet_size_bits() | ||||
| { | ||||
| 	local interface=$1 | ||||
| 	local -n max_wire_packet_size_bits=$2 | ||||
|   | ||||
| 	read -r max_wire_packet_size_bits < "/sys/class/net/${interface}/mtu"  | ||||
| 	[[ $(tc qdisc show dev $interface) =~ (atm|noatm)[[:space:]]overhead[[:space:]]([0-9]+) ]] | ||||
| 	[[ ! -z "${BASH_REMATCH[2]}" ]] && max_wire_packet_size_bits=$((8*($max_wire_packet_size_bits+${BASH_REMATCH[2]})))  | ||||
| 	# atm compensation = 53*ceil(X/48) bytes = 8*53*((X+8*(48-1)/(8*48)) bits = 424*((X+376)/384) bits | ||||
| 	[[ "${BASH_REMATCH[1]}" == "atm" ]] && max_wire_packet_size_bits=$(( 424*(($max_wire_packet_size_bits+376)/384) )) | ||||
| } | ||||
| 
 | ||||
| update_max_wire_packet_compensation() | ||||
| { | ||||
| 	# Compensate for delays imposed by active traffic shaper | ||||
| 	# This will serve to increase the delay thr at rates below around 12Mbit/s | ||||
| 
 | ||||
| 	max_wire_packet_rtt_us=$(( (1000*$dl_max_wire_packet_size_bits)/$dl_shaper_rate_kbps + (1000*$ul_max_wire_packet_size_bits)/$ul_shaper_rate_kbps  )) | ||||
| 	compensated_delay_thr_us=$(( $delay_thr_us + $max_wire_packet_rtt_us )) | ||||
| 
 | ||||
| 	# write out max_wire_packet_rtt_us | ||||
| 	printf '%s' "$max_wire_packet_rtt_us" > /tmp/CAKE-autorate-${dl_if}/max_wire_packet_rtt_us | ||||
| } | ||||
| 
 | ||||
| concurrent_read_positive_integer() | ||||
| { | ||||
| 	# in the context of separate processes writing using > and reading form file | ||||
|         # it seems costly calls to the external flock binary can be avoided | ||||
| 	# read either succeeds as expected or occassionally reads in bank value | ||||
| 	# so just test for blank value and re-read until not blank | ||||
| 
 | ||||
| 	local -n value=$1 | ||||
|  	local path=$2 | ||||
| 	while true  | ||||
| 	do | ||||
| 		read -r value < $path;  | ||||
| 		if [[ -z "${value##*[!0-9]*}" ]]; then | ||||
| 			if (($debug)); then | ||||
| 				read -r caller_output< <(caller) | ||||
| 				echo "DEBUG concurrent_read_positive_integer() misfire with the following particulars:" | ||||
| 				echo "DEBUG caller="$caller_output"; value="$value"; and path="$path | ||||
| 			fi  | ||||
| 			sleep_us $concurrent_read_positive_integer_interval_us | ||||
| 			continue | ||||
| 		else | ||||
| 			break | ||||
| 		fi | ||||
| 	done | ||||
| } | ||||
| 
 | ||||
| verify_ifs_up() | ||||
| { | ||||
| 	# Check the rx/tx paths exist and give extra time for ifb's to come up if needed | ||||
| 	# This will block if ifs never come up | ||||
| 
 | ||||
| 	while [[ ! -f $rx_bytes_path || ! -f $tx_bytes_path ]] | ||||
| 	do | ||||
| 		(($debug)) && [[ ! -f $rx_bytes_path ]] && echo "DEBUG Warning: $rx_bytes_path does not exist. Waiting "$if_up_check_interval_s" seconds for interface to come up."  | ||||
| 		(($debug)) && [[ ! -f $tx_bytes_path ]] && echo "DEBUG Warning: $tx_bytes_path does not exist. Waiting "$if_up_check_interval_s" seconds for interface to come up."  | ||||
| 		sleep_s $if_up_check_interval_s | ||||
| 	done | ||||
| } | ||||
| 
 | ||||
| sleep_s() | ||||
| { | ||||
| 	# calling external sleep binary is slow | ||||
| 	# bash does have a loadable sleep  | ||||
| 	# but read's timeout can more portably be exploited and this is apparently even faster anyway | ||||
| 
 | ||||
| 	local sleep_duration_s=$1 # (seconds, e.g. 0.5, 1 or 1.5) | ||||
| 
 | ||||
| 	read -t $sleep_duration_s < /tmp/CAKE-autorate-${dl_if}/sleep_fifo | ||||
| } | ||||
| 
 | ||||
| sleep_us() | ||||
| { | ||||
| 	# calling external sleep binary is slow | ||||
| 	# bash does have a loadable sleep  | ||||
| 	# but read's timeout can more portably be exploited and this is apparently even fastera anyway | ||||
| 
 | ||||
| 	local sleep_duration_us=$1 # (microseconds) | ||||
| 	 | ||||
| 	sleep_duration_s=000000$sleep_duration_us | ||||
| 	sleep_duration_s=${sleep_duration_s::-6}.${sleep_duration_s: -6} | ||||
| 	read -t $sleep_duration_s < /tmp/CAKE-autorate-${dl_if}/sleep_fifo | ||||
| } | ||||
| 
 | ||||
| sleep_remaining_tick_time() | ||||
| { | ||||
| 	# sleeps until the end of the tick duration | ||||
| 
 | ||||
| 	local t_start_us=$1 # (microseconds) | ||||
| 	local tick_duration_us=$2 # (microseconds) | ||||
| 
 | ||||
| 	sleep_duration_us=$(( $t_start_us + $tick_duration_us - ${EPOCHREALTIME/./} )) | ||||
| 	 | ||||
|         if (( $sleep_duration_us > 0 )); then | ||||
| 		sleep_us $sleep_duration_us | ||||
| 	fi | ||||
| } | ||||
| 
 | ||||
| # Set up tmp directory, sleep fifo and perform various sanity checks | ||||
| 
 | ||||
| # /tmp/CAKE-autorate-${dl_if}/ is used to store temporary files | ||||
| # it should not exist on startup so if it does exit, else create the directory | ||||
| if [[ -d /tmp/CAKE-autorate-${dl_if} ]]; then  | ||||
| 	echo "Error: /tmp/CAKE-autorate-${dl_if} already exists. Is another instance running? Exiting script." | ||||
| 	trap - INT TERM EXIT | ||||
| 	exit | ||||
| else  | ||||
| 	mkdir /tmp/CAKE-autorate-${dl_if} | ||||
| fi | ||||
| 
 | ||||
| mkfifo /tmp/CAKE-autorate-${dl_if}/sleep_fifo | ||||
| exec 3<> /tmp/CAKE-autorate-${dl_if}/sleep_fifo | ||||
| 
 | ||||
| no_reflectors=${#reflectors[@]}  | ||||
| 
 | ||||
| # Check no_pingers <= no_reflectors | ||||
| (( $no_pingers > $no_reflectors)) && { echo "Error: number of pingers cannot be greater than number of reflectors. Exiting script."; exit; } | ||||
| 
 | ||||
| # Check dl/if interface not the same | ||||
| [[ $dl_if == $ul_if ]] && { echo "Error: download interface and upload interface are both set to: '"$dl_if"', but cannot be the same. Exiting script."; exit; } | ||||
| 
 | ||||
| # Check bufferbloat detection threshold not greater than window length | ||||
| (( $bufferbloat_detection_thr > $bufferbloat_detection_window )) && { echo "Error: bufferbloat_detection_thr cannot be greater than bufferbloat_detection_window. Exiting script."; exit; } | ||||
| 
 | ||||
| # Wait if $startup_wait_s > 0 | ||||
| if (($startup_wait_s>0)); then | ||||
| 	(($debug)) && echo "DEBUG Waiting "$startup_wait_s" seconds before startup." | ||||
| 	sleep_s $startup_wait_s | ||||
| fi | ||||
| 
 | ||||
| # Check interfaces are up and wait if necessary for them to come up | ||||
| verify_ifs_up | ||||
| 
 | ||||
| # Initialize variables | ||||
| 
 | ||||
| # Convert human readable parameters to values that work with integer arithmetic | ||||
| printf -v alpha_baseline_increase %.0f\\n "${alpha_baseline_increase}e3" | ||||
| printf -v alpha_baseline_decrease %.0f\\n "${alpha_baseline_decrease}e3"    | ||||
| printf -v achieved_rate_adjust_down_bufferbloat %.0f\\n "${achieved_rate_adjust_down_bufferbloat}e3" | ||||
| printf -v shaper_rate_adjust_down_bufferbloat %.0f\\n "${shaper_rate_adjust_down_bufferbloat}e3" | ||||
| printf -v shaper_rate_adjust_up_load_high %.0f\\n "${shaper_rate_adjust_up_load_high}e3" | ||||
| printf -v shaper_rate_adjust_down_load_low %.0f\\n "${shaper_rate_adjust_down_load_low}e3" | ||||
| printf -v shaper_rate_adjust_up_load_low %.0f\\n "${shaper_rate_adjust_up_load_low}e3" | ||||
| printf -v high_load_thr_percent %.0f\\n "${high_load_thr}e2" | ||||
| printf -v medium_load_thr_percent %.0f\\n "${medium_load_thr}e2" | ||||
| printf -v reflector_ping_interval_us %.0f\\n "${reflector_ping_interval_s}e6" | ||||
| printf -v monitor_achieved_rates_interval_us %.0f\\n "${monitor_achieved_rates_interval_ms}e3" | ||||
| printf -v sustained_idle_sleep_thr_us %.0f\\n "${sustained_idle_sleep_thr_s}e6" | ||||
| printf -v reflector_response_deadline_us %.0f\\n "${reflector_response_deadline_s}e6" | ||||
| bufferbloat_refractory_period_us=$(( 1000*$bufferbloat_refractory_period_ms )) | ||||
| decay_refractory_period_us=$(( 1000*$decay_refractory_period_ms )) | ||||
| delay_thr_us=$(( 1000*$delay_thr_ms )) | ||||
| 
 | ||||
| for (( i=0; i<${#sss_times_s[@]}; i++ )); | ||||
| do | ||||
| 	printf -v sss_times_us[i] %.0f\\n "${sss_times_s[i]}e6" | ||||
| done | ||||
| printf -v sss_compensation_pre_duration_us %.0f\\n "${sss_compensation_pre_duration_ms}e3" | ||||
| printf -v sss_compensation_post_duration_us %.0f\\n "${sss_compensation_post_duration_ms}e3" | ||||
| 
 | ||||
| ping_response_interval_us=$(($reflector_ping_interval_us/$no_pingers)) | ||||
| 
 | ||||
| concurrent_read_positive_integer_interval_us=$(($ping_response_interval_us/4)) | ||||
| 
 | ||||
| dl_shaper_rate_kbps=$base_dl_shaper_rate_kbps | ||||
| ul_shaper_rate_kbps=$base_ul_shaper_rate_kbps | ||||
| 
 | ||||
| last_dl_shaper_rate_kbps=$dl_shaper_rate_kbps | ||||
| last_ul_shaper_rate_kbps=$ul_shaper_rate_kbps | ||||
| 
 | ||||
| get_max_wire_packet_size_bits $dl_if dl_max_wire_packet_size_bits   | ||||
| get_max_wire_packet_size_bits $ul_if ul_max_wire_packet_size_bits | ||||
| 
 | ||||
| set_cake_rate $dl_if $dl_shaper_rate_kbps t_prev_dl_rate_set_us | ||||
| set_cake_rate $ul_if $ul_shaper_rate_kbps t_prev_ul_rate_set_us | ||||
| 
 | ||||
| update_max_wire_packet_compensation | ||||
| 
 | ||||
| t_start_us=${EPOCHREALTIME/./} | ||||
| t_end_us=${EPOCHREALTIME/./} | ||||
| t_prev_ul_rate_set_us=$t_start_us | ||||
| t_prev_dl_rate_set_us=$t_start_us | ||||
| t_ul_last_bufferbloat_us=$t_start_us | ||||
| t_ul_last_decay_us=$t_start_us | ||||
| t_dl_last_bufferbloat_us=$t_start_us | ||||
| t_dl_last_decay_us=$t_start_us | ||||
| 
 | ||||
| t_sustained_connection_idle_us=0 | ||||
| 
 | ||||
| declare -a delays=( $(for i in {1..$bufferbloat_detection_window}; do echo 0; done) ) | ||||
| delays_idx=0 | ||||
| sum_delays=0 | ||||
| 
 | ||||
| mkfifo /tmp/CAKE-autorate-${dl_if}/ping_fifo | ||||
| exec 4<> /tmp/CAKE-autorate-${dl_if}/ping_fifo | ||||
| 
 | ||||
| maintain_pingers & | ||||
| maintain_pingers_pid=$! | ||||
| 
 | ||||
| # Initiate achived rate monitor | ||||
| monitor_achieved_rates $rx_bytes_path $tx_bytes_path $monitor_achieved_rates_interval_us& | ||||
| monitor_achieved_rates_pid=$! | ||||
| 
 | ||||
| prev_timestamp=0 | ||||
| 
 | ||||
| if (($debug)); then | ||||
| 	if (( $bufferbloat_refractory_period_us <= ($bufferbloat_detection_window*$ping_response_interval_us) )); then | ||||
| 		echo "DEBUG Warning: bufferbloat refractory period: " $bufferbloat_refractory_period_us " us." | ||||
| 		echo "DEBUG Warning: but expected time to overwrite samples in bufferbloat detection window is: " $(($bufferbloat_detection_window*$ping_response_interval_us)) " us."  | ||||
| 		echo "DEBUG Warning: Consider increasing bufferbloat refractory period or decreasing bufferbloat detection window." | ||||
| 	fi | ||||
| fi | ||||
| 
 | ||||
| while true | ||||
| do | ||||
| 	while read -t $global_ping_response_timeout_s -r timestamp reflector seq rtt_baseline_us rtt_us rtt_delta_us | ||||
| 	do  | ||||
| 		t_start_us=${EPOCHREALTIME/./} | ||||
| 		if ((($t_start_us - 10#"${timestamp//[[\[\].]}")>500000)); then | ||||
| 			(($debug)) && echo "DEBUG processed response from [" $reflector "] that is > 500ms old. Skipping."  | ||||
| 			continue | ||||
| 		fi | ||||
| 		 | ||||
| 		# Keep track of number of delays across detection window | ||||
| 		(( ${delays[$delays_idx]} )) && ((sum_delays--)) | ||||
| 		delays[$delays_idx]=$(( $rtt_delta_us > $compensated_delay_thr_us ? 1 : 0 )) | ||||
| 		((delays[$delays_idx])) && ((sum_delays++)) | ||||
| 		(( delays_idx=(delays_idx+1)%$bufferbloat_detection_window )) | ||||
| 
 | ||||
| 		bufferbloat_detected=$(( (($sum_delays>=$bufferbloat_detection_thr)) ? 1 : 0 )) | ||||
| 
 | ||||
| 		get_loads | ||||
| 
 | ||||
| 		classify_load $dl_load_percent $dl_achieved_rate_kbps dl_load_condition | ||||
| 		classify_load $ul_load_percent $ul_achieved_rate_kbps ul_load_condition | ||||
| 	 | ||||
| 		dl_load_condition="dl_"$dl_load_condition | ||||
| 		ul_load_condition="ul_"$ul_load_condition | ||||
| 
 | ||||
| 		get_next_shaper_rate $min_dl_shaper_rate_kbps $base_dl_shaper_rate_kbps $max_dl_shaper_rate_kbps $dl_achieved_rate_kbps $dl_load_condition $t_start_us t_dl_last_bufferbloat_us t_dl_last_decay_us dl_shaper_rate_kbps | ||||
| 		get_next_shaper_rate $min_ul_shaper_rate_kbps $base_ul_shaper_rate_kbps $max_ul_shaper_rate_kbps $ul_achieved_rate_kbps $ul_load_condition $t_start_us t_ul_last_bufferbloat_us t_ul_last_decay_us ul_shaper_rate_kbps | ||||
| 
 | ||||
| 		(($output_processing_stats)) && printf '%s %-6s %-6s %-3s %-3s %s %-15s %-6s %-6s %-6s %-6s %-6s %s %-14s %-14s %-6s %-6s\n' $EPOCHREALTIME $dl_achieved_rate_kbps $ul_achieved_rate_kbps $dl_load_percent $ul_load_percent $timestamp $reflector $seq $rtt_baseline_us $rtt_us $rtt_delta_us $compensated_delay_thr_us $sum_delays $dl_load_condition $ul_load_condition $dl_shaper_rate_kbps $ul_shaper_rate_kbps | ||||
| 
 | ||||
| 		set_shaper_rates | ||||
| 
 | ||||
| 		# If base rate is sustained, increment sustained base rate timer (and break out of processing loop if enough time passes) | ||||
| 		if (($enable_sleep_function)); then | ||||
| 			if [[ $dl_load_condition == idle* && $ul_load_condition == idle* ]]; then | ||||
| 				((t_sustained_connection_idle_us+=$((${EPOCHREALTIME/./}-$t_end_us)))) | ||||
| 				(($t_sustained_connection_idle_us>$sustained_idle_sleep_thr_us)) && break | ||||
| 			else | ||||
| 				# reset timer | ||||
| 				t_sustained_connection_idle_us=0 | ||||
| 			fi | ||||
| 		fi | ||||
| 		t_end_us=${EPOCHREALTIME/./} | ||||
| 
 | ||||
| 	done</tmp/CAKE-autorate-${dl_if}/ping_fifo | ||||
| 
 | ||||
| 	(($debug)) && {(( ${PIPESTATUS[0]} == 142 )) && echo "DEBUG Warning: global ping response timeout. Enforcing minimum shaper rates." || echo "DEBUG Connection idle. Enforcing minimum shaper rates.";} | ||||
| 	 | ||||
| 	# in any case, we broke out of processing loop, so conservatively set hard minimums and wait until there is a load increase again | ||||
| 	dl_shaper_rate_kbps=$min_dl_shaper_rate_kbps | ||||
| 	ul_shaper_rate_kbps=$min_ul_shaper_rate_kbps | ||||
| 	set_shaper_rates | ||||
| 
 | ||||
| 	# Initiate termination of ping processes and wait until complete | ||||
| 	kill $maintain_pingers_pid 2> /dev/null | ||||
| 	wait $maintain_pingers_pid | ||||
| 
 | ||||
| 	# reset idle timer | ||||
| 	t_sustained_connection_idle_us=0 | ||||
| 
 | ||||
| 	# verify interfaces are up (e.g. following ping response timeout from interfaces going down) | ||||
| 	verify_ifs_up | ||||
| 
 | ||||
| 	# wait until load increases again | ||||
| 	while true | ||||
| 	do | ||||
| 		t_start_us=${EPOCHREALTIME/./}	 | ||||
| 		get_loads | ||||
| 		(($dl_load_percent>$medium_load_thr_percent || $ul_load_percent>$medium_load_thr_percent)) && break  | ||||
| 		sleep_remaining_tick_time $t_start_us $reflector_ping_interval_us | ||||
| 	done | ||||
| 
 | ||||
| 	# Start up ping processes | ||||
| 	maintain_pingers & | ||||
| 	maintain_pingers_pid=$! | ||||
| done | ||||
							
								
								
									
										1790
									
								
								luci-app-sqm-autorate/root/usr/share/sqm-autorate/cake-autorate.sh
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										1790
									
								
								luci-app-sqm-autorate/root/usr/share/sqm-autorate/cake-autorate.sh
									
										
									
									
									
										Executable file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										209
									
								
								luci-app-sqm-autorate/root/usr/share/sqm-autorate/cake-autorate_defaults.sh
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										209
									
								
								luci-app-sqm-autorate/root/usr/share/sqm-autorate/cake-autorate_defaults.sh
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,209 @@ | |||
| #!/bin/bash | ||||
| 
 | ||||
| # cake-autorate automatically adjusts bandwidth for CAKE in dependence on detected load and RTT | ||||
| 
 | ||||
| # cake-autorate_config.sh is a script that sets up defaults for cake-autorate | ||||
| 
 | ||||
| # Author: @Lynx (OpenWrt forum) | ||||
| # Inspiration taken from: @moeller0 (OpenWrt forum) | ||||
| 
 | ||||
| cake_autorate_version="2.0.0" | ||||
| 
 | ||||
| # *** OUTPUT AND LOGGING OPTIONS *** | ||||
| 
 | ||||
| output_processing_stats=1 	# enable (1) or disable (0) output monitoring lines showing processing stats | ||||
| output_load_stats=1       	# enable (1) or disable (0) output monitoring lines showing achieved loads | ||||
| output_reflector_stats=1  	# enable (1) or disable (0) output monitoring lines showing reflector stats | ||||
| output_cake_changes=0     	# enable (1) or disable (0) output monitoring lines showing cake bandwidth changes | ||||
| debug=1 		  	# enable (1) or disable (0) out of debug lines | ||||
| 
 | ||||
| # This can generate a LOT of records so be careful: | ||||
| log_DEBUG_messages_to_syslog=0	# enable (1) or disable (0) logging of all DEBUG records into the system log.  | ||||
| 
 | ||||
| # ** Take care with these settings to ensure you won't run into OOM issues on your router *** | ||||
| # every write the cumulative write time and bytes associated with each log line are checked | ||||
| # and if either exceeds the configured values below, the log log file is rotated | ||||
| log_to_file=1              # enable (1) or disable (0) output logging to file (/tmp/cake-autorate.log) | ||||
| log_file_max_time_mins=10  # maximum time between log file rotations | ||||
| log_file_max_size_KB=2000  # maximum KB (i.e. bytes/1024) worth of log lines between log file rotations | ||||
| 
 | ||||
| # log file path defaults to /var/log/ | ||||
| # or, if set below, then ${log_file_path_override} | ||||
| log_file_path_override="" | ||||
| 
 | ||||
| # *** STANDARD CONFIGURATION OPTIONS *** | ||||
| 
 | ||||
| ### For multihomed setups, it is the responsibility of the user to ensure that the probes  | ||||
| ### sent by this instance of cake-autorate actually travel through these interfaces. | ||||
| ### See ping_extra_args and ping_prefix_string | ||||
| 
 | ||||
| dl_if=ifb-wan # download interface | ||||
| ul_if=wan     # upload interface | ||||
| 
 | ||||
| # pinger selection can be any of: | ||||
| # fping - round robin pinging (rtts) | ||||
| # ping - (iputils-ping) individual pinging (rtts) | ||||
| # hping3 - individidual pinging (owds) | ||||
| pinger_binary=ping | ||||
| 
 | ||||
| # list of reflectors to use and number of pingers to initiate | ||||
| # pingers will be initiated with reflectors in the order specified in the list  | ||||
| # additional reflectors will be used to replace any reflectors that go stale | ||||
| # so e.g. if 6 reflectors are specified and the number of pingers is set to 4, the first 4 reflectors will be used initially | ||||
| # and the remaining 2 reflectors in the list will be used in the event any of the first 4 go bad | ||||
| # a bad reflector will go to the back of the queue on reflector rotation | ||||
| reflectors=( | ||||
| "1.1.1.1" "1.0.0.1"  # Cloudflare | ||||
| "8.8.8.8" "8.8.4.4"  # Google | ||||
| "9.9.9.9" "9.9.9.10" "9.9.9.11" # Quad9 | ||||
| "94.140.14.15" "94.140.14.140" "94.140.14.141" "94.140.15.15" "94.140.15.16" # AdGuard | ||||
| "64.6.65.6" "156.154.70.1" "156.154.70.2" "156.154.70.3" "156.154.70.4" "156.154.70.5" "156.154.71.1" "156.154.71.2" "156.154.71.3" "156.154.71.4" "156.154.71.5" # Neustar | ||||
| "208.67.220.2" "208.67.220.123" "208.67.220.220" "208.67.222.2" "208.67.222.123" # OpenDNS | ||||
| "185.228.168.9" "185.228.168.10" # CleanBrowsing | ||||
| ) | ||||
| 
 | ||||
| randomize_reflectors=1 # enable (1) or disable (0) randomization of reflectors on startup | ||||
| 
 | ||||
| # Think carefully about the following settings | ||||
| # to avoid excessive CPU use (proportional with ping interval / number of pingers) | ||||
| # and to avoid abusive network activity (excessive ICMP frequency to one reflector) | ||||
| # The author has found an ICMP rate of 1/(0.2/4) = 20 Hz to give satisfactory performance on 4G | ||||
| no_pingers=6 # number of pingers to maintain | ||||
| reflector_ping_interval_s=0.3 # (seconds, e.g. 0.2s or 2s) | ||||
| 
 | ||||
| # delay threshold in ms is the extent of OWD increase to classify as a delay | ||||
| # these are automatically adjusted based on maximum on the wire packet size | ||||
| # (adjustment significant at sub 12Mbit/s rates, else negligible)   | ||||
| dl_delay_thr_ms=30 # (milliseconds) | ||||
| ul_delay_thr_ms=30 # (milliseconds) | ||||
| 
 | ||||
| # Set either of the below to 0 to adjust one direction only  | ||||
| # or alternatively set both to 0 to simply use cake-autorate to monitor a connection | ||||
| adjust_dl_shaper_rate=1 # enable (1) or disable (0) actually changing the dl shaper rate | ||||
| adjust_ul_shaper_rate=1 # enable (1) or disable (0) actually changing the ul shaper rate | ||||
| 
 | ||||
| min_dl_shaper_rate_kbps=5000  # minimum bandwidth for download (Kbit/s) | ||||
| base_dl_shaper_rate_kbps=20000 # steady state bandwidth for download (Kbit/s) | ||||
| max_dl_shaper_rate_kbps=80000  # maximum bandwidth for download (Kbit/s) | ||||
| 
 | ||||
| min_ul_shaper_rate_kbps=5000  # minimum bandwidth for upload (Kbit/s) | ||||
| base_ul_shaper_rate_kbps=20000 # steady state bandwidth for upload (KBit/s) | ||||
| max_ul_shaper_rate_kbps=35000  # maximum bandwidth for upload (Kbit/s) | ||||
| 
 | ||||
| # sleep functionality saves unecessary pings and CPU cycles by | ||||
| # pausing all active pingers when connection is not in active use | ||||
| enable_sleep_function=1 # enable (1) or disable (0) sleep functonality  | ||||
| connection_active_thr_kbps=1000  # threshold in Kbit/s below which dl/ul is considered idle | ||||
| sustained_idle_sleep_thr_s=60.0  # time threshold to put pingers to sleep on sustained dl/ul achieved rate < idle_thr (seconds) | ||||
| 
 | ||||
| min_shaper_rates_enforcement=0 # enable (1) or disable (0) dropping down to minimum shaper rates on connection idle or stall | ||||
| 
 | ||||
| startup_wait_s=0.0 # number of seconds to wait on startup (e.g. to wait for things to settle on router reboot) | ||||
| 
 | ||||
| # *** ADVANCED CONFIGURATION OPTIONS *** | ||||
| 
 | ||||
| log_file_export_compress=1 # compress log file exports using gzip and append .gz to export filename | ||||
| 
 | ||||
| ### In multi-homed setups, it is mandatory to use either ping_extra_args | ||||
| ### or ping_prefix_string to direct the pings through $dl_if and $ul_if. | ||||
| ### No universal recommendation exists, because there are multiple | ||||
| ### policy-routing packages available (e.g. vpn-policy-routing and mwan3). | ||||
| ### Typically they either react to a firewall mark set on the pings, or | ||||
| ### provide a convenient wrapper. | ||||
| ### | ||||
| ### In a traditional single-homed setup, there is usually no need for these parameters. | ||||
| ### | ||||
| ### These arguments can also be used for any other purpose - e.g. for setting a | ||||
| ### particular QoS mark. | ||||
| 
 | ||||
| # extra arguments for ping or fping | ||||
| # e.g., here is how you can set the correct outgoing interface and | ||||
| # the firewall mark for ping: | ||||
| # ping_extra_args="-I wwan0 -m $((0x300))" | ||||
| # Unfortunately, fping does not offer a command line switch to set | ||||
| # the firewall mark. | ||||
| # WARNING: no error checking so use at own risk! | ||||
| ping_extra_args="" | ||||
| 
 | ||||
| # a wrapper for ping binary - used as a prefix for the real command | ||||
| # e.g., when using mwan3, it is recommended to set it like this: | ||||
| # ping_prefix_string="mwan3 use gpon exec" | ||||
| # WARNING: the wrapper must exec ping as the final step, not run it as a subprocess. | ||||
| # Running ping or fping as a subprocess will lead to problems stopping it. | ||||
| # WARNING: no error checking - so use at own risk! | ||||
| ping_prefix_string="" | ||||
| 
 | ||||
| # interval in ms for monitoring achieved rx/tx rates | ||||
| # this is automatically adjusted based on maximum on the wire packet size | ||||
| # (adjustment significant at sub 12Mbit/s rates, else negligible)   | ||||
| monitor_achieved_rates_interval_ms=200 # (milliseconds)  | ||||
| 
 | ||||
| # bufferbloat is detected when (bufferbloat_detection_thr) samples | ||||
| # out of the last (bufferbloat detection window) samples are delayed | ||||
| bufferbloat_detection_window=6   # number of samples to retain in detection window | ||||
| bufferbloat_detection_thr=3      # number of delayed samples for bufferbloat detection | ||||
| 
 | ||||
| # OWD baseline against which to measure delays | ||||
| # the idea is that the baseline is allowed to increase slowly to allow for path changes | ||||
| # and slowly enough such that bufferbloat will be corrected well before the baseline increases, | ||||
| # but it will decrease very rapidly to ensure delays are measured against the shortest path | ||||
| alpha_baseline_increase=0.001  # how rapidly baseline RTT is allowed to increase | ||||
| alpha_baseline_decrease=0.9  # how rapidly baseline RTT is allowed to decrease | ||||
| 
 | ||||
| # OWD delta from baseline is tracked using ewma with alpha set below | ||||
| alpha_delta_ewma=0.095 | ||||
| 
 | ||||
| # rate adjustment parameters  | ||||
| # bufferbloat adjustment works with the lower of the adjusted achieved rate and adjusted shaper rate | ||||
| # to exploit that transfer rates during bufferbloat provide an indication of line capacity | ||||
| # otherwise shaper rate is adjusted up on load high, and down on load idle or low | ||||
| achieved_rate_adjust_down_bufferbloat=0.9 # how rapidly to reduce achieved rate upon detection of bufferbloat  | ||||
| shaper_rate_adjust_down_bufferbloat=0.9   # how rapidly to reduce shaper rate upon detection of bufferbloat  | ||||
| shaper_rate_adjust_up_load_high=1.01      # how rapidly to increase shaper rate upon high load detected  | ||||
| shaper_rate_adjust_down_load_low=0.99     # how rapidly to return down to base shaper rate upon idle or low load detected  | ||||
| shaper_rate_adjust_up_load_low=1.01       # how rapidly to return up to base shaper rate upon idle or low load detected  | ||||
| 
 | ||||
| # the load is categoried as low if < high_load_thr and high if > high_load_thr relative to the current shaper rate | ||||
| high_load_thr=0.75   # % of currently set bandwidth for detecting high load | ||||
| 
 | ||||
| # refractory periods between successive bufferbloat/decay rate changes | ||||
| # the bufferbloat refractory period should be greater than the  | ||||
| # average time it would take to replace the bufferbloat | ||||
| # detection window with new samples upon a bufferbloat event | ||||
| bufferbloat_refractory_period_ms=300 # (milliseconds) | ||||
| decay_refractory_period_ms=1000 # (milliseconds) | ||||
| 
 | ||||
| # interval for checking reflector health | ||||
| reflector_health_check_interval_s=1.0 # (seconds) | ||||
| # deadline for reflector response not to be classified as an offence against reflector | ||||
| reflector_response_deadline_s=1.0 # (seconds) | ||||
| 
 | ||||
| # reflector misbehaving is detected when $reflector_misbehaving_detection_thr samples | ||||
| # out of the last (reflector misbehaving detection window) samples are offences | ||||
| # thus with a 1s interval, window 60 and detection_thr 3, this is tantamount to | ||||
| # 3 offences within the last 60s  | ||||
| reflector_misbehaving_detection_window=60 | ||||
| reflector_misbehaving_detection_thr=3 | ||||
| 
 | ||||
| reflector_replacement_interval_mins=60 # how often to replace a random reflector from the present list | ||||
| 
 | ||||
| reflector_comparison_interval_mins=1       # how often to compare reflectors  | ||||
| reflector_owd_baseline_delta_thr_ms=10     # max increase from min baseline before reflector rotated | ||||
| reflector_owd_delta_ewma_delta_thr_ms=10   # mac increase from min delta ewma before reflector rotated | ||||
| 
 | ||||
| # stall is detected when the following two conditions are met: | ||||
| # 1) no reflector responses within $stall_detection_thr*$ping_response_interval_us; and | ||||
| # 2) either $rx_achieved_rate or $tx_achieved_rate < $connection_stall_thr | ||||
| stall_detection_thr=5 | ||||
| connection_stall_thr_kbps=10 | ||||
| 
 | ||||
| global_ping_response_timeout_s=10.0 # timeout to set shaper rates to min on no ping response whatsoever (seconds) | ||||
| 
 | ||||
| if_up_check_interval_s=10.0 # time to wait before re-checking if rx/tx bytes files exist (e.g. from boot state or sleep recovery) | ||||
| 
 | ||||
| # Starlink satellite switch (sss) compensation options | ||||
| sss_compensation=0 # enable (1) or disable (0) Starlink handling | ||||
| # satellite switch compensation start times in seconds of each minute | ||||
| sss_times_s=("12.0" "27.0" "42.0" "57.0") | ||||
| sss_compensation_pre_duration_ms=300 | ||||
| sss_compensation_post_duration_ms=200 | ||||
							
								
								
									
										26
									
								
								luci-app-sqm-autorate/root/usr/share/sqm-autorate/cake-autorate_launcher.sh
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										26
									
								
								luci-app-sqm-autorate/root/usr/share/sqm-autorate/cake-autorate_launcher.sh
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,26 @@ | |||
| #!/bin/bash | ||||
| 
 | ||||
| cake_instances=(/usr/share/sqm-autorate/cake-autorate_config*sh) | ||||
| cake_instance_pids=() | ||||
| 
 | ||||
| trap kill_cake_instances INT TERM EXIT | ||||
| 
 | ||||
| kill_cake_instances() | ||||
| { | ||||
| 	trap - INT TERM EXIT | ||||
| 
 | ||||
| 	echo "Killing all instances of cake one-by-one now." | ||||
| 
 | ||||
| 	for ((cake_instance=0; cake_instance<${#cake_instances[@]}; cake_instance++)) | ||||
| 	do | ||||
| 		kill "${cake_instance_pids[${cake_instance}]}" 2>/dev/null || true | ||||
| 	done | ||||
| 	wait | ||||
| } | ||||
| 
 | ||||
| for cake_instance in "${cake_instances[@]}" | ||||
| do | ||||
| 	/usr/share/sqm-autorate/cake-autorate.sh "${cake_instance}" & | ||||
| 	cake_instance_pids+=(${!}) | ||||
| done | ||||
| wait | ||||
							
								
								
									
										257
									
								
								luci-app-sqm-autorate/root/usr/share/sqm-autorate/cake-autorate_lib.sh
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										257
									
								
								luci-app-sqm-autorate/root/usr/share/sqm-autorate/cake-autorate_lib.sh
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,257 @@ | |||
| #!/bin/bash | ||||
| # cake-autorate_lib.sh -- common functions for use by cake-autorate.sh | ||||
| # This file is part of cake-autorate. | ||||
| 
 | ||||
| __set_e=0 | ||||
| if [[ ! ${-} =~ e ]]; then | ||||
|     set -e | ||||
|     __set_e=1 | ||||
| fi | ||||
| 
 | ||||
| exec {__sleep_fd}<> <(:) || true | ||||
| 
 | ||||
| sleep_s() | ||||
| { | ||||
| 	# Calling the external sleep binary could be rather slow, | ||||
| 	# especially as it is called very frequently and typically on mediocre hardware. | ||||
| 	# | ||||
| 	# bash's loadable sleep module is not typically available | ||||
| 	# in OpenWRT and most embedded systems, and use of the bash | ||||
| 	# read command with a timeout offers performance that is | ||||
| 	# at least on a par with bash's sleep module. | ||||
| 	# | ||||
| 	# For benchmarks, check the following links: | ||||
| 	# - https://github.com/lynxthecat/cake-autorate/issues/174#issuecomment-1460057382 | ||||
| 	# - https://github.com/lynxthecat/cake-autorate/issues/174#issuecomment-1460074498 | ||||
| 
 | ||||
| 	local sleep_duration_s=${1} # (seconds, e.g. 0.5, 1 or 1.5) | ||||
| 	read -r -t "${sleep_duration_s}" -u "${__sleep_fd}" || : & | ||||
| 	wait "${!}" | ||||
| } | ||||
| 
 | ||||
| sleep_us() | ||||
| { | ||||
| 	local sleep_duration_us=${1} # (microseconds) | ||||
| 
 | ||||
| 	sleep_duration_s=000000${sleep_duration_us} | ||||
| 	sleep_duration_s=$((10#${sleep_duration_s::-6})).${sleep_duration_s: -6} | ||||
| 	sleep_s "${sleep_duration_s}" | ||||
| } | ||||
| 
 | ||||
| sleep_remaining_tick_time() | ||||
| { | ||||
| 	# sleeps until the end of the tick duration | ||||
| 
 | ||||
| 	local t_start_us=${1} # (microseconds) | ||||
| 	local tick_duration_us=${2} # (microseconds) | ||||
| 
 | ||||
| 	# shellcheck disable=SC2154 | ||||
| 	sleep_duration_us=$(( t_start_us + tick_duration_us - ${EPOCHREALTIME/./} )) | ||||
| 
 | ||||
| 	if (( sleep_duration_us > 0 )); then | ||||
| 		sleep_us "${sleep_duration_us}" | ||||
| 	fi | ||||
| } | ||||
| 
 | ||||
| randomize_array() | ||||
| { | ||||
| 	local -n array=${1} | ||||
| 
 | ||||
| 	subset=("${array[@]}") | ||||
| 	array=() | ||||
| 	for ((set=${#subset[@]}; set>0; set--)) | ||||
| 	do | ||||
| 		idx=$((RANDOM%set)) | ||||
| 		array+=("${subset[idx]}") | ||||
| 		unset "subset[idx]" | ||||
| 		subset=("${subset[@]}") | ||||
| 	done | ||||
| } | ||||
| 
 | ||||
| lock() | ||||
| { | ||||
| 	local path=${1} | ||||
| 
 | ||||
| 	while true; do | ||||
| 		( set -o noclobber; echo "$$" > "${path:?}" ) 2> /dev/null && return 0 | ||||
| 		sleep_us 100000 | ||||
| 	done | ||||
| } | ||||
| 
 | ||||
| unlock() | ||||
| { | ||||
| 	local path=${1} | ||||
| 
 | ||||
| 	rm -f "${path:?}" | ||||
| } | ||||
| 
 | ||||
| _proc_man_set_key() | ||||
| { | ||||
| 	local key=${1} | ||||
| 	local value=${2} | ||||
| 
 | ||||
| 	lock "${PROC_STATE_FILE_LOCK:?}" | ||||
| 	trap 'unlock "${PROC_STATE_FILE_LOCK:?}"' RETURN | ||||
| 
 | ||||
| 	local entered=0 | ||||
| 	while read -r line; do | ||||
| 		if [[ ${line} =~ ^${key}= ]]; then | ||||
| 			printf '%s\n' "${key}=${value}" | ||||
| 			entered=1 | ||||
| 		else | ||||
| 			printf '%s\n' "${line}" | ||||
| 		fi | ||||
| 	done < "${PROC_STATE_FILE:?}" > "${PROC_STATE_FILE:?}.tmp" | ||||
| 	if (( entered == 0 )); then | ||||
| 		printf '%s\n' "${key}=${value}" >> "${PROC_STATE_FILE:?}.tmp" | ||||
| 	fi | ||||
| 	mv "${PROC_STATE_FILE:?}.tmp" "${PROC_STATE_FILE:?}" | ||||
| 	return 0 | ||||
| } | ||||
| 
 | ||||
| _proc_man_get_key_value() | ||||
| { | ||||
| 	local key=${1} | ||||
| 
 | ||||
| 	lock "${PROC_STATE_FILE_LOCK:?}" | ||||
| 	trap 'unlock "${PROC_STATE_FILE_LOCK:?}"' RETURN | ||||
| 
 | ||||
| 	while read -r line; do | ||||
| 		if [[ ${line} =~ ^${key}= ]]; then | ||||
| 			printf '%s\n' "${line#*=}" | ||||
| 			return 0 | ||||
| 		fi | ||||
| 	done < "${PROC_STATE_FILE:?}" | ||||
| 	return 1 | ||||
| } | ||||
| 
 | ||||
| proc_man() | ||||
| { | ||||
| 	local action=${1} | ||||
| 	local name=${2} | ||||
| 	shift 2 | ||||
| 
 | ||||
| 	if [[ ! -f "${PROC_STATE_FILE:?}" ]]; then | ||||
| 		return 1 | ||||
| 	fi | ||||
| 
 | ||||
| 	# shellcheck disable=SC2311 | ||||
| 	case "${action}" in | ||||
| 		"start") | ||||
| 			pid=$(_proc_man_get_key_value "${name}") | ||||
| 			if (( pid && pid > 0 )) && kill -0 "${pid}" 2> /dev/null; then | ||||
| 				return 1; | ||||
| 			fi | ||||
| 
 | ||||
| 			"${@}" & | ||||
| 			local pid=${!} | ||||
| 			_proc_man_set_key "${name}" "${pid}" | ||||
| 			;; | ||||
| 		"stop") | ||||
| 			local pid | ||||
| 			pid=$(_proc_man_get_key_value "${name}") | ||||
| 			if ! (( pid && pid > 0 )); then | ||||
| 				return 0; | ||||
| 			fi | ||||
| 
 | ||||
| 			kill "${pid}" 2> /dev/null || true | ||||
| 
 | ||||
| 			# wait for process to die | ||||
| 			killed=0 | ||||
| 			for ((i=0; i<10; i++)); | ||||
| 			do | ||||
| 				if kill -0 "${pid}" 2> /dev/null; then | ||||
| 					sleep_us 100000 | ||||
| 				else | ||||
| 					killed=1 | ||||
| 					break | ||||
| 				fi | ||||
| 			done | ||||
| 
 | ||||
| 			# if process still alive, kill it with fire | ||||
| 			if (( killed == 0 )); then | ||||
| 				kill -9 "${pid}" 2> /dev/null || true | ||||
| 			fi | ||||
| 
 | ||||
| 			_proc_man_set_key "${name}" "-1" "${PROC_STATE_FILE:?}" | ||||
| 			;; | ||||
| 		"status") | ||||
| 			local pid | ||||
| 			pid=$(_proc_man_get_key_value "${name}") | ||||
| 			if (( pid && pid > 0 )); then | ||||
| 				if kill -0 "${pid}" 2> /dev/null; then | ||||
| 					printf '%s\n' "running" | ||||
| 				else | ||||
| 					printf '%s\n' "dead" | ||||
| 				fi | ||||
| 			else | ||||
| 				printf '%s\n' "stopped" | ||||
| 			fi | ||||
| 			;; | ||||
| 		"wait") | ||||
| 			local pid | ||||
| 			pid=$(_proc_man_get_key_value "${name}") | ||||
| 			if (( pid && pid > 0 )); then | ||||
| 				wait "${pid}" && return 0 | ||||
| 			fi | ||||
| 
 | ||||
| 			return 1 | ||||
| 			;; | ||||
| 		"signal") | ||||
| 			shift 3 | ||||
| 
 | ||||
| 			local pid | ||||
| 			pid=$(_proc_man_get_key_value "${name}") | ||||
| 			if (( pid && pid > 0 )); then | ||||
| 				kill -s "${1}" "${pid}" 2>/dev/null && return 0 | ||||
| 			fi | ||||
| 
 | ||||
| 			return 1 | ||||
| 			;; | ||||
| 		"initialize") | ||||
| 			proc_man_initialize | ||||
| 			return $? | ||||
| 			;; | ||||
| 		*) | ||||
| 			printf '%s\n' "unknown action: ${action}" >&2 | ||||
| 			return 1 | ||||
| 			;; | ||||
| 	esac | ||||
| 
 | ||||
| 	return 0 | ||||
| } | ||||
| 
 | ||||
| proc_man_initialize() | ||||
| { | ||||
| 	true > "${PROC_STATE_FILE:?}" | ||||
| } | ||||
| 
 | ||||
| proc_man_start() | ||||
| { | ||||
| 	proc_man start "${@}" | ||||
| } | ||||
| 
 | ||||
| proc_man_stop() | ||||
| { | ||||
| 	proc_man stop "${@}" | ||||
| } | ||||
| 
 | ||||
| proc_man_status() | ||||
| { | ||||
| 	proc_man status "${@}" | ||||
| } | ||||
| 
 | ||||
| proc_man_wait() | ||||
| { | ||||
| 	proc_man wait "${@}" | ||||
| } | ||||
| 
 | ||||
| proc_man_signal() | ||||
| { | ||||
| 	proc_man signal "${@}" | ||||
| } | ||||
| 
 | ||||
| if (( __set_e == 1 )); then | ||||
|     set +e | ||||
| fi | ||||
| unset __set_e | ||||
							
								
								
									
										213
									
								
								luci-app-sqm-autorate/root/usr/share/sqm-autorate/cake-autorate_template.sh
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										213
									
								
								luci-app-sqm-autorate/root/usr/share/sqm-autorate/cake-autorate_template.sh
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,213 @@ | |||
| #!/bin/bash | ||||
| 
 | ||||
| # cake-autorate automatically adjusts bandwidth for CAKE in dependence on detected load and RTT | ||||
| 
 | ||||
| # cake-autorate_config.sh is a script that sets up defaults for cake-autorate | ||||
| 
 | ||||
| # Author: @Lynx (OpenWrt forum) | ||||
| # Inspiration taken from: @moeller0 (OpenWrt forum) | ||||
| 
 | ||||
| INTERFACE=$(basename "$0" | cut -d. -f2) | ||||
| 
 | ||||
| cake_autorate_version="2.0.0" | ||||
| 
 | ||||
| # *** OUTPUT AND LOGGING OPTIONS *** | ||||
| 
 | ||||
| output_processing_stats=$(uci -q get sqm.${INTERFACE}.output_processing_stats || echo '0')	# enable (1) or disable (0) output monitoring lines showing processing stats | ||||
| output_load_stats=$(uci -q get sqm.${INTERFACE}.output_load_stats || echo '0')			# enable (1) or disable (0) output monitoring lines showing achieved loads | ||||
| output_reflector_stats=$(uci -q get sqm.${INTERFACE}.output_reflector_stats || echo '0')	# enable (1) or disable (0) output monitoring lines showing reflector stats | ||||
| output_cake_changes=$(uci -q get sqm.${INTERFACE}.output_cake_changes || echo '0')		# enable (1) or disable (0) output monitoring lines showing cake bandwidth changes | ||||
| debug=$(uci -q get sqm.${INTERFACE}.debug || echo '0')						# enable (1) or disable (0) out of debug lines | ||||
| 
 | ||||
| # This can generate a LOT of records so be careful: | ||||
| log_DEBUG_messages_to_syslog=0	# enable (1) or disable (0) logging of all DEBUG records into the system log.  | ||||
| 
 | ||||
| # ** Take care with these settings to ensure you won't run into OOM issues on your router *** | ||||
| # every write the cumulative write time and bytes associated with each log line are checked | ||||
| # and if either exceeds the configured values below, the log log file is rotated | ||||
| log_to_file=1              # enable (1) or disable (0) output logging to file (/tmp/cake-autorate.log) | ||||
| log_file_max_time_mins=10  # maximum time between log file rotations | ||||
| log_file_max_size_KB=2000  # maximum KB (i.e. bytes/1024) worth of log lines between log file rotations | ||||
| 
 | ||||
| # log file path defaults to /var/log/ | ||||
| # or, if set below, then ${log_file_path_override} | ||||
| log_file_path_override="" | ||||
| 
 | ||||
| # *** STANDARD CONFIGURATION OPTIONS *** | ||||
| 
 | ||||
| ### For multihomed setups, it is the responsibility of the user to ensure that the probes  | ||||
| ### sent by this instance of cake-autorate actually travel through these interfaces. | ||||
| ### See ping_extra_args and ping_prefix_string | ||||
| 
 | ||||
| dl_if=ifb4$(uci -q get sqm.${INTERFACE}.interface)	# download interface | ||||
| ul_if=$(uci -q get sqm.${INTERFACE}.interface)		# upload interface | ||||
| 
 | ||||
| # pinger selection can be any of: | ||||
| # fping - round robin pinging (rtts) | ||||
| # ping - (iputils-ping) individual pinging (rtts) | ||||
| # hping3 - individidual pinging (owds) | ||||
| pinger_binary=ping | ||||
| 
 | ||||
| # list of reflectors to use and number of pingers to initiate | ||||
| # pingers will be initiated with reflectors in the order specified in the list  | ||||
| # additional reflectors will be used to replace any reflectors that go stale | ||||
| # so e.g. if 6 reflectors are specified and the number of pingers is set to 4, the first 4 reflectors will be used initially | ||||
| # and the remaining 2 reflectors in the list will be used in the event any of the first 4 go bad | ||||
| # a bad reflector will go to the back of the queue on reflector rotation | ||||
| reflectors=($(uci -q get omr-tracker.defaults.hosts)) | ||||
| #reflectors=( | ||||
| #"1.1.1.1" "1.0.0.1"  # Cloudflare | ||||
| #"8.8.8.8" "8.8.4.4"  # Google | ||||
| #"9.9.9.9" "9.9.9.10" "9.9.9.11" # Quad9 | ||||
| #"94.140.14.15" "94.140.14.140" "94.140.14.141" "94.140.15.15" "94.140.15.16" # AdGuard | ||||
| #"64.6.65.6" "156.154.70.1" "156.154.70.2" "156.154.70.3" "156.154.70.4" "156.154.70.5" "156.154.71.1" "156.154.71.2" "156.154.71.3" "156.154.71.4" "156.154.71.5" # Neustar | ||||
| #"208.67.220.2" "208.67.220.123" "208.67.220.220" "208.67.222.2" "208.67.222.123" # OpenDNS | ||||
| #"185.228.168.9" "185.228.168.10" # CleanBrowsing | ||||
| #) | ||||
| 
 | ||||
| randomize_reflectors=1 # enable (1) or disable (0) randomization of reflectors on startup | ||||
| 
 | ||||
| # Think carefully about the following settings | ||||
| # to avoid excessive CPU use (proportional with ping interval / number of pingers) | ||||
| # and to avoid abusive network activity (excessive ICMP frequency to one reflector) | ||||
| # The author has found an ICMP rate of 1/(0.2/4) = 20 Hz to give satisfactory performance on 4G | ||||
| no_pingers=$(uci -q get sqm.${INTERFACE}.no_pingers || echo "6")					# number of pingers to maintain | ||||
| reflector_ping_interval_s=$(uci -q get sqm.${INTERFACE}.reflector_ping_interval_s || echo "0.3")	# (seconds, e.g. 0.2s or 2s) | ||||
| 
 | ||||
| # delay threshold in ms is the extent of OWD increase to classify as a delay | ||||
| # these are automatically adjusted based on maximum on the wire packet size | ||||
| # (adjustment significant at sub 12Mbit/s rates, else negligible)   | ||||
| dl_delay_thr_ms=$(uci -q get sqm.${INTERFACE}.delay_thr_ms || echo "30") # (milliseconds) | ||||
| ul_delay_thr_ms=$(uci -q get sqm.${INTERFACE}.delay_thr_ms || echo "30") # (milliseconds) | ||||
| 
 | ||||
| # Set either of the below to 0 to adjust one direction only  | ||||
| # or alternatively set both to 0 to simply use cake-autorate to monitor a connection | ||||
| adjust_dl_shaper_rate=1 # enable (1) or disable (0) actually changing the dl shaper rate | ||||
| adjust_ul_shaper_rate=1 # enable (1) or disable (0) actually changing the ul shaper rate | ||||
| 
 | ||||
| min_dl_shaper_rate_kbps=$(uci -q get sqm.${INTERFACE}.min_download || echo "5000")	# minimum bandwidth for download (Kbit/s) | ||||
| base_dl_shaper_rate_kbps=$(uci -q get sqm.${INTERFACE}.download || echo "40000")	# steady state bandwidth for download (Kbit/s) | ||||
| max_dl_shaper_rate_kbps=$(uci -q get sqm.${INTERFACE}.max_download || echo "80000")	# maximum bandwidth for download (Kbit/s) | ||||
| 
 | ||||
| min_ul_shaper_rate_kbps=$(uci -q get sqm.${INTERFACE}.min_upload || echo "5000")	# minimum bandwidth for upload (Kbit/s) | ||||
| base_ul_shaper_rate_kbps=$(uci -q get sqm.${INTERFACE}.upload || echo "20000")		# steady state bandwidth for upload (KBit/s) | ||||
| max_ul_shaper_rate_kbps=$(uci -q get sqm.${INTERFACE}.max_upload || echo "35000")	# maximum bandwidth for upload (Kbit/s) | ||||
| 
 | ||||
| # sleep functionality saves unecessary pings and CPU cycles by | ||||
| # pausing all active pingers when connection is not in active use | ||||
| enable_sleep_function=$(uci -q get sqm.${INTERFACE}.enable_sleep_functions || echo "1")			# enable (1) or disable (0) sleep functonality  | ||||
| connection_active_thr_kbps=$(uci -q get sqm.${INTERFACE}.connection_active_thr_kpbs || echo "1000")	# threshold in Kbit/s below which dl/ul is considered idle | ||||
| sustained_idle_sleep_thr_s=$(uci -q get sqm.${INTERFACE}.sustained_idle_sleep_thr || echo "60.0")	# time threshold to put pingers to sleep on sustained dl/ul achieved rate < idle_thr (seconds) | ||||
| 
 | ||||
| min_shaper_rates_enforcement=$(uci -q get sqm.${INTERFACE}.min_shaper_rates_enforcement || echo "0")	# enable (1) or disable (0) dropping down to minimum shaper rates on connection idle or stall | ||||
| 
 | ||||
| startup_wait_s=$(uci -q get sqm.${INTERFACE}.startup_wait_s || echo "60.0")	# number of seconds to wait on startup (e.g. to wait for things to settle on router reboot) | ||||
| 
 | ||||
| # *** ADVANCED CONFIGURATION OPTIONS *** | ||||
| 
 | ||||
| log_file_export_compress=1 # compress log file exports using gzip and append .gz to export filename | ||||
| 
 | ||||
| ### In multi-homed setups, it is mandatory to use either ping_extra_args | ||||
| ### or ping_prefix_string to direct the pings through $dl_if and $ul_if. | ||||
| ### No universal recommendation exists, because there are multiple | ||||
| ### policy-routing packages available (e.g. vpn-policy-routing and mwan3). | ||||
| ### Typically they either react to a firewall mark set on the pings, or | ||||
| ### provide a convenient wrapper. | ||||
| ### | ||||
| ### In a traditional single-homed setup, there is usually no need for these parameters. | ||||
| ### | ||||
| ### These arguments can also be used for any other purpose - e.g. for setting a | ||||
| ### particular QoS mark. | ||||
| 
 | ||||
| # extra arguments for ping or fping | ||||
| # e.g., here is how you can set the correct outgoing interface and | ||||
| # the firewall mark for ping: | ||||
| # ping_extra_args="-I wwan0 -m $((0x300))" | ||||
| # Unfortunately, fping does not offer a command line switch to set | ||||
| # the firewall mark. | ||||
| # WARNING: no error checking so use at own risk! | ||||
| ping_extra_args="- B -I ${INTERFACE}" | ||||
| 
 | ||||
| # a wrapper for ping binary - used as a prefix for the real command | ||||
| # e.g., when using mwan3, it is recommended to set it like this: | ||||
| # ping_prefix_string="mwan3 use gpon exec" | ||||
| # WARNING: the wrapper must exec ping as the final step, not run it as a subprocess. | ||||
| # Running ping or fping as a subprocess will lead to problems stopping it. | ||||
| # WARNING: no error checking - so use at own risk! | ||||
| ping_prefix_string="" | ||||
| # interval in ms for monitoring achieved rx/tx rates | ||||
| # this is automatically adjusted based on maximum on the wire packet size | ||||
| # (adjustment significant at sub 12Mbit/s rates, else negligible)   | ||||
| monitor_achieved_rates_interval_ms=200 # (milliseconds)  | ||||
| 
 | ||||
| # bufferbloat is detected when (bufferbloat_detection_thr) samples | ||||
| # out of the last (bufferbloat detection window) samples are delayed | ||||
| bufferbloat_detection_window=6   # number of samples to retain in detection window | ||||
| bufferbloat_detection_thr=3      # number of delayed samples for bufferbloat detection | ||||
| 
 | ||||
| # OWD baseline against which to measure delays | ||||
| # the idea is that the baseline is allowed to increase slowly to allow for path changes | ||||
| # and slowly enough such that bufferbloat will be corrected well before the baseline increases, | ||||
| # but it will decrease very rapidly to ensure delays are measured against the shortest path | ||||
| alpha_baseline_increase=0.001  # how rapidly baseline RTT is allowed to increase | ||||
| alpha_baseline_decrease=0.9  # how rapidly baseline RTT is allowed to decrease | ||||
| 
 | ||||
| # OWD delta from baseline is tracked using ewma with alpha set below | ||||
| alpha_delta_ewma=0.095 | ||||
| 
 | ||||
| # rate adjustment parameters  | ||||
| # bufferbloat adjustment works with the lower of the adjusted achieved rate and adjusted shaper rate | ||||
| # to exploit that transfer rates during bufferbloat provide an indication of line capacity | ||||
| # otherwise shaper rate is adjusted up on load high, and down on load idle or low | ||||
| achieved_rate_adjust_down_bufferbloat=0.9 # how rapidly to reduce achieved rate upon detection of bufferbloat  | ||||
| shaper_rate_adjust_down_bufferbloat=0.9   # how rapidly to reduce shaper rate upon detection of bufferbloat  | ||||
| shaper_rate_adjust_up_load_high=1.01      # how rapidly to increase shaper rate upon high load detected  | ||||
| shaper_rate_adjust_down_load_low=0.99     # how rapidly to return down to base shaper rate upon idle or low load detected  | ||||
| shaper_rate_adjust_up_load_low=1.01       # how rapidly to return up to base shaper rate upon idle or low load detected  | ||||
| 
 | ||||
| # the load is categoried as low if < high_load_thr and high if > high_load_thr relative to the current shaper rate | ||||
| high_load_thr=0.75   # % of currently set bandwidth for detecting high load | ||||
| 
 | ||||
| # refractory periods between successive bufferbloat/decay rate changes | ||||
| # the bufferbloat refractory period should be greater than the  | ||||
| # average time it would take to replace the bufferbloat | ||||
| # detection window with new samples upon a bufferbloat event | ||||
| bufferbloat_refractory_period_ms=300 # (milliseconds) | ||||
| decay_refractory_period_ms=1000 # (milliseconds) | ||||
| 
 | ||||
| # interval for checking reflector health | ||||
| reflector_health_check_interval_s=1.0 # (seconds) | ||||
| # deadline for reflector response not to be classified as an offence against reflector | ||||
| reflector_response_deadline_s=1.0 # (seconds) | ||||
| 
 | ||||
| # reflector misbehaving is detected when $reflector_misbehaving_detection_thr samples | ||||
| # out of the last (reflector misbehaving detection window) samples are offences | ||||
| # thus with a 1s interval, window 60 and detection_thr 3, this is tantamount to | ||||
| # 3 offences within the last 60s  | ||||
| reflector_misbehaving_detection_window=60 | ||||
| reflector_misbehaving_detection_thr=3 | ||||
| 
 | ||||
| reflector_replacement_interval_mins=60 # how often to replace a random reflector from the present list | ||||
| 
 | ||||
| reflector_comparison_interval_mins=1       # how often to compare reflectors  | ||||
| reflector_owd_baseline_delta_thr_ms=10     # max increase from min baseline before reflector rotated | ||||
| reflector_owd_delta_ewma_delta_thr_ms=10   # mac increase from min delta ewma before reflector rotated | ||||
| 
 | ||||
| # stall is detected when the following two conditions are met: | ||||
| # 1) no reflector responses within $stall_detection_thr*$ping_response_interval_us; and | ||||
| # 2) either $rx_achieved_rate or $tx_achieved_rate < $connection_stall_thr | ||||
| stall_detection_thr=5 | ||||
| connection_stall_thr_kbps=10 | ||||
| 
 | ||||
| global_ping_response_timeout_s=10.0 # timeout to set shaper rates to min on no ping response whatsoever (seconds) | ||||
| 
 | ||||
| if_up_check_interval_s=10.0 # time to wait before re-checking if rx/tx bytes files exist (e.g. from boot state or sleep recovery) | ||||
| 
 | ||||
| # Starlink satellite switch (sss) compensation options | ||||
| sss_compensation=$(uci -q get sqm.${INTERFACE}.sss_compensation || echo "0")	# enable (1) or disable (0) Starlink handling | ||||
| # satellite switch compensation start times in seconds of each minute | ||||
| sss_times_s=("12.0" "27.0" "42.0" "57.0") | ||||
| sss_compensation_pre_duration_ms=300 | ||||
| sss_compensation_post_duration_ms=200 | ||||
| 
 | ||||
| config_file_check="cake-autorate" | ||||
							
								
								
									
										32
									
								
								luci-app-sqm-autorate/root/usr/share/sqm-autorate/config.sh
									
										
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										32
									
								
								luci-app-sqm-autorate/root/usr/share/sqm-autorate/config.sh
									
										
									
									
									
										
										
										Normal file → Executable file
									
								
							|  | @ -19,7 +19,8 @@ output_processing_stats=$(uci -q get sqm.${INTERFACE}.output_processing_stats || | |||
| #output_cake_changes=0     # enable (1) or disable (0) output monitoring lines showing cake bandwidth changes | ||||
| output_cake_changes=$(uci -q get sqm.${INTERFACE}.output_cake_changes || echo "0") | ||||
| #debug=0			  # enable (1) or disable (0) out of debug lines | ||||
| debug=$(uci -q get sqm.common.debug || echo "0") | ||||
| #debug=$(uci -q get sqm.common.debug || echo "0") | ||||
| debug=1 | ||||
| 
 | ||||
| # *** STANDARD CONFIGURATION OPTIONS *** | ||||
| 
 | ||||
|  | @ -128,32 +129,3 @@ global_ping_response_timeout_s=10 # timeout to set shaper rates to min on no pin | |||
| 
 | ||||
| if_up_check_interval_s=10 # time to wait before re-checking if rx/tx bytes files exist (e.g. from boot state) | ||||
| 
 | ||||
| # verify these are correct using 'cat /sys/class/...' | ||||
| case "${dl_if}" in | ||||
|     \veth*) | ||||
|         rx_bytes_path="/sys/class/net/${dl_if}/statistics/tx_bytes" | ||||
|         ;; | ||||
|     \ifb*) | ||||
|         rx_bytes_path="/sys/class/net/${dl_if}/statistics/tx_bytes" | ||||
|         ;; | ||||
|     *) | ||||
|         rx_bytes_path="/sys/class/net/${dl_if}/statistics/rx_bytes" | ||||
|         ;; | ||||
| esac | ||||
| 
 | ||||
| case "${ul_if}" in | ||||
|     \veth*) | ||||
|         tx_bytes_path="/sys/class/net/${ul_if}/statistics/rx_bytes" | ||||
|         ;; | ||||
|     \ifb*) | ||||
|         tx_bytes_path="/sys/class/net/${ul_if}/statistics/rx_bytes" | ||||
|         ;; | ||||
|     *) | ||||
|         tx_bytes_path="/sys/class/net/${ul_if}/statistics/tx_bytes" | ||||
|         ;; | ||||
| esac | ||||
| 
 | ||||
| if (( $debug )) ; then | ||||
|     echo "DEBUG: rx_bytes_path: $rx_bytes_path" | ||||
|     echo "DEBUG: tx_bytes_path: $tx_bytes_path" | ||||
| fi | ||||
|  |  | |||
|  | @ -1010,6 +1010,7 @@ if [ "$OMR_TRACKER_INTERFACE" = "glorytun" ] || [ "$OMR_TRACKER_INTERFACE" = "om | |||
| 		uci -q set openmptcprouter.$OMR_TRACKER_INTERFACE.latency="$OMR_TRACKER_LATENCY" | ||||
| 		#if [ "$(uci -q get glorytun.vpn.enable)" != "1" ] || [ "$(uci -q get glorytun-udp.vpn.enable)" != "1" ]; then | ||||
| 			OMR_NETWORK_DEVICE=$(find_network_device ${OMR_TRACKER_INTERFACE}) | ||||
| 			#_log "OMR_NETWORK_DEVICE: $OMR_NETWORK_DEVICE for $OMR_TRACKER_DEVICE - $OMR_TRACKER_INTERFACE" | ||||
| 			if [ -n "$OMR_NETWORK_DEVICE" ] && [ -n "$(uci -q get network.$OMR_NETWORK_DEVICE.mtu)" ] && [ -n "$OMR_TRACKER_DEVICE" ]; then | ||||
| 				mtu=$(uci -q get network.$OMR_NETWORK_DEVICE.mtu) | ||||
| 				uci -q set openmptcprouter.${OMR_TRACKER_INTERFACE}.mtu=$mtu | ||||
|  | @ -1751,7 +1752,7 @@ if [ "$(pgrep -f openmptcprouter-vps)" = "" ] && ([ "$(uci -q show openmptcprout | |||
| 	sleep 5 | ||||
| fi | ||||
| 
 | ||||
| if [ "$(uci -q get sqm.${OMR_TRACKER_INTERFACE}.enabled)" = "1" ] && [ "$(uci -q get sqm.${OMR_TRACKER_INTERFACE}.autorate)" = "1" ] && [ -z $(pgrep -f "autorate.sh ${OMR_TRACKER_INTERFACE}") ]; then | ||||
| if [ "$(uci -q get sqm.${OMR_TRACKER_INTERFACE}.enabled)" = "1" ] && [ "$(uci -q get sqm.${OMR_TRACKER_INTERFACE}.autorate)" = "1" ] && [ -n "$OMR_TRACKER_DEVICE" ] && [ -z $(pgrep -f "autorate.*${OMR_TRACKER_DEVICE}") ]; then | ||||
| 	/etc/init.d/sqm-autorate restart >/dev/null 2>&1 | ||||
| 	sleep 5 | ||||
| fi | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue