關於linux tc多網段限速的解決方案

一樣原先發布在:http://www.ywjt.org/index/archives/556.html,如今發佈在這裏分享一下:html

以192.168.1.2爲客戶端爲例,tc限制下載的關鍵命令:linux

IDEV=eth1
ODEV=eth0
/sbin/tc qdisc del dev $IDEV root handle 10:
/sbin/tc qdisc add dev $IDEV root handle 10: cbq bandwidth 100Mbit avpkt 1000
 /sbin/tc class add dev $IDEV parent 10:0 classid 10:1 cbq bandwidth 100Mbit rate 100Mbit allot 1514 weight 1Mbit prio 8 maxburst 20 avpkt 1000
/sbin/tc class  add dev $IDEV parent 10:1 classid 10:12 cbq bandwidth 100Mbit rate $DOWNLOAD allot 1514 weight 20Kbit prio 5 maxburst 20 avpkt 1000 bounded
/sbin/tc qdisc  add dev $IDEV parent 10:12 sfq quantum 1514b perturb 15
/sbin/tc filter add dev $IDEV parent 10:0 protocol ip prio 100 u32 match ip dst192.168.1.2 flowid 10:12

 

先把原先的規則刪除,而後建立一個排隊規則qdisc:shell

QDisc(排隊規則)是queueing discipline的簡寫,它是理解流量控制(traffic control)的基礎。不管什麼時候,內核若是須要經過某個網絡接口發送數據包,它都須要按照爲這個接口配置的qdisc(排隊規則)把數據包加入隊列。而後,內核會盡量多地從qdisc裏面取出數據包,把它們交給網絡適配器驅動模塊。網絡

使用最簡單的qdisc,純粹的先進先出。只有一個參數:limit,用來設置隊列的長度,pfifo是以數據包的個數爲單位;bfifo是以字節數爲單位。函數

一個QDisc會被分配一個主序列號,叫作句柄(handle),而後把從序列號做爲類的命名空間。句柄採用象10:同樣的表達方式。習慣上,須要爲有子類的QDisc顯式地分配一個句柄。測試

關於類(class),在同一個QDisc裏面的類分享這個QDisc的主序列號,可是每一個類都有本身的從序列號,叫作類識別符(classid)。類識別符只與父QDisc有關,和父類無關。類的命名習慣和QDisc的相同。spa

咱們在內網網卡上建立一個句柄handle 10:code

而後定義好限速的帶寬信息:htm

/sbin/tc qdisc add dev $IDEV root handle 10: cbq bandwidth 100Mbit avpkt 1000接口

接着定義好實行規則的根分類和子分類好比10:1之類的。

/sbin/tc class  add dev $IDEV parent 10:1 classid 10:12 cbq bandwidth 100Mbit rate $DOWNLOAD allot 1514 weight 20Kbit prio 5 maxburst 20 avpkt 1000 bounded
/sbin/tc qdisc  add dev $IDEV parent 10:12 sfq quantum 1514b perturb 15

而後針對具體的ip進行分類,對每一個ip定義一個flowid,以目標ip爲準,建立相應的過濾器,綁定到指定的子類(10:1)裏面去:

tc filter add dev $IDEV parent 10:0 protocol ip prio 100 u32 match ip dst 192.168.1.2 flowid 10:12

這樣能夠搞定針對指定ip的限速,可是如今須要的是針對十幾個網段,咱們以前的方案是來一個循環,好比match ip dst 後面循環接指定的全部ip,而後匹配到flowid這個惟一的標識碼,這樣就針對這些ip達到了限速功能。實現方法:

INET="192.168.2. 192.168.3. 192.168.4. 192.168.5. 192.168.6. 192.168.7. 192.168.8. 192.168.15.0 192.168.100. 192.168.30."
IPS=2
IPE=254
IDEV=eth1
ODEV=eth0
/sbin/tc qdisc del dev $IDEV root handle 10:
/sbin/tc qdisc add dev $IDEV root handle 10: cbq bandwidth 100Mbit avpkt 1000
/sbin/tc class add dev $IDEV parent 10:0 classid 10:1 cbq bandwidth 100Mbit rate 100Mbit allot 1514 weight 1Mbit prio 8 maxburst 20 avpkt 100
0
net_down(){
COUNTER=$IPS
while [ $COUNTER -le $IPE ] 
do
    /sbin/tc class  add dev $IDEV parent 10:1 classid 10:1$COUNTER cbq bandwidth 100Mbit rate $DOWNLOAD allot 1514 weight 20Kbit prio 5 maxbu
rst 20 avpkt 1000 bounded
    /sbin/tc qdisc  add dev $IDEV parent 10:1$COUNTER sfq quantum 1514b perturb 15
    /sbin/tc filter add dev $IDEV parent 10:0 protocol ip prio 100 u32 match ip dst $1$COUNTER flowid 10:1$COUNTER
    COUNTER=` expr $COUNTER + 1 `
done
}
for i in $INET
do
net_down "$i"
done


