#!/bin/bash # Author: Robert E. Gilligan # Date: 2008 # Description: CLI back-end script to manipulate NIC interrupt CPU affinity. # **** License **** # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # This code was originally developed by Vyatta, Inc. # Portions created by Vyatta are Copyright (C) 2006, 2007, 2008 Vyatta, Inc. # All Rights Reserved. # **** End License **** # 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 # # Max number of hex characters in an IRQ affinity mask. Support up to 16 CPUs. MAX_MASK=4 # Set up some global values... numcpus=`grep -c -e "^processor" /proc/cpuinfo` declare -i maxmask=(2**numcpus) let maxmask=maxmask-1 maxmaskhex=`printf "%x" ${maxmask}` print_usage() { echo "Usage:" echo -e "\t$0 check " echo -e "\t$0 set " echo -e "\t$0 reset " echo -e "\t$0 print " } get_irqnum() { irqnum=`cat /sys/class/net/$1/device/irq` 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-fA-F]//g` # if anything is left, its not hex if [ ! -z "$exmask" ]; then echo "Invalid characters in hex mask: $exmask" return 1 fi declare -i intmask=0x${mask} # Make sure that mask holds at least one bit, and holds no more bits # than we have CPUs. if [ ${intmask} -eq 0 ]; then echo "Mask can not be 0." return 1 fi if [ $intmask -gt $maxmask ]; then echo "Mask is too large. Maximum hexidecimal bitmask is: ${maxmaskhex}" return 1 fi return 0 } # # Don't waste our time with uniprocessor machines # check_uniproc() { if [ $maxmask -eq 1 ]; then echo "This machine has only 1 CPU." echo "Can only set SMP affinity on multi-processor machines" return 1; fi return 0 } case "$1" in check) if [ $# -ne 3 ]; then print_usage exit 1 fi if ! check_uniproc ; then 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 ! check_uniproc ; then 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 $maxmaskhex > /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