OSGi框架實例化controller類,初始化其變量包括事件隊列、消息監聽及交換機監聽器集合,然后創建事件處理線程,在創建I/O處理線 程。controllerIOThread監聽底層交換機連接請求,建立連接則監聽消息,當收到消息后判斷消息類型再調用相應方法處理:
123456789101112131415161718192021while(running){try{//waitforan incoming connection//check interfacestate every5secselector.select(5000);IteratorhandleNewConnection從事件隊列中獲取處理事件,如果是新增交換機事件,則換存該交換機并通知監聽器交換機信息改變;如果是刪除或異常事件,則斷開I/O連接;如果是OFMessage消息,則通知SwitchHandler來處理該消息。
I/O處理線程中的消息處理TCP 連接建立后,交換機和控制器就會互相發送 hello 報文(SwitchHandler處理函數handleMessages處理的第一個消息類型)。Hello 報文是使用 OpenFlow 協議的一個對稱的數據包。Hello 報文中唯一的內容 是 OpenFlow 報文頭中的“類型值=0”。
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758for(OFMessage msg:msgs){logger.trace("Message received: {}",msg);this.lastMsgReceivedTimeStamp=System.currentTimeMillis();OFType type=msg.getType();switch(type){caseHELLO:sendFeaturesRequest();break;caseECHO_REQUEST:OFEchoReply echoReply=(OFEchoReply)factory.getMessage(OFType.ECHO_REPLY);byte[]payload=((OFEchoRequest)msg).getPayload();if(payload!=null&&payload.length!=0){//the response must have the same payload asthe requestechoReply.setPayload(payload);echoReply.setLength((short)(echoReply.getLength()+payload.length));}//respond immediatelyasyncSendNow(echoReply,msg.getXid());//send features request ifnotsent yetsendFeaturesRequest();break;caseECHO_REPLY:this.probeSent=false;break;caseFEATURES_REPLY:processFeaturesReply((OFFeaturesReply)msg);break;caseGET_CONFIG_REPLY://makesure that the switchcan send the whole packet tothe//controllerif(((OFGetConfigReply)msg).getMissSendLength()==(short)0xffff){this.state=SwitchState.OPERATIONAL;}break;caseBARRIER_REPLY:processBarrierReply((OFBarrierReply)msg);break;caseERROR:processErrorReply((OFError)msg);break;casePORT_STATUS:processPortStatusMsg((OFPortStatus)msg);break;caseSTATS_REPLY:processStatsReply((OFStatisticsReply)msg);break;casePACKET_IN:break;default:break;}//endof switchif(isOperational()){((Controller)core).takeSwitchEventMsg(thisISwitch,msg);}}//endof for1.首先讀取到Hello消息后,發送請求報文(Feature Request)。這是控制器發向交換機的一條Openflow消息,目的是為了獲取交換機性能,功能以及一些系統參數。該報文中OpenFlow數據頭“類型值=5”。
2.Echo請求(Echo request)和Echo 響應(Echo reply)屬于OpenFlow中的對稱型報文,他們通常作為在OpenFlow交換機和OpenFlow控制器之間保持連接的消息(Keep- alive)來使用。通常echo請求使用OpenFlow數頭“類型值=2”,echo響應使用OpenFlow數據頭“類型值=3”。不同各廠商提供 的不同實現中,echo請求和響應報文中攜帶的信息也會有所不同。如果是Echo request消息,則發送Echo reply響應和Feature Request請求消息;如果是Echo reply消息,則標識交換機正常連接。
3. 控制器和交換機之間的連接經過 TCP 建立、Hello 報文、功能請求與響應環節后建立。這些連接的存在是 Packet-In 事件發生的前提。交換機怎樣觸發 Packet-In 事件。當 OpenFlow 交換機收到數據包后,如果流表中與數據包沒有任何匹配條目,這時候 Packet-In 事件就被觸發了,交換機會將這個數據包封閉到Openflow 協議報文中發送至控制器。 opendaylight中Packet-In 事件是交給了IMessageListener監聽器的實現類來處理的,比如DataPacketMuxDemux類,Packet-In 域提供數據包的信息,這些信息都是在那些特定的 Packet-In 被封裝的。得到 Packet-In 信息后,控制器根據需要對原始數據包做出處理。
12345678910caseSWITCH_MESSAGE:OFMessage msg=ev.getMsg();if(msg!=null){IMessageListener listener=messageListeners.get(msg.getType());if(listener!=null){listener.receive(sw,msg);}}break;4.控制器要發送數據包至交換機時,就會觸發 Packet-Out 事件將數據包發送至交換機。這一事件的觸發可以看做是控制器主動通知交換機發送一些數據報文的操作。通常,當控制器想對交換機的某一端口進行操作時,就會使用 Packet-Out 報文。
5. 交換機端口狀態發生改變(端口 up/down、增添或移除)或者端口配置標志發生改變時,會觸發端口狀態(Port Status)消息事件的發生。這一消息由 OpenFlow 交換機觸發,端口狀態(Port Status)消息由 OpenFlow 交換機發往控制器,用于通告交換機端口狀態的改變。
6. 當控制器想要改變交換機的配置時,就會發送一個設置配置信息,這信息是控制器—>交換機信息。設置配置信息(Set Configuration)包括:
交換機配置標志Miss發送長度,表示重新配置后發送至控制器的流的最大8位字節,默認值1287.獲取配置請求的報文(Get Config)中沒有內容(只包含 OpenFlow 常規數據頭);OpenFlow 交換機通過“TypeCode = 7”識別這個報文。 交換機發出配置答復消息作為反饋,該消息包含了交換機的所有配置信息,配置答復消息包括:
交換機配置標志Miss發送長度表示發送至控制器的新的流的最大8位字節,默認值1288.當控制器需要增添、修改或刪除交換機中流表的時候,觸發 修改流(Flow-Modification)事件。
9.控制器(管理員)試圖修改端口配置標志—“admin down,” “no STP,” “no receive,” “no receive STP,” “no flood,” “no FWD,” “no packet-in” 的時候,會觸發修改端口(Port-Modify)事件。
10.當控制器試圖從交換機處獲得不同類型的統計數據信息時,統計(Stats)請求和響應事件被觸發。
11.當控制器試圖了解其分配給 OpenFlow 交換機的任務是否完成或將在何時完成的時候,Barrier 請求和響應事件將被觸發。Barrier 請求消息用OpenFlow 數據頭消息“類型值=19”表示。 收到請求消息的交換機,在完成控制器分配的任務后,會發送響應消息至控制器。 障礙響應消息用 OpenFlow 數據頭消息“類型值=20”表示,并附有 Barrier 請求消息的交換標識。
12.當控制器試圖問詢 OpenFlow 交換機端口的隊列配置時候,觸發隊列獲取配置(Queue Get Configuration)請求和響應事件。隊列請求包括所請求隊列信息的端口號。隊列配置響應消息包括端口號和該端口的隊列配置信息。
13.當控制器發送的數據包不能被讀出或支持,或者交換機不能執行的時候,就產生了錯誤事件。所以任何發送至交換機的控制數據包都可能觸發錯誤事件。
鏈路發現(LLDP)OF協議模塊還提供鏈路發現服務,它為拓撲模塊提供鏈路數據支持(topomanager實現IListenTopoUpdates的 edgeUpdate,它是有TopologyServiceShim中的線程TopologyNotify調用,此線程是個阻塞線 程,notifyEdge方法使得notifyQ的成員的增加會觸發此線程,而notifyEdge是由DiscoveryService的 updateEdge調用的,依次addEdge,processDiscoveryPacket,receiveDataPacket DataPacketMuxDemux通過receive調用receiveDataPacket receive是由Controller監聽SWITCH_MESSAGE消息時調用的)。
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849public PacketResult receiveDataPacket(RawPacket inPkt){if(inPkt==null){logger.debug("Ignoring null packet");returnPacketResult.IGNORED;}byte[]data=inPkt.getPacketData();if(data.length<=0){logger.trace("Ignoring zero length packet");returnPacketResult.IGNORED;}if(!inPkt.getEncap().equals(LinkEncap.ETHERNET)){logger.trace("Ignoring non ethernet packet");returnPacketResult.IGNORED;}NodeConnector nodeConnector=inPkt.getIncomingNodeConnector();if(((Short)nodeConnector.getID()).equals(NodeConnector.SPECIALNODECONNECTORID)){logger.trace("Ignoring ethernet packet received on special port: "+inPkt.getIncomingNodeConnector().toString());returnPacketResult.IGNORED;}if(!connectionOutService.isLocal(nodeConnector.getNode())){logger.debug("Discoery packets will not be processed from {} in a non-master controller",nodeConnector.toString());returnPacketResult.IGNORED;}Ethernet ethPkt=newEthernet();try{ethPkt.deserialize(data,0,data.length*NetUtils.NumBitsInAByte);}catch(Exceptione){logger.warn("Failed to decode LLDP packet from {}: {}",inPkt.getIncomingNodeConnector(),e);returnPacketResult.IGNORED;}if(ethPkt.getPayload()instanceofLLDP){NodeConnector dst=inPkt.getIncomingNodeConnector();if(isEnabled(dst)){if(!processDiscoveryPacket(dst,ethPkt)){//Snoop the discovery pkt ifnotgenerated from ussnoopDiscoveryPacket(dst,ethPkt);}returnPacketResult.CONSUME;}}returnPacketResult.IGNORED;}控制器在執行鏈路發現過程時,會首先通過一個packet-out消息向所有與之連接的交換機發送LLDP數據包,該消息命令交換機將LLDP數據 包發送給所有端口,一旦交換機接收到packet-out消息,他就會把LLDP數據包通過其所有的端口發送給與之連接的設備,如果其鄰居交換機是一臺 OpenFlow交換機,那么該交換機將自行相應的流表查找操作。因為交換機中并沒有專門的流表項用于處理LLDP消息,所有它將通過一個packet- in消息將數據包發送給控制器。而控制器在收到packet-in消息后,會對數據包進行分析并在其保存的鏈路發現表中創建2臺交換機之間的鏈接記錄。網 絡中其他交換機也都采用相同的方式向控制器發送packet-in消息,因此控制器就能夠創建完整的網絡拓撲視圖,基于這樣的視圖,控制器可以根據業務應 用的流量需求,為每臺交換機推送下發不同的流表項。鏈路發現可分為兩個部分:
1.LLDP數據分組監聽解析,通過LLDP分組中LTV信息獲得節點鏈路狀態,保存到本地同時通知拓撲模塊變化及時更新。
2.自動鏈路探測部分,通過控制器的交換機連接信息獲取探測節點,發送LLDP探測分組,再由監聽部分獲取探測分組更新鏈路。