Floodlight开发者文档之MACTracker

概述

  Floodlight内部定义报文格式的代码位于net.floodlightcontroller.packet,其中定义的报文类型有ARP,BPDU,BSN,BSNPROBE,DHCP,Ethernet,ICMP,IPv4,LLC,LLDP,TCP,UDP。

其中定义了一个名为IPacket的接口,该接口结构如图:

包内还定义了一个实现了IPacket接口的抽象类BasePacket,BasePacket数据域中定义了两个IPacket类型的对象parent和payload。所有报文对象都继承了BasePacket类并根据不同情况添加了新的方法。以一个IPv4报文为例,其parent域为一个Ethernet对象,其payload域为一个TCP/UDP对象。

在Floodlight内部IFloodlightProviderService类中定义了一个名为bcStore的对象来存储OpenFlow消息所传递上来的消息,其中存储的数据为一个Ethernet对象,其payload域携带着该报文的三层信息,而payload域对象自身的payload域又携带着该报文的四层信息。

一个典型的二层报文Ethernet对象数据结构如下:

现在已获取到了一个Ethernet对象(假设对象名为eth),假设我们想从中取出报文的源目IP地址,可对报文进行如下操作:

if(eth.getPayload() instanceof IPv4) //或if(eth.getEtherType() == Ethernet.TYPE_IPv4)  
{
IPv4 pkt =(IPv4)eth.getPayload().clone();//IPv4 pkt =(IPv4)eth.getPayload();应该也可以,未测试。
String src = pkt.fromIPv4Address(pkt.getSourceAddress());
String dst = pkt.fromIPv4Address(pkt.getSourceAddress());
}

要在Floodlight内部获取到OpenFlow消息的步骤如下:

1.新建一个类,使其实现IOFMessageListener, IFloodlightModule接口
2.在getModuleDependencies()方法中声明模块的依赖关系
3.在init()方法中初始化一个IFloodlightProviderService对象
4.在startUp()方法中为上一步中初始化好的对象添加OF消息监听器,并指明要监听的消息类型,如OFType.PACKET_IN
5.在receive方法中,用IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);为一个Ethernet对象赋值。此方法的功能为从 Floodlight控制器上下文对象中取出bcStore所携带的数据。此方法中CONTEXT_PI_PAYLOAD被预定以为一个静态字符串常量 “net.floodlightcontroller.core.IFloodlightProvider.piPayload”。

eclipse设置:

打开eclipse创建一个新的工程
文件->导入->常规->现有项目到工程中->下一步
点击“选择根目录”,点击“浏览”。选择之前放置Floodlight的父路径
点击Floodlight
点击“完成”
现在就产生了一个Floodlight的Eclipse工程。由于我们是使用静态模块加载系统运行Floodlight,我们必须配置eclipse来正确的运行Floodlight。
创建Floodlight目标文件:
点击运行->运行配置
右击java 应用->新建
“Name”使用“FloodlightLaunch”
“Project”使用“Floodlight”
“Main”使用“net.floodlightcontroller.core.Main”
点击“应用”

这里要设置一下eclipse 里console,在window->preperences->Run/Debug->console 中,把’show when program writes to standard out’的勾去掉,这样console消息缓存就不受限制。

Run->Run Configurations->Common->File 使eclipse控制台输出重定向到文件

程序框架:

a.新建一个类继承IOFMessageListerner和IFloodlightModule。

b.声明变量:

protected IFloodlightProviderService floodlightProvider;
protected Set macAddresses;
protected static Logger logger;

由于要监听openflow消息,所以要向FloodlightProvider 注册。同时需要一个集合变量macAddresses 来存放控制器发现的MAC地址。最终,需要一个记录变量logger来输出发现过程中的记录信息。

c.实现getModuleDependencies方法,把依赖关系告诉模块加载系统:

@Override
public Collection<Classextends IFloodlightService>> getModuleDependencies() {
Collection<Classextends IFloodlightService>> l =
new ArrayList<Classextends IFloodlightService>>();
l.add(IFloodlightProviderService.class);
return l;
}

编写模块加载代码。 通过完善getModuleDependencies() 告知加载器在floodlight启动时将自己加载。

d.实现init方法,这个方法会在controller启动时调用,以加载依赖和数据结构:

@Override
public void init(FloodlightModuleContext context) throws FloodlightModuleException {
floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
macAddresses = new ConcurrentSkipListSet();
logger = LoggerFactory.getLogger(MACTracker.class);
}

创建Init方法,Init()将在控制器启动初期被调到,其主要功能室加载依赖关系并初始化数据结构。

e. 实现startUp方法,为PACKET_IN消息绑定事件处理委托,在这之前我们必须保证所有依赖的模块已经 初始化

@Override
public void startUp(FloodlightModuleContext context) {
floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
}

在实现基本监听功能时,packet-in消息需在startup方法中被记录和注册,同时确认新增模块需要依赖的其他模块已被正常初始化。

f.实现getName方法为OFMessage监听器添加ID

@Override
public String getName() {
return "MACTracker";      // 或 return MACTracker.class.getSimpleName();
}

g.为PACKET_IN事件处理程序添加实现代码,该方法返回Command.CONTINUE以便Ifloodprovider能够将Packin消息发往下一个模块,其它事件处理程序继 续处理。

@Override
public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
Ethernet eth
=IFloodlightProviderService.bcStore.get(cntx,IFloodlightProviderService.CONTEXT_PI_PAYLOA
D);
Long sourceMACHash = Ethernet.toLong(eth.getSourceMACAddress());
if (!macAddresses.contains(sourceMACHash))
{
macAddresses.add(sourceMACHash);
logger.info("MAC Address: {} seen on switch:{}",HexString.toHexString(sourceMACHash),
sw.getId());
}
return Command.CONTINUE;
}

