#!/bin/bash # # **** License **** # Version: VPL 1.0 # # The contents of this file are subject to the Vyatta Public License # Version 1.0 ("License"); you may not use this file except in # compliance with the License. You may obtain a copy of the License at # http://www.vyatta.com/vpl # # Software distributed under the License is distributed on an "AS IS" # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See # the License for the specific language governing rights and limitations # under the License. # # This code was originally developed by Vyatta, Inc. # Portions created by Vyatta are Copyright (C) 2008 Vyatta, Inc. # All Rights Reserved. # # Author: Robert E. Gilligan # Date: 2008 # Description: # # **** End License **** # # 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 # # 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