2007年7月20日 星期五

Qos module


sch_ingress.c
http://bbs.chinaunix.net/viewthread.php?tid=849145&highlight=qtdszws

使用ingress的內核處理流程
tc qdisc add dev eth0 handle ffff: ingress
tc filter add dev eth0 parent ffff: pref 10 protocol ip u32

1.init_module->nf_register_hook
註冊ingress的鉤子到
static struct nf_hook_ops ing_ops =
{
{ NULL, NULL},
ing_hook,
PF_INET,// 2
NF_IP_PRE_ROUTING,//註冊到PRE_ROUTING
NF_IP_PRI_FILTER + 1
};

2.網卡接收到一個ip資料包後調用ip_input.c中的ip_rcv
NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,ip_rcv_finish)
NF_HOOK定義如下
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) \
(list_empty(&nf_hooks[(pf)][(hook)]) \
? (okfn)(skb) \
: nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn)))
因此將調用nf_hook_slow,在core/netfilter.c中
nf_hook_slow->nf_iterate-> hook-> ing_hook(ingress的鉤子函數)-> ingress_enqueue(入隊)-> tc_classify(分類)

3.根據分類結果決定繼續處理該包,還是丟棄(例如被管制器管制)

======================================================================
sch_teql.c
teql原理

1.在Linux的高級路由和流量控制HOWTO.pdf有一些說明,可以參照

2.teql實現了一個簡單的多網卡負載均衡.簡單,是因為它不考慮實際的硬體情況,只是在關聯的實際設備之間輪轉轉發包,即使是一個千兆網卡和MODEM被關聯在一起.可以稱做發包數負載均衡吧.

3.insmod sch_teql.o時, init_module會註冊一個名為teql0的虛網路介面和一個名為teql0的佇列規程,他們被集成在struct teql_master結構中,彼此分不開.
可以使用一下命令綁定實設備到佇列規程teql0
tc qdisc add dev eth0 root teql0
tc qdisc add dev eth1 root teql0
然後用命令ip link set dev teql0 up啟動虛設備teql0
這樣一個teql設備就配置完成了
接下來可以再配置另一個teql設備
insmod –o sch_teql1 sch_teql.o
我這是RED HAT 7.2,由於已經載入了sch_teql.o模組,只能重命名載入了.
新版本內核已經實現一次insmod就可指定若干個teql
tc qdisc add dev eth2 root teql1
tc qdisc add dev eth3 root teql1
ip link set dev teql1 up

4.當有資料包到達teql0時先進入自己的佇列,缺省為pfifo_fast,然後內核就調用teql_master_xmit來在從設備中迴圈輪轉選擇一個設備eth*發包.如果teql*是該實設備的根佇列規程,就直接調用eth*的hard_start_xmit函數發包.如果不是就選擇下一個設備,只至成功或失敗.而配置在該設備上的teql*規程,它的行為就類似於pfifo規程.這是給那些直接通過該設備發送的包準備的規程.
teql.rar

======================================================================
sch_red.c random early detection
隨機早期探測

參考http://www.icir.org/floyd/papers/red/red.html 中的early.pdf

說明
1.qlen 為當前佇列長度
2.qave 平均佇列長度,它的計算公式是qave=qave*(1-W)+qlen*W,W為權重,W一般選得很小 ,這可以使突發包對qave不會產生太大波動
3.qmin,qmax 當qmin<=qave<=qmax時,開始隨機標記/丟包,標記/丟包的概率為 max_P * (qave- qmin)/(qmax-qmin),,隨著qave增長,概率逼近max_P 標記包是希望用戶端知道目前網路已經開始擁擠,放慢發包速度吧 如果qave>=qmax,標記/丟棄所有的包
4.如果網路空閒了一段時間,就應該相應地減少qave的大小,qave=qave*(1-W)^m,m為空閒時間段長度
sch_red.rar

路由分類器cls_route.c
路由分類器的原理很簡單,就是在路由的時候由路由規則對資料包打標記.路由分類器就用這個標記來對資料包分類.
路由規則語法如下
ip route add Host/Network via Gateway dev Device realm RealmNumber

ip route add 192.168.10.0/24 via 192.168.10.1 dev eth1 realm 10
至於如何打標記,我現在還不瞭解
在設置了路由規則以後,就可以使用路由分類器分類資料了
tc filter add dev eth0 protocol ip prio 100 route to 10 classid :2
tc filter add dev eth0 protocol ip prio 100 route from 10 classid :1
路由分類器參考的參數有fromdev/from,to,fromdev和from互斥,只能使用其中一個,由他們在分類器的二層hash表中索引和查找.

資源預留協議分類器cls_rsvp.h
資源預留協定分類器的原理也很簡單,就是用ip協定(也支援ipv6,此處不涉及)的目的地址,可能的目的埠,源位址,可能的源埠來索引和查找一個二層hash表.
"可能的"意思是不一定使用,由用戶決定.也就是它是基於session(會話)的.
tc filter add dev eth0 pref 10 protocol ip rsvp ipproto tcp session 10.1.1.1/80 classid :1
這條規則的意思就是,到10.1.1.1:80的資料流程分類到:1的佇列
還可以加入sender,指定發送者,或者不指定埠,而指定一個GPI,也就是在offset處的值&mask==key方式更加靈活地指定一個匹配.

route_rsvp.rar

sch_dsmark.c和cls_tcindex.c

diffserv是一個體系,需要一個有若干個路由和一定規模的網路來協作實現,就單個主機來說用處不大.在這個網路中,大家都遵守同樣的diffserv協定,例如哪個dsfield的優先順序高,哪個低,以及怎樣處理等.

