版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、本文档的Copyleft归wwwlkk所有,使用GPL发布,可以自由拷贝、转载,转载时请保持文档的完整性,严禁用于任何商业用途。 E-mail: wwwlkk来源: TC流量控制初步分析(一)基本概念1(二)运行出口流控对象2(三)流控对象的具体实现3(3.1)建立一个根流控对象3(3.2)建立一个子流控对象6(3.3)添加一个过滤器8(3.4)流控类和过滤器类型的的组织10(3.5)入口流控对象11(四)用户空间如何和内核通信12(一)基本概念为了更好的描述TC流量控制,先明确一些概念。流控对象:队列规定。无类流控对象:无类队列规定。分类流控对象:分类的队列规定。每个分类流控对象都有默认的子
2、流控对象,默认的子流控对象必定是无类流控对象。子流控对象:分类流控对象中包含的流控对象。无类流控对象必定包含一个或者多个的数据包队列,用于存储数据包。无类和分类流控对象都有默认的分类规定,也可以使用过滤器增加分类规则。分类流控对象是流控对象的容器(包含无类和分类),无类流控对象是数据包的容器。(注意:一些复杂的流控对象可同时作为流控对象和数据包的容器,比如分层的令牌桶)数据包进入一个分类流控对象,分类流控对象将根据分类规则(默认的或者过滤器),决定将数据包送到某个子流控对象。数据包进入一个无类流控对象,无类流控对象将根据分类规则(默认的或者过滤器),决定将数据包加入到某个数据包队列。分类流控对
3、象出队操作:分类流控对象将根据出队规则(固定的),选择一个子流控对象,并执行子流控对象的出队操作。无类流控对象出队操作:无类流控对象将根据出队规则(固定的),选择一个数据包出队。每块网卡都有一个出口根流控对象。每个流控对象都指定一个句柄,以便以后的配置语句能够引用这个流控对象。除了出口流控对象之外,每块网卡还有一个入口流控对象,入口流控对象的类型是固定的(是ingress类型)。运行流控对象:都是指运行出口流控对象,也就是根据出口流控对象的出队规则(固定的),发送流控对象中的所有数据包。流控对象为空:流控对象中没有数据包。入口流控对象没有真正意义上的出队和入队操作,只是根据过滤规则来决定是否丢
4、弃数据包,流控的实现主要在出口流控对象,下面先分析出口流控的实现。(二)运行出口流控对象数据到达出口流控时,上层的所有处理已经完成,数据包已经可以交到网卡设备进行发送,在数据交到网卡设备发送前将会进入出口流控,进入出口流控的函数为dev_queue_xmit(); 如果是入口流控, 数据只是刚从网卡设备中收到, 还未交到网络上层处理, 不过网卡的入口流控不是必须的, 缺省情况下并不进行流控,进入入口流控函数为ing_filter()函数,该函数被skb_receive_skb()调用。dev_queue_xmit中进入出口流控对象的函数段如下:txq = dev_pick_tx(dev, sk
5、b);/获取出口流控的控制结构q = rcu_dereference(txq->qdisc);/获取出口流控的根流控对象if (q->enqueue) rc = _dev_xmit_skb(skb, q, dev, txq);/使用流控对象发送数据包(包含入队和出队)goto out;_dev_xmit_skb函数主要做两件事情:1. 如果流控对象为空的,试图直接发送数据包。2. 如果流控对象不空,将数据包加入流控对象,并运行流控对象。调用qdisc_run()将会运行一个流控对象,有两个时机将会调用qdisc_run():1_dev_xmit_skb()2. 软中断服务线程NET
6、_TX_SOFTIRQ软中断线程NET_TX_SOFTIRQ中将会运行的流控对象组织如下:图1 软中断中的流控对象组织static inline void qdisc_run(struct Qdisc *q)if (!test_and_set_bit(_QDISC_STATE_RUNNING, &q->state)/测试是否有其他例程正在运行本对象_qdisc_run(q);_QDISC_STATE_RUNNING标志用于保证一个流控对象不会同时被多个例程运行。软中断线程的动作:运行加入到output_queue链表中的所有流控对象,如果试图运行某个流控对象时,发现已经有其他内核
7、路径在运行这个对象,直接返回,并试图运行下一个流控对象。void _qdisc_run(struct Qdisc *q)/运行流控对象qunsigned long start_time = jiffies;while (qdisc_restart(q) /返回值大于0,说明流控对象非空。/* * Postpone processing if * 1. another process needs the CPU; * 2. we've been doing it for too long. */if (need_resched() | jiffies != start_time) /已经
8、不允许继续运行本流控对象。_netif_schedule(q);/将本队列加入软中断的output_queue链表中。break;clear_bit(_QDISC_STATE_RUNNING, &q->state);如果发现本队列运行的时间太长了,将会停止队列的运行,并将队列加入output_queue链表头。现在数据包的发送流程可以总结如下:(流控对象为空表示对象中没有数据包)1. 调用dev_queue_xmit()发送一个数据包,如果出口流控对象为空,试图直接发送数据包。2. 如果出口流控对象非空,数据包加入出口流控对象。3. 调用qdisc_run(struct Qdis
9、c *q)运行出口流控对象,也就是,调用对象对象的出队函数选择一个数据包,并发送这个数据包,如果时间允许就循环执行这个过程,直到流控对象为空。注意:如果已经有其他内核路径正在运行队列,函数将不做任何事情,并提前返回。4. 本流控对象运行时间太长了,停止本对象运行,并且将本流控对象加入软中断服务NET_TX_SOFTIRQ的output_queue链表头。5. 当执行软中断服务线程NET_TX_SOFTIRQ时,将从output_queue链表头开始顺序运行链表中的所有流控对象。(三)流控对象的具体实现(3.1)建立一个根流控对象下面使用具体的例子来说明流控对象的具体实现首先使用如下命令在eth
10、0建立一个根流控对象。#tc qdisc add dev eth0 root handle 22 prio bands 4其中流控对象的类型是”prio”,对象句柄是22,对象使用4个带(也就是包含4个子流控对象,默认的子流控对象类型是”pfifo”,出队时第一个子流控对象的优先级最高)则内核中建立的流控对象如图2,3所示:图2 建立”prio”类型的根流控对象_1图3 建立”prio”类型的根流控对象_2这个prio流控对象的句柄是22,使用4个带,每个带都是一个pfifo类型的对象,每个pfifo类型的对象都有一个数据包队列,用于存储数据包。根据数据包的skb->priority值确
11、定数据包加入哪个带,这里使用默认的prio2band,默认的skb->priority值与带的对应关系如图3中所示。现在假设要发送一个skb->priority值是8的数据包,发送流程如下:1. 使用网卡的根流控对象的入队函数将数据包入队2. 由于未设置过滤器,则直接根据数据包的skb->priority=8找到对应的带是0,则将数据包加入第一个pfifo流控对象。3. 调用pfifo流控对象的入队函数,将数据包加入对象中的数据包队列。4. 调用qdisc_run()启动根流控对象。5. 调用根流控对象的出队函数,函数内先选择第一个pfifo流控对象并调用其出队函数选择一个数
12、据包,出队函数返回,如果第一个pfifo流控对象为空,选择第二个pfifo流控对象并调用其出队函数选择一个数据包,直到找到一个数据包。6. 发送5找到的数据包。7. 只要时间允许且流控对象不为空,就一直循环5,6的过程。(3.2)建立一个子流控对象prio流控对象是分类对象,可以添加子对象(未添加子对象时使用默认子对象)。接下来使用以下命令在根队列的第4个带增加一个prio类型的子队列(此前第4个带是pfifo类型的对象,现在将替换为prio类型的对象。)#tc qdisc add dev eth0 parent 22:4 handle 33 prio bands 5 priomap 3 3
13、2 2 1 2 0 0 1 1 1 1 1 1 1 1这个prio对象是根对象的第4个带的子对象,句柄是33,并且这个子对象有5个带,skb->priority和带的映射关系是3 3 2 2 1 2 0 0 1 1 1 1 1 1 1 1。则内核中建立的子流控对象如图4所示:图4 建立prio子对象(3.3)添加一个过滤器由于根对象的使用默认的prio2band映射,默认映射只映射前3个带,而prio子对象在第4个带,所以在这里,数据包是不会被加入prio子对象,下面使用过滤器将目的ip是的数据包加入到prio子对象,命令如下:# tc filter add dev eth
14、0 protocol ip parent 22: prio 2 u32 > match ip dst /32 flowid 22:4在网卡eth0的根队列增加一个优先级是2且类型是u32的过滤器,过滤器将目的ip是的数据包定位到第4个带。u32过滤器的结构如图5所示:图5 u32类型过滤器结构其中val存储的信息,off存储偏移位置(目的ip字段的偏移)。现在数据包的入队流程如下:1. 根对象的过滤器链非空,遍历根对象的过滤器链,遇到第一个匹配的过滤器就返回,并根据返回的结果选择子类。2. 每个过滤器都调用相应的分类函数,并根据过滤器的私有数据来
15、匹配数据包。(3.4)流控类和过滤器类型的的组织相同类型的对象将使用相同的操作函数(比如出/入队函数),相同类型的过滤器也是相同的操作函数(比如分类函数)。对象中struct Qdisc_ops*ops字段指向并对象的操作函数,过滤器中struct tcf_proto_ops* ops字段指向本过滤器的操作函数。下面看一下对象类型和过滤器类型是如何组织的:图6对象类型的组织,图7过滤器类型的组织。图6 对象类型组织图7 过滤器类型组织使用int register_qdisc(struct Qdisc_ops *qops)注册对象类型。使用int register_tcf_proto_ops(s
16、truct tcf_proto_ops *ops)注册过滤器类型。以上分析了prio类型流控对象,pfifo类型流控对象,u32类型的过滤器的实现机制,内核还提供了很多其它的更复杂的流控对象和过滤器对象,有待进一步分析,但是基本的框架还是类似的。(3.5)入口流控对象int netif_receive_skb(struct sk_buff *skb)àskb = handle_ing(skb, &pt_prev, &ret, orig_dev);àing_filter(skb)增加一个入口流控队列# tc qdisc add dev eth0 ingress
17、入口流控的对象类型必定是:static struct Qdisc_ops ingress_qdisc_ops _read_mostly = .cl_ops=&ingress_class_ops,.id="ingress",.priv_size=sizeof(struct ingress_qdisc_data),.enqueue=ingress_enqueue,.destroy=ingress_destroy,.dump=ingress_dump,.owner=THIS_MODULE,;入口流控对象的私有数据是:struct ingress_qdisc_data st
18、ruct tcf_proto*filter_list;入口流控对象只有入队函数,没有出队函数。 入队动作:先遍历过滤器,如果某个过滤器匹配,执行action(接收或者丢弃数据包),并将结果返回,最终根据这个返回的结果决定是否丢弃数据包。(四)用户空间如何和内核通信iproute2是一个用户空间的程序,它的功能是解释以tc开头的命令,如果解释成功,把它们通过AF_NETLINK的socket传给Linux的内核空间,使用的netlink协议类型是NETLINK_ROUTE。发送的netlink数据包都必须包含两个字段:protocol和msgtype,内核根据这两个字段来定位接收函数。在系统初始
19、化的时候将会调用如下函数:static int _init pktsched_init(void)register_qdisc(&pfifo_qdisc_ops);register_qdisc(&bfifo_qdisc_ops);register_qdisc(&mq_qdisc_ops);proc_net_fops_create(&init_net, "psched", 0, &psched_fops);rtnl_register(PF_UNSPEC, RTM_NEWQDISC, tc_modify_qdisc, NULL);rtnl
20、_register(PF_UNSPEC, RTM_DELQDISC, tc_get_qdisc, NULL);rtnl_register(PF_UNSPEC, RTM_GETQDISC, tc_get_qdisc, tc_dump_qdisc);rtnl_register(PF_UNSPEC, RTM_NEWTCLASS, tc_ctl_tclass, NULL);rtnl_register(PF_UNSPEC, RTM_DELTCLASS, tc_ctl_tclass, NULL);rtnl_register(PF_UNSPEC, RTM_GETTCLASS, tc_ctl_tclass,
21、tc_dump_tclass);return 0;其中的rtnl_register()函数用于注册TC要接收的消息类型以及对应的接收函数。注册到图8所示的结构中。图8 接收函数的组织下面以命令#tc qdisc add dev eth0 root handle 22 prio bands 4为例子说明如何进行通信的。分析tc:main(int argc, char *argv)被调用,此函数在tc/tc.c中;分析tc qdisc:do_qdisc(argc-2, argv+2);被调用,此函数在tc/tc_qdisc.c中;分析tc qdisc add: tc_qdisc_modify(RTM_NEWQDISC, NLM_F_EXCL|NLM_F_CREATE, argc-1, argv+1); 被调用,此函数在tc/tc_qdisc.c中,在这个函数中,将分析完这一行tc的命令,各种参数(例如RTM_NEWQDISC) 被写到netlink包中,并且
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年建筑工程施工员聘用协议标准文本版B版
- 2024大客车短期租赁合同范本版B版
- 2024年共同经营业务合同2篇
- 风险管理策略与计划培训
- 2024年全新版借款合同协议书
- 高铁维护打井施工协议
- 环保服务技术交流协议
- 工程学院浮雕施工协议
- 美妆行业销售人才招聘合同
- 公共信息挖机租赁合同协议
- 人教版四年级上册数学【选择题】专项练习100题附答案
- 建筑施工安全生产治本攻坚三年行动方案(2024-2026年)
- 《短视频拍摄与制作》课件-3短视频拍摄的三大技巧
- 前置胎盘PPT(共31张PPT)课件
- 铁代谢障碍性贫血 (2)课件PPT
- 曼昆《经济学原理》(微观)第五版测试题库 (13)
- 9数学广角——集合(课件) 数学三年级上册(共15张PPT)人教版
- 幼儿园家园共育管理制度
- 《人体与运动》PPT课件(初中体育与健康)
- 玻璃幕墙工程技术规范(完整版)
- 苯-乙苯连续精馏塔的设计
评论
0/150
提交评论