第一范文网 - 专业文章范例文档资料分享平台

Linux - QOS实现框架分析

来源:用户分享 时间:2025/7/2 15:23:25 本文由loading 分享 下载这篇文档手机版
说明:文章内容仅供预览,部分内容可能不全,需要完整文档或者需要复制内容,请下载word后使用。下载word有问题请添加微信号:xxxxxxx或QQ:xxxxxx 处理(尽可能给您提供完整文档),感谢您的支持与谅解。

Linux QOS实现框架分析

作者:徐晓东(joyxxd@163.com)

Linux中的QOS分为入口(Ingress)部分和出口(Egress)部分,入口部分主要用于进行入口流量限速(policing),出口部分的QOS用于队列调度(queuing scheduling)。

以下分析所参考的linux内核版本为2.6.21。 1. Ingress QOS

Ingress QOS在内核的入口点有两个,但是不能同时启用,这取决于内核编译选项。当打开了

CONFIG_NET_CLS_ACT时,入口点在src/net/core/dev.c的netif_receive_skb函数中,代码片段如下: #ifdef CONFIG_NET_CLS_ACT if (pt_prev) {

ret = deliver_skb(skb, pt_prev, orig_dev);

pt_prev = NULL; /* noone else should process this after*/ } else {

skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd); }

ret = ing_filter(skb);

if (ret == TC_ACT_SHOT || (ret == TC_ACT_STOLEN)) { kfree_skb(skb); goto out; }

skb->tc_verd = 0; ncls: #endif

进入ing_filter后,代码片段如下: if ((q = dev->qdisc_ingress) != NULL) result = q->enqueue(skb, q);

我们可以看到,在这里判断了是否在设备上配置了ingress调度规则,如果配置了则调用其enqueue函数进行处理。在这里实际上调用的是src/net/core/sched/sch_ingress.c中的ingress_enqueue函数。

当没有打开CONFIG_NET_CLS_ACT,而是打开了CONFIG_NET_CLS_POLICE和CONFIG_NETFILTER时,就会在netfilter的PREROUTING钩子点处调用ing_hook函数,该函数的代码片段如下: if (dev->qdisc_ingress) {

spin_lock(&dev->queue_lock);

if ((q = dev->qdisc_ingress) != NULL) fwres = q->enqueue(skb, q); spin_unlock(&dev->queue_lock); }

可以看出与ing_filter的处理部分类似,最终都是调用了ingress qdisc的enqueue函数(即ingress_enqueue函数)。 ing_hook函数是在src/net/sched/sch_ingress.c文件中进行注册的,在sch_ingress文件中定义了一个结构实例ingress_qdisc_ops,如下所示: static struct Qdisc_ops ingress_qdisc_ops = { .next = NULL,

.cl_ops = &ingress_class_ops, .id = \

.priv_size = sizeof(struct ingress_qdisc_data), .enqueue = ingress_enqueue, .dequeue = ingress_dequeue, .requeue = ingress_requeue, .drop = ingress_drop, .init = ingress_init, .reset = ingress_reset, .destroy = ingress_destroy, .change = NULL,

.dump = ingress_dump, .owner = THIS_MODULE, };

所有的qdisc都会有这样的一个对象实例,在模块初始化时会调用register_qdisc函数将自己的struct Qdisc_ops结构实例注册到链表中,该链表头是qdisc_base,定义在sch_api.c文件中,static struct Qdisc_ops *qdisc_base。 当通过tc qdisc命令配置了ingress qdisc规则时,会调用到ingress_init函数,进入ingress_init函数代码片段如下:

#ifndef CONFIG_NET_CLS_ACT #ifdef CONFIG_NETFILTER if (!nf_registered) {

