一樣原先發布在: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開源網關更完美一些了。