1. 程式人生 > >網絡卡軟中斷繫結–網絡卡中斷親和力

網絡卡軟中斷繫結–網絡卡中斷親和力

在這裡先解釋下啥是中斷親和力

中斷親和力是指將一個或多箇中斷源繫結到特定的 CPU 上執行

具體如何操作我這裡就不說了,網路上一大片一大片的.我今天這篇文件是用來吐槽的..具體操作請見連結

這個連結的文章已經說的很清楚了在操作方面, 只要看過這個,跟著做一邊 就知道怎麼去操作了,

我這裡要吐槽的是這個文章的指令碼

# setting up irq affinity according to /proc/interrupts
# 2008-11-25 Robert Olsson
# 2009-02-19 updated by Jesse Brandeburg
#
# > Dave Miller:
# (To get consistent naming in /proc/interrups) # I would suggest that people use something like: # char buf[IFNAMSIZ+6]; # # sprintf(buf, "%s-%s-%d", # netdev->name, # (RX_INTERRUPT ? "rx" : "tx"), # queue->index); # # Assuming a device with two RX and TX queues. # This script will assign:
# # eth0-rx-0 CPU0 # eth0-rx-1 CPU1 # eth0-tx-0 CPU0 # eth0-tx-1 CPU1 # set_affinity() { MASK=$((1<<$VEC)) printf "%s mask=%X for /proc/irq/%d/smp_affinity\n" $DEV $MASK $IRQ printf "%X" $MASK > /proc/irq/$IRQ/smp_affinity #echo $DEV mask=$MASK for /proc/irq/$IRQ/smp_affinity #echo $MASK > /proc/irq/$IRQ/smp_affinity
} if [ "$1" = "" ] ; then echo "Description:" echo " This script attempts to bind each queue of a multi-queue NIC" echo " to the same numbered core, ie tx0¦rx0 --> cpu0, tx1¦rx1 --> cpu1" echo "usage:" echo " $0 eth0 [eth1 eth2 eth3]" fi # check for irqbalance running IRQBALANCE_ON=`ps ax ¦ grep -v grep ¦ grep -q irqbalance; echo $?` if [ "$IRQBALANCE_ON" == "0" ] ; then echo " WARNING: irqbalance is running and will" echo " likely override this script's affinitization." echo " Please stop the irqbalance service and/or execute" echo " 'killall irqbalance'" fi # # Set up the desired devices. # for DEV in $* do for DIR in rx tx TxRx do MAX=`grep $DEV-$DIR /proc/interrupts ¦ wc -l` if [ "$MAX" == "0" ] ; then MAX=`egrep -i "$DEV:.*$DIR" /proc/interrupts ¦ wc -l` fi if [ "$MAX" == "0" ] ; then echo no $DIR vectors found on $DEV continue #exit 1 fi for VEC in `seq 0 1 $MAX` do IRQ=`cat /proc/interrupts ¦ grep -i $DEV-$DIR-$VEC"$" ¦ cut -d: -f1 ¦ sed "s/ //g"` if [ -n "$IRQ" ]; then set_affinity else IRQ=`cat /proc/interrupts ¦ egrep -i $DEV:v$VEC-$DIR"$" ¦ cut -d: -f1 ¦ sed "s/ //g"` if [ -n "$IRQ" ]; then set_affinity fi fi done done done

“ linux network子系統的負責人David Miller提供了一個指令碼 ”

據說這個是某個大牛寫的指令碼.. 看上去很好很強大,但是這裡有一個大坑, 非常大的坑.. 今天本人就被它坑到了…

它的坑在

MASK=$((1<<$VEC))

這個位置, 這裡是計算cpu掩碼的, 比如網絡卡eth0 第一個佇列eth0-0 那麼這裡的結果就是MASK=1 將0左移一位 得到2進位制0b10 十進位制1 ,

