#!/bin/sh
#
# $Id$
#
# multi-ethtool
#
# chkconfig: - 95 99
# description:	pS-Performance Toolkit script to configure the NIC parameters based on enabled services
# 
# see:
# http://code.google.com/p/perfsonar-ps/issues/detail?id=122
# https://bugzilla.redhat.com/show_bug.cgi?id=179877
#
#

# Source function library.
. /etc/init.d/functions

LATENCY_ENABLED=
BANDWIDTH_ENABLED=
NDTNPAD_ENABLED=

ENABLED_SERVICES=`/opt/perfsonar_ps/toolkit/scripts/get_enabled_services`;
for service in $ENABLED_SERVICES; do
        if [ "$service" == "ndt" -o "$service" == "npad" ]; then
                NDTNPAD_ENABLED=1
        elif [ "$service" == "owamp" -o "$service" == "pinger" ]; then
                LATENCY_ENABLED=1
        elif [ "$service" == "bwctl" ]; then
                BANDWIDTH_ENABLED=1
        fi
done

# XXX: should make these configurable via configuration file

TCP_CONGESTION_CONTROL=
DISABLE_TCP_OFFLOAD=
DISABLE_INTERRUPT_COALESCING=
TXQUEUELEN=

echo "NDTNPAD_ENABLED: $NDTNPAD_ENABLED"
echo "LATENCY_ENABLED: $LATENCY_ENABLED"
echo "BANDWIDTH_ENABLED: $BANDWIDTH_ENABLED"

if [ "$NDTNPAD_ENABLED" ]; then
    TCP_CONGESTION_CONTROL=reno
else
    TCP_CONGESTION_CONTROL=htcp
fi

if [ "$LATENCY_ENABLED" -o "$NDTNPAD_ENABLED" ]; then
    DISABLE_TCP_OFFLOAD=1
    DISABLE_INTERRUPT_COALESCING=1
fi

if [ "$BANDWIDTH_ENABLED" ]; then
    TXQUEUELEN=10000
fi

# find all the interfaces besides loopback.
# ignore aliases, alternative configurations, and editor backup files
interfaces=$(ls /etc/sysconfig/network-scripts/ifcfg* | \
            LANG=C sed -e "$__sed_discard_ignored_files" \
                       -e '/\(ifcfg-lo\|:\|ifcfg-.*-range\)/d' \
                       -e '/ifcfg-[A-Za-z0-9\._-]\+$/ { s/^ifcfg-//g;s/[0-9]/ &/}' | \
            LANG=C sort -k 1,1 -k 2n | \
            LANG=C sed 's/ //' | \
            LANG=C cut -d/ -f 5 | \
        LANG=C sed -e 's/ifcfg-//g' )

start() {
ret=0

# Do not save and apply if we've already run
for interface in $interfaces; do
    /sbin/ifconfig $interface > /dev/null 2>&1
    if [ $? -ne 0 ]; then
        continue;
    fi

    if [ $DISABLE_INTERRUPT_COALESCING ]; then
        # test if this interface supports IC adjustments
        /sbin/ethtool -c $interface > /dev/null 2>&1
        RETVAL=$?
        if [ $RETVAL -eq 0 ]; then
            # apply multi-ethtool settings
            echo -n $"disabling interrupt coalescing for interface $interface: "
            IC_OFF $interface
            if [ $? -eq 0 ]; then
                success; echo
            else
                failure; echo; ret=1
            fi
        fi
    fi

    if [ $DISABLE_TCP_OFFLOAD ]; then
        echo -n $"disabling TCP offload for interface $interface: "
        TSO_OFF $interface
        if [ $? -eq 0 ]; then
            success; echo
        else
            failure; echo; ret=1
        fi
    fi

    if [ $TXQUEUELEN -ne 0 ]; then
        echo -n $"Setting txqueuelen for $interface to $TXQUEUELEN: "
        TXQUEUELEN_SET $interface $TXQUEUELEN
        if [ $? -eq 0 ]; then
            success; echo
        else
            failure; echo; ret=1
        fi
    fi
done

if [ -n "$TCP_CONGESTION_CONTROL" ]; then
    echo -n $"Setting TCP congestion control algorithm to $TCP_CONGESTION_CONTROL: "
    TCP_CONG_SET $TCP_CONGESTION_CONTROL
    if [ $? -eq 0 ]; then
        success; echo
    else
        failure; echo; ret=1
    fi
fi

return $ret
}

TXQUEUELEN_SET() {
/sbin/ifconfig $1 txqueuelen $2
}

TCP_CONG_SET() {
retval=0;
echo $1 > /proc/sys/net/ipv4/tcp_congestion_control
result=`cat /proc/sys/net/ipv4/tcp_congestion_control`;
if [ "$result" != "$1" ]; then
retval=1;
fi
return $retval;
}

IC_OFF() {
for i in "$1"; do
    /usr/sbin/ethtool -C $i rx-frames 1
    /usr/sbin/ethtool -C $i rx-usecs 0
done
}

TSO_ON() {
/usr/sbin/ethtool -K "$1" tso on
}

TSO_OFF() {
/usr/sbin/ethtool -K "$1" tso off
}


case "$1" in
    start)
        [ -f "$VAR_SUBSYS_TCP_TUNING" ] && exit 0
        start
        RETVAL=$?
        ;;
    *)
        echo $"Usage: $0 {start}"
        RETVAL=2
        ;;
esac

exit $RETVAL
