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的模塊,由模塊進行處理。至此交換機和控制器的數據就進入了各個模塊中進行處理。下一節應該學習學習模塊了.

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