開發者文檔
模塊描述及javadoc
控制器模塊
簡介:
控制器模塊實現了大多數應用程序常用的一些功能,例如:
a).發現和揭露網絡狀態和事件
b)實現控制器和網絡交換機的通訊
c)控制Floodlight模塊以及資源共享,如存儲、線程、測試
d)實現一個web UI以及調試服務器
FloodLight目前已經實現的控制器模塊
FloodlightProvider
描述:
FloodlightProvider提供了兩個主要部分的功能,它處理交換機之間的連接並且將OpenFlow的消息轉化成其他模塊可以監聽的事件。第二個主要的功能,它決定某些特定的OpenFlow消息(即PacketIn,FlowRemoved,PortStatus等)被分派到該偵聽消息的模塊的順序。然後模塊可以決定允許該消息進入下一個監聽對象或停止處理消息。
提供的服務:
· IFloodlightProviderService
服務依賴性:
· IStorageSourceService
· IPktinProcessingTimeService
· IRestApiService
· ICounterStoreService
· IThreadPoolService
Java實現位置:
net.floodlightcontroller.core.FloodlightProvider.
如何工作:
FloodlightProvider使用Netty庫來處理到交換機的線程和連接,每個OpenFlow消息將通過一個Netty的線程進行處理,並執行與所有模塊的消息相關聯的所有邏輯。其他模塊也可以註冊類似交換機連接或斷開和端口狀態通知特定事件。FloodlightProvider將把這些線協議通知轉換成基於Java的消息,以便其它模塊可以處理。爲了使模塊註冊爲基於OpenFlow消息的,他們必須實現IOFMessageListener接口。
侷限性:
None
配置:
該模塊是默認啓用的,要想加載此模塊,不需要改變任何配置
配置選項:
Name |
Type |
Default |
Description |
openflowport |
Int |
6633 |
TCP端口用於監聽來自支持OpenFlow的設備的連接。 |
workerthreads |
Int |
0 (2 * # of CPUs) |
產生的Netty線程數,如果這個數字爲0,則線程數默認爲機器CPU數量的兩倍。 |
controllerid |
String |
localhost |
控制器的ID |
role |
String |
master |
值可以是: master, slave, equal。從(slave)控制器將不接受來自交換機連接,留作備用。 |
REST API :
URI |
Description |
Arguments |
|
/wm/core/switch/all/<statType>/json |
獲取所有交換機的狀態 |
statType: port, queue, flow, aggregate, desc, table, features, host |
|
/wm/core/switch/<switchId>/<statType>/json |
獲取單個交換機的狀態 |
switchId: Valid Switch DPID (XX:XX:XX:XX:XX:XX:XX:XX) |
|
/wm/core/controller/switches/json |
列出所有連接到控制器的交換機DPID |
none |
|
/wm/core/role/json |
獲得當前的控制器角色 |
None. |
|
/wm/core/counter/<counterTitle>/json |
控制器中的所有流量計數列表 |
counterTitle: "all" or something of the form DPID_Port#OFEventL3/4_Type. See CounterStore.java for details. |
|
/wm/core/counter/<switchId>/<counterName>/json |
某個交換機的流量計數列表 |
switchId: Valid Switch DPID |
|
/wm/core/memory/json |
當前控制器的內存使用情況 |
none |
|
/wm/core/module/{all}/json |
模塊以及模塊依賴性的返回信息 |
all: "all" or "loaded". |
|
DeviceManagerImpl
描述:、
DeviceManagerImpl追蹤網絡周圍的設備,併爲目標設備定義一個新的流。
提供的服務:
IDeviceService
服務依賴性:
IStorageSourceService
IRestApiService
ICounterStoreService
IThreadPoolService
IFlowReconcileService
IFloodlightProviderService
Java實現位置:
net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl.
如何工作:
設備管理器通過PacketIn請求瞭解設備,通過PacketIn消息獲取信息,根據實體如何建立進行分類。默認情況下,entity classifies使用了MAC地址和VLAN來識別設備。這兩個屬性定義一個獨一無二的設備,設備管理器將瞭解其他屬性,如IP地址。信息中一個重要的部分是設備的連接點,如果一個交換機接收到一個PacketIn消息,則交換機將會創建一個連接點, A device can have as many as one attachment point per OpenFlow island, where an island is defined as a strongly connected set of OpenFlow switches talking to the same Floodlight controller. 設備管理器也將根據時間清空連接點,IP地址,以及設備本身。最近看到的時間戳是用來保持清空過程的控制。
限制:
設備是不可變的,這意味着你不能持有設備的引用,這些引用必須通過IDeviceService APIs獲取。
配置:
該模塊是默認啓用的,加載模塊不需要改變任何配置。
配置參數:
None
REST API :
URI |
Description |
Arguments |
|
/wm/device/ |
控制器追蹤設備的列表,包括 MACs,IPs以及接入點 |
Passed as GET parameters: mac (colon-separated hex-encoded), ipv4 (dotted decimal),vlan, dpid attachment point DPID (colon-separated hex-encoded) and port the attachment point port. |
|
通過curl調用簡單的REST
獲取所有設備:
curl -s http://localhost:8080/wm/device/ |
獲取IP地址爲1.1.1.1的設備:
LinkDiscoveryManager (Dev)
描述:
鏈接發現服務負責發現和維護OpenFlow網絡中的網絡鏈接的狀態。
提供的服務:
ILinkDiscoveryService
服務依賴性:
IStorageSourceService
IThreadPoolService
IFloodlightProviderService
Java實現位置:
net.floodlightcontroller.linkdiscovery.internal.LinkDiscoveryManager.
如何工作:
鏈路發現服務使用LLDPs和廣播包檢測鏈路。LLDP的目的MAC爲01:80:C2:00:00:0 e和BDDP目的MAC是FF:FF:FF:FF:FF:FF(廣播地址),LLDP和BDDP的以太類型爲 0x88cc 和 0x8999。爲了使拓撲結構被正確的學習,還有兩個假設:
A).任何交換機(包括OpenFlow交換機)將包括一個本地鏈路包(LLDP)
B).Honors layer 2 broadcasts
鏈路可以是直接的或廣播的,如果一個LLDP從一個端口被送出並被另一個端口接受,則建立直接的鏈路,這意味着端口是直連的。如果一個BDDP從一個端口發出,被另一個端口接受,這意味着還有另外一個二層交換機沒有這在兩個端口之間的控制器的控制下。
限制:
None
配置:
該模塊是默認啓用的,加載模塊不需要改變任何配置。
配置參數:
None
REST API
URI |
Description |
Arguments |
|
/wm/topology/links/json |
列出控制器檢測出的所有鏈路 |
None. |
|
通過curl調用簡單的REST
獲得所有設備:curl -s http://localhost:8080/wm/topology/links/json
TopologyService
描述:
TopologyService爲控制器維護拓撲信息,以及在網路中尋找路由。
在網絡中提供的服務:
ITopologyService
IRoutingService
服務依賴性:
ILinkDiscoveryService
IThreadPoolService
IFloodlightProviderService
IRestApiService
Java位置:
net.floodlightcontroller.topology.TopologyManager.
如何工作:
拓撲服務基於從lLinkDiscoveryService學習到的鏈路信息進行計算拓撲,該TopologyService保持的一個重要概念是OpenFlow的“island”的想法。一個island被定義爲一組同一floodlight實例下強連接d的OpenFlow交換機。isLand可以使用在同一個2層域中非OpenFlow的交換機進行互連,例如:
[OF switch 1] -- [OF switch 2] -- [traditional L2 switch] -- [OF switch 3]
兩個island將由拓撲服務來形成,isLand1包含switch1和switch2,而island2只包含switch3。
當前的拓撲信息將被存儲在稱爲拓撲實例的不可變的數據結構中,在拓撲結構中如果有任何變化,一個新的實例將被創建並且拓撲變化通知消息將被調用。如果其他模塊想監聽拓撲結構的變化,它們需要實現 ITopologyListener接口。
限制:
儘管你可以在一個OpenFlow isLand中有冗餘鏈路,但不可以有從非OpenFlow交換機到OpenFlow island的冗餘鏈路。
配置:
此模塊被默認加載,不需要其它配置。
配置參數:
None
REST API
URI |
Description |
Arguments |
/wm/topology/switchclusters/json |
列出由控制器計算出的交換機集羣 |
None. |
簡單應用:
獲取所有設備:
Curl -s http://localhost:8080/wm/topology/switchclust
RestApiServer
描述:
REST API服務器允許模塊通過HTTP暴露REST API。
提供的服務:
IRestApiService
服務依賴性:
None
Java位置:
net.floodlightcontroller.restserver.RestApiServer.
如何工作:
REST API服務使用Restlets library。通過REST服務器作爲一個依賴的其他模塊通過添加一個實現RestletRoutable的類進行公開API。每個RestletRoutable包含附加一個Restlet資源的路由器(最常見的是ServerResource)。用戶會附上自己的類擴展Restlet的資源,以處理特定URL的請求。裏面的資源註釋,如@ GET,@ PUT等,都是選擇哪個方法將被用於HTTP請求。序列化通過包含在Restlet庫中的Jackson library實現。Jackson可以通過兩種方式進行序列化對象,第一,它會自動使用可用的getter對對象進行序列化這些字段,否則,自定義序列化可以創建和註釋在類的頂部。
限制:
基本的路徑不能重疊,並且是唯一的。
Restlets只能通過服務接口訪問模塊的數據。如果一個模塊需要通過REST服務器來公開數據,則它必須通過公開接口來得到這個數據。
配置:
此模塊被默認加載,不需要其它配置。
配置參數:
Name |
Type |
Default |
Description |
port |
Int |
8080 |
The TCP port to listen on for HTTP connections. |
None.
ThreadPool
描述:
ThreadPool是一個floodlight模塊被封裝爲一個Java的ScheduledExecutorService,它可用於使線程在特定的時間或週期性地運行。
提供的服務:
IThreadPoolService
服務依賴性:
None
文件位置:
net.floodlightcontroller.threadpool.ThreadPool.
限制:
None
配置:
此模塊被默認加載,不需要其它配置。
配置參數:
None
REST API:
None
MemoryStorageSource
描述:
該MemoryStorageSource是在內存中的NoSQL風格的存儲源。也支持更改通知數據庫
提供服務:
IStorageSourceService
服務依賴性:
ICounterStoreService
IRestApiService
Java位置:
net.floodlightcontroller.storage.memory.MemoryStorageSource.
如何工作:
其它依賴於IStorageSourceService 接口的FloodLight模塊可以create/delete/modify 內存資源中的數據,所有的數據是共享的,且沒有強制執行。模塊還可以註冊在制定表和制定行的數據中進行修改,其它任何想實現這樣功能的模塊需要實現IStorageSourceListener 接口。
限制:
一旦數據存儲在內存中,當FloodLight關閉時,所有的狀態將會丟失。
沒有隔離強制執行的數據,即使一個模塊創建了一張表,另一個模塊可以覆寫那部分數據。
配置:
此模塊被默認加載,不需要其它配置。
配置參數:
None
REST API:
Flow Cache
flowCache API 由於記住在網絡中一系列不同類型的事件的需要而被定義,而事件的處理,以及如何處理往往構建於不同的Floodlight SDN應用程序。例如,處理交換機/鏈路故障事件流是大多數應用程序最典型的需要。
Floodlight定義了一個流緩存API和一組框架方法作爲通用框架爲應用程序開發人員實現適合他們的應用需求的解決方案。
我們正在努力的編寫API,晚些時候會提交到floodlight的官方網站上,與此同時,API調用簡潔的說明也可以在flow cache源中找到。
交換機/鏈路故障事件的例子:
對於流緩存目的的一個更高層次的解釋,我們可以通過switch/link中斷事件的生命週期來了解各種被調用的模塊。
1.目前,當LinkDiscoveryManager檢測到鏈路或端口出現故障,該事件由在TopologyManager中的一個“NewInstanceWorker”線程處理。請注意,在線程結束時,它調用informListeners,這是一個標記用於告知此事件於其它對處理此事件有興趣的模塊。
2.所以,你會從實現一個實現了ITologyListener接口和topologyChanged()方法的模塊開始,並且通過調用TopologyManager.addListener將此模塊添加到偵聽器列表中。
3.在這個模塊中你可以通過 Topology.getLastLinkUpdates()方法獲取所有的之前發現的拓撲變化,並對事件進行排序去查看你感興趣的事件。一個交換機出現故障導致相鄰交換機鏈路斷開,所以你應該尋找ILinkDiscoery.UpdateOperation.LINK_REMOVED事件(每個受影響的交換機有一個事件),找到的條目將告訴你所涉及的交換機端口。
4.接下來是要查詢每一個受影響的交換機中所有的流表和受影響的端口進行匹配。該查詢應該是一個OFStatisticsRequest消息,該消息將通過sw.sendStatsQuery()被送到交換機。
5.一旦查詢被髮送出去,稍後你會收到響應,爲了能夠接收到OF包的響應,你的模塊必須實現IOFMessageListener接口以及OFType.STATS_REPLY消息。一旦你接收到響應,你會看到它所有的流表項。現在你可以決定是否想要創建刪除流表修改消息來清理流表項。
這似乎已經解決了這個問題,但我們還沒有用到過流緩存以及與其相關的服務接口呢。
流緩存的概念是爲了使控制器記錄所有有效流,並且當事件被一個控制器的其它模塊觀察或者實時查詢交換機時,此流緩存記錄會更新。這種方式整合了不同模塊更新和檢索流記錄。
流高速緩衝存儲器的數據結構是留給實現者來決定的,而查詢和響應(反流高速緩衝存儲器)格式顯示在API中。每個查詢也可以指定其處理程序。
Flow reconcile類是爲了清理緩存以及交換機中的流表項,你可以由多個模塊來處理不同的事件,每個模塊將實現IFlowReconcileListene接口和reconcileFlows方法。這種方法既可以立即產生操作,你也可以通過OFMatchReconcile對象將決定傳遞給另一個模塊。也有一些接口被定義爲保持掛起的查詢。
Packet Streamer
描述:
Packetstreamer是包流服務,可以選擇性的在交換機和控制器之間流式傳輸OpenFlow包。它包含了兩個功能性接口:
1).基於REST的接口來定義自己感興趣的OpenFlow消息的特性,被稱爲過濾器
2)一個基於Thrift接口的流過濾的數據包
REST API
過濾器定義的一個Post請求:"http://<controller>:8080/wm/core/packettrace/json".輸入的數據是定義了我們感興趣的OpenFlow消息特點的參數。FloodLight配備了一個基於Mac地址的過濾器,例如,下面是一個過濾器的格式:
{'mac':<hostMac>, 'direction':<direction>, 'period':<period>, 'sessionId':<sessionid>}
Name |
Value |
Description |
mac |
<hostMac> |
The OFMessage with matching hostMac (in the Ethernet frame in its payload) will be streamed. |
direction |
in |
OFPacketIn |
|
out |
OFPacketOut and FlowMod |
|
both |
in and out |
period |
<period> |
Defines the duration of the streaming session in seconds. |
|
-1 |
terminate the given session |
sessionid |
<sessionid> |
The session to be terminated when period = -1. Otherwise, it is ignored. |
對REST API返回的sessionId,它可以被用來從流過濾服務器接收數據,數據是以Json格式返回的。
{'sessionId':<sessionid>}
下面是創建一個1000秒流會話的Python例子以及一個用來終止會話的函數。
在開始之前,確定你已經啓動了PacketStreamerServer
url = 'http://%s:8080/wm/core/packettrace/json' % controller filter = {'mac':host, 'direction':'both', 'period':1000} post_data = json.dumps(filter) request = urllib2.Request(url, post_data, {'Content-Type':'application/json'}) response_text = None
try: response = urllib2.urlopen(request) response_text = response.read() except Exception, e: # Floodlight may not be running, but we don't want that to be a fatal # error, so we just ignore the exception in that case. print "Exception:", e exit
if not response_text: print "Failed to start a packet trace session" sys.exit()
response_text = json.loads(response_text)
sessionId = None if "sessionId" in response_text: sessionId = response_text["sessionId"]
def terminateTrace(sid): global controller
filter = {SESSIONID:sid, 'period':-1} post_data = json.dumps(filter) url = 'http://%s:8080/wm/core/packettrace/json' % controller request = urllib2.Request(url, post_data, {'Content-Type':'application/json'}) try: response = urllib2.urlopen(request) response_text = response.read() except Exception, e: # Floodlight may not be running, but we don't want that to be a fatal # error, so we just ignore the exception in that case. print "Exception:", e
|
基於過濾器的流服務:
包流服務是由一個基於Thrift流服務器代理。
該Thrift接口如下表所示,完整的Thrift接口見:src/main/thrift/packetstreamer.thrift
service PacketStreamer {
/** * Synchronous method to get packets for a given sessionid */ list<binary> getPackets(1:string sessionid),
/** * Synchronous method to publish a packet. * It ensure the order that the packets are pushed */ i32 pushMessageSync(1:Message packet),
/** * Asynchronous method to publish a packet. * Order is not guaranteed. */ oneway void pushMessageAsync(1:Message packet)
/** * Terminate a session */ void terminateSession(1:string sessionid) } |
floodlight創建腳本爲Thrift服務創建java和python庫,其它語言的支持可以很容易的通過向創建腳本中添加語言選項:setup.sh
REST API描述了流回話的創建。一旦sessionId被創建,過濾接口getPackets(sessionId),可以被用於給特定的部分接收OF包,terminateSession(sessionId)可以被用於終止實時會話。
下面是一個python的例子:
try: # Make socket transport = TSocket.TSocket('localhost', 9090) # Buffering is critical. Raw sockets are very slow transport = TTransport.TFramedTransport(transport) # Wrap in a protocol protocol = TBinaryProtocol.TBinaryProtocol(transport) # Create a client to use the protocol encoder client = PacketStreamer.Client(protocol) # Connect! transport.open()
while 1: packets = client.getPackets(sessionId) for packet in packets: print "Packet: %s"% packet if "FilterTimeout" in packet: sys.exit()
except Thrift.TException, e: print '%s' % (e.message) terminateTrace(sessionId) |
客戶端例子:
Floodlight當前的版本帶有基於Mac地址的數據包流的例子。客戶端的一些代碼都列在了前面的章節。
一個完整的python客戶端例子,即描述了REST API和Thrift客戶端的使用情況,可以再floodlight的源代碼net.floodlightcontroller.packetstreamer中找到。
請確保在客戶端機器中已經安裝了thrift並且爲packetstreamer的gen-gy和thrift python的目錄給於了正確的路徑
應用模塊
虛擬網絡過濾器(Quantum插件)
簡述:
虛擬網絡過濾器模塊是基於虛擬化網絡的數據鏈路層。它允許你在獨立的數據鏈路層上創建多個邏輯鏈路。這個模塊可用於OpenStack的部署或者單例。
服務提供:
· IVirtualNetworkService
服務依賴:
· IDeviceService
· IFloodlightProviderService
· IRestApiService
Java文件:
此模塊實現在 net.floodlightcontroller.virtualnetwork.VirtualNetworkFilter。
如何工作:
在Floodlight啓動時,沒有虛擬網絡創建,這時主機之間不能相互通信。一旦用戶創建虛擬網絡,則主機就能夠被添加。在PacketIn消息轉發實現前,模塊將啓動。一旦,一條PacketIn消息被接受,模塊將查看源MAC 地址和目的MAC 地址。如果2個MAC地址是在同一個虛擬網絡,模塊將返回Command.CONTINUE消息,並且繼續處理流。如果MAC地址不在同一虛擬網絡則返回Command.STOP消息,並且丟棄包。
限制:
· 必須在同一個物理數據鏈路層中。
· 每個虛擬網絡只能擁有一個網關()(一個網關可被多個虛擬網絡共享)。
· 多播和廣播沒有被隔離。
· 允許所有的DHCP路徑。
配置:
模塊不是默認啓用的。它必須被加入配置文件,加入後,爲了成功加載,重啓Floodlight。這個模塊叫做“VirtualNetworkFilter”。包含此模塊的默認配置文件位置:src/main/resources/quantum.properties
# The default configuration for openstack floodlight.modules = net.floodlightcontroller.storage.memory.MemoryStorageSource,\ net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher,\ net.floodlightcontroller.forwarding.Forwarding,\ net.floodlightcontroller.jython.JythonDebugInterface,\ net.floodlightcontroller.counter.CounterStore,\ net.floodlightcontroller.perfmon.PktInProcessingTime,\ net.floodlightcontroller.ui.web.StaticWebRoutable,\ net.floodlightcontroller.virtualnetwork.VirtualNetworkFilter net.floodlightcontroller.restserver.RestApiServer.port = 8080 net.floodlightcontroller.core.FloodlightProvider.openflowport = 6633 net.floodlightcontroller.jython.JythonDebugInterface.port = 6655 |
如果你正在使用Floodlight虛擬機,機子中已經有配置文件,簡單的執行一下命令來啓動它。
floodlight@localhost:~$ touch /opt/floodlight/floodlight/feature/quantum floodlight@localhost:~$ sudo service floodlight stop floodlight@localhost:~$ sudo service floodlight start |
REAT API
URL |
Method |
URL Arguments |
Data |
Data fields |
description |
/networkService/v1.1/tenants/{tenant}/networks/{network} |
PUT/POST/ DELETE |
Tenant:忽略 網絡:網絡的id |
{"network": { "gateway": "<IP>", "name": "<Name>" }}\ |
IP:網關IP以“1.1.1.1”的格式,可爲空 名字:網絡以字符串命名。 |
創建新的虛擬網絡,名字和ID是必須的,網關可選 |
/networkService/v1.1/tenants/{tenant}/networks/{network}/ports/{port}/attachment |
PUT/ DELETE |
網絡:網絡ID 端口:邏輯端口名 |
{"attachment": {"id": "<Network ID>", "mac": "<MAC>"}} |
Network ID: Network ID 自己創建的字符串 MAC: MAC 地址以 "00:00:00:00:00:09" 格式 |
將主機與虛擬網絡連接 |
/networkService/v1.1/tenants/{tenant}/networks |
GET |
|
|
|
以json格式將所有網絡的網關,ID以及主機的MAC地址顯示出來 |
實例:
創建一個名爲“VirtualNetwork1”的虛擬網,ID設爲“NetworkId1”,網關爲“10.0.0.7”,租戶是默認的(當前是忽略的)。
curl -X PUT -d '{ "network": { "gateway": "10.0.0.7", "name": "virtualNetwork1" } }' http://localhost:8080/networkService/v1.1/tenants/default/networks/NetworkId1 |
向虛擬網絡中添加一個MAC地址爲“00:00:00:00:00:08”,端口爲“port1”的主機。
curl -X PUT -d '{"attachment": {"id": "NetworkId1", "mac": "00:00:00:00:00:08"}}' http://localhost:8080/networkService/v1.1/tenants/default/networks/NetworkId1/ports/port1/attachment |
轉發
簡介:
轉發將在2個設備之見轉發包。源設備和目的設備通過IDeviceService區分。
服務提供:
· 沒有
服務依賴:
· IDeviceService
· IFloodlightProviderService
· IRestApiService
· IRoutingService
· ITopologyService
· ICounterStoreService
Java文件:
此模塊實現在 net.floodlightcontroller.forwarding.Forwarding。
如何工作:
交換機需要考慮到,控制器可能需要工作在一個包含Openflow交換機和非Openflow交換機的網絡中。模塊將發現所有的 OF 島。FlowMod 將被安裝到最短路徑上。如果一條 PacketIn被接收到一個OF島,而該島沒有掛載點,則這個網包將被洪泛。
限制:
不提供路由功能。
沒有VLAN的加減包頭。
配置:
該模塊默認啓動,在加載模塊時,配置無需更改。
防火牆
簡介:
防火牆已被作爲一個模塊實現,它通過ACL規則實現流量過濾。每個被首包觸發的 PacketIn 消息將跟規則集進行匹配,按照最高權值匹配規則行爲進
行處理。防火牆匹配的最高優先級決定流的操作。通配符在OFMatc中用作定義。
防火牆策略:
防火牆被動運行。防火牆規則在他們被創建時(通過REST API)通過優先級排序。每個packet_in將從列表中的最高級開始匹配,直到列表結束。如果找到匹配,操作指令(允許或拒絕)儲存到一個IRoutingDecision 對象中,併發送其餘的pack_in處理管道。指令最後將到達轉發模塊或者其他數據包轉發的模塊(例如 LearningSwitch)。如果,指令允許操作,轉發模塊將推送一個常規的轉發流表,否則,推送一個丟棄流表。不管哪種,被推送給交換機的流表都必須準確的反應出防火牆規則的匹配屬性(包括通配符).
因此實現的防火牆,根據不同的優先級,允許擁有部分重疊的流空間。下面是個簡單的例子,192.168.1.0/24 段內的子網的流量都是被拒絕的,除了入站HTTP(TCP端口80)流量.
協議 |
目的IP |
目的端口 |
指令 |
優先級 |
TCP |
192.168.1.0/24 |
80 |
ALLOW |
1 |
TCP |
192.168.1.0/24 |
Wildcard |
DENY |
2 |
優先級數字越低,優先級別越高。
這裏要特別處理通配符。如果流沒有匹配最高級,而匹配了次高級,那麼由轉發模塊發送給交換的流表將不會通配目的端口,
而是在流表中指定端口,所以80端口的包將不會被丟棄。
REST 接口
防火牆模塊實現了REST接口,該接口實現了採用REST API服務的 RestletRoutable的接口。下面是REST方法的列表。
URI |
Method |
URI Arguments |
Data |
Data Fields |
Description |
|
/wm/firewall/module/<op>/json |
GET |
op: status, enable, disable, storageRules, subnet-mask |
None |
None |
查詢防火牆的啓動專業。 |
|
/wm/firewall/rules/json |
GET |
None |
None |
None |
以json的格式列出規則集 |
|
|
POST |
None |
{"<field 1>":"<value 1>", "<field 2>":"<value 2>", ...} |
"field":"value" pairs below in any order and combination: |
創建新的防火牆規則 |
|
|
DELETE |
None |
{"<ruleid>":"<int>"} |
"ruleid": "<int>" |
通過ruleid 刪除rule |
實例:
假定控制器運行在本機。顯示出防火牆是否被啓動。
啓動防火牆。默認的,防火牆拒絕所有流,除非一個顯式的ALLOW rule被創建。
curl http://localhost:8080/wm/firewall/module/enable/json |
添加一個ALLOW rules爲所有的流,來能夠通過交換機 00:00:00:00:00:00:00:01。
curl -X POST -d '{"switchid": "00:00:00:00:00:00:00:01"}' http://localhost:8080/wm/firewall/rules/json |
爲ip爲10.0.0.3和10.0.0.7的主機的所有的流添加一個ALLOW rules。Action 意味着ALLOW rules
curl -X POST -d '{"src-ip": "10.0.0.3/32", "dst-ip": "10.0.0.7/32"}' http://localhost:8080/wm/firewall/rules/json curl -X POST -d '{"src-ip": "10.0.0.7/32", "dst-ip": "10.0.0.3/32"}' http://localhost:8080/wm/firewall/rules/json |
爲mac地址爲00:00:00:00:00:0a和00:00:00:00:00:0b的主機的所有流添加一個ALLOW rules。
curl -X POST -d '{"src-mac": "00:00:00:00:00:0a", "dst-mac": "00:00:00:00:00:0b"}' http://localhost:8080/wm/firewall/rules/json curl -X POST -d '{"dst-mac": "00:00:00:00:00:0b", "dst-mac": "00:00:00:00:00:0a"}' http://localhost:8080/wm/firewall/rules/json |
添加一個ALLOW rules使ip爲10.0.0.3和10.0.0.7的主機能夠ping通
curl -X POST -d '{"src-ip": "10.0.0.3/32", "dst-ip": "10.0.0.7/32", "dl-type":"ARP" }' http://localhost:8080/wm/firewall/rules/json curl -X POST -d '{"src-ip": "10.0.0.7/32", "dst-ip": "10.0.0.3/32", "dl-type":"ARP" }' http://localhost:8080/wm/firewall/rules/json
curl -X POST -d '{"src-ip": "10.0.0.3/32", "dst-ip": "10.0.0.7/32", "nw-proto":"ICMP" }' http://localhost:8080/wm/firewall/rules/json curl -X POST -d '{"src-ip": "10.0.0.7/32", "dst-ip": "10.0.0.3/32", "nw-proto":"ICMP" }' http://localhost:8080/wm/firewall/rules/json |
添加一個ALLOW rules,ip爲10.0.0.4和10.0.0.10主機之間能夠UDP通信,同時阻塞5010、端口
curl -X POST -d '{"src-ip": "10.0.0.4/32", "dst-ip": "10.0.0.10/32", "dl-type":"ARP" }' http://localhost:8080/wm/firewall/rules/json curl -X POST -d '{"src-ip": "10.0.0.10/32", "dst-ip": "10.0.0.4/32", "dl-type":"ARP" }' http://localhost:8080/wm/firewall/rules/json
curl -X POST -d '{"src-ip": "10.0.0.4/32", "dst-ip": "10.0.0.10/32", "nw-proto":"UDP" }' http://localhost:8080/wm/firewall/rules/json curl -X POST -d '{"src-ip": "10.0.0.10/32", "dst-ip": "10.0.0.4/32", "nw-proto":"UDP" }' http://localhost:8080/wm/firewall/rules/json
curl -X POST -d '{"src-ip": "10.0.0.4/32", "dst-ip": "10.0.0.10/32", "nw-proto":"UDP", "tp-src":"5010", "action":"DENY" }' http://localhost:8080/wm/firewall/rules/json curl -X POST -d '{"src-ip": "10.0.0.10/32", "dst-ip": "10.0.0.4/32", "nw-proto":"UDP", "tp-dst":"5010", "action":"DENY" }' http://localhost:8080/wm/firewall/rules/json |
測試方法:
測試包括自動化單元,自動化單元通過EasyMock創建。”Firewalltest”類包括可由JUnit和Eclipse執行的測試案例。在大多數的測試案例中,packer_in事件是模擬的,由此產生的防火牆行爲能夠被驗證,它們是基於被定義的規則集的。以下是各種測試案例。
testNoRules
Description: 沒有任何的rules,發送一個packet_in事件,.防火牆將會拒絕所有流。這是一個邊界測試案例
testRuleInsertionIntoStorage
Description: 添加一個rules,通過檢查存儲來驗證. 這是一個簡單positive 測試案例.
testRuleDeletion
Description: 刪除一個rules,通過檢查存儲來驗證. Again, 這是一個簡單positive 測試案例.
testFirewallDisabled
Description: 在防火牆沒有啓動時,插入一個rules,併發送一個packet_in事件. 防火牆將會拒絕所有的流.這是一個簡單的 negative 的測試案例.
testSimpleAllowRule
Description:添加一個簡單的rules,使兩個2不同的ip之間能夠tcp通信,並且發送一個packet_in事件。在驗證防火牆行爲之後,能夠發送另一個應該被丟棄的包 。This test case covers normal rules (non-boundary case – i.e. no malformed packets or broadcasts)這個測試案例包含一個簡單的rules(無邊界案例——例如 一個完好的包或者廣播)
testOverlappingRules
Description:添加overlapping rules (拒絕所有的TCP流 除非目的端口是80). 這個測試案例包含複雜情況下的多個規則(multiple allow-deny overlapping rules).
testARP
Description:測試一個ARP廣播請求包和單播ARP迴應。沒有允許ARP迴應的防火牆rules,所以只有廣播請求包能夠通過.
testIPBroadcast
Description: 夠在防火牆沒有任何rules情況下,發送一個ip廣播(L3)packt_in事件。這是一個包含IP廣播的positive測試案例(L3+L2廣播).
testMalformedIPBroadcast
Description:在沒有任何rules情況下,發送一個壞的IP廣播packet_in事件. 防火牆將會拒絕這個流, 因爲這個包一個L2廣播L3單播. 這是一個邊界案例.
testLayer2Rule
Description:一個規則允許指定的MAC通信,另一個規則拒絕所有的TCP通信. 防火牆將接受這個流. 這是一個negative測試案例,這裏規則包含L2.
問題和侷限:
1.防火牆 模塊DELETE REST API功能的調用沒有刪除交換機上的流表。Rules將會被從控制器存儲中刪除,當交換機上的流表處理時間超過標準。這意味着在一段時間後,刪除規則是有效的。流可以持續存在,只要它在交換機中持續通信.
2.最初的,TCP/UDP端口範圍是通過防火牆rules來支持的。但是,作爲OpenFlow流匹配機制不允許指定端口範圍,此功能沒有實現。
Port Down Reconciliation
簡介:
PortDownReconciliation模塊的實現是爲了在端口關閉的時候處理網絡中的流。在PORT_DOWN鏈路發現更新消息之後,這個模塊將會找出並且刪除直接指向這個端口的流。所有無效的流都被刪除之後,floodlight應該重新評估鏈路,流量也要採用新的拓撲。如果沒有這個模塊,流量會持續的進入到這個壞掉的端口,因爲流的過期時間還沒有到。
工作原理:
想象一下我們有一個拓撲,包含了交換機s1,s1連接了一個主機h1,和兩個交換機s2、s3,現在流量從s2、s3進入到s1,目標地址是h1,但是到h1的鏈路關閉了,s1將會給controller發送一個PORT_DOWN通知。
在收到PORT_DOWN鏈路更新之後,該模塊就會找到那個關閉的端口,然後向s1查詢所有目的端口是鏈路發現更新描述的端口的流,它會分析這些流,並且爲進入端口和把流路由到已關閉端口的OFMatch創建索引。
索引可能看起來像這樣:
Short ingressPort |
List<OFMatch> (Invalid match objects of flows directing traffic to down port) |
1 |
[ match1: dataLayerDestination: "7a:59:cd:34:a7:9b", dataLayerSource: "c6:cb:ad:80:49:70" ] |
2 |
[ match2: dataLayerDestination: "7a:59:cd:34:a7:9b", dataLayerSource: "c6:cb:ad:80:49:69"] |
跟隨s1的索引,該模塊向拓撲服務詢問網絡中所有交換機的連接,以此追溯鏈路。找出所有的交換機,這些交換機包含了目標交換機對應s1,目標端口對應索引中描述的無效進入端口,如果找到這樣的匹配,那麼這個交換機就會被添加到相鄰交換機索引中,此時指向源端口的連接和無效的OFMatch。
相鄰交換機索引:
IOFSwitch sw |
Short outPort (outPort to link connected to the base switch) |
List<OFMatch> (Invalid match objects of flows directing traffic towards the base switch) |
sw2 |
3 |
[ match1: dataLayerDestination: "7a:59:cd:34:a7:9b", dataLayerSource: "c6:cb:ad:80:49:70" ] |
sw3 |
3 |
[ match2: dataLayerDestination: "7a:59:cd:34:a7:9b", dataLayerSource: "c6:cb:ad:80:49:69"] |
現在s1就不需要這些信息了,所有目標端口是故障端口的流都將會從s1中刪除,然後該模塊遍歷和s1相鄰交換機的索引,並在上邊執行相同的操作,這個過程會逐跳的遞歸進行,直到網絡中沒有無效的流。
問題和侷限:
1.如果在一個源地址和目的地址的路由中有重疊的交換機,那些重疊的交換機將會因不同的流被統計多次,這就花費了額外的時間,但是對於維護網絡中流的完整性,這也是必要的。
2.這個模塊依賴於轉發模塊實現。
模塊加載系統
簡介:
Floodlight使用自己的模塊系統來決定哪些模塊會運行,這個系統的設計目標是:
1.通過修改配置文件決定哪些模塊會被加載
2.實現一個模塊不需要修改他所依賴的模塊
3.創建一個定義良好的平臺和API以擴展Floodlight
4.對代碼進行強制的模塊化
主要部件:
模塊系統包含幾個主要的部件:模塊加載器、模塊、服務、配置文件和一個在jar文件中包含了了可用模塊列表的文件。
模塊:
模塊被定以爲一個實現了IFloodlightModule接口的類。IFloodlightModule接口的定義如批註所示。
/** * Defines an interface for loadable Floodlight modules. * * At a high level, these functions are called in the following order: * <ol> * <li> getServices() : what services does this module provide * <li> getDependencies() : list the dependencies * <li> init() : internal initializations (don't touch other modules) * <li> startUp() : external initializations (<em>do</em> touch other modules) * </ol> * * @author alexreimers */ public interface IFloodlightModule {
/** * Return the list of interfaces that this module implements. * All interfaces must inherit IFloodlightService * @return */
public Collection<Class<? extends IFloodlightService>> getModuleServices();
/** * Instantiate (as needed) and return objects that implement each * of the services exported by this module. The map returned maps * the implemented service to the object. The object could be the * same object or different objects for different exported services. * @return The map from service interface class to service implementation */ public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls();
/** * Get a list of Modules that this module depends on. The module system * will ensure that each these dependencies is resolved before the * subsequent calls to init(). * @return The Collection of IFloodlightServices that this module depnds * on. */
public Collection<Class<? extends IFloodlightService>> getModuleDependencies();
/** * This is a hook for each module to do its <em>internal</em> initialization, * e.g., call setService(context.getService("Service")) * * All module dependencies are resolved when this is called, but not every module * is initialized. * * @param context * @throws FloodlightModuleException */
void init(FloodlightModuleContext context) throws FloodlightModuleException;
/** * This is a hook for each module to do its <em>external</em> initializations, * e.g., register for callbacks or query for state in other modules * * It is expected that this function will not block and that modules that want * non-event driven CPU will spawn their own threads. * * @param context */
void startUp(FloodlightModuleContext context); } |
服務:
一個模塊可能包含一個或多個服務,服務被定義爲一個繼承IFloodlightService接口的接口。
/** * This is the base interface for any IFloodlightModule package that provides * a service. * @author alexreimers * */ public abstract interface IFloodlightService { // This space is intentionally left blank....don't touch it } |
現在這是一個空接口,在我們的加載系統中它是用來強制保證類型安全的。
配置文件:
配置文件明確的規定了哪些模塊可以加載,它的格式是標準的java屬性,使用鍵值對,在模塊列表中鍵是floodlight.modules,值是以逗號分隔的模塊列表,可以在一行,或者使用 \ 斷行,下邊是Floodlight默認的配置文件:
floodlight.modules = net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher,\ net.floodlightcontroller.forwarding.Forwarding,\ net.floodlightcontroller.jython.JythonDebugInterface |
有許多沒有寫在這個列表裏的模塊也被加載了,這是因爲模塊系統自動加載了依賴,如果一個模塊沒有提供任何服務,那麼就必須在這裏明確的定義。
模塊文件:
我們使用java的ServiceLoader找到類路徑中的模塊,這就要求我們列出文件中所有的類,這個文件的格式是在每一行都有一個完整的類名,這個文件在src/main/resource/MEAT-INFO/service/net.floodlightcontroller.module.IFloodModule。你使用的每個jar文件(如果使用多個jar文件就接着看 )都要有它自己的META-INFO/services/net.floodlightcontroller.module.IFloodlightModule文件,列出實現了IFloodlightModule接口的類。下邊是一個示例文件:
net.floodlightcontroller.core.CoreModule net.floodlightcontroller.storage.memory.MemoryStorageSource net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl net.floodlightcontroller.topology.internal.TopologyImpl net.floodlightcontroller.routing.dijkstra.RoutingImpl net.floodlightcontroller.forwarding.Forwarding net.floodlightcontroller.core.OFMessageFilterManager net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher net.floodlightcontroller.perfmon.PktInProcessingTime net.floodlightcontroller.restserver.RestApiServer net.floodlightcontroller.learningswitch.LearningSwitch net.floodlightcontroller.hub.Hub net.floodlightcontroller.jython.JythonDebugInterface |
啓動序列:
1.模塊發現
所有在類路徑中的模塊(實現IFloodlightModule的類)都會被找到,並且建立三個映射(map)
服務映射:建立服務和提供該服務的模塊之間的映射
模塊服務映射:建立模塊和他提供的所有服務之間的映射
模塊名稱映射:建立模塊類和模塊類名之間的映射
2.找出需要加載的最小集合
使用深度優先遍歷算法找出需要加載模塊的最小集合,所有在配置文件中定義的模塊都會添加到隊列中,每個模塊出對後都會被添加到模塊啓動列表中,如果一個模塊的依賴還沒有添加到模塊啓動列表中,將會在該模塊上調用getModuleDependenceies方法。在這裏有兩種情況可能引起FloodlightModuleException異常,第一種情況找不到在配置文件中定義的模塊或者模塊的依賴,第二種情況是兩個模塊提供了相同的服務,卻沒有指明使用哪個。
3.初始化模塊
集合中的模塊會迭代的加載,並且在上邊調用init方法,現在模塊會做兩件事情
1.在FloodlightModuleContext上調用getServiceImpl方法把它的依賴寫到一起。
2.對自己內部的數據結構執行初始化。
init方法調用的順序是不確定的。
4.啓動模塊:
在每個模塊上調用init方法後,就會調用startUp方法,在這個方法中模塊將會調用它所依賴的模塊,例如:使用IStorageSourceService模塊在數據庫中建立一個表、或者用IFloodlightProviderService的executor服務建立一個線程。
通過命令行使用控制器:
只使用floodlight.jar:如果你只是想使用默認配置運行floodlight,最簡單的方法就是運行這個命令
$java -jar floodlight.jar |
使用多個jar文件:也可以使用多個jar文件運行openflow,如果你想用另外的包分發,這將會非常有用 ,只是命令有些不同。
java -cp floodlight.jar:/path/to/other.jar net.floodlightcontroller.core.Main
-cp參數告訴java使用類路徑中的那些jar文件,main方法坐在的類由net.floodlightconntroller.core.Main指定。如果你添加的jar文件包含了實現IFloodlightModule接口的類,你就要確保創建了MAIN-INF/services/net.floodlightcontroller.core.module.IFloodlightModule。
指定其它的配置文件:
使用這兩種方法 你可以指定一個其它的配置文件,這需要用到-cf選項。
java -cp floodlight.jar:/path/to/other.jar net.floodlightcontroller.core.Main -cf path/to/config/file.properties
-cf參數必須放到所有選項的後邊,這就讓參數傳遞到了java程序而不是java虛擬機。使用哪個配置文件的順序是:
使用-cf選項指定的配置文件
config/floodlight.properties文件(如果存在的話)
在jar文件中的floodlightdefault.properties文件(在src/main/resources中)。
每個模塊的配置選項:
Properties文件能夠指定每個模塊的配置選項。格式是<規範的模塊名>.<配置選項名>=<內容>。
我們使用規範的模塊名,這樣任何的模塊都可以創建配置選項來實現自身.
例如,如果我們想指定REST API 端口,就向 property文件中加入。
net.floodlightcontroller.restserver.RestApiServer.port = 8080
我們來分析一下RestApiServer的init方法.
// read our config options Map<String, String> configOptions = context.getConfigParams(this); String port = configOptions.get("port"); if (port != null) { restPort = Integer.parseInt(port); } |
注意null檢查是必須的.如果配置選項沒有提供,. FloodlightModuleLoader 模塊將不會將其添加到文本中。
通過命令行,選項可以指定爲Java屬性. 這些可以重寫Floodlight配置文件中任何指定的東西.
java -Dnet.floodlightcontroller.restserver.RestApiServer.port=8080 -jar floodlight.jar |
有兩點要注意,第一 ,Java屬性在運行floodlight.jar之前First應被指定.之後,所有的被作爲可執行的命令行文本傳遞給Java. The second is that there are no spaces with the -D option.
· 爲了處理循環依賴關係,init()方法和startup()方法的調用順序是不確定的,因此,你不能假設任何的init()和startUp方法的調用。.
· 你的配置文件不能調用FLoodlight,properties文件,這是jar包中的默認配置文件。.
· 每個模塊必須有一個0參數(最好是空的)構造函數.做什麼應該在構造函數中實現,而不是調用init()。.
· .模塊之間可能沒有服務重疊,但是存在功能重疊,例如, LearningSwitch 模塊Forwarding都有轉發包的方法 Since they do not provide a common service w do not detect and overlap.
Javadoc entry
綜述:
Overview 頁面提供了所有的包的摘要,也包含了包集合的說明
包
每個包都有一個列出它的接口和類的頁面,並都對每個類和接口有個簡介.這個頁面可能包含的:
· Interfaces (italic)
· Classes
· Enums
· Exceptions
· Errors
· Annotation Types
每個類,接口以及嵌套類和嵌套接口有自己的單獨的頁面.這些頁面有三個部分,包括a class/interface description, summary tables, and detailed member descriptions:
· Class inheritance diagram
· Direct Subclasses
· All Known Subinterfaces
· All Known Implementing Classes
· Class/interface declaration
· Class/interface description
· Nested Class Summary
· Field Summary
· Constructor Summary
· Method Summary
· Field Detail
· Constructor Detail
· Method Detail
每個摘要通過第一段來詳細描述的內容.摘要條目按照字母順序排列,而詳細描述以出現在源代碼的順序. 這個保存由程序員建立的邏輯組.
每種註釋有自己的頁面,並有一下幾個部分:
· Annotation Type declaration
· Annotation Type description
· Required Element Summary
· Optional Element Summary
· Element Detail
每個枚舉有自己單獨的頁面,並有以下部分
· Enum declaration
· Enum description
· Enum Constant Summary
· Enum Constant Detail
每個文件包,類和接口有自己的Use頁面。這個頁面描述,包,類,構造器和字段用的了哪些包和類。
Tree (Class Hierarchy)樹(類的層次結構)
這兒有所有包的層次結構,也有每個包的層次結構.每個頁面就是類和接口的列表.注意接口不是從 java.lang.Object繼承的
當查看概覽頁面,點擊“樹”顯示所有包的層次結構.
當瀏覽一個特定的包,類或接口頁面,點擊“樹”顯示,包的層次結構.
Deprecated API 頁面列出了所有不贊同使用的API,之所以,不贊同使用,是爲了優化,或者一個代替的API已經給出。
索引是一個字母列表,其中包含了所有類、接口、構造函數、方法和字段。
Prev/Next上/下頁
These links take you to the next or previous class, interface, package, or related page.這些鏈接指向下一頁,其中包括相關的類,接口,包,或相關頁面。
These links show and hide the HTML frames. All pages are available with or without frames.
序列化格式
每個序列化類或者外部類都有一個描述它的字段和方法。這是 re-implementors興趣的,而不是使用API的開發者。雖然沒有鏈接在導航欄中,你可以得到這個信息,通過定位任何序列化的類並單擊“Serialized Form”。
固定字段值頁面列出了靜態的final字段和他們的值
This help file applies to API documentation generated using the standard doclet.