#!/bin/bash
#
# CLI back-end script to manipulate NIC interrupt CPU affinity.
#
# Provides sub-commands to:
#   - Check the validity of an interface name and affinity mask value
#   - Set the affinity mask to the IRQ being used by an interface
#   - Reset the affinity mask of the IRQ being used by an interface to the
#     system default value of all-ones.
#   - Print the affinity mask of the IRQ being used by an interface
#

# The default "all-ones" IRQ affinity mask.  Used in the "reset" sub-command.
DEFAULT_MASK=ffff

# Max number of hex characters in an IRQ affinity mask.  Support up to 16 CPUs.
MAX_MASK=4

print_usage()
{
    echo "Usage:"
    echo -e "\t$0 check <ifname> <mask>"
    echo -e "\t$0 set <ifname> <mask>"
    echo -e "\t$0 reset <ifname>"
    echo -e "\t$0 print <ifname>"
}

get_irqnum()
{
    irqnum=`find /proc/irq -name $1 -print | awk -F / '{ print $4 }'`
    if [ -z "$irqnum" ]; then
	echo "Invalid interface name: $1"
	return 1
    fi
    return 0
}


get_mask()
{
    mask=$1
    # mask must be a short hex value
    if [ ${#mask} -gt $MAX_MASK ]; then
	echo "mask too long: ${#2} characters."
	return 1
    fi

    # strip out all the hex digits
    exmask=`echo $mask | sed -e s/[0-9a-f]//g`

    # if anything is left, its not hex
    if [ ! -z "$exmask" ]; then
	echo "Invalid characters in hex mask: $exmask"
	return 1
    fi
    return 0
}

case "$1" in
    check)
	if [ $# -ne 3 ]; then
		print_usage
		exit 1
	fi

	if ! get_irqnum $2 ; then
	    exit 1
	fi

	if ! get_mask $3 ; then
	    exit 1
	fi
	exit 0
	;;

    set)
	if [ $# -ne 3 ]; then
		print_usage
		exit 1
	fi
	if ! get_irqnum $2 ; then
	    exit 1
	fi

	if ! get_mask $3 ; then
	    exit 1
	fi

	echo $mask > /proc/irq/$irqnum/smp_affinity

	if [ $? -ne 0 ]; then
	    echo "Couldn't assign smp_affinity.  Exit status: $?"
	    exit 1
	fi
	;;

    reset)
	if [ $# -ne 2 ]; then
		print_usage
		exit 1
	fi
	if ! get_irqnum $2 ; then
	    exit 1
	fi

	echo $DEFAULT_MASK > /proc/irq/$irqnum/smp_affinity
	if [ $? -ne 0 ]; then
	    echo "Couldn't assign smp_affinity.  Exit status: $?"
	    exit 1
	fi
	;;
     

    print)
	if [ $# -ne 2 ]; then
		print_usage
		exit 1
	fi
	if ! get_irqnum $2 ; then
	    exit 1
	fi

	mask=`cat /proc/irq/$irqnum/smp_affinity`
	
	if [ -z $mask ]; then
	    echo "Couldn't get smp_affinity for interface $2, irq $irqnum"
	    exit 1
	fi

	echo "Interface $2 is using IRQ: $irqnum"
	echo "SMP affinity mask for IRQ $irqnum is: $mask"
	;;

    *)
	print_usage
	exit 1
	;;
	
esac