1、QoS原理与使用以及其中WRR策略的设计与实现QoS原理与使用以及其中WRR策略的设计与实现文档编号:00-6201-100当前版本:1.0.0.0创建日期:2011-6-13编写作者:ganjingweiQoS原理与使用以及其中WRR策略的设计与实现摘要Linux系统由于它的开放源代码、内核小、效率高、免费性等特点,使得它在嵌入式领域极具优势。另外,Linux适应于多种CPU和多种硬件平台,是一个跨平台的系统,具有非常强的移植性,可以在几乎任何嵌入式硬件上经过一些裁剪很容易地工作起来。总之,Linux在嵌入式领域占有重要的地位。Linux对于网络功能方面也具有强大的支持。它的其中一个最重要的
2、特点就是“零拷贝”。所谓“零拷贝”就是数据包在内核中的层次传递过程,完全由指针完成,中间没有任何由于函数的调用而产生的数据复制。这样既提升了处理速度,又节省了空间。使得Linux也是嵌入式网络产品的第一选择。QoS,从字面意思看,就是服务质量。它是Linux内核中对于数据包的一种调度方式,根据数据包的不同服务,提供不同的带宽质量。它解决了Linux内核对于数据包的传统处理方式无法适应当今多样的网络业务需求的问题。加权循环调度策略(WRR)是QoS的概念下,对于数据包的调度的一种算法。它为每种数据包分配不同的权重,按照权重提供不同比例的带宽。本文重点是、阐述QoS的实现原理,并在其基础上实现我们
3、的加权循环调度策略。关键词:Linux,网络,QoS,TC,嵌入式Design and Implementation of Weight Round RobinAbstractLinux release its source opening for free. And it works efficiently with a reduced kernel. So it lives a high advantage in the field of embedded system. In addition, Linux can work on many kinds of CPU and hardwa
4、re platform. It is a cross-platform system, has a very strong portability, and can work on all most every embedded hardware with some part simply cut. In short, Linux plays an important role in the field of embedded system. Linux offer a strong support on Internet network function. One of its most i
5、mportant advantages is called “zero-copy”. The so-called “zero-copy” is that packets are passed through the kernel layers all by pointers. No data is copied when function is called. In this way, it not only enhance the processing speed, but also saves memory. So Lniux is the first choise of network
6、embedded system.QoS, viewed from the literal meaning, is quality of service. It is a method of scheduling within packages in Linux kernel. It offers different quality of bandwidth for different service of packages. It solved the problem that the traditional method of Linux kernel can not meet the de
7、mand of various network service. Weight Round Robin (WRR) is an algorithm of scheduling within packages under the concept of QoS. It allocates every kinds of packages different weight, and offers them different bandwidth in light of the weight. This document illustrate the Implementation of QoS, and
8、 implement our WRR based on it.Keywords: Linux,Network,QoS,TC,Embedded System第1章 绪论1.1传统的网络数据包发送机制传统的IP网络无区别地对待所有的报文,路由器处理报文采用的策略是先入先出FIFO(First In First Out),它依照报文到达时间的先后顺序分配转发所需要的资源。所有报文共享网络和路由器的带宽等资源,至于得到资源的多少完全取决于报文到达的时机。这种服务策略称作Best-Effort(尽力而为),它尽最大的努力将报文送到目的地,但对分组投递的延迟、延迟抖动、丢包率和可靠性等需求不提供任何承诺和
9、保证。传统的Best-Effort服务策略只适用于对带宽、延迟性能不敏感的WWW、文件传输、E-Mail等业务。1.2 QoS需求的提出随着计算机网络的高速发展,越来越多的网络接入因特网。Internet无论从规模、覆盖范围和用户数量上都拓展得非常快。越来越多的用户使用Internet作为数据传输的平台,开展各种应用。同样地,服务提供商也希望通过新业务的开展来增加收益。网络发展日新月异随着IP网络上新应用的不断出现对IP网络的服务质量也提出了新的要求例如VoIP (Voice over IP) , IP语音等实时业务就对报文的传输延迟提出了较高要求。如果报文传送延时太长将是用户所不能接受的相对
10、而言E-Mail和FTP业务对时间延迟并不敏感为了支持具有不同服务需求的语音视频以及数据等业务要求网络能够区分出不同的通信进而为之提供相应的服务传统IP网络的尽力服务不可能识别和区分出网络中的各种通信类别而具备通信类别的区分能力。正是为不同的通信提供不同服务的前提所以说传统网络的尽力服务模式已不能满足应用的需要QoS(Quality of Service) 服务质量技术的出现便致力于解决这个问题,同时也解决网络中拥塞的问题1.3 研究WRR的目的当网络拥塞时,我们很容易想到带宽应该分配给实时性要求高的业务(例如VoIP、视频点播等)。然而如果一味地偏袒这些业务,会使得实时性不是那么高的业务(例
11、如E-Mail)完全得不到发送,从而在另一个角度也降低了服务质量。加权循环调度策略(WRR)是为了解决这一矛盾,既能够给一些业务较高的带宽保证拥塞时尽力支持它们的通畅,又能够不“饿死”其他数据。1.4 关于本文本文第1章阐述了QoS提出的背景,也就是传统数据包在网络中发送的机制,并分析它的缺陷。之后根据这个缺陷,提出如何弥补这个缺陷,并进而提出QoS。而本文的最终主题WRR则是QoS概念中的一种解决方案。本文第2章详细描述了QoS的工作原理。包括QoS的作用地点,QoS框架设计等等。并结合ISO层次结构和Linux内核协议栈和Netfilter框架,对整个Linux网络处理功能进行概要阐述。第
12、3章阐述如何使用QoS方面的应用层机制TC命令。并通过两个例子来帮助读者理解和学习使用它。第4章和第5章则完整地讲述WRR算法的原理及其实现。第2章 QoS工作原理2.1 ISO层次结构图1-1展示了一个完整的ISO网络层次结构。每一层完成各自的功能,层与层之间是相互透明的。把网络的需求分配到各个层次有许多优点,这里不再一一列举。以下是每一层的概要性描述1:图1-1 ISO层次结构物理层-定义了为建立、维护和拆除物理链路所需的机械的、电气的、功能的和规程的特性,其作用是使原始的数据比特流能在物理媒体上传输。具体涉及接插件的规格、“0”、“1”信号的电平表示、收发双方的协调等内容。数据链路层-比
13、特流被组织成数据链路协议数据单元(通常称为帧),并以其为单位进行传输,帧中包含地址、控制、数据及校验码等信息。数据链路层的主要作用是通过校验、确认和反馈重发等手段,将不可靠的物理链路改造成对网络层来说无差错的数据链路。数据链路层还要协调收发双方的数据传输速率,即进行流量控制,以防止接收方因来不及处理发送方来的高速数据而导致缓冲器溢出及线路阻塞。网络层-数据以网络协议数据单元(分组)为单位进行传输。网络层关心的是通信子网的运行控制,主要解决如何使数据分组跨越通信子网从源传送到目的地的问题,这就需要在通信子网中进行路由选择。另外,为避免通信子网中出现过多的分组而造成网络阻塞,需要对流入的分组数量进
14、行控制。当分组要跨越多个通信子网才能到达目的地时,还要解决网际互连的问题。运输层-是第一个端-端,也即主机-主机的层次。运输层提供的端到端的透明数据运输服务,使高层用户不必关心通信子网的存在,由此用统一的运输原语书写的高层软件便可运行于任何通信子网上。运输层还要处理端到端的差错控制和流量控制问题。会话层-是进程-进程的层次,其主要功能是组织和同步不同的主机上各种进程间的通信(也称为对话)。会话层负责在两个会话层实体之间进行对话连接的建立和拆除。在半双工情况下,会话层提供一种数据权标来控制某一方何时有权发送数据。会话层还提供在数据流中插入同步点的机制,使得数据传输因网络故障而中断后,可以不必从头
15、开始而仅重传最近一个同步点以后的数据。表示层-为上层用户提供共同的数据或信息的语法表示变换。为了让采用不同编码方法的计算机在通信中能相互理解数据的内容,可以采用抽象的标准方法来定义数据结构,并采用标准的编码表示形式。表示层管理这些抽象的数据结构,并将计算机内部的表示形式转换成网络通信中采用的标准表示形式。数据压缩和加密也是表示层可提供的表示变换功能。应用层-是开放系统互连环境的最高层。不同的应用层为特定类型的网络应用提供访问OSI环境的手段。网络环境下不同主机间的文件传送访问和管理(FTAM)、传送标准电子邮件的文电处理系统(MHS)、使不同类型的终端和主机通过网络交互访问的虚拟终端(VT)协
16、议等都属于应用层的范畴。2.2 Linux内核数据包流程和Netfilter框架Netfilter是Linux内核中关于网络数据包处理的一个框架,它实现不同数据包在内核中要经过不同的处理,不同的处理程序这个需求。它就像许多层的筛子,层层过滤。它在网络数据包的处理流程中设置了一个又一个的函数HOOK(钩子),这些钩子对应每一层“筛子”。当某一个筛子过滤出了一些满足条件的数据包以后,“钩子”会调用对应这些数据包要流向的处理流程的函数,进入下一步的处理。在内核中,我们叫这种“钩子”为HOOK点。在代码中,这些HOOK点被定义为一个一个的宏,然后通过一个函数指针数组,在每个过滤的地方,通过调用不同的函
17、数在实现对数据包的不同处理。进入不同函数的数据包,还会遇到下一个HOOK点,等等。表2-1列出了IPv4的主要5个HOOK点。Nef_receive_skb是网卡中世纪接收到数据包的函数。这个函数之后有一个过程解析接收到的数据包,分析它的协议类型,如果是PF_INTERNET,也就是IPv4类型的数据包,将会被提交给ip_rcv这个函数处理。之后就进入了Netfilter处理过程。PRE_ROUTING是第一个HOOK点,这个HOOK点主要做的是,分析数据包是发送给本地当前这个主机的,还是要经过这个主机而进行转发的。如果是发送给本地的,则分流进入本地处理过程进入LOCAL_IN这个HOOK点进
18、行操作,否则进入数据包的进一步处理。之后的FORWARD和POST_ROUTING是转发数据包的处理过程,这两个HOOK点主要是对数据包进行NAT(地址转换)过程。这里涉及到了IPv4的各种协议,这里不再深究。还要提一下的是,在POST_ROUTING中也处理本地产生的数据包,也就是LOCAL_OUT这个HOOK点出来的数据包。表2-1 可用的IPv4 hookHook调用的时机NF_IP_PRE_ROUTING在完整性校验之后,选路确定之前NF_IP_LOCAL_IN在选路确定之后,且数据包的目的是本地主机NF_IP_FORWARD目的地是其它主机地数据包NF_IP_LOCAL_OUT来自本
19、机进程的数据包在其离开本地主机的过程中NF_IP_POST_ROUTING在数据包离开本地主机“上线”之前图2-1简要列出了IPv4的Netfilter过程。图2-1 IPv4的Netfilter框架基本流程在POST_ROUTING这个HOOK点的处理完成以后内核已经选定一个网卡设备来发送这个数据包,内核会调用dev_queue_xmit,来使用选中的网卡设备来发送这个数据包。dev_queue_xmit这个函数的主要流程是,检查设备是否有安装QoS,如果有,则调用dev-qdisc-enqueue来让数据包计入这个网卡设备的发送队列。到这里,就进入了QoS对数据包输出的处理和调度程序。2.
20、3 QoS工作定位2.3.1 流入口数据包控制对于入口数据包的控制是通过HOOK函数来实现的。关于HOOK点,上一节中已经进行了一定程度的介绍。每个HOOK点有若干个挂钩处理函数:typedef unsigned int nf_hookfn(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)对于入口数据部分的控制,LINUX 中挂载的HOOK点如下:/* after ipt_filte
21、r */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,;ingress policing用的是NF_IP_PRE_ROUTING这个HOOK点,其挂钩处理函数用的是net/sched/sch_ingress.c ing_hook()。函数处理流程如图2-2所示。图2-2所示接收数据包的过程中,通过软中断调用net_rx_action()
22、将硬件层得到的数据传输到IP层。ip_rcv()这个函数在net/ipv4/ip_input.c中,它丢弃校验和不正确的ip包。nf_hook_slow()在net/core/netfilter.c中。nf_iterate()在net/core/netfilter.c中。ing_hook() 在net/sched/sch_ingress.c中。之后是QoS的处理过程:如果设置了qdisc_ingress,则调用ingress_dequeue()。此处可以对流量进行限制,相关代码在net/sched/sch_ingress.c中。ip_rcv_finish()函数在net/ipv4/ip_inp
23、ut.c中。ip_route_input()函数完成路由的功能,在net/ipv4/route.c中实现。net/ipv4/route.c中的ip_route_input_slow()是转发的数据包的下一步处理函数,而同样在net/ipv4/route.c中的ip_route_input_mc()与之相反,处理的是发给本地的数据包。图2-2 Netfilter与ingress流量控制这里要提一下的是sch_ingress.c 中的enqueue()有限流制作用,然而dequeue()却是空函数。这是Linux对输入流量控制的缺失,这一部分的功能是不完善的。这也正是作者为什么只做了输出流量控制的
24、WRR,而忽略输入流控。2.3.2 流出数据包的控制首先我们了解一下Linux网络协议栈在没有TC模块时发送数据包的大致流程。从图2-3可以看出,没有TC的情况下,每个数据包的发送都会调用dev_queue_xmit,然后判断是否需要向AF_PACKET协议支持体传递数据包内容,最后直接调用网卡驱动注册的发送函数把数据包发送出去。发送数据包的机制就是本文开始讲到的FIFO机制。一旦出现拥塞,协议栈只是尽自己最大的努力去调用网卡发送函数。所以这种传统的处理方法存在着很大的弊端。图2-3 Linux网络协议栈在没有TC模块时发送数据包的大致流程为了支持QoS,Linux的设计者在发送数据包的代码中
25、加入了TC模块。从而可以对数据包进行分类,管理,检测拥塞和处理拥塞。为了避免和以前的代码冲突,并且让用户可以选择是否使用TC。内核开发者在图2-3中的两个红色圆圈之间添加了TC模块。为了实现QOS的支持LINUX 内核中添加如下的代码:以下是net/core/dev.c中的dev_queue_xmit函数(其中略了部分代码):int dev_queue_xmit(struct sk_buff *skb) . q = dev-qdisc; if (q-enqueue) /*如果这个设备启动了TC,那么把数据包压入队列*/ int ret = q-enqueue(skb, q); /*启动这个设备
26、发送*/ qdisc_run(dev); return; if (dev-flags&IFF_UP) . if (netdev_nit) dev_queue_xmit_nit(skb,dev); /*对AF_PACKET协议的支持*/ if (dev-hard_start_xmit(skb, dev) = 0) /*调用网卡驱动发送函数发送数据包*/ return 0; 从上面的代码中可以看出,当q-enqueue为假的时候,就不采用TC处理,而是直接发送这个数据包。如果为真,则对这个数据包进行QoS处理。处理流程如图2-4所示。图2-4 流出的数据包的控制过程QoS:如果有排队方式,那么sk
27、b先进入排队q-enqueue(skb,q),然后运行qdisc_run()。qdisc_run()函数在include/net/pkt_sched.h中,代码如下(有省略):.while (!netif_queue_stopped(dev) & qdisc_restart(dev)dequeue(q)把数据包从队列中取出。图2-4中q-enqueue是对数据包入队,而q-dequeue是选择队列中的一个数据包然后取出。进行数据包的发送。当然入队、出队根据不同的策略有不同的动作具体后面讨论。2.3.3 在Linux内核中给一个设备安装一个新的流量控制对象2.3.3.1 struct Qdisc
28、_ops 说明Qdisc_ops是策略对象,内核中提供了很多中的策略对象比如说TBF、CBQ、HTB、SFQ、DSMARK等的策略对象,这么多的策略对象内核是怎么组织起来的呢?当然内核是通过Qdisc_ops这个结构进行组织的,每个策略都有一个策略对象,并且内核把他们组织成一个链表,根据需要直接从链表中查找相应的策略对象进行安装就可以。Qdisc_ops数据结构如下2:struct Qdisc_ops struct Qdisc_ops *next; struct Qdisc_class_ops *cl_ops; char idIFNAMSIZ; int priv_size; int (*enq
29、ueue)(struct sk_buff *, struct Qdisc *); struct sk_buff* (*dequeue)(struct Qdisc *); int (*requeue)(struct sk_buff *, struct Qdisc *); unsigned int (*drop)(struct Qdisc *); int (*init)(struct Qdisc *, struct rtattr *arg); void (*reset)(struct Qdisc *); void (*destroy)(struct Qdisc *); int (*change)(
30、struct Qdisc *, struct rtattr *arg); int (*dump)(struct Qdisc *, struct sk_buff *); struct module *owner;例如对于sch_tbf.c,这个文件实现的是令牌桶算法,最后生成一个struct Qdisc_ops的结构变量tbf_qdisc_ops,在模块初始化的时候,注册tbf_qdisc_ops,调用register_qdisc(&tbf_qdisc_ops),注册的过程其实就是加入一个链表的过程,sch_api.c提供这个注册的函数。以下是sch_tbf.c文件的一部分代码(其余的sch*.
31、c的第二部分的文件与之类似):struct Qdisc_ops tbf_qdisc_ops = NULL, NULL, tbf, sizeof(struct tbf_sched_data), tbf_enqueue, tbf_dequeue, tbf_requeue, tbf_drop, tbf_init, tbf_reset, tbf_destroy, tbf_change, tbf_dump,;#ifdef MODULEint init_module(void) return register_qdisc(&tbf_qdisc_ops);void cleanup_module(void) unregister_qdisc(&tbf_qdisc_ops);#endif 2.3.3.2 Linux内核中安装策略对象过程在网卡注册的时候,都会调用register
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1