流调度模型A-Flow的设计
1.1 主动网中传统的数据包调度策略及其改善
在主动网中,每个节点都会处理带有程序的数据包。对输入数据包的处理,由于以下两个原因不利于资源管理:1) 当收到数据包时,处理中断所需的时间不能强加给任何应用,因为数据包的目的地址是未知的,需要检查数据包的内容来确定;2) 接收数据包所需的内存不能立即计算、分配。
对这类问题传统的解决方法是,尽量简化对无效数据包的处理。为此,数据包的处理过程分成两个步骤:包分类和后继协议处理。包分类主要是决定数据包的接收者,其思想主要体现在协议分层上:协议栈的某一层使用本层头部的一个域来决定数据包送往上层的哪个协议。后继协议处理则侧重于对接受者的资源控制,网络包的延迟处理技术LRP就是为了解决太多时间花在那些最终需要丢弃的数据包的处理上而导致的网络吞吐率严重下降的问题(尤其在网络过载的情况下)[2]。
LRP是在内核空间用C语言实现的,且仅限于对传统IP包的处理。为了同时调度主动包及传统IP包,且从移动代码的安全性考虑,本文提出一个架构于传统网络技术之上采用Java语言在用户模式实现的A-Flow模型,它为每个主动数据流分配一个流队列,与上层EE相关的主动包将直接递交给上层进行计算处理,其他主动包则交给默认流处理,这样可以大大减少对无效数据包的处理时间。
1.2 A-Flow主要模块设计
在A-Flow模型中如图1所示,流管理器(Flow Manager)采用对数据流注册的方法,可以屏蔽底层网络传输技术对上层主动计算功能的影响;流处理器(Flow Processor)实现对数据包的缓存、认证及净荷调度等核心功能。其他辅助类包括流缓冲队列(Flow Buffer)用于数据包缓存,流调度接口(Flow Dispatcher)声明调度函数原型,流调度器(ANEPDispatcher)则负责将数据包调往正确的流。以下是各主要模块的实现:
图1 流调度模型A-Flow
1) 流调度接口
首先,需要定义Dispatcher接口以调度输入数据包,该接口声明了一个抽象函数dispatchBuffer()。一个Dispatcher或者缓存一个数据包,或者指向另一个缓存该数据包的Dispatcher。
2) 流调度器
一个实现Dispatcher接口的类ANEPDispatcher可以完成对输入数据流的识别与分发。其算法比较简单:
首先查看Buffer中的主动网标识符(ANid)。
如果该ANid已经在某个EE的Flow Dispatcher中注册,则将此Buffer发往该Flow。
如果一个ANid没有注册并且未设置Discard位(其值由ANEP数据包头部的Flags域标识),则调度此Buffer到默认Flow。
否则,丢弃该Buffer。
3) 流处理器
这是A-Flow模型的核心类,它有三个功能:(1) 数据包缓存。每个流中都有两个队列:一个是空闲队列(freeBuffers),另一个是已用队列(usedBuffers)。后者用来存放已经接收但尚未投递的数据包。除非有空闲队列可用,否则不能缓存数据包。使用者必须保证有足够的缓存可使用。(2) 净荷调度。一个Processor和另一个Dispatcher相关联的。因此,分发到某个Processor的所有数据包的净荷也同样要分发到跟它相关联的Dispatcher处,从而实现协议分层。调度之前,Processor会将自己的头长度加到调度的偏移量上。(3) 数据包认证。Processor必须能够识别某个数据包是否属于某个流。这可以通过分析它所携带的数据来完成。Processor是通过下面的过程来完成对输入流的调度工作的。首先,Processor检查它的freeBuffers队列是否为空。若为空,则说明这个Flow的Buffer空间已经用完,即未给予Processor以足够的内存。这时,直接丢弃该数据包即可,无需进行额外的处理。若不为空,则将Buffer从队列中取出,并与调度路径中的系统Buffer“交换”。这样,包含数据的Buffer就被插入Processor的接收队列中。
4) 流管理器
该类提供了一套方法以在系统中注册Flow Processor。它提供了直接访问设备的方法,或访问现有的协议栈,比如IPv4/UDP协议。下面是一个注册UDP流的例子:
IniTIalizaTIon:
private Hashtable udpFlows = new Hashtable();
Register Flow module : registerUDPFlow(int port, FlowDispatcher fd)
Integer udpPort = new Integer(port);
UDPFlow udpFlow = (UDPFlow)udpFlows.get(udpPort);
if (udpFlow == NULL) then
udpFlow = new UDPFlow(port, fd);
udpFlows.put(udpPort, udpFlow);
5) 流缓冲队列
拷贝数据包是Dispatcher不能完成的 *** 作之一。因为一个数据包有可能被传给多个Flow Processor进行处理,所以要求有它自己的可写的数据备份。第一个接收包的Processor将它的freeBuffers跟收到数据包的系统Buffer进行交换,这个Buffer中带有实际的数据,称为原始Buffer(originalBuffer)。其余的Processor也会进行同样的 *** 作,但得到的Buffer中不包含实际数据,称之为从属Buffer(dependentBuffer)。originalBuffer与dependentBuffer之间通过链表连接起来。
当在一个Buffer上进行写 *** 作或匹配 *** 作时,必须先将它声明为“independent”,指的是:将它从链表中移出,必要的话还需拷贝数据。分两种情况:1) 对于dependentBuffer,需先将原始数据拷贝到它的内存中,然后才能将该Buffer从链表中删除;2) 对于originalBuffer,则需先拷贝数据到第一个dependentBuffer,并将它声明为余下Buffer的originalBuffer。将Buffer设置为相关链表的目的是,当一个Buffer需要发往多个目的地时,可以避免进行大量实际的数据拷贝。
主动网流调度模型A-Flow的研究
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)