#!/bin/bash
#
# Detect incoming UDP bandwidth and tune traffic shaping to reserve adeguate
# minimum guaranteed bandwidth.
#

LOG_FACILITY="local6"


# Traffic shaper script
TC=/usr/local/sbin/traffic-shaping.sh

# Bandwidth change detection range (+/-).  Detected maximum bandwidth has to
# change over this range to be accepted
range=30

# Time interval in seconds for bandwidth sampling
interval=2

# Verbose logging
verbose=1

# UDP bandwidth sampling
bytes=0       # bytes received per $interval period
bwidth=0      # calculated bandwidth

# Last 10 bandwidth samples
samples=(0 0 0 0 0 0 0 0 0 0)
curr_sample=0

# Keep track of previous max bandwidth value to do peak sustaining
prevmax=0
prevbw=0


while [ 1 ]; do
	# FIXME: best iptables grepping
	prev=$bytes

	# Add incoming UDP rule in iptables config
	IPTABLES_OUTPUT=`iptables -t mangle -L -xnv | grep -E 'udp.*eth0 *\* *0\.0\.0\.0/0.* +0\.0\.0\.0/0 *udp $'`
	if [ $? -ne 0 ]; then
		logger -p $LOG_FACILITY.notice -t $0 "Adding missing iptables rule"
		iptables -t mangle -A PREROUTING -i eth0 -p udp -m udp
	else
		bytes=`echo $IPTABLES_OUTPUT | awk '{ print $2 }'`
	fi

	[ $prev -ne 0 ] && bwidth=$(( (($bytes-$prev)/$interval)*8/1024 ))

	samples[$curr_sample]=$bwidth
	curr_sample=$(( ($curr_sample + 1) % 10 ))

	max=0
	for i in ${samples[*]}; do
		[ $i -gt $max ] && max=$i
	done

	if [ $max -gt $(( $prevmax+$range )) ] || [ $max -lt $(( $prevmax-$range )) ] || [ $prevmax -eq 0 ]; then
		new_bwidth=$(( $max+$range+150 ))
		if [ "$new_bwidth" -ne "$prevbw" ]; then
			if [ "$verbose" = 1 ]; then
				logger -p $LOG_FACILITY.info -t $0 "Changing minimum UDP bandwidth to $new_bwidth kbit"
			fi
			$TC tune_ingress $new_bwidth
			prevmax=$max
			prevbw=$new_bwidth
		fi
	fi

	# debug
	# echo ${samples[*]}
	# echo "bwidth: $bwidth, max $max"

	sleep $interval
done

