Floodlight各模块处理PacketIn消息的顺序

Floodlight各模块处理PacketIn消息的顺序

在OpenFlow网络中PacketIn消息是交换机向控制器发送最多的消息,也是控制器最需要关注的消息,没有之一。在Floodlight有很多模块都会处理PacketIn消息,他们之间是以什么顺序执行的是一个很重要的问题。

在Floodlight中所有监听OpenFlow消息的模块都需要实现IOFMessageListener接口,在Eclipse里打开IOFMessageListener,Type Hierarchy窗口可以看到所有监听OpenFlow消息的类,如下:

Floodlight各模块处理PacketIn消息的顺序_第1张图片

它们之间执行的先后顺序如下图:

到这里已经把文章标题所提出的问题解决了,如果你只是想知道Floodlight各模块之间处理PacketIn的先后顺序就可以点右上角的叉号了。如果想知道的多点,请继续往下看。

如果PacketIn消息并没有按照上图的顺序进行处理,交换他们之间的处理顺序会发生什么情况呢,那就假设forwarding模块在virtualizer之前执行对PacketIn消息的处理,当某个交换机向控制器发送了一个PacketIn消息之后,Floodlight将按照以下过程处理该消息:

1) PacketIn消息先交给forwarding,forwarding模块会决定如何转发该数据包,并向OpenFlow网络中的各个交换机添加响应的流,以保证数据包可以准确的到达目的地。

2) PacketIn消息又交给virtualizer,virtualizer模块会看看源mac和目的mac是否在同一个virtual network,然后决定时候转发该数据包。但是已经没有任何意义了,因为就算virtualizer发现源mac和目的mac不在同一个virtual network,不应该转发该数据包,可是forwarding向交换机下发过转发命令了。

由此可见,各个模块之间的顺序并不能随意打乱,所以Floodlight必须以某种方式保证每个模块的执行顺序。现在就开始介绍Floodlight是如何决定模块执行顺序的。

我们已经知道每个处理OpenFlow消息的模块都要实现IOFMessageListener接口,而IOFMessageListener接口又继承了IListener接口,所以每个监听OpenFlow消息的模块都必须实现以下四个方法:

public String getName();

public boolean isCallbackOrderingPrereq(T type, String name);

public boolean isCallbackOrderingPostreq(T type, String name);

public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx);

getName方法返回该模块的名字,在决定模块执行顺序的时候,会用到模块名字。

receive方法是用来处理OpenFlow消息的,一个模块注册监听OpenFlow消息后,如果有OpenFlow消息到来,Floodlight就会调用该模块的receive方法。

isCallbackOrderingPrereq方法和isCallbackOrderingPostreq方法是用来控制模块调用顺序的,这两个方法的参数都是T type和String name。其中type是泛型参数,在IOFMessageListener中已被声明为OFType,也就是使用getName方法得到的字符串,用来标示一个消息监听模块。如果将模块A的名称传给模块B的isCallbackOrderingPrereq方法,且该方法返回True,那就表示模块A要在模块B之前执行,如果返回False那就表示模块A不在乎自己是否在模块B之前执行;同样,如果将模块A的名称传给模块B的isCallbackOrderingPostreq方法,且该方法返回True,那就表示模块A要在模块B之后执行,如果返回False那就表示模块A不在乎自己是否在模块B之后执行。在有些模块中这两个方法都返回False,那就表示这个模块不在乎自己在PacketIn处理序列中的顺序,比如linkdiscovery模块,但这并不能表明该模块可以处于PacketIn处理序列中的任何位置,例如在topology模块中就明确指明linkdiscovery要在topology模块之前执行。所以必须遍历所有实现了IOFMessageListener的类才能确定各个模块的执行顺序。

遍历完所有实现了IOFMessageListener的类之后,Floodlight需要两个步骤来确定所有模块的执行顺序:

1)寻找Terminal module(不知道如何翻译才合适)

Terminal module是指没有任何模块在需要在其后面执行,此类模块并不执行顺序的限制,需要注意的是Terminal module不止一个。伪代码如下:

for(int i=0; i<modules.size; i++){

isTerminal = true;
for(int j=0;j<modules.size;j++){
if( modules[j] is after modules[i]){
isTerminal = false;
break;
}
}
if(isTerminal)
terminalQueue.add(modules[i]);
}

只要任何一个模块需要在modules[i]之后执行,modules[i]就不是最后执行的模块。

2)在每个最后执行的模块上执行DFS算法以建立执行顺序,伪代码如下:

function dfs(){

for(int i=0; i<terminalQueue.size(); i++){
visit(terminalQueue[i]);
}
}

function visit(listener){
if(!visted.contain(listener){
visted.add(listener)
for(int i=0;i<modules.size();i++){
if( modules[i] is before listener)
visit(modules[i])
}
orderingQueue.add(listener);
}
}

到这里就讲完了,如果要为Floodlight添加模块,就应该先想清楚自己的模块应该在什么时候运行,然后再实现isCallbackOrderingPrereq方法和isCallbackOrderingPostreq即可。

—————————————————————————–

以下为一些本文的一些说明

1)你可能注意到这个图中没有Hub和StaticFlowEntryPusher模块;原因是Hub并不关心自己在PacketIn处理序列中的顺序,而且Hub默认没有启动,默认没有启动的模块还有learningswitch。没有StaticFlowEntryPusher的原因是该模块不但不关心自己的执行顺序,而且它也并不处理PacketIn消息。

2)模块名称和类名对照表

Floodlight各模块处理PacketIn消息的顺序_第2张图片

3)Floodlight所指定的模块执行顺序表

上边的图是省略了某些不需要的箭头,而简化后的结果,Floodlight的具体实现可在下表中看到(忽略了消息类型参数)。


你可能感兴趣的:(sdn)