当前位置: 首页 > news >正文

Linux sch_fq公平队列FQ流分类与credit机制

Linux sch_fq公平队列FQ流分类与credit机制

Fair Queue(FQ)qdisc位于net/sched/sch_fq.c,核心目标是每个流(flow)一个FIFO队列,按轮询(DRR, Deficit Round Robin)方式调度,保证各流间的公平性,同时支持 pacing 和 per-flow 限速。

FQ的流分类基于sk_buff的hash值,默认使用内核计算的skb->hash。fq_classify函数将报文分配到对应流:

static struct fq_flow *fq_classify(struct Qdisc *sch, struct sk_buff *skb)
{
struct fq_sched_data *q = qdisc_priv(sch);
struct fq_flow *f;
u32 hash;

if (skb->protocol == htons(ETH_P_IP) ||
skb->protocol == htons(ETH_P_IPV6)) {
hash = skb_get_hash_perturb(skb, q->perturbation);
} else {
hash = skb->hash;
if (!hash)
hash = (u32)(unsigned long)skb_dst(skb) ^
skb->sk_hash;
}

hash = reciprocal_scale(hash, FQ_HASH_SIZE);
f = &q->flows[hash];

if (f->flowchain.prev == NULL) {
struct fq_flow *new_flow;

new_flow = fq_find_fitting_flow(q, skb, hash);
if (new_flow)
return new_flow;

if (f->qlen > 1 || f->stats.stoll > q->flow_refill)
return &q->internal;

f->fq_tin = skb_find_txq(skb, q->flow_max_rate ?
&q->rate_limiting_struct : NULL);
}

return f;
}

每个flow通过定时器进行pacing控制。fq_dequeue是核心调度函数:

static struct sk_buff *fq_dequeue(struct Qdisc *sch)
{
struct fq_sched_data *q = qdisc_priv(sch);
struct fq_flow *f;
struct sk_buff *skb;
u32 now = ktime_get_ns();
s64 credit;

f = list_first_entry_or_null(&q->new_flows, struct fq_flow,
flowchain);
if (!f) {
f = list_first_entry_or_null(&q->old_flows, struct fq_flow,
flowchain);
if (!f)
return NULL;
}

if (f->time_next_packet > now) {
if (!q->timer_active) {
q->timer_active = true;
hrtimer_start(&q->fq_timer,
ns_to_ktime(f->time_next_packet - now),
HRTIMER_MODE_REL_PINNED);
}
return NULL;
}

credit = f->credit;
skb = f->head;

if (skb) {
credit -= skb->len;

if (credit < 0 && !q->rate_enable) {
return NULL;
}

__skb_unlink(skb, &f->queue);
sch->q.qlen--;

f->credit = credit;
if (f->credit <= 0) {
f->credit += q->quantum;
list_move_tail(&f->flowchain, &q->old_flows);
}
}

if (f->credit > 0 && f->qlen > 0)
list_move_tail(&f->flowchain, &q->new_flows);
else if (f->qlen == 0)
list_del_init(&f->flowchain);

if (q->rate_enable) {
f->time_next_packet = now +
max_t(u64, q->flow_max_rate ?
div64_u64(skb->len * 1000ULL * NSEC_PER_USEC,
q->flow_max_rate) : 0,
skb->len * q->pacing_divider);
}

return skb;
}

credit机制是DRR的核心。每个flow拥有一个credit计数器,初始值为quantum。每次从该flow出队一个报文,减去其长度。当credit变为负数(或零以下)时,该flow被移到old_flows链表,并补充一个quantum的credit。调度器优先服务new_flows链表中的flow,只有new_flows为空时才处理old_flows。这种设计确保新产生的active flow不会被old_flows中的flow饿死。

quantum参数的默认值在fq_change函数中设定:

static int fq_change(struct Qdisc *sch, struct nlattr *opt,
struct netlink_ext_ack *extack)
{
struct fq_sched_data *q = qdisc_priv(sch);
struct tc_fq_qopt *ctl = nla_data(opt);

if (ctl->quantum)
q->quantum = ctl->quantum;
else
q->quantum = 2 * psched_mtu(qdisc_dev(sch));

if (ctl->initial_quantum)
q->initial_quantum = ctl->initial_quantum;
else
q->initial_quantum = 0;

if (ctl->maxrate) {
q->flow_max_rate = ctl->maxrate;
q->rate_enable = 1;
}

if (ctl->pacing) {
q->pacing_divisor = ctl->pacing;
}
}

在credit计算中,fq_dequeue对每个flow出队后重新计算credit:

