一 、摘要
本文主要針對Openflowjava部分進行實例簡述,初學(xué)者需要對java了解一些,總結(jié)一些我自己的學(xué)習(xí)收獲漓拾,不足之處請指正。
Openflowjava工程作為Opendaylight南向接口的協(xié)議棧存在长赞,與openflowplugin工程及外部的netty.io網(wǎng)絡(luò)庫緊密聯(lián)系晦攒。其主要作用是接受南向接口上報的消息、解碼得哆、將其交給Openflowplugin以便進一步上報以及接收Openflowplugin傳達的發(fā)送消息的指令并將其編碼為字節(jié)流從南向接口中發(fā)出。結(jié)構(gòu)上與功能相關(guān)的是Openflow-protocol-api及Openflow-protocol-impl兩個文件夾下的代碼哟旗。 前者中用一系列yang文件定義了控制器支持的Openflow消息結(jié)構(gòu)及對應(yīng)的收贩据、發(fā)行為栋操,后者包含了消息的解碼、編碼及上報饱亮、下發(fā)的功能邏輯矾芙。
netty.io網(wǎng)絡(luò)庫在Opendaylight中負責(zé)處理控制器與switch間的TCP連接〗希控制器接收上報的Openflow消息時剔宪,消息的二進制字節(jié)流會被裝入netty的Bytebuf類對象中傳遞給Openflowjava來提供解碼,發(fā)送消息時壹无,消息相關(guān)的數(shù)據(jù)在編碼序列化后被封裝進Bytebuf類中交給netty完成發(fā)送葱绒。Openflowplugin作為opendaylight處理openflow消息的外掛組件進一步負責(zé)解碼后消息的分類、處理斗锭、上傳以及發(fā)送消息時控制器指令數(shù)據(jù)的分發(fā)地淀、消息體數(shù)據(jù)的組織與打包。Openflowplugin控制著openflow消息收發(fā)的流程和邏輯岖是,openflowjava作為其末端動作的執(zhí)行者存在帮毁。
二?、Openflow-protocol-api部分開發(fā)
openflow-protocol-api文?件?夾?下?的?代?碼?主?要?是openflow-protocol-api/src/main/yang路徑下的一系列yang文件豺撑,yang是一種表示結(jié)構(gòu)與屬性的語言烈疚,同時也是一個RFC標(biāo)準(zhǔn)(RFC6020)?。Opendaylight使用這種語言來定義其所支持的openflow消息結(jié)構(gòu)以及消息的收發(fā)動作聪轿。在項目編譯階段爷肝,maven會調(diào)用opendaylight的yangtools工具根據(jù)yang文件生成一系列java文件,包括各openflow消息的容器類屹电、?容器類的構(gòu)造器以及偵聽并接收這些容器類的接口阶剑。?通過yang文件,我們可以簡單清晰地定義我們需要的消息類型以及其上傳/下發(fā)管道危号。
在上述路徑下最為重要的是openflow-protocol.yang及openflow-types.yang兩個文件牧愁,前者定義了openflow消息和動作,后者包含了自定義外莲、非yang語言內(nèi)置的特殊數(shù)據(jù)類型猪半。此目錄下我們主要進行yang文件的改寫,將一些協(xié)議的字段寫成yang的形式偷线,主要進行openflow-protocol.yang與openflow-types.yang兩個model中的協(xié)議添加磨确。
在openflow-protocol.yang文件中,grouping語句用于定義一個數(shù)據(jù)結(jié)構(gòu)塊声邦,uses語句可將其他grouping結(jié)構(gòu)塊復(fù)用進當(dāng)前結(jié)構(gòu)塊乏奥。通過這種方法可定義對應(yīng)于所有openflow消息的數(shù)據(jù)結(jié)構(gòu)塊。但這些結(jié)構(gòu)快并非對openflow消息中所有字段的映射亥曹。如果這是一個從南向接口接受的消息邓了,則結(jié)構(gòu)快中只需要包含希望從消息獲取并進一步上報的字段恨诱。如果是發(fā)送的消息,其結(jié)構(gòu)快中只需要包含那些來自于控制器指令的數(shù)據(jù)骗炉。而length照宝、padding等字段則不需要包括。也就是說句葵,yang文件中消息的定義是對實際的openflow消息中有用數(shù)據(jù)的一種抽象厕鹃。下面是yang文件中對flow-stats消息的數(shù)據(jù)結(jié)構(gòu)塊定義。
在定義了消息結(jié)構(gòu)后乍丈,還需要在同一yang文件內(nèi)定義消息的行為剂碴。相關(guān)的語句是notification和rpc。notification用于定義控制器被動等待收取的消息的收取行為诗赌。rpc用于定義控制器主動發(fā)送的消息的發(fā)送行為以及可能的switch應(yīng)答消息的收取行為汗茄。如使用notification定義的hello消息的收取行為是:
其中input語句塊是發(fā)送的定義,output語句塊是收取的定義铭若,uses語句后的是之前定義的對應(yīng)消息的結(jié)構(gòu)塊洪碳。利用上述的yang語法我們就可以定義各個openflow消息的結(jié)構(gòu)和行為了。在openflow-protocol-api目錄或openflowjava根目錄下用maven完成項目編譯后在openflow-protocol-api/target/generated-sources/sal路徑下可以找到y(tǒng)ang文件生成的消息結(jié)構(gòu)相關(guān)的java文件叼屠。他們將會在編解碼中被用到瞳腌。Yang和java之間的對應(yīng)生成關(guān)系詳見opendaylight的如下wiki頁面。
三?镜雨、Openflow-?-?protocol-?-?impl部分
該文件夾下的開發(fā)主要針對消息的編解碼模塊以及上報/下發(fā)邏輯嫂侍。先講解碼模塊及邏輯流程。解碼模塊位于路徑Openflow?protocolimpl/src/main/java/org/opendaylight/openflowjava/protocol/impl/deserialization
TypeToClassMapInitializer.java和MessageDeserializerInitializer.java兩個文件荚坞。它們初始化兩張表挑宠,前者包含了openflow消息type值到消息類型的映射關(guān)系,?后者包含了消息type值颓影、?消息類型和對應(yīng)的解碼模塊間的映射關(guān)系各淀。
根據(jù)這兩張表,可以將netty傳遞來的包含了openflow消息二進制字節(jié)流的Bytebuf對象傳遞給對應(yīng)消息類型的解碼模塊诡挂。如果對opendaylight的消息有增刪修改的話碎浇,?需要相應(yīng)地調(diào)整這兩張表,?同事import語句也需要做相應(yīng)調(diào)整璃俗。解碼模塊位于路徑openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/deserialization/factories下奴璃,每一個java文件對應(yīng)一種消息。文件中的java類繼承OFDeserializer和DeserializerRegistryInjector兩個類城豁,解碼過程由其中的deserialize方法實現(xiàn)苟穆。這個方法接受netty傳來的一個Bytebuf類實例rawmessage作為參數(shù),在內(nèi)部使用yang文件生成的該類型消息的的構(gòu)造器及消息子結(jié)構(gòu)的構(gòu)造器(xxbuilder)以及Bytebuf類的方法進行解碼。具體來說鞭缭,使用Bytebuf的一系列read方法線性地將rawmessage中存儲的二進制字節(jié)流中的各消息字段讀出來剖膳,然后使用消息構(gòu)造器或消息子結(jié)構(gòu)構(gòu)造器的set函數(shù)寫入到消息構(gòu)造器的各實例域中魏颓。每調(diào)用一次rawmessage的read方法岭辣,rawmessage中指示讀取位置的一個游標(biāo)就會向后移動相應(yīng)位數(shù),以便下次調(diào)用時讀取下一個字段甸饱。讀取和寫入的順序按照消息中字段的順序沦童。?如此將一條消息中所有有用的字段都讀取并賦給消息的構(gòu)造器(xxbuilder)?,最終構(gòu)造器使用自己的build方法返回作為解碼結(jié)果的類實例叹话。這個類的定義同樣是由yang文件編譯生成的偷遗。Hello消息的示例代碼如下:
解碼的結(jié)果——一個類實例將被傳遞給connectionadapter模塊, 該模塊的實現(xiàn)位于
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/connection/ConnectionAdapterImpl.java文件中驼壶,?其中一系列以Future>為返回值的函數(shù)是yang中使用rpc定義的消息動作的收發(fā)實現(xiàn)氏豌,而consume方法是notification定義的消息動作的實現(xiàn)。先看consume方法热凹,解碼的結(jié)果——一個類實例作為參數(shù)message傳遞進來泵喘,在方法內(nèi)部使用一系列if語句判斷該message屬于何種消息的類,?一旦匹配則傳遞給messageListener類中相應(yīng)的on方法(這些on方法是根據(jù)yang文件中的notification語句生成的)般妙,之后message就被傳遞到openflowplugin中去了纪铺。示例如下:
編碼模塊位于路徑openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/serialization下,其中的MessageFactoryInitializer.java用于初始化一張表碟渺,表示將要發(fā)送的消息類型與其編碼模塊間的映射關(guān)系鲜锚。Openflowjava得到openflowplugin傳遞來的消息類實例調(diào)用connectionadapterimpl中的那些以Future>為返回值的函數(shù)并通過這張表找到需要的編碼模塊。實際的編碼工作在路徑openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/serialization/factories下的java文件中展開苫拍。這些類繼承OFSerializer<>類芜繁,其中的serialize方法以openflowplugin傳遞來的xxinput類實例message和Bytebuf類實例outBuffer為參數(shù)。將message中的實例域提取出來傳遞給
outBuffer绒极,調(diào)用outBuffer的一系列write方法將其以二進制字節(jié)流形式寫入outBuffer中骏令,寫入的順序按照openflow消息的定義,其中也可能包括消息子結(jié)構(gòu)的編碼集峦,類似于解碼中的子結(jié)構(gòu)解碼伏社。除了message中包含的字段外,還需要根據(jù)情況填寫length塔淤、padding等字段摘昌。填寫完畢后outBuffer由netty完成對外發(fā)送,編碼的流程就此結(jié)束高蜂。至此openflowjava工程中的工作結(jié)束聪黎。
四?、?總結(jié)
以上是關(guān)于openflowjava部分的開發(fā)文檔簡述,?具體的消息類型或協(xié)議可以自行進行添加和修改稿饰,本人知識水平有限锦秒,不足之處還請諒解。
本篇文章由OpenDaylight群(194240432)@北郵-Kobe提供喉镰,歡迎共同探討旅择。