#!/bin/sh
# Copyright (C) 2009 Ubicom, Inc.

. /etc/rgw_config

if [ $# -ne 2 ] && [ $# -ne 5 ] ; then
echo "Usage: setup_shaper (<dynamic_frag> auto) || (<tx_rate_bps> <min_payload_bps> <tx_overhead_bits> <tx_cell_bits>)"
echo "   <dynamic_frag>: 1 to enable dynamic fragmentation, 0 to disable dynanic fragmentation"
echo "   With auto supplied the shaper will be configured from the last rate estimation run, when not supplied:"
echo "      <tx_rate_bps>: Rate in bits per seconds of the interface"
echo "      <min_payload_bps>: Minimum size of any packet that we will send out, padding will be applied if necessary"
echo "      <tx_overhead_bits>: Transmit overhead in bits imposed by the network"
echo "      <tx_cell_bits>: On frame relay networks this is the cell overhead in bits"
echo "      NOTE: When auto is specified, if the speed is > 2097152bps (2048Kbps) then shaping is DISABLED"
exit 1
fi

DYNAMIC_FRAG=$1

if [ $# = 5 ] ; then
	TX_RATE_BPS=$2
	MIN_PAYLOAD_BITS=$3
	TX_OVERHEAD_BITS=$4
	TX_CELL_BITS=$5
else
	if [ $2 != "auto" ] ; then
		echo "Unknown command $2"
		exit 2
	fi

	MIN_PAYLOAD_BITS=0

	#
	# Take configuration from rate estimation sysfs data points
	#
	TX_RATE_BPS=$(cat /sys/devices/system/ubicom_streamengine/ubicom_streamengine0/ubicom_streamengine_calculated_rate)

	#
	# Set the per-packet transmit overhead.  This is the overhead of bit-times per
	# packet that we don't see at the point of sending the data through the QoS
	# queue.
	# Note that by the time a packet hits the QoS queue it already has an
	# Ethernet header so we remove that from the calculation here.
	#
	TX_OVERHEAD_BITS=`expr $(cat /sys/devices/system/ubicom_streamengine/ubicom_streamengine0/ubicom_streamengine_protocol_overhead) - 112`

	#
	# If frame relay then switch on cell handling in the QoS queue.
	#
	if [ $(cat /sys/devices/system/ubicom_streamengine/ubicom_streamengine0/ubicom_streamengine_frame_relay) = 0 ] ; then
		TX_CELL_BITS=0
	else
		TX_CELL_BITS=384
	fi
fi

echo Setting shaper on $WAN_MODE_INTERFACE, Rate $TX_RATE_BPS, Min payload $MIN_PAYLOAD_BITS, Overhead $TX_OVERHEAD_BITS, Cell bits $TX_CELL_BITS

echo $TX_RATE_BPS > /sys/devices/system/ubicom_streamengine/ubicom_streamengine0/ubicom_streamengine_tx_rate
echo $MIN_PAYLOAD_BITS > /sys/devices/system/ubicom_streamengine/ubicom_streamengine0/ubicom_streamengine_min_payload_bits
echo $TX_OVERHEAD_BITS > /sys/devices/system/ubicom_streamengine/ubicom_streamengine0/ubicom_streamengine_tx_overhead_bits
echo $TX_CELL_BITS > /sys/devices/system/ubicom_streamengine/ubicom_streamengine0/ubicom_streamengine_tx_cell_bits

#
# What is the default MTU for our internet connection type?
# Note that we use WAN_MODE_INTERFACE rather than WANINTERFACE as we want the MTU of any carrying interface e.g. ppp0.
#
DEFAULT_MTU=`ifconfig $WAN_MODE_INTERFACE | grep 'MTU' | cut -f2 -d':' | cut -f1 -d' '`

#
# Prep by removing the DYNFRAG chain from the prerouting chain in the mangle table
# NOTE: Redirect output to null beause we may not have these rules and we don't want to generate errors
#
iptables -t mangle -D PREROUTING -g DYNFRAG > /dev/null 2> /dev/null

#
# Now flush and destroy the DYNFRAG table
#
iptables -t mangle -F DYNFRAG > /dev/null 2> /dev/null
iptables -t mangle -X DYNFRAG > /dev/null 2> /dev/null

#
# Set up dynamic fragmentaion if required
#
if [ $DYNAMIC_FRAG != 1 ] ; then
	echo "Dynamic fragmentation: $WAN_MODE_INTERFACE DISABLED"
	exit 0
fi

#
# Set up dynamic fragmentation.
# Compute the MTU such that the largest datagram will consume a bandwidth of no more than 20ms for upstream TCP packets
#
FRAG_SIZE=`expr \( \( $TX_RATE_BPS \* 20 \) / 8 \) / 1000`
if [ $TX_RATE_BPS = 0 ] ; then
	FRAG_SIZE=$DEFAULT_MTU
fi

#
# Fragment size should be a multiple of 8 bytes
#
QOS_FRAG_SIZE=`expr \( \( $FRAG_SIZE + 7 \) / 8 \) \* 8`

#
# Keep the fragment size within 576 to default mtu
#
if [ $QOS_FRAG_SIZE -lt 576 ] ; then
	QOS_FRAG_SIZE=576
elif [ $QOS_FRAG_SIZE -gt $DEFAULT_MTU ] ; then
	QOS_FRAG_SIZE=$DEFAULT_MTU
fi

#
# Get our WAN IP Address for creating the MSS rule.
#
WANIPADDRESS=`ifconfig $WAN_MODE_INTERFACE | grep 'inet addr' | cut -f2 -d':' | cut -f1 -d' '`

#
# Create a chain in the mangle table that will allow us to clamp MSS for upstream TCP packets
# We create a seperate chain called DYNFRAG because this makes it easier to craft a rule
# to remove DYNFRAG from mangle PREROUTING without affecting other rules in there.
#
echo "Dynamic fragmentation: $WAN_MODE_INTERFACE ($WANIPADDRESS) ENABLED, Set to $QOS_FRAG_SIZE (MTU is $DEFAULT_MTU)"
iptables -t mangle -N DYNFRAG
iptables -t mangle -A DYNFRAG -d $WANIPADDRESS -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss $QOS_FRAG_SIZE
iptables -t mangle -A PREROUTING -g DYNFRAG
iptables -t mangle -L DYNFRAG
iptables -t mangle -L PREROUTING

exit 0

