Floodlight的forwarding模块流程简单分析

来源:互联网 发布:看电影翻译软件 编辑:程序博客网 时间:2024/05/18 09:32

http://lamoop.com/post/2013-11-28/40060265578

主模块在初始化并启动各个二级模块后,通过Netty网络应用框架监听6633端口,当有packet-in进来的时候,会调用各个二级模块的receive函数(java中似乎喜欢称之为方法,那下面就都用”方法”来表述吧),此处暂不详表。

对于Forward模块很轻松可以定位到Forwarding.java文件,但是这个文件中或者说Forwarding类中并没有定义receive方法,其实这里可以通过两个途径找到receive函数:1、Forwarding类中首先定义了一个processPacketInMessage方法,见名知义,这个方法是负责处理packet-in消息的,那么通过eclipse中的”open call hierarchy”直接定位到调用该方法的方法,发现是ForwardingBase.java文件中的receive方法;2、Farwording类在声明时继承了ForwardingBase类,可以直接即继承了ForwardingBase类的receive方法。

为了方便描述,以下分析只分析我们关心的流程:Forwarding模块如何向各个交换机添加flow。
通过以上描述,我们找到了Forwarding模块处理packet-in的入口receive方法,该方法中调用了processPacketInMessage方法,该方法又调用doForwardFlow方法。

下面描述doForwardFlow方法的实现细节:

首先声明一个OFMatch对象,并将packet-in中的相关信息加载到该对象中:

OFMatch match = new OFMatch(); match.loadFromPacket(pi.getPacketData(), pi.getInPort());


 

然后通过packet-in消息获取目标和源设备(idevice),即以下代码:

 

IDevice dstDevice =IDeviceService.fcStore.get(cntx, IDeviceService.CONTEXT_DST_DEVICE);if (dstDevice != null) {IDevice srcDevice =IDeviceService.fcStore.get(cntx, IDeviceService.CONTEXT_SRC_DEVICE);

再然后定位发生packet-in消息的switch所属于的island的标志

Long srcIsland = topology.getL2DomainId(sw.getId());

接下来,判断目标和源设备是否处于同一个island,是则继续,否则执行doFlood方法(类似广播),代码如下:

boolean on_same_island = false;boolean on_same_if = false;for (SwitchPort dstDap : dstDevice.getAttachmentPoints()) {long dstSwDpid = dstDap.getSwitchDPID();Long dstIsland = topology.getL2DomainId(dstSwDpid);if ((dstIsland != null) && dstIsland.equals(srcIsland)) {on_same_island = true;if ((sw.getId() == dstSwDpid) &&(pi.getInPort() == dstDap.getPort())) {on_same_if = true;}break;}}if (!on_same_island) {// Flood since we don’t know the dst deviceif (log.isTraceEnabled()) {log.trace(“No first hop island found for destination ” +“device {}, Action = flooding”, dstDevice);}doFlood(sw, pi, cntx);return;}

如果在同一个island中,则通过getAttachmentPoints方法获取目标和源设备相连的交换机的端口信息

SwitchPort[] srcDaps = srcDevice.getAttachmentPoints();Arrays.sort(srcDaps, clusterIdComparator);SwitchPort[] dstDaps = dstDevice.getAttachmentPoints();Arrays.sort(dstDaps, clusterIdComparator);

获取到的结果是两个排序的端口数组,数组的元素类似:

SwitchPort [switchDPID=7, port=2, errorStatus=null]


 

再接下来进入一个while循环,循环的终止条件是取完上一步得到的两个数组中的元素,目标是找到属于同一个island的分布在两个数组中的元素。循环内部先通过getL2DomainId方法判断,所选取的与目标和源相连接的交换机是否在同一个island,如果不在,则根据两个island标志的大小选择性的选取srcDaps或dstDaps中的其它元素,继续比较,之所以可以这么做,是因为两个数组是经过排序的,而且key就是各个交换机所属的island标志,代码为while循环最后的if-else语句:

} else if (srcVsDest < 0) {iSrcDaps++;} else {iDstDaps++;}

如果找到两个island相同的元素,会调用routingEngine的getRoute方法获取两个端口之间的路由,这才是我们真正关心的流程。这里并未继续跟踪getRoute是如何获取两个交换机端口之间的最短路径(官网提到获取的路由是最短路径),其获取的结果类似:

 [[id=00:00:00:00:00:00:00:07, port=2], [id=00:00:00:00:00:00:00:07, port=3], [id=00:00:00:00:00:00:00:05, port=2], [id=00:00:00:00:00:00:00:05, port=3], [id=00:00:00:00:00:00:00:01, port=2], [id=00:00:00:00:00:00:00:01, port=1], [id=00:00:00:00:00:00:00:02, port=3], [id=00:00:00:00:00:00:00:02, port=1], [id=00:00:00:00:00:00:00:03, port=3], [id=00:00:00:00:00:00:00:03, port=1]] 


 


接下来利用最初生成的OFMatch对象信息定义一个规则:

wildcard_hints = ((Integer) sw.getAttribute(IOFSwitch.PROP_FASTWILDCARDS)).intValue()& ~OFMatch.OFPFW_IN_PORT& ~OFMatch.OFPFW_DL_VLAN& ~OFMatch.OFPFW_DL_SRC& ~OFMatch.OFPFW_DL_DST& ~OFMatch.OFPFW_NW_SRC_MASK& ~OFMatch.OFPFW_NW_DST_MASK;

最后调用pushRoute方法,下发路由策略,即flow信息。

pushRoute(route, match, wildcard_hints, pi, sw.getId(), cookie,cntx, requestFlowRemovedNotifn, false,OFFlowMod.OFPFC_ADD);

继续追踪pushRoute函数,其在ForwardingBase.java中实现,其实就是循环上面route获取到的最短路径,在每个交换机上添加一条flow,包含inport和outport,当然上面提到的wildcard_hints也会通过setMatch方法设置到没条flow中。

以上过程建立了从07:2([id=00:00:00:00:00:00:00:07, port=2])到03:1的一条单向通路,从03:1到07:2的通路又是一个相同的过程。
再回到Forwarding.java文件,PushRoute结束之后,while循环会同时增加两个数组的元素下标,继续进行比较判断,这个地方我被迷惑掉了,既然已经找到一条通路,并下发了流表,那接下来的比较意义是什么?找到一个比之前的路径有优的路径?但是流表已经下发了,找到了又会发生什么,而且前面的路径应该是没有记录的,怎么判断更优呢?很奇怪为什么在pushRoute之后没有break掉while循环,邮件开发论坛。

开发论坛回复:the purpose in incrementing those variables is to support forwarding in multi island toplogies. Each island in this case gets a separate route pushed.

无法想象多island的拓扑结构o(╯□╰)o,按照回复所说的,在doForwardFlow函数的第二步

IDevice dstDevice =IDeviceService.fcStore.get(cntx, IDeviceService.CONTEXT_DST_DEVICE);   if (dstDevice != null) {IDevice srcDevice =IDeviceService.fcStore.get(cntx, IDeviceService.CONTEXT_SRC_DEVICE);

获取到的结果

Device [deviceKey=5, entityClass=DefaultEntityClass, MAC=00:00:00:00:00:01, IPs=[10.0.0.1], APs=[SwitchPort [switchDPID=2, port=1, errorStatus=null]]] 

其中APs应该是AttachmentPoints的缩写,如果是多island拓扑结构,这里APs应该是由多个SwitchPort构成的数组!但是想象不出一个设备(一块网卡)如何连接到两个交换机上(猜测桥接)。

无论如何,针对单island的情况上述流程分析是行的通的。

 

0 0
原创粉丝点击