這個是之前的方案,看似沒有邏輯錯誤了,循環下來,針對每一個ip段的2到254ip,相應地跑一下以前的tc filter這樣就ok了。跑一下腳本,發現有這種報錯

覺得是系統內核的反饋,是正常現象,可是,用久了就發現了其中的bug,好比192.168.2.2在下載東西,2.2的網絡包隊列滿了,卡了,不只2.2卡了,一樣會影響到全部的2爲結尾的ip,好比3.2 4.2這些ip都會被限速,表現爲到網關延遲很是大。

仔細研究一下用了一年多的腳本,發現有地方不對勁:位數是同樣的會形成flowid重複,即每一個段,同尾數的ip會共用一個flowid,找到bug了,立刻解決,思路就是把flowid分開就能夠了,本想以ip爲標識符,把小數點去掉,看成flowid跑一下,這樣就不會重複了,不過發現報錯:Illegal 「classid」,感受很奇怪。。找不到問題所在,對照了一下以前跑的腳本,發現出來這個數字有點大,好比19216822,以爲是這裏超出了定義內置的範圍,把他改小一點發現正是這個問題,經測試用10:11到10:19999這些是正常的,即每一個子分類只有998個ip能夠用,好說,咱們多定義幾個父類就能夠了,

/sbin/tc class add dev $IDEV parent 10:0 classid 10:1 cbq bandwidth 100Mbit rate 100Mbit allot 1514 weight 1Mbit prio 8 maxburst 20 avpkt 100

把這裏的10:1多複製幾個10:2 10:3之類的就能夠了。

/sbin/tc class add dev $IDEV parent 10:0 classid 10:1 cbq bandwidth 100Mbit rate 100Mbit allot 1514 weight 1Mbit prio 8 maxburst 20 avpkt 1000
/sbin/tc class add dev $IDEV parent 10:0 classid 10:2 cbq bandwidth 100Mbit rate 100Mbit allot 1514 weight 1Mbit prio 8 maxburst 20 avpkt 1000

 

每一個子類跑3個網段,2到254的,而後把原先的 flowid 10:1$COUNTER裏面的COUNTER變量改成一個不重複的數字便可, 這樣就解決了範圍過大和flowid重複的問題。

最後修改的地方:

 

 

net_down1(){
COUNTER=$IPS
while [ $COUNTER -le $IPE ]
do
a=$(($a+1))
COUNT=$a
echo  "$1$COUNTER $COUNT" >>  tcc.log
 #   如下三句限制各IP的下載帶寬
/sbin/tc class  add dev $IDEV parent 10:1 classid 10:1$COUNT cbq bandwidth 100Mbit rate $DOWNLOAD allot 1514 weight 20Kbit prio 5 maxburst 20 avpkt 1000 bounded
/sbin/tc qdisc  add dev $IDEV parent 10:1$COUNT sfq quantum 1514b perturb 15
/sbin/tc filter add dev $IDEV parent 10:0 protocol ip prio 100 u32 match ip dst 1$COUNTER flowid 10:1$COUNT
COUNTER=` expr $COUNTER + 1 `
done
}

 

記得得把定義的ip段從新分段一下:

INET1=」192.168.2. 192.168.4. 192.168.5. 192.168.8. 」

INET2=」192.168.15. 192.168.100. 192.168.30.」

這樣下面再對這些ip段跑一下netdown的函數就能夠了

               a=$(($a+1))

COUNT=$a

echo  「$1$COUNTER $COUNT」 >>  tcc.log

其中這裏的做用是爲了要另外作一個解速的命令,在臨時下載大文件時候用獲得:咱們把全部的ip和對應的flowid記錄起來了,而後作過解速腳本:

 

#!/bin/sh
echo "$1" |grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' >/dev/null 2>&1|| { echo "第一個參數是ip"; exit 1 ;}
ip=$1
IP=`echo $ip | awk -F . '{$NF="";OFS=".";print $0}' `
inet=`grep ^INET tc.sh`
U=`echo "$inet" |grep $IP | awk -F = '{print $1}' | grep -oE "[0-9]{1,}"`
IIPP=`grep "$ip " tcc.log | awk '{print $2}'`
UIP=${U}${IIPP}
limit=4000
test -z $2 || limit=$2
tc class change dev eth1 parent 10:$U classid 10:$UIP cbq bandwidth 100Mbit rate ${limit}Kbit allot 1514 weight 20Kbit prio 5 maxburst 20 avpkt 1000 bounded

 

後面接具體ip,默認是解速到4兆的網絡,後面能夠再接具體的帶寬。

這樣結合以前的iptables限QQ號碼和微博之類的方法,讓linux開源網關更完美一些了。

相關文章
相關標籤/搜索