Linux

关注公众号 jb51net

关闭
首页 > 网站技巧 > 服务器 > Linux > Linux TC流控实现机制

Linux TC流控实现机制过程

作者:Linux解析

Linux TC通过模块化分层设计(Qdisc、Class、Filter、Policer、Action)实现灵活流量控制,支持从简单FIFO到复杂分层调度,其优势在于可扩展性,但存在配置复杂、单核瓶颈及新技术整合等挑战

一、TC核心架构

Linux TC采用模块化分层设计,核心组件包括:

  1. Qdisc(排队规则):流量调度的基本单元(如pfifo_fasthtb
  2. Class(分类):Qdisc内部的子队列(仅存在于分类型Qdisc中)
  3. Filter(过滤器):将流量分类到特定Class(如u32fwmark
  4. Policer(策略器):执行速率限制(如tbf
  5. Action(动作):对数据包执行操作(如mirred重定向)

二、核心数据结构

1.Qdisc结构体(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操作函数集
    struct netdev_queue *dev_queue;    // 关联的网络设备队列
};

2.Qdisc操作集(include/net/sch_generic.h)

struct Qdisc_ops {
    struct Qdisc_ops *next;
    const struct Qdisc_class_ops *cl_ops; // Class操作函数集
    int (*enqueue)(struct sk_buff *, struct Qdisc *);
    struct sk_buff * (*dequeue)(struct Qdisc *);
    // ... 其他钩子函数(init, destroy, reset等)
};

3.Filter结构体(net/sched/cls_api.c)

struct tcf_proto {
    __be16 protocol;          // 匹配的协议(如ETH_P_IP)
    struct tcf_proto_ops *ops; // Filter操作函数集
    struct tcf_result result; // 分类结果(指向Class)
};

三、关键处理流程

1.数据包入队流程

graph TD
    A[数据包到达] --> B{设备是否启用TC?}
    B -->|是| C[调用dev_queue_xmit()]
    C --> D[执行__dev_xmit_skb()]
    D --> E[调用sch_direct_xmit() -> qdisc->enqueue()]
    E --> F[Qdisc特定入队逻辑]
    F --> G[按调度算法缓存/丢弃]

2.数据包出队调度

无分类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) {
        // 按类别优先级和令牌桶算法出队
    }
}

四、经典Qdisc实现分析

1.HTB(Hierarchical Token Bucket)

核心机制

关键数据结构

struct htb_class {
    struct Qdisc_class_common common;
    struct psched_ratecfg rate;   // 速率配置
    struct psched_ratecfg ceil;   // 上限配置
    s64 tokens, ctokens;          // 令牌计数
    struct htb_class *parent;     // 父类指针
};

2.Netem(网络模拟器)

实现延迟/丢包/乱序:

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) // 匹配关键值
        res->classid = key->classid; // 设置分类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); // 执行eBPF程序
    if (ret == TC_ACT_SHOT) return -1;         // 丢弃包
    res->classid = ret;                        // 设置分类ID
}

六、TC配置接口(Netlink)

用户空间工具iproute2tc命令

内核处理路径

// 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);
    // 解析并调用qdisc/class/filter操作函数
}

七、性能优化机制

多队列Qdisc (mq):

FQ_Codel (Fair Queuing with Controlled Delay):

​
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;
        // ... 出队逻辑
    }
}

​

八、调试与监控

TC统计信息

tc -s qdisc show dev eth0

内核Tracepoint

perf record -e 'net:net_dev_queue' -e 'net:net_dev_xmit'

九、代码目录结构

net/sched/
├── sch_generic.c     // Qdisc基础框架
├── sch_htb.c         // HTB实现
├── sch_netem.c       // Netem实现
├── cls_api.c         // Filter框架
├── cls_u32.c         // U32分类器
├── act_api.c         // Action框架
└── act_mirred.c      // 重定向Action

十、总结与挑战

优势

挑战

通过深入分析可见,Linux TC通过抽象Qdisc/Class/Filter三层模型,实现了从简单FIFO到复杂分层调度的灵活控制,其代码设计充分体现了UNIX的"组合小工具"哲学。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文