這樣看是很正常.. 因為根據網路上大片的文章顯示計算cpu掩碼 就是第幾個網絡卡佇列就位移幾為, 比如一個4核4佇列網絡卡, 第4佇列的cpu掩碼為 1<<3 等於8 反推回去可以得到前面三個佇列的cpu掩碼, 然後將這個cpu掩碼分別寫入每個佇列中斷號的smp_affinity.類似這樣

echo $((1<<3)) > /proc/irq/xx/smp_affinity 這樣就將xx中斷繫結到第4個cpu上,

這樣看還是很符合規律的,但是假設我們的cpu是8核, 網絡卡佇列也是8個呢..

根據$((1<<7))得到的cpu掩碼將是128 ,然後將128寫入xx中斷的smp_affinity中,觀察發現:尼瑪說好的繫結到第8個cpu上的呢.. 怎麼跑到第4個cpu上了?

33: 73905753 0 0 0 0 0 0 0 IR-PCI-MSI-edge eth0-4 
34: 0 5596608 0 0 0 0 0 0 IR-PCI-MSI-edge eth0-5 
35: 0 0 5590023 0 0 0 0 0 IR-PCI-MSI-edge eth0-6 
36: 0 0 0 5574803 0 0 0 0 IR-PCI-MSI-edge eth0-7

然後我又放狗..找到這麼一句話”計算cpu的方法第一顆為00000001換算成16進製為1,第2顆cpu為00000010換算成16進製為2,依次類推得出,第8顆cpu為80″

這裡有一個重點就是” 將2進位制轉換成16進位制 ” 看到這裡再看上面的指令碼,尼瑪這不是坑爹麼… $((1<<n)) 直接是將2進位制給轉成10進位制了哇.. 假如n = 0-3的話,還好. 結果還是正確的,但是一旦超過了3結果就開始偏差了..這樣就直接導致我8核cpu8佇列網絡卡,在繫結中斷的時候產生重疊…. 即佇列0-3繫結到cpu0-3,佇列4-7繫結到cpu0-3.. 坑爹呢….

看著上面的指令碼是某國外大牛所寫,自己也認為合情合理,直接用在自己伺服器上.. 結果卻有這麼一個大坑…

無奈自己重寫了一遍,用py寫的,shell的字元處理方面我用的實在不順手..

#!/usr/bin/python
#coding=utf8

import os,re

def irq():
    #return irq number and network interface number
    #exp:
    #irq iface
    #61  0
    #62  1
    cpunum = os.popen("cat /proc/cpuinfo¦grep \"model name\"¦wc -l").read().replace("\n","")
    r = os.popen("cat /proc/interrupts ¦grep -E \"eth[0-9]-\"¦awk '{sub(\"eth[0-9]-\",\"\",$%s);print $1,$%s}'"%(int(cpunum)+3,int(cpunum)+3)).readlines()
    return [ (i.split()[0].split(":")[0],re.sub("[a-zA-Z]", "",i.replace("\n","").split()[1])) for i in r ]

def main(irq_queuenum):

    # if exists irqbalance process,will killed"
    irqbalance = int(os.popen("ps axu¦grep irqbalance¦grep -v grep¦wc -l").read())
    if irqbalance > 0:os.popen("pkill irqbalance");print "irqbalance is kill"

    # set irq_affinity
    for i in irq_queuenum:
        set_irq_affinity(i[0],hex(1 << int(i[1])).replace('0x',''))

def set_irq_affinity(IRQ,MASK):
    print 'echo %s to /proc/irq/%s/smp_affinity'%(MASK,IRQ)
    fp = open('/proc/irq/%s/smp_affinity'%IRQ,'w')
    fp.write(str(MASK))
    fp.close()

main(irq())

ps: 之所以研究中斷親和力,主要是為了增加網絡卡的負載能力,減少被大量小包攻擊致死的機率. 將網絡卡的佇列中斷分別繫結到不同的 cpu core上,可以有效的提高小包負載能力,由於之前我們前端伺服器被小包攻擊致死,因此這也是算我們的一種防禦措施吧,

附,參考資料: