一 前提
- 安装mininet和Open vSwitch软件,也可以直接下载一个装有mininet和Open vSwitch的虚拟机 Virtual Machine Image (OVF format, 64-bit, Mininet 2.0)
- 下载Floodlight源码,并导入Eclipse中
我们将编写一个简单的Floodlight模块,用来检测在网络中新的、未被发现的MAC地址,并记录被检测到的MAC地址和交换机。
二 创建监听器
2.1在Eclipse中添加类
a). 将“floodlight”项目导入Eclipse中,并在包管理器中展开,然后找到
“src/main/java”目录。
b). 右键单击“src/main/java”目录,选择“New / Class”.
c). 在“Package”框中输入“net.floodlightcontroller.mactracker”。
d). 在“Name”框中输入“MACTracker”。
e). 接下来找到“Interface”那一栏,点击旁边的“Add...”按钮。
f). 添加“IOFMessageListener”和“IFloodlightModule”,点击“OK”按钮。
g). 点击对话框上的“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;
}
}
2.2 设置模块的依赖关系和初始化
在开始前,我们需要引入一些依赖包。使用像eclipse一样的工具可以很方便的添加,如果你没有使用eclipse,只需要将下面的代码添加到类的前面。
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;
现在,我们有了类的框架,我们还需要实现相关的功能才能使得模块能够被加载。首先,我们添加一些在类中需要的成员变量。因为要监听OpenFLow的消息,我们需要用FloodlightProvider(IFloodlightProviderService类)注册信息,我们也需要一个Set集合来存储被检测到的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;
}
现在我们开始写模块的初始化方法init(),init()会在控制器启动过程的早期被调用——它主要用来加载相关依赖和初始化数据结构。
@Override
public void init(FloodlightModuleContext context) throws FloodlightModuleException {
floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
macAddresses = new ConcurrentSkipListSet<Long>();
logger = LoggerFactory.getLogger(MACTracker.class);
}
2.3 处理Packet-In消息
接下来实现基本的监听器。我们将在startUp()方法中注册PACKET_IN消息。在这里,我们确保其他被依赖的模块已经被初始化。
@Override
public void startUp(FloodlightModuleContext context) {
floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
}
我们也必须在OFMessage消息监听器中设置一个ID,这可以在getName()方法中实现。
@Override
public String getName() {
return MACTracker.class.getSimpleName();
}
现在我们来定义我们想要的对PACKET_IN消息的处理行为。注意,为了使PACKET_IN
消息在后面可以继续被其他相关消息处理程序处理,我们需要返回Command.CONTINUE。
@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;
}
2.4 注册模块
我们已经基本完成了模块的编写工作,现在我们只需要告诉Floodlight在启动的时候加载本模块。首先,我们必须告诉加载器本模块的存在,这需要在文件src/main/resources/META-INF/services/
net.floodlightcontroller.core.module.IFloodlightModule 中添加一行模块的全名。打开该文件,然后在下面添加一行:
net.floodlightcontroller.mactracker.MACTracker
接下来需要让模块被加载。我们可以在Floodlight模块配置文件中添加MACTracker模块,这个默认的文件在src/main/resources/floodlightdefault.properties。它的key值是floodlight.modules,value是一个将模块名用逗号分割的列表。
floodlight.modules = <leave the default list of modules in place>, net.floodlightcontroller.mactracker.MACTracker
最后运行控制器,右键Main.java文件,选择"Run As... / Java Application"。
三 检验模块功能
3.1 建立网络拓扑
打开mininet虚拟机,输入命令
sudo mn --topo single,3 --controller=remote,ip=<你本机的ip地址>,port=6653 --switch ovsk,protocols=OpenFlow13
结果如下图所示:
3.2 查看floodlight输出结果
在Eclipse的控制台输出信息里,查找MACTracker,可以看到如下信息,可以看到网络中新接入设备的MAC地址和相关交换机