if (nf_register_hook(&ing_ops) < 0) {

printk(\ return -EINVAL; }

nf_registered++;

if (nf_register_hook(&ing6_ops) < 0) {

printk(\ \ } else

nf_registered++; }

#endif #endif

我们看到当没有定义CONFIG_NET_CLS_ACT,但是定义了CONFIG_NETFILTER时,会调用

nf_register_hook函数注册ing_ops和ing6_ops结构实例,ing_ops和ing6_ops的定义如下: static struct nf_hook_ops ing_ops = { .hook = ing_hook, .owner = THIS_MODULE,

.pf = PF_INET,

.hooknum = NF_IP_PRE_ROUTING, .priority = NF_IP_PRI_FILTER + 1, };

static struct nf_hook_ops ing6_ops = { .hook = ing_hook, .owner = THIS_MODULE,

.pf = PF_INET6,

.hooknum = NF_IP6_PRE_ROUTING, .priority = NF_IP6_PRI_FILTER + 1, };

针对IPV4和IPV6协议,注册的hook函数都是ing_hook,hook点是在PREROUTING,优先级低于NF_IP_PRI_FILTER。

当前比较推荐第一种使用方法,即打开CONFIG_NET_CLS_ACT选项,在netif_receive_skb函数中进入ingress的处理流程。

下面我们再跟踪一下ingress的enqueue处理流程,进入ingress_enqueue函数,代码片段如下: result = tc_classify(skb, p->filter_list, &res); ……

在ingress_enqueue函数中最主要的就是调用tc_classify函数进行分类操作,进入tc_classify函数,代码片段如下:

for ( ; tp; tp = tp->next) {

if ((tp->protocol == protocol ||

tp->protocol == __constant_htons(ETH_P_ALL)) && (err = tp->classify(skb, tp, res)) >= 0) { ……

其中tp是一个指向struct tcf_proto类型的指针,struct tcf_proto中包含了与filter相关的参数和函数指针。tp->classify调用了与该filter规则相相关联的classify函数,如果我们使用的是FW类型的filter,那么对应的classify函数就是fw_classify,该函数定义在src/net/sched/cls_fw.c文

件中。以FW分类器为例,我们再进入fw_classify函数,代码片段如下: struct fw_head *head = (struct fw_head*)tp->root; struct fw_filter *f; int r;

u32 id = skb->mark;

if (head != NULL) { id &= head->mask;

for (f=head->ht[fw_hash(id)]; f; f=f->next) { if (f->id == id) { *res = f->res;

#ifdef CONFIG_NET_CLS_IND

if (!tcf_match_indev(skb, f->indev)) continue;

#endif /* CONFIG_NET_CLS_IND */

r = tcf_exts_exec(skb, &f->exts, res); if (r < 0) continue;

return r; } }

} else {

/* old method */

if (id && (TC_H_MAJ(id) == 0 || !(TC_H_MAJ(id^tp->q->handle)))) { res->classid = id; res->class = 0; return 0; } }

return -1;

如上面代码所示,当filter中有规则时,遍历规则表,寻找与skb->mark(由ebtables或ip(6)tables来配置)相匹配的表项,如果找到了则会进一步调用tcf_exts_exec函数对扩展的action进行处理。再进入tcf_exts_exec函数,代码片段如下: #ifdef CONFIG_NET_CLS_ACT if (exts->action)

return tcf_action_exec(skb, exts->action, res); #elif defined CONFIG_NET_CLS_POLICE if (exts->police)

return tcf_police(skb, exts->police); #endif

如上面代码所示,当定义了CONFIG_NET_CLS_ACT选项,并且存在扩展action时调用tcf_action_exec函数进行处理,当定义了CONFIG_NET_CLS_POLICE选项,并且存在police扩展时会调用tcf_police函数。实际上CONFIG_NET_CLS_POLICE是一套老的police机制,它假定了在ingress处理

搜索更多关于: Linux - QOS实现框架分析 的文档
Linux - QOS实现框架分析.doc 将本文的Word文档下载到电脑,方便复制、编辑、收藏和打印
本文链接:https://www.diyifanwen.net/c8g38b7a39h5nd0e7mk4c_1.html(转载请注明文章来源)
热门推荐
Copyright © 2012-2023 第一范文网 版权所有 免责声明 | 联系我们
声明 :本网站尊重并保护知识产权,根据《信息网络传播权保护条例》,如果我们转载的作品侵犯了您的权利,请在一个月内通知我们,我们会及时删除。
客服QQ:xxxxxx 邮箱:xxxxxx@qq.com
渝ICP备2023013149号
Top