当前位置: 代码网 > 服务器>服务器>Linux > Linux TC流控实现机制过程

Linux TC流控实现机制过程

2025年09月30日 Linux 我要评论
一、tc核心架构linux tc采用模块化分层设计,核心组件包括:qdisc(排队规则):流量调度的基本单元(如pfifo_fast、htb)class(分类):qdisc内部的子队列(仅存在于分类型

一、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):

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

​

八、调试与监控

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

十、总结与挑战

优势

  • 灵活的分层流量控制
  • 可扩展的模块化设计

挑战

  • 复杂配置导致学习曲线陡峭
  • 单核处理瓶颈(部分qdisc未充分并行化)
  • 与xdp/bpf等新技术的整合

通过深入分析可见,linux tc通过抽象qdisc/class/filter三层模型,实现了从简单fifo到复杂分层调度的灵活控制,其代码设计充分体现了unix的"组合小工具"哲学。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com