至此,与packet-in消息相关的操作完成。另外还需注意,要返回 Command.CONTINUE 以保证这个消息能够继续被packet-in消息处理。

h. 编写完事件处理程序还需要向Floodlight注册模块,这样Floodlight启动的时候才能加载

具体实现步骤:

添加模块
创建一个监听模块
在Eclipse中添加类
在floodlight中找出“src/main/java”。
在“src/main/java”目录下选择“New/Class”.
在packet中输入“net.floodlightcontroller.mactracker”
在 name中输入“MACTracker”
在“Interfaces”中,单击“Add…”,“chooseinterface”增加“IOFMessageListener”and the “IFloodlightModule”, 单击“OK”.
单击“Finish”
产生的对应程序如下:

public class MACTracker implements IOFMessageListener, IFloodlightModule {

    @Override
    public Collection<Classextends IFloodlightService>> getModuleServices() {
        // TODO Auto-generated method stub
        return null;
    }

 @Override
    public Map<Classextends IFloodlightService>, IFloodlightService> getServiceImpls() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Collection<Classextends 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 String getName() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
        // TODO Auto-generated method stub
        return null;
    }
}

    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;
    }

设置模块化关系并初始化

开始前需处理一系列代码依赖关系。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.openflow.util.HexString;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

至此,代码基本框架完成,进而要实现必要功能使模块能正确被加载。首先,注册Java类中需要的成员变量。由于要监听openflow消息,所以要向FloodlightProvider 注册。同时需要一个集合变量macAddresses 来存放控制器发现的MAC地址。最终,需要一个记录变量logger来输出发现过程中的记录信息。

protected IFloodlightProviderService floodlightProvider;

protected Set macAddresses;

protected static Logger logger;

编写模块加载代码。 通过完善getModuleDependencies() 告知加载器在floodlight启动时将自己加载。

@Override

public Collection<Classextends IFloodlightService>> getModuleDependencies() {

    Collection<Classextends IFloodlightService>> l =

        new ArrayList<Classextends 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();

    logger = LoggerFactory.getLogger(MACTracker.class);

}

处理Packet-In 消息
在实现基本监听功能时,packet-in消息需在startup方法中被记录和注册,同时确认新增模块需要依赖的其他模块已被正常初始化。

@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消息相关的操作完成。另外还需注意,要返回 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 = Ethernet.toLong(eth.getSourceMACAddress());

        if (!macAddresses.contains(sourceMACHash)) {

            macAddresses.add(sourceMACHash);

            logger.info("MAC Address: {} seen on switch: {}",

                    HexString.toHexString(sourceMACHash),

                    sw.getId());

        }

        return Command.CONTINUE;

    }

注册模块

如果要在floodlight启动时加载新增模块,需向加载器告知新增模块的存在,在src/main/resources/META-INF/services/net.floodlight.core.module.IFloodlightModule文件上增加一个符合规则的模块名,即打开该文件并在最后加上如下代码。

net.floodlightcontroller.mactracker.MACTracker

然后,修改floodlight的配置文件将 MACTracker相关信息添加在文件最后。Floodlight的缺省配置文件是src/main/resources/floodlightdefault.properties。其中,floodlight.module选项的各个模块用逗号隔开,相关信息如下:

floodlight.modules = (leave the default list of modules in place),
net.floodlightcontroller.mactracker.MACTracker

最终,即可运行控制器并观察新增模块的功能:mininet创建拓扑执行pingall命令。  

完整代码

package net.floodlightcontroller.mactracker;

import java.util.Collection;
import java.util.Map;

import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFType;

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;

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.openflow.util.HexString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MACTracker implements IFloodlightModule, IOFMessageListener {

    protected IFloodlightProviderService floodlightProvider;
    protected Set macAddresses;
    protected static Logger logger;

    @Override
    public String getName() {
        // TODO Auto-generated method stub
          return MACTracker.class.getSimpleName();
    }

    @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 net.floodlightcontroller.core.IListener.Command receive(
            IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
        // TODO Auto-generated method stub
           Ethernet eth =
                    IFloodlightProviderService.bcStore.get(cntx,
                                                IFloodlightProviderService.CONTEXT_PI_PAYLOAD);

            Long sourceMACHash = Ethernet.toLong(eth.getSourceMACAddress());
            if (!macAddresses.contains(sourceMACHash)) {
                macAddresses.add(sourceMACHash);

                logger.info("MAC Address: {} seen on switch: {}",
                        HexString.toHexString(sourceMACHash),
                        sw.getId());
            }
            return Command.CONTINUE;
    }

    @Override
    public Collection<Classextends IFloodlightService>> getModuleServices() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Map<Classextends IFloodlightService>, IFloodlightService> getServiceImpls() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Collection<Classextends IFloodlightService>> getModuleDependencies() {
        // TODO Auto-generated method stub
         Collection<Classextends IFloodlightService>> l =
                    new ArrayList<Classextends IFloodlightService>>();
            l.add(IFloodlightProviderService.class);
            return l;
    }

    @Override
    public void init(FloodlightModuleContext context)
            throws FloodlightModuleException {
        // TODO Auto-generated method stub
         floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
            macAddresses = new ConcurrentSkipListSet();
            logger = LoggerFactory.getLogger(MACTracker.class);
    }

    @Override
    public void startUp(FloodlightModuleContext context) {
        // TODO Auto-generated method stub
          floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
    }

}

你可能感兴趣的:(SDN,floodlight篇,floodlight,SDN)