#!/usr/bin/sh
#
# $Id$
#
# multi-ethtool
#
# chkconfig: - 95 99
# description:	pS-Performance Toolkit script to configure the NIC parameters
# 
# 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

# always set these on perfsonar hosts
DISABLE_TCP_OFFLOAD=1
DISABLE_INTERRUPT_COALESCING=1
TXQUEUELEN=10000

# detect the location of ethtool binary
if [ -x /usr/sbin/ethtool ]; then
    ETHTOOL=/usr/sbin/ethtool
elif [ -x /sbin/ethtool ]; then
    ETHTOOL=/sbin/ethtool
fi

# try to load local configuration
if [ -f /etc/sysconfig/perfsonar-configure_nic_parameters ]; then
    . /etc/sysconfig/perfsonar-configure_nic_parameters
elif [ -f /etc/default/perfsonar-configure_nic_parameters ]; then
    . /etc/default/perfsonar-configure_nic_parameters
fi

# find all the interfaces besides loopback.
# ignore aliases, alternative configurations, and editor backup files
interfaces=$(/sbin/ip addr show | grep -v LOOPBACK | awk -F ':' '/^[0-9]+:.*state (UP|UNKNOWN).*/ { sub("@.*","",$2); sub(" ","",$2); print $2 }')

start() {
ret=0

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

    if [ $DISABLE_INTERRUPT_COALESCING ]; then
        # test if this interface supports IC adjustments
        $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
                # coalescing support is driver dependent so ignore errors here
                failure; echo
            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

return $ret
}

TXQUEUELEN_SET() {
/sbin/ip link set $1 txqueuelen $2
}

IC_OFF() {
IC_RET=0

# if not set in local configuration try to detect coalescing values
if [ "${RX_FRAMES-unset}" = "unset" ]; then
    DRIVER=$(ethtool -i $1 | sed -n 's/^driver: //p')
    case $DRIVER in
        igb)     RX_FRAMES=;  RX_USECS=1;;
        tg3)     RX_FRAMES=1; RX_USECS=1;;
        vmxnet3) RX_FRAMES=;  RX_USECS=;;
        *)       RX_FRAMES=1; RX_USECS=0;;
    esac
fi

if [ "$RX_FRAMES" ] && ! $ETHTOOL -c $1 | grep -q "^rx-frames: $RX_FRAMES\$"; then
    $ETHTOOL -C $1 rx-frames $RX_FRAMES || IC_RET=$?
fi

if [ "$RX_USECS" ] && ! $ETHTOOL -c $1 | grep -q "^rx-usecs: $RX_USECS\$"; then
    $ETHTOOL -C $1 rx-usecs $RX_USECS || IC_RET=$?
fi

return $IC_RET
}

TSO_ON() {
$ETHTOOL -K "$1" tso on
}

TSO_OFF() {
$ETHTOOL -K "$1" tso off
}


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

exit $RETVAL