這裏引入了域的概念,就是遵守某一diffserv協定的網路組成一個ds域.剩下的就是非ds域.一台域中的主機要發的包,可以在自己的出口佇列分類,或在接入的路由上分類.
1.在本機分類,出口綁定dsmark佇列規程和u32等分類器
2.在路由分類,路由入口綁定ingress佇列規程和u32等分類器
注:上面的分類器一般不用tcindex分類器,因為是從非ds域到ds域的轉換,而tcindex實用於使用已有ds field來分類流(見3)和不同ds域之間的轉換,不同域之間的轉換一般發生在入口上,例如上面的2,如果資料是從另外一個ds域來的話.
這樣所有的流就被區分開了.
3.然後路由器就可以在自己的出口綁定dsmark佇列規程(和一些內部佇列,例如cbq)和tcindex分類器,讓tcidnex分類來對不同級別的流(只根據ds field)進行整形和qos.

上面都是我的理解,化了我很長時間,不對之處,請大家指正.大家參考lartc上的說明.
下面的例子也是摘之lartc
tc qdisc add dev eth0 handle 1:0 root dsmark indices 64 set_tc_index#綁定dsmark佇列規程
tc filter add dev eth0 parent 1:0 protocol ip prio 1 tcindex mask 0xfc shift 2#建立tcindex分類器
tc qdisc add dev eth0 parent 1:0 handle 2:0 cbq bandwidth 10Mbit cell 8 avpkt 1000 mpu 64 # EF traffic class內部佇列
tc class add dev eth0 parent 2:0 classid 2:1 cbq bandwidth 10Mbit rate 1500Kbit avpkt 1000 prio 1 bounded isolated allot 1514 weight 1 maxburst 10 # Packet fifo qdisc for EF traffic子類
tc qdisc add dev eth0 parent 2:1 pfifo limit 5 #子類的佇列規程
tc filter add dev eth0 parent 1:0 protocol ip prio 1 handle 0x2e tcindex classid 2:1 pass_on #例子中是parent 2:0,我認為是parent 1:0,把EF流分類到2:1子類,不懂EF流是怎麼回事,半桶水^_^


sch_gred.c Generic Random Early Detection

這個演算法是在red的基礎上擴展引入virtual queue的概念形成的.
在gred中最多可以引入16個vq,其中至少有一個缺省vq.
每個vq都基本按red演算法來操作(有區別),但所有的這些vq都公用一個實際的佇列
sch->q.

gred演算法有四種模式,由參數eqp和grio控制(不知道是什麼的縮寫)
(注意是否開始隨機丟包由qave+q->qaveqth_min控制)
eqp grio
0 0 每個vq一個獨立red (qave=0),但共用一個實佇列
0 1 每個vq和比它優先順序高的vq構成一個部分相關red,保證優先順序高的vq優先發包
qave+q->qave的值是按照相關的每個vq自己計算的ave的總和
1 0 每個vq一個部分相關red,和sch->backlog相關 (qave=0)
q->qave的值是把sch->backlog按本vq的方式計算ave的值
1 1 每個vq一個全部相關red (qave=0)
q->qave的值是把sch->backlog按本vq的方式計算ave的累計總和

我認為比較有用的是(0,0)(有點類似於sfq)和(0,1)(有點類似於prio)
gred實際上和red一樣都比較難配置,主要應用于路由器上
因為它是採用skb->tc_index來選擇vq的,可以和dsmark規程和tcindex分類器協作

gred.rar

estimator.c和police.c

--------------------------------------------------------------
estimator用於估計包的速度,包括bps(每秒位元組數)和pps(每秒包數).
estimator的調用獨立於qos架構,每個estimator一個內核計時器,可以每1/4s,1/2s,1s,2s,4s,8s被調用一次,定時計算

它可以應用在佇列規程上和分類器上.
1.在佇列規程上,它把計算結果放在qdisc->stats中,到目前為止我還沒有看到誰在使用這個結果,不過這可以讓用戶監視和評估該規程上的流量
2.在分類器上,在分類器的每個策略中都有一個tcf_police結構,估計結果就放入該結構的stats成員中.在策略被命中後,將調用tcf_police,如果使用了估計器,tc_police就根據估計結果決定通過該策略的資料流程量是否超限,是的話就執行規定的動作,ok,drop,reclassify,unspec.

Usage: ... estimator INTERVAL TIME-CONST
interval為定時間隔,time-const的計算方法是w=interval/time-const,w為加權比,例est 1s 8s,則定時間隔為1s,w=1/8=0.125

------------------------------------------------------------------
police用於分類器上,前面已經提到,策略被命中就會調用tcf_police,對通過該策略資料的進行管制

除了使用可選的estimator的結果進行管制以外,police主要使用tbf(權杖桶篩檢程式)對流進行管制操作.tbf的理論在前面已經敍述過了.tbf使用常規桶和峰值桶來控制流量.對於超限的包執行規定的動作.

Usage: ... police rate BPS burst BYTES[/BYTES] [ mtu BYTES[/BYTES] ]
[ peakrate BPS ] [ avrate BPS ]
[ ACTION ]
Where: ACTION := reclassify drop continue
avrate用於estimator,判斷流量是否超限
lartc上有一個"防護SYN洪水攻擊例子"用到police
iptables -A PREROUTING -i $INDEV -t mangle -p tcp --syn -j MARK --set-mark 1
$TC qdisc add dev $INDEV handle ffff: ingress
$TC filter add dev $INDEV parent ffff: protocol ip prio 50 handle 1 fw
police rate 1kbit burst 40 mtu 9k drop flowid :1