SDN控制器Floodlight源码学习(五)--控制器和交换机交互(3)

上两篇诣在说明控制器和交换机的交互,但是感觉还是没有理的特别清楚

http://blog.csdn.net/crystonesc/article/details/70143117
http://blog.csdn.net/crystonesc/article/details/70170482

今天打算结合openflow协议和代码来说明,openflow版本较多,我选了具有代表性的1.0和1.3版本进行学习,主要还是要搞清楚floodlight中控制器和交换机的交互过程.
前面的两篇文章讲到,控制器与交换机建立连接后,是通过netty的pipeline交由

net.floodlightcontroller.core.internal.OFChannelHandler

这个handler来处理,这个handler主要完成hello,Feature,echo的状态交互,完成这些简单的握手后,OFChannelHandler将连接传递给更高级的处理层面,它是:
net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler
那么这个handler完成更多复杂的交互.值得说明这两个handler都在其内部设置了类似于状态机的内部类来完成状态的切换,所以通过查看这两个状态类,能够很快的跟踪到交互的过程。以下是OFChannelHandler的状态机类:
这里写图片描述
OFSwitchHandshakeHandler 状态机类如下:
这里写图片描述
当然通过抓包也能够很快的看出交互的过程,以下分别为of1.0和of1.3的抓包截图:
这里写图片描述
这里写图片描述
具体这些交互过程在做什么这里不做具体的介绍,有兴趣可以参考
OpenFlow Switch Specification(1.0/1.3)
我们继续往下看代码,在交换机和控制器交互的过程中,控制器会声明自己的角色(master/slave/equal),这里多嘴一句,只有master的控制器才能对交换机进行写的操作,而slave状态的控制器只能够进行读操作。那么我们看看作为master的控制器要做哪些工作:

public class MasterState extends OFSwitchHandshakeState {

        MasterState() {
            super(true);
        }

        @Override
        void enterState() {
            if (OFSwitchManager.clearTablesOnEachTransitionToMaster) {
                log.info("Clearing flow tables of {} on upcoming transition to MASTER.", sw.getId().toString());
                //清除已有的流表
                clearAllTables();
            } else if (OFSwitchManager.clearTablesOnInitialConnectAsMaster && initialRole == null) { /* don't do it if we were slave first */
                initialRole = OFControllerRole.ROLE_MASTER;
                log.info("Clearing flow tables of {} on upcoming initial role as MASTER.", sw.getId().toString());
                clearAllTables();
            }

            sendBarrier(); /* Need to make sure the tables are clear before adding default flows */
            addDefaultFlows();

            /*
             * We also need a barrier between adding flows and notifying modules of the
             * transition to master. Some modules might modify the flow tables and expect 
             * the clear/default flow operations above to have completed.
             */
            sendBarrier();

            setSwitchStatus(SwitchStatus.MASTER);
        }
}

可以看到,在master状态的交换机,首先要清除交换机的流表信息,然后添加默认的流表信息,最后将交换机的中自己的角色设置为master。(交换机是不能够自己修改其中维护的controller的角色的)
同时处于master的控制器还承担这分发交换机上传消息的职责,例如pack_i数据包:

@Override
void processOFPacketIn(OFPacketIn m) {
            dispatchMessage(m);
}
/**
     * Dispatches the message to the controller packet pipeline
     */
private void dispatchMessage(OFMessage m) {
        this.switchManager.handleMessage(this.sw, m, null);
}
 @Override
 public void handleMessage(IOFSwitchBackend sw, OFMessage m, FloodlightContext bContext) {
        floodlightProvider.handleMessage(sw, m, bContext);
 }

最终pack_in数据包的处理是在floodlightProvider中来处理,也就是controller类中.

//controller将消息分发到IOFMessageListeners
@Override
public void handleMessage(IOFSwitch sw, OFMessage m,
                                 FloodlightContext bContext) {
        Ethernet eth = null;
        log.trace("Dispatching OFMessage to listeners.");
        //如果contrller角色不是master,则不进行分发
        if (this.notifiedRole == HARole.STANDBY) {
            counters.dispatchMessageWhileStandby.increment();
            // We are SLAVE. Do not dispatch messages to listeners.
            return;
        }
        counters.dispatchMessage.increment();

        switch (m.getType()) {
            case PACKET_IN:
                counters.packetIn.increment();
                OFPacketIn pi = (OFPacketIn)m;

                //获取packet-in消息的数据
                if (pi.getData().length <= 0) {
                    log.error("Ignoring PacketIn (Xid = " + pi.getXid() + ") because the data field is empty.");
                    return;
                }

                //反序列化pack-in消息中的data
                if (alwaysDecodeEth) {
                    eth = new Ethernet();
                    eth.deserialize(pi.getData(), 0, pi.getData().length);
                }
                // fall through to default case...

            default:

                List<IOFMessageListener> listeners = null;
                if (messageListeners.containsKey(m.getType())) {
                    listeners = messageListeners.get(m.getType()).getOrderedListeners();
                }

                FloodlightContext bc = null;
                if (listeners != null) {
                    // Check if floodlight context is passed from the calling
                    // function, if so use that floodlight context, otherwise
                    // allocate one
                    if (bContext == null) {
                        bc = flcontext_alloc();
                    } else {
                        bc = bContext;
                    }
                    if (eth != null) {
                        IFloodlightProviderService.bcStore.put(bc,
                                IFloodlightProviderService.CONTEXT_PI_PAYLOAD,
                                eth);
                    }

                    // Get the starting time (overall and per-component) of
                    // the processing chain for this packet if performance
                    // monitoring is turned on
                    pktinProcTimeService.bootstrap(listeners);
                    pktinProcTimeService.recordStartTimePktIn();
                    Command cmd;
                    for (IOFMessageListener listener : listeners) {
                        pktinProcTimeService.recordStartTimeComp(listener);
                        cmd = listener.receive(sw, m, bc);
                        pktinProcTimeService.recordEndTimeComp(listener);

                        if (Command.STOP.equals(cmd)) {
                            break;
                        }
                    }
                    pktinProcTimeService.recordEndTimePktIn(sw, m, bc);
                }
                // paag
                // And just before we exit the controller loop we see if anyone
                // is interested in knowing that we are exiting the loop
                for (IControllerCompletionListener listener : completionListeners)
                    listener.onMessageConsumed(sw, m, bc);

                if ((bContext == null) && (bc != null)) flcontext_free(bc);
        }
    }

可以看出pack_in消息会通过controller传递给其它实现了IOFMessageListeners的模块,由模块进行处理。至此交换机和控制器的数据就进入了各个模块中进行处理。下一节应该学习学习模块了.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章