前言
看源码最痛苦的是知其然而不知其所以然,当然也有人建议我不要在意这些细节~~,可是看不懂浑身不舒服啊亲,我也希望自己有高超的写代码能力,事实是还需努力。接触Floodlight这么久了,以前做的最多的是调用RET API进行一些实验,改过官方为开发者提供的MACTracker代码,但实际上没花太多时间看源码,最近做实验啥的感觉瓶颈了,唉,遂决心好好研究一下源码,看是否能给自己新的灵感。此次参考的源码是我修改过的MACTracker,我将要分析的是其中对Packet_in事件处理的方法recevie()。
Packet_in处理分析
首先,贴上代码,主要功能是获取连上控制器的主机的MAC地址,IP地址并在控制台显示出来。
public net.floodlightcontroller.core.IListener.Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) { |
Packet_in包处理流程
1.receive()是模块用来处理Packt_in数据包的函数,每个需要处理Packet_in包的模块均默认以它命名,所以它们获取OpenFlow消息的方式也是相同的。
2.首先通过代码
Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD) |
获取消息。其中通过调用接口IFloodlightProviderService的静态方法bcstore获取OpenFlow消息,而该消息是一个Ethernet对象。我们可以通过Ethernet里的方法getSourceMACaddress()获取该报文的源MAC地址;然后再通过getPayload()获取报文的有效载荷(所谓有效载荷,指的是除去协议头部之外实际传输的数据),根据有效载荷可以判断报文的协议类型:ARP,IPv4,ICMP,DUCP等网络层协议类型。
3.若是IPv4包:IPv4类里有个方法getSourceAddress()获取源IP地址(二进制),通过方法fromIPv4Address将IP地址转换为点分十进制的。
bcstore
bcstore是接口IFloodlightProvider里定义的一个对象,主要是存储OpenFlow消息,消息的对象是Ethernet类型的。bcstore本身是FloodightContextStore<>类型的,该类型有个方法用来获取存储的消息:get(FloodlightContext bc,String key).方法具体实现如下:
public V get(FloodlightContext bc, String key) { |
return.Command.CONTINUE
最开始照着开发者文档做的时候,看到recieve()结尾处的return.Command.CONTINUE的解释是“该方法返回Command.CONTINUE以便其他处理程序继续处理”,而且我查看了其他好几个模块recieve函数返回值都是Command.CONTINUE,于是就找到了Command的源头。原来Command是接口Ilistener下的一个枚举类型:
public enum Command { |
当时我就纳闷了,返回一个枚举类型值,谁来处理它?怎么处理这个值以实现能让其他模块继续执行的功能?于是我挨个模块源码寻找,终于在模块net.floodlight.core.internal.controller找到了它的身影:
pktinProcTime.recordStartTimePktIn(); |
这段代码就是对recevie()返回值进行处理,如果返回的是STOP,则该事件停止处理,也就是当前模块处理完后其他模块就没法处理了,而默认情况下事件会被每个模块遍历处理,所以我们会看到大多处理事件的模块返回的值都是CONTINUE。