Linux TC(Traffic Control)框架原理解析
或許是我對(duì)TC框架沒有對(duì)Netfilter框架理解深刻吧?;蛟S是的。iptables/Netfilter相應(yīng)的就是tc/TC。
?????? Linux內(nèi)核內(nèi)置了一個(gè)Traffic Control框架。能夠?qū)崿F(xiàn)流量限速。流量整形,策略應(yīng)用(丟棄,NAT等)。從這個(gè)框架你能想到別的什么嗎?或許如今不能,可是我會(huì)先簡單說一下。和TC框架比較相似的是Netfilter框架,可是二者卻又有非常大的不同。
?????? 在精通了Netfilter框架之后。再來體會(huì)TC框架會(huì)簡單得多,特別是,當(dāng)你認(rèn)為Netfilter具有這樣那樣的局限時(shí),帶著這些問題去體會(huì)TC框架的設(shè)計(jì),你可能會(huì)發(fā)現(xiàn),TC在某些方面彌補(bǔ)了Netfilter的不足。在具體深入到細(xì)節(jié)前,我先來介紹一下二者的同樣點(diǎn)以及因其初衷不同而導(dǎo)致設(shè)計(jì)的大相徑庭。
?????? 先說Netfilter。無疑這個(gè)框架被設(shè)計(jì)用來在網(wǎng)絡(luò)協(xié)議棧的內(nèi)核路徑上過濾數(shù)據(jù)包,就像在一條路上的關(guān)卡一樣,Netfilter在協(xié)議棧處理網(wǎng)絡(luò)數(shù)據(jù)包的路徑上的5個(gè)位置設(shè)置了這樣的關(guān)卡,一個(gè)數(shù)據(jù)包在被處理的路徑上經(jīng)過這些關(guān)卡被檢查。結(jié)果就是若干個(gè)動(dòng)作:接受。丟棄,排隊(duì),導(dǎo)入其他路徑等,框架僅僅需針對(duì)一個(gè)數(shù)據(jù)包得出一個(gè)結(jié)果就可以,關(guān)卡內(nèi)部提供什么服務(wù)在Netfilter框架中并沒有不論什么規(guī)定。
?????? 如今我們看TC。它旨在對(duì)數(shù)據(jù)包或者數(shù)據(jù)流提供一種服務(wù),比方限速,整形等,而這并非一個(gè)相似Netfilter的結(jié)果能夠表達(dá)的,提供這些服務(wù)須要運(yùn)行一系列的動(dòng)作。因此怎樣來“規(guī)劃和組織這些動(dòng)作的運(yùn)行”是TC框架設(shè)計(jì)的關(guān)鍵!
也就是說,TC框架關(guān)注的是怎樣運(yùn)行而不是僅僅想要得到一個(gè)要運(yùn)行的動(dòng)作。換句話說,Netfilter框架關(guān)鍵做什么,而TC框架關(guān)注怎么做。(關(guān)于Netfilter我已經(jīng)寫了大量的代碼和文章,不再贅述了...)
?????? 有關(guān)限速。流量整形方面的理論已經(jīng)非常多了,比較常見的比方使用令牌桶,可是本文關(guān)注的是Linux對(duì)TC框架的實(shí)現(xiàn)而不是令牌桶算法相關(guān)的內(nèi)容,然而在一篇短文中又不可能具體描寫敘述從流量控制理論到各種操作系統(tǒng)版本號(hào)實(shí)現(xiàn)的歷史,可是我們知道。使用隊(duì)列是大多數(shù)實(shí)現(xiàn)中實(shí)際的選擇,那么如今問題來了,Linux的TC框架是怎樣組織隊(duì)列的。在具體深入討論隊(duì)列組織之前。我最后一次比較一下Netfilter和TC。
?????? 假設(shè)你知道UNIX的字符設(shè)備和塊設(shè)備之間的差別。那么理解Netfilter框架和TC框架之間的差別就比較easy了。Netfilter的一個(gè)HOOK點(diǎn)相似一個(gè)管道字符設(shè)備,而skb就是這個(gè)設(shè)備中的單向字符流,一般都是依照從一端流入。然后依照進(jìn)入的順序從還有一端流出,附帶一個(gè)結(jié)果,比方ACCEPT。DROP等。而TC框架比較相似一個(gè)塊設(shè)備。對(duì)內(nèi)容進(jìn)行隨機(jī)存儲(chǔ)和隨機(jī)訪問,即skb進(jìn)入的順序并不一定是skb出來的順序。而這正是流量整形須要做的。也就是說。TC框架必須實(shí)現(xiàn)一個(gè)隨機(jī)訪問的數(shù)據(jù)包存儲(chǔ)緩沖區(qū)。在這個(gè)緩沖區(qū)中進(jìn)行流量控制。當(dāng)然,我們已經(jīng)知道,這是由隊(duì)列實(shí)現(xiàn)的。
?????? 當(dāng)然,不論什么事情都不是絕對(duì)的,Netfilter的一個(gè)HOOK點(diǎn)也能夠有存儲(chǔ)緩沖區(qū)或者運(yùn)行一系列的動(dòng)作,典型的就是conntrack中的分片重組以及NAT功能,對(duì)于PREROUTING這個(gè)HOOK點(diǎn)的分片重組。無疑對(duì)于分片而言,僅僅是進(jìn)入HOOK,臨時(shí)保存在里面。直到全部分片都來了切重組成功后才一次性流出這個(gè)HOOK點(diǎn),而對(duì)于NAT而言,Netfilter的處理結(jié)果無疑是“運(yùn)行了一系列的動(dòng)作”而不僅僅是ACCEPT。此外,我也寫過一些模塊,用Netfilter來實(shí)現(xiàn)流量控制,反過來,TC框架也能夠?qū)崿F(xiàn)Netfilter的功能,總之,當(dāng)你理解了這些框架的設(shè)計(jì)原則以及其本質(zhì)后。在使用和擴(kuò)展上。你就能夠庖丁解牛。游刃有余了。
?????? 個(gè)人認(rèn)為,對(duì)于單獨(dú)的一個(gè)Netfilter HOOK點(diǎn),TC框架是其超集。實(shí)現(xiàn)上更加靈活,當(dāng)然也就更加復(fù)雜。
Netfilter所擁有的TC不具備的魅力在于其HOOK點(diǎn)位置的定義。
?????? 好了。如今開始正式介紹TC框架的設(shè)計(jì)。
?????? 非常多網(wǎng)上搜到的資料在介紹TC的時(shí)候。無一例外地介紹了TC是由“隊(duì)列規(guī)程,類別。過濾器”三者組成的。大多數(shù)含糊不清,我敢說這些都是出自一篇文檔或者一本書。
非常少有人從另外一個(gè)角度去理解TC框架的設(shè)計(jì),而這本身就是一個(gè)比較有挑戰(zhàn)性的事,我個(gè)人比較喜歡這樣的事情。在介紹TC的隊(duì)列組織之前。我先來介紹一下什么叫作遞歸控制。所謂的遞歸控制就是分層次地控制,而對(duì)于每個(gè)層次,控制方式都是一致的。熟悉CFS調(diào)度的都知道,對(duì)于組調(diào)度和task調(diào)度都採用了全然同樣的調(diào)度方式。然而顯然組和task是屬于不同層次的,我畫了以下一張圖來簡單描寫敘述這樣的情況:
?????? 遞歸的控制便于控制邏輯的隨意疊加,這個(gè)我們在協(xié)議棧的設(shè)計(jì)中看到過,比方X over Y,簡稱XoY,比方PPPoE,IP over UDP(tun模式的OpenVPN),TCP over IP(原生的TCP/IP棧)...對(duì)于TC而言,考慮以下一個(gè)需求:
1.將整個(gè)帶寬依照2:3的比例分給TCP和UDP;
2.在TCP流量中,依照源IP地址段將其劃分為不同的優(yōu)先級(jí)。
3.在同樣的優(yōu)先級(jí)隊(duì)列中,依照2:8的比例將帶寬分給HTTP應(yīng)用和其他;
4....
從以上需求能夠看出,這是一個(gè)遞歸控制的需求。當(dāng)中1和3均使用了帶寬比例分配??墒秋@而易見,這是屬于不同層次的。整個(gè)架構(gòu)看起來應(yīng)該是以下這個(gè)樣子:
幾個(gè)典型的問題擺在那里,你怎么甄別數(shù)據(jù)包到不同的隊(duì)列,圖中的非葉子節(jié)點(diǎn)要呈現(xiàn)成什么數(shù)據(jù)結(jié)構(gòu),既然不是真正的隊(duì)列卻又要有隊(duì)列的行為,那么怎樣表達(dá)它們?...
?????? Linux在實(shí)現(xiàn)TC的時(shí)候,對(duì)“隊(duì)列”進(jìn)行了抽象?;旧纤S護(hù)了兩個(gè)回調(diào)函數(shù)指針,一個(gè)是enqueue入隊(duì)操作,一個(gè)是dequeue出隊(duì)操作。無論是enqueue還是dequeue,都并不一定真正將數(shù)據(jù)包排入隊(duì)列,而僅僅是“運(yùn)行一系列的操作”。
這個(gè)“運(yùn)行一系列的操作”能夠是:
1.對(duì)于葉子節(jié)點(diǎn)。真正排入一個(gè)真實(shí)的隊(duì)列或者從真正的隊(duì)列拉出一個(gè)數(shù)據(jù)包;
2.遞歸調(diào)用其他抽象隊(duì)列的enqueue/dequeue。
注意上面的第2點(diǎn)。提到了“其他抽象隊(duì)列”,那么怎樣來定位這個(gè)抽象隊(duì)列呢?這就須要一個(gè)抉擇。也就是一個(gè)選擇器,依據(jù)數(shù)據(jù)包的特征來將數(shù)據(jù)包歸入一個(gè)抽象隊(duì)列,這個(gè)時(shí)候,TC的設(shè)計(jì)框圖能夠用下圖來表達(dá):
?????? 好了,如今說點(diǎn)題外話,還是和Netfilter有關(guān)的。當(dāng)然不是它和TC的比較。而是我個(gè)人的一點(diǎn)想法。
曾幾何時(shí),我十分推崇Cisco的ACL,應(yīng)為它們是應(yīng)用于網(wǎng)卡接口的。而Netfilter則是攔截在處理路徑上而不是處理設(shè)備上。對(duì)于Netfilter而言,處理設(shè)備僅僅是一個(gè)毫無特殊之處的match,無論有無關(guān)系。全部的數(shù)據(jù)包均要經(jīng)過Netfilter HOOK點(diǎn)的抉擇。起碼你要推斷它是否匹配-i ethX...我想在net_device上掛一個(gè)filter_list,也寫過一些代碼。發(fā)現(xiàn)效果比較好,準(zhǔn)備採用。我是一個(gè)常常反復(fù)造輪子的人。當(dāng)我后來看了TC的實(shí)現(xiàn)后,發(fā)現(xiàn)TC框架正是我想要找的。于是我放言。能用Netfilter實(shí)現(xiàn)的。用TC也一樣能實(shí)現(xiàn)。而且。TC基于隊(duì)列規(guī)程(數(shù)據(jù)結(jié)構(gòu)字段正是這么寫,Qdisc-queue discipline,這并非受經(jīng)典三元組表達(dá)法的影響)的,抽象的入隊(duì)/出隊(duì)并沒有規(guī)定怎樣實(shí)現(xiàn),且隊(duì)列規(guī)程和網(wǎng)卡綁定(更精確地說是網(wǎng)卡的隊(duì)列-假設(shè)網(wǎng)卡支持多隊(duì)列的話)而不是攔截在處理路徑上。于是我有兩種選擇:
1.實(shí)現(xiàn)一個(gè)新的Qdisc,其內(nèi)置一個(gè)簡單的FIFO隊(duì)列,enqueue操作進(jìn)行從Netfilter移植過來的matches/target,全部ACCEPT的數(shù)據(jù)包排入FIFO;
2.在分類器上做文章,是否將數(shù)據(jù)包歸于一個(gè)類別不光要看數(shù)據(jù)包的特征,還要額外運(yùn)行一個(gè)action回調(diào)函數(shù),僅僅有該函數(shù)返回0才代表成功。而既然作為回調(diào)。你便能夠在當(dāng)中進(jìn)行不論什么action(drop,nat等)。關(guān)起門來lualu。
以上1和2中,第2點(diǎn)已經(jīng)實(shí)現(xiàn)了,第一點(diǎn)非常easy實(shí)現(xiàn),你僅僅須要實(shí)現(xiàn)一個(gè)隊(duì)列規(guī)程就可以,或者說為每個(gè)隊(duì)列規(guī)程都加一個(gè)action,看上去例如以下圖所看到的:
?????? 好了。到此為止,相信我已經(jīng)把該說的都說了。都是框架性的,沒有不論什么細(xì)節(jié)在里面,盡管不太喜歡TC命令行。可是我還是希望最后用一幅圖展示一下每一條TC命令和內(nèi)核數(shù)據(jù)結(jié)構(gòu)的關(guān)系,依舊是沒有細(xì)節(jié)。命令也不全,省略了match,由于我知道那些不重要:
可是我認(rèn)為,思想大于實(shí)現(xiàn)。假設(shè)你理解了實(shí)現(xiàn)背后或者現(xiàn)實(shí)背后的本質(zhì),那么你就會(huì)得心應(yīng)手,游刃有余。
轉(zhuǎn)載于:https://www.cnblogs.com/yxwkf/p/5424383.html
總結(jié)
以上是生活随笔為你收集整理的Linux TC(Traffic Control)框架原理解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android深度探索(卷1)HAL与驱
- 下一篇: 设置同一Label内涵不同颜色字体