Linux TC流控實現(xiàn)機制過程
一、TC核心架構(gòu)
Linux TC采用模塊化分層設(shè)計,核心組件包括:
- Qdisc(排隊規(guī)則):流量調(diào)度的基本單元(如
pfifo_fast、htb) - Class(分類):Qdisc內(nèi)部的子隊列(僅存在于分類型Qdisc中)
- Filter(過濾器):將流量分類到特定Class(如
u32、fwmark) - Policer(策略器):執(zhí)行速率限制(如
tbf) - Action(動作):對數(shù)據(jù)包執(zhí)行操作(如
mirred重定向)
二、核心數(shù)據(jù)結(jié)構(gòu)
1.Qdisc結(jié)構(gòu)體(net/sched/sch_generic.c)
struct Qdisc {
int (*enqueue)(struct sk_buff *skb, struct Qdisc *sch); // 入隊操作
struct sk_buff* (*dequeue)(struct Qdisc *sch); // 出隊操作
struct Qdisc_ops *ops; // Qdisc操作函數(shù)集
struct netdev_queue *dev_queue; // 關(guān)聯(lián)的網(wǎng)絡(luò)設(shè)備隊列
};
2.Qdisc操作集(include/net/sch_generic.h)
struct Qdisc_ops {
struct Qdisc_ops *next;
const struct Qdisc_class_ops *cl_ops; // Class操作函數(shù)集
int (*enqueue)(struct sk_buff *, struct Qdisc *);
struct sk_buff * (*dequeue)(struct Qdisc *);
// ... 其他鉤子函數(shù)(init, destroy, reset等)
};
3.Filter結(jié)構(gòu)體(net/sched/cls_api.c)
struct tcf_proto {
__be16 protocol; // 匹配的協(xié)議(如ETH_P_IP)
struct tcf_proto_ops *ops; // Filter操作函數(shù)集
struct tcf_result result; // 分類結(jié)果(指向Class)
};
三、關(guān)鍵處理流程
1.數(shù)據(jù)包入隊流程
graph TD
A[數(shù)據(jù)包到達] --> B{設(shè)備是否啟用TC?}
B -->|是| C[調(diào)用dev_queue_xmit()]
C --> D[執(zhí)行__dev_xmit_skb()]
D --> E[調(diào)用sch_direct_xmit() -> qdisc->enqueue()]
E --> F[Qdisc特定入隊邏輯]
F --> G[按調(diào)度算法緩存/丟棄]
2.數(shù)據(jù)包出隊調(diào)度
無分類Qdisc(如pfifo):
static struct sk_buff *pfifo_fast_dequeue(struct Qdisc *sch) {
struct sk_buff *skb = __qdisc_dequeue_head(&sch->q);
return skb;
}
分類型Qdisc(如HTB):
struct sk_buff *htb_dequeue(struct Qdisc *sch) {
while ((skb = htb_do_dequeue(sch, prio, band)) != NULL) {
// 按類別優(yōu)先級和令牌桶算法出隊
}
}
四、經(jīng)典Qdisc實現(xiàn)分析
1.HTB(Hierarchical Token Bucket)
核心機制:
- 令牌桶按層次分配帶寬
- 子類可借用父類空閑帶寬
關(guān)鍵數(shù)據(jù)結(jié)構(gòu):
struct htb_class {
struct Qdisc_class_common common;
struct psched_ratecfg rate; // 速率配置
struct psched_ratecfg ceil; // 上限配置
s64 tokens, ctokens; // 令牌計數(shù)
struct htb_class *parent; // 父類指針
};
2.Netem(網(wǎng)絡(luò)模擬器)
實現(xiàn)延遲/丟包/亂序:
static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) {
if (loss_condition) { // 按概率丟包
kfree_skb(skb);
return NET_XMIT_SUCCESS;
}
if (delay_calculated) { // 計算延遲時間
tfifo = netem_skb_cb(skb);
tfifo->time_to_send = now + delay;
}
__qdisc_enqueue_tail(skb, &sch->q); // 加入延遲隊列
}
五、Filter與Classifier機制
1.U32過濾器示例
static int u32_classify(struct sk_buff *skb, const struct tcf_proto *tp, struct tcf_result *res) {
struct tc_u32_key *key = tp->data;
if (skb->len < key->off + 4) // 檢查偏移量是否有效
return -1;
if (*(u32*)(skb->data + key->off) == key->val) // 匹配關(guān)鍵值
res->classid = key->classid; // 設(shè)置分類ID
}
2.eBPF集成(cls_bpf)
允許加載eBPF程序進行高級分類:
static int cls_bpf_classify(struct sk_buff *skb, const struct tcf_proto *tp, struct tcf_result *res) {
struct cls_bpf_prog *prog = tp->data;
int ret = bpf_prog_run(prog->filter, skb); // 執(zhí)行eBPF程序
if (ret == TC_ACT_SHOT) return -1; // 丟棄包
res->classid = ret; // 設(shè)置分類ID
}
六、TC配置接口(Netlink)
用戶空間工具:iproute2的tc命令
內(nèi)核處理路徑:
// net/sched/sch_api.c
static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n) {
struct net *net = sock_net(skb->sk);
struct tcmsg *tcm = nlmsg_data(n);
struct net_device *dev = __dev_get_by_index(net, tcm->tcm_ifindex);
// 解析并調(diào)用qdisc/class/filter操作函數(shù)
}
七、性能優(yōu)化機制
多隊列Qdisc (mq):
- 每個CPU核心一個隊列,減少鎖競爭
FQ_Codel (Fair Queuing with Controlled Delay):
- 使用流哈希分離流量
- 基于延遲的ECN標記
?
static struct sk_buff *fq_codel_dequeue(struct Qdisc *sch) {
struct fq_codel_flow *flow;
list_for_each_entry(flow, &q->new_flows, flowchain) {
skb = flow->head;
if (codel_time_after(skb->tstamp, now)) // 檢查是否需延遲
continue;
// ... 出隊邏輯
}
}
?八、調(diào)試與監(jiān)控
TC統(tǒng)計信息:
tc -s qdisc show dev eth0
內(nèi)核Tracepoint:
perf record -e 'net:net_dev_queue' -e 'net:net_dev_xmit'
九、代碼目錄結(jié)構(gòu)
net/sched/ ├── sch_generic.c // Qdisc基礎(chǔ)框架 ├── sch_htb.c // HTB實現(xiàn) ├── sch_netem.c // Netem實現(xiàn) ├── cls_api.c // Filter框架 ├── cls_u32.c // U32分類器 ├── act_api.c // Action框架 └── act_mirred.c // 重定向Action
十、總結(jié)與挑戰(zhàn)
優(yōu)勢:
- 靈活的分層流量控制
- 可擴展的模塊化設(shè)計
挑戰(zhàn):
- 復雜配置導致學習曲線陡峭
- 單核處理瓶頸(部分Qdisc未充分并行化)
- 與XDP/BPF等新技術(shù)的整合
通過深入分析可見,Linux TC通過抽象Qdisc/Class/Filter三層模型,實現(xiàn)了從簡單FIFO到復雜分層調(diào)度的靈活控制,其代碼設(shè)計充分體現(xiàn)了UNIX的"組合小工具"哲學。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
CentOS Linux系統(tǒng)搭建Android開發(fā)環(huán)境詳細介紹
這篇文章主要介紹了CentOS Linux系統(tǒng)搭建Android開發(fā)環(huán)境詳細介紹的相關(guān)資料,需要的朋友可以參考下2016-11-11
用DNSPod和Squid打造自己的CDN (八) 測試并運行SQUID
想要測試SQUID是否正常,必須要先把www.naizhao.com這個域名解析到2.2.2.2這個IP上。跟上一章一樣,如果你是網(wǎng)通用戶就不需要做任何操作,DNSPod會給你返回2.2.2.2這個IP2013-04-04