static void fq_flow_add_to_list(struct fq_sched_data *q,
struct fq_flow *f)
{
if (f->credit <= 0) {
f->credit += q->quantum;
list_add_tail(&f->flowchain, &q->old_flows);
} else {
list_add_tail(&f->flowchain, &q->new_flows);
}
}

flow从new_flows转移到old_flows的条件是credit耗尽,转移后补充quantum credit。但如果补充后credit仍为正,则留在new_flows继续参与调度。这种设计保证credit用尽的flow暂时让出调度机会,实现按字节严格公平。

per-flow的pacing依靠fq->time_next_packet字段,hrtimer到期后才会调用fq_dequeue,控制报文发送速率。timer回调函数为fq_timer:

static enum hrtimer_restart fq_timer(struct hrtimer *timer)
{
struct fq_sched_data *q = container_of(timer, struct fq_sched_data,
fq_timer);
struct Qdisc *sch = q->sch;
struct net_device *dev = qdisc_dev(sch);

q->timer_active = false;
__netif_schedule(sch);

return HRTIMER_NORESTART;
}

timer仅触发一次调度,fq_dequeue在必要时重新启新timer。这种defer机制将pacing粒度控制在纳秒级,适合高速网卡下精确流量整形。

http://www.jsqmd.com/news/1064607/

相关文章:

  • 3个技巧快速掌握ComfyUI中文工作流:从AI绘图新手到专业创作者的转变
  • 【毕业设计】基于 Python Web 的智能自习室人脸核验预约系统设计与实现 智能化自习室座位管理平台(源码+文档+远程调试,全bao定制等)
  • 基于谱图理论的LEO星座星间链路拓扑优化:以代数连通度最大化降低网络直径
  • 2026年软文推广平台实力排行榜:8大平台深度测评与效果对比 - GEORANK
  • AI透明度与人格特质如何影响人机谈判中的信任建立与协作效率
  • 数字电路模拟程序总结性博客
  • 树莓派打造便携式Kali Linux渗透测试工作站:硬件选型、系统优化与实战指南
  • 2026年中国软文发稿平台TOP8综合测评报告:权威排名与选购指南 - GEORANK
  • 免费解决Mac读写NTFS难题:Nigate开源工具完整指南
  • 嵌入式调试器命令实战:从自动化脚本到高效问题定位
  • 智能语音交互的声学革新:从降噪到体验的全方位突破
  • 基于Stein变分梯度下降的分布估计算法:组合优化新范式
  • 软件工程中的关怀伦理:从抽象关注到具体关怀的实践指南
  • Elasticsearch持久化 Agent 记忆系统(一个开源工具)
  • 2026年当下四川靠谱的LED显示屏安装服务商深度解析与选择指南 - 品牌鉴赏官2026
  • 如何选择最适合的文档解析方案:3种技术路径深度对比
  • 发稿平台哪家好?2026年8大类平台全方位对比评测 - GEORANK
  • 2026韶关漏水检测维修本地口碑防水商家榜单:厨卫/阳台/屋面/地下室渗漏水维修,持证施工+明码实价,防水补漏公司TOP5推荐 - 即刻修防水
  • 全球主流 Online Judge (OJ) 的全景式总结(二)
  • 天津离婚诉讼律师联系方式推荐 家理天津分所姜春梅专业服务 - 外贸老黄
  • 2026辽阳防水补漏避坑指南:卫生间/厨房/阳台/屋顶/地下室漏水检测维修全攻略,正规施工+透明报价+口碑榜靠谱服务商推荐 - 安佳防水
  • 声音的“魔法橡皮擦”:语音降噪技术是如何工作的?
  • 效率直接起飞 AI论文写作软件测评:2026最新推荐与对比
  • 2026达州防水补漏避坑指南:卫生间/厨房/阳台/屋顶/地下室漏水检测维修全攻略,正规施工+透明报价+口碑榜靠谱服务商推荐 - 安佳防水
  • 深入解析Cortex-M4指令集:浮点运算与中断控制实战指南
  • 解决音频格式混乱的终极方案:fre:ac音频转换器实战指南
  • 人血清与人血清白蛋白HSA解析:纤维蛋白原去除、cGMP人AB血清与细胞治疗原料选型
  • 用友GRP-U8 SQL注入漏洞复现与防御:从listSelectDialogServlet接口看企业软件安全
  • 天津财产分割律所联系方式推荐 专业处理婚姻家事财产纠纷案件 - 外贸老黄
  • OpenVAS漏洞扫描结果精准评估:从海量告警到可行动风险矩阵