Floodlight 入門 之 起步篇 - 建立一個Floodlight模塊
- 2017-3-1
網上也有不少關於Floodlight的入門教程了,我寫該博文的目的主要是問了整理個人在學習和使用Floodlight時掌握的知識,如果這些文字能爲大家帶來幫助是最好不過的了。
博文會持續更新,如果想要跟蹤該博文的進度,推薦使用RSS。每次更新會在博文開始出更改時間戳。
該博文系列是從Floodlight官網的官方教程翻譯而來,想嚼原味教程請點擊鏈接Tutorials。
前提條件
我們在進行下面的實驗前,首先要檢查我們的實驗環境是否滿足下面的條件:
- 成功地完成了Getting Started的教程,包括配置Eclipse。
- 安裝了Mininet或者有一個可以使用的OpenFlow物理交換機。
確保滿足上述條件後,就可以進行下面的實驗了。
創建一個監聽器
在Eclipse中添加一個Class
- 展開floodlight項,你會看到“src/main/java”文件夾。
- 選中“src/main/java”文件夾,然後右擊,在彈出的菜單中選中 “New/Class”。
- 在“Package”欄寫入net.floodlightcontroller.mactracker。
- 在“Name”欄寫入MACTracker。
- 然後就是“Interfaces”欄,我們點擊旁邊的“Add..”爲該類添加接口。
- 添加”IOFMessageListener”和”IFloodlightModule”,然後點擊OK。
- 點擊“Finish”完成類的創建。
上面的步驟完成後,你將會看到下面的代碼:
package net.floodlightcontroller.mactracker;
import java.util.Collection;
import java.util.Map;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFType;
import org.projectfloodlight.openflow.types.MacAddress;
import net.floodlightcontroller.core.FloodlightContext;
import net.floodlightcontroller.core.IOFMessageListener;
import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.module.FloodlightModuleException;
import net.floodlightcontroller.core.module.IFloodlightModule;
import net.floodlightcontroller.core.module.IFloodlightService;
public class MACTracker implements IOFMessageListener, IFloodlightModule {
@Override
public String getName() {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isCallbackOrderingPrereq(OFType type, String name) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean isCallbackOrderingPostreq(OFType type, String name) {
// TODO Auto-generated method stub
return false;
}
@Override
public Collection<Class<? extends IFloodlightService>> getModuleServices() {
// TODO Auto-generated method stub
return null;
}
@Override
public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
// TODO Auto-generated method stub
return null;
}
@Override
public void init(FloodlightModuleContext context)
throws FloodlightModuleException {
// TODO Auto-generated method stub
}
@Override
public void startUp(FloodlightModuleContext context) {
// TODO Auto-generated method stub
}
@Override
public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
// TODO Auto-generated method stub
return null;
}
}
設置模塊依賴項和初始化
在我們開始之前,我們需要爲我們創建的代碼設置一系列的依賴項。使用Eclipse的話,添加這些依賴項會很容易。如果你沒有使用Eclipse來編寫代碼,你就需要手動將下面的依賴項添加到java文件的開頭:
import net.floodlightcontroller.core.IFloodlightProviderService;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.Set;
import net.floodlightcontroller.packet.Ethernet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
現在我們有了必需的依賴項,而且通過之前創建類的操作,我們有了一個有框架的類。然而這樣的類肯定還是不能正常使用的,我們需要實現一些方法來確保我們創建的模塊可以被加載。首先,我們需要在該類中添加一些必要的成員變量。我們現在要創建的模塊是要實現跟蹤MAC地址的功能,所以我們需要監聽Openflow messages,需要添加一個FloodlightProvider((IFloodlightProviderService class)。我們還需要一個數據結構存儲我們監聽到的MAC地址,需要一個logger來輸出我們監聽到的信息。最後我們需要的成員變量如下所示:
protected IFloodlightProviderService floodlightProvider;
protected Set<Long> macAddresses;
protected static Logger logger;
現在我們需要完成模塊被加載的功能。我們對getModuleDependencies()方法進行更改,以此來告訴模塊加載器我們依賴於它:
@Override
public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Collection<Class<? extends IFloodlightService>> l =
new ArrayList<Class<? extends IFloodlightService>>();
l.add(IFloodlightProviderService.class);
return l;
}
現在我們的模塊可以被加載了。一般來說,一個模塊被加載時是要進行初始化的。所以接下來我們來對初始化方法進行實現:
@Override
public void init(FloodlightModuleContext context) throws FloodlightModuleException {
floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
macAddresses = new ConcurrentSkipListSet<Long>();
logger = LoggerFactory.getLogger(MACTracker.class);
}
處理Packet-In消息
經過上面的操作,我們的模塊已經可以作爲一個模塊正常的運行了。然而我們的目的是創建一個能跟蹤MAC地址的模塊,所以我們接下來還要對模塊的功能進行實現。首先,我們需要實現一個簡單的監聽器(用來監聽OpenFlow消息)。我們將會在我們的startUp方法中註冊一個監聽PACKET_IN消息的監聽器。這裏我們假定我們依賴的其他模塊已經初始化好了:
@Override
public void startUp(FloodlightModuleContext context) {
floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
}
我們還須要爲我們的OFMessage監聽器放入一個ID什麼的(原文:We also have to put in an ID for our OFMessage listener.)。這裏可以在在回調函數getName()中完成:
@Override
public String getName() {
return MACTracker.class.getSimpleName();
}
現在我們就可以叫我們的PACKET_IN消息與特定的行爲進行綁定了。這在receive方法中實現,注意:我們這裏要返回Command.CONTINUE,這樣在我們之後模塊纔可以繼續執行鍼對該PACKET_IN消息的操作:
@Override
public net.floodlightcontroller.core.IListener.Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
Ethernet eth =
IFloodlightProviderService.bcStore.get(cntx,
IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
Long sourceMACHash = eth.getSourceMACAddress().getLong();
if (!macAddresses.contains(sourceMACHash)) {
macAddresses.add(sourceMACHash);
logger.info("MAC Address: {} seen on switch: {}",
eth.getSourceMACAddress().toString(),
sw.getId().toString());
}
return Command.CONTINUE;
}
在處理Openflow消息是模塊的序列
這一段說明在該教程中並不是必要的,但當我們用IOFMessageListeners處理OpenFlow消息時,定義處理順序往往是必要的。IOFMessageListeners的isCallbackOrderingPrereq(OFType type, String name)和isCallbackOrderingPostreq(OFType type, String name)方法定義了處理來自交換機的消息的模塊的處理順序。
isCallbackOrderingPrereq()定義了在處理某一類的OpenFlow消息時,哪些模塊應該跑在我們的模塊前。 isCallbackOrderingPostreq()定義了在處理某一類的OpenFlow消息時,哪些模塊應該跑在我們的模塊後。
註冊模塊
經過上面的操作,我們差不多已經完成了模塊的實現。現在我們只需要告訴Floodlight我們要在啓動時加載該模塊。首先我們要告訴加載器這些模塊的存在。我們打開src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule,然後添加下面一行文字:
net.floodlightcontroller.mactracker.MACTracker
然後我們還需要修改配置文件src/main/resources/floodlightdefault.properties:
floodlight.modules = <leave the default list of modules in place>, net.floodlightcontroller.mactracker.MACTracker
最後,我們啓動控制器(選中Run As…/Java Application,然後選中Main.java)。
如何將Mininet與Floodlight控制器相連
Floodlight默認的監聽端口是6653(可以在配置文件中查看和修改src/main/resources/floodlightdefault.properties),我們連接Floodlight需要知道Floodlight所在主機的IP地址(如果是本地,就輸入127.0.0.1或0.0.0.0),注意:好像只有Floodlight v1.2版本支持OpenFlow1.3協議,如果使用早期版本的Floodlight如v1.0,建議將protocols=OpenFlow13改爲protocols=OpenFlow10:
mininet@mininet:~$ sudo mn --controller=remote,ip=<Floodlight IP Address>,port=6653 --switch=ovsk,protocols=OpenFlow13
*** Loading ofdatapath
*** Adding controller
*** Creating network
*** Adding hosts:
h2 h3
*** Adding switches:
s1
*** Adding edges:
(s1, h2) (s1, h3)
*** Configuring hosts
h2 h3
*** Starting controller
*** Starting 1 switches
s1
*** Starting CLI:
mininet>pingall
連接成功後,輸入pingall,則可以在Eclipse的Console中看到模塊的輸出信息。
練習
作爲練習,我寫了一個模塊,但並不是MACtracer,而是監聽所有Packet-In然後輸出Payload,輸出結果如下:
13:56:05.521 INFO [n.f.p.m.NetMonitor:nioEventLoopGroup-3-4] Switch Id:00:00:00:00:00:00:00:01,Payload:IPv6 [version=6, trafficClass=0, flowLabel=0, payloadLength=16, nextHeader=0x3a, hopLimit=-1, sourceAddress=fe80::ac97:c0ff:fe0b:a39b, destinationAddress=ff02::2, parent=
0x86dd
dl_vlan: untagged
dl_vlan_pcp: 0
dl_src: ae:97:c0:0b:a3:9b
dl_dst: 33:33:00:00:00:02
nw_src: fe80::ac97:c0ff:fe0b:a39b
nw_dst: ff02::2
nw_tclass: 0
nw_proto: 0x3a, payload=net.floodlightcontroller.packet.Data@da31eb25]
13:56:08.717 INFO [n.f.p.m.NetMonitor:nioEventLoopGroup-3-4] Switch Id:00:00:00:00:00:00:00:01,Payload:IPv6 [version=6, trafficClass=0, flowLabel=0, payloadLength=16, nextHeader=0x3a, hopLimit=-1, sourceAddress=fe80::ac7d:88ff:fe59:6165, destinationAddress=ff02::2, parent=
0x86dd
dl_vlan: untagged
dl_vlan_pcp: 0
dl_src: ae:7d:88:59:61:65
dl_dst: 33:33:00:00:00:02
nw_src: fe80::ac7d:88ff:fe59:6165
nw_dst: ff02::2
nw_tclass: 0
nw_proto: 0x3a, payload=net.floodlightcontroller.packet.Data@f8ec7dee]
13:56:09.529 INFO [n.f.p.m.NetMonitor:nioEventLoopGroup-3-4] Switch Id:00:00:00:00:00:00:00:01,Payload:IPv6 [version=6, trafficClass=0, flowLabel=0, payloadLength=16, nextHeader=0x3a, hopLimit=-1, sourceAddress=fe80::ac97:c0ff:fe0b:a39b, destinationAddress=ff02::2, parent=
0x86dd
dl_vlan: untagged
dl_vlan_pcp: 0
dl_src: ae:97:c0:0b:a3:9b
dl_dst: 33:33:00:00:00:02
nw_src: fe80::ac97:c0ff:fe0b:a39b
nw_dst: ff02::2
nw_tclass: 0
nw_proto: 0x3a, payload=net.floodlightcontroller.packet.Data@da31eb25]