添加模块

创建一个监听模块

在Eclipse中添加类

  • 在floodlight中找出“src/main/java”。
  • 在“src/main/java” 目录下选择“New/Class”.
  • 在packet中输入 “net.floodlightcontroller.mactracker”
  • 在 name中输入“MACTracker”
  • 在“Interfaces”中, 单击“Add…”,“choose interface”增加“IOFMessageListener” and the “IFloodlightModule”, 单击“OK”.
  • 单击“Finish”

产生的对应程序如下:

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;
 
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中可根据代码需要在编译过程中自动添加依赖包描述。没有相关工具,就需要手动添加代码如下:

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

处理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虚拟网络连接floodlight 如果在某主机的虚拟机中运行mininet,同时floodlight也运行在该主机上,必须确保主机IP地址和mininet对应,下例中都设置为网关(192.168.110.2)

mininet@mininet:~$ sudo route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
192.168.110.0   0.0.0.0         255.255.255.0   U     0      0        0 eth0
0.0.0.0         192.168.110.2   0.0.0.0         UG    0      0        0 eth0
 
mininet@mininet:~$ sudo mn --mac --controller=remote --ip=192.168.110.2 --port=6633
*** 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命令生成的debug信息都将从MACTracker发送到控制台

添加模块服务

简介 控制器由一个负责监听openflow socket并派发时间的核心模块,以及一些向核心模块注册用于处理响应事件的二级模块构成。当控制器启动时,可启用debug log,进而看的这些二级模块的注册过程,示例如下:

17:29:23.231 [main] DEBUG n.f.core.internal.Controller - OFListeners for PACKET_IN: devicemanager,
17:29:23.231 [main] DEBUG n.f.core.internal.Controller - OFListeners for PORT_STATUS: devicemanager,
17:29:23.237 [main] DEBUG n.f.c.module.FloodlightModuleLoader - Starting net.floodlightcontroller.restserver.RestApiServer
17:29:23.237 [main] DEBUG n.f.c.module.FloodlightModuleLoader - Starting net.floodlightcontroller.forwarding.Forwarding
17:29:23.237 [main] DEBUG n.f.forwarding.Forwarding - Starting net.floodlightcontroller.forwarding.Forwarding
17:29:23.237 [main] DEBUG n.f.core.internal.Controller - OFListeners for PACKET_IN: devicemanager,forwarding,
17:29:23.237 [main] DEBUG n.f.c.module.FloodlightModuleLoader - Starting net.floodlightcontroller.storage.memory.MemoryStorageSource
17:29:23.240 [main] DEBUG n.f.restserver.RestApiServer - Adding REST API routable net.floodlightcontroller.storage.web.StorageWebRoutable
17:29:23.242 [main] DEBUG n.f.c.module.FloodlightModuleLoader - Starting net.floodlightcontroller.core.OFMessageFilterManager
17:29:23.242 [main] DEBUG n.f.core.internal.Controller - OFListeners for PACKET_IN: devicemanager,forwarding,messageFilterManager,
17:29:23.242 [main] DEBUG n.f.core.internal.Controller - OFListeners for PACKET_OUT: messageFilterManager,
17:29:23.242 [main] DEBUG n.f.core.internal.Controller - OFListeners for FLOW_MOD: messageFilterManager,
17:29:23.242 [main] DEBUG n.f.c.module.FloodlightModuleLoader - Starting net.floodlightcontroller.routing.dijkstra.RoutingImpl
17:29:23.247 [main] DEBUG n.f.c.module.FloodlightModuleLoader - Starting net.floodlightcontroller.core.CoreModule
17:29:23.248 [main] DEBUG n.f.core.internal.Controller - Doing controller internal setup
17:29:23.251 [main] INFO  n.f.core.internal.Controller - Connected to storage source
17:29:23.252 [main] DEBUG n.f.restserver.RestApiServer - Adding REST API routable net.floodlightcontroller.core.web.CoreWebRoutable
17:29:23.252 [main] DEBUG n.f.c.module.FloodlightModuleLoader - Starting net.floodlightcontroller.topology.internal.TopologyImpl
17:29:23.254 [main] DEBUG n.f.core.internal.Controller - OFListeners for PACKET_IN: topology,devicemanager,forwarding,messageFilterManager,
17:29:23.254 [main] DEBUG n.f.core.internal.Controller - OFListeners for PORT_STATUS: devicemanager,topology,

针对不同事件,对应不同类型的openflow消息生成,这些动作大部分与packetin有关,packet-in是交换机没流表项能与数据包想匹配时,由交换机发给控制器的openflow消息,控制器进而出来数据包,用一组flowmod消息在交换机上部署流表项,下文示例增加一个新packet-in监听器用于存放packet-in消息,进而允许rest API获得这些消息。 创建类 在Eclipse中添加类 1 在floodlight项目中找到”src/main/java” 文件 2 在 “src/main/java”文件下选择 “New/Class.” 3 在packet中输入”net.floodlightcontroller.pktinhistory” 4 在name中输入 “PktInHistory”。 5 在”Interfaces”中选择choose “Add…“,单击“choose interface”增加”IFloodlightListener”和”IFloodlightModule”,然后单击“OK” 6 最后单击“finish”。 得到如下程序:

package net.floodlightcontroller.pktinhistory;
 
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;
 
public class PktInHistory implements IFloodlightModule, IOFMessageListener {
 
	@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 net.floodlightcontroller.core.IListener.Command receive(
			IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
		// TODO Auto-generated method stub
		return null;
	}
 
	@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
	}
}

设置模块依赖关系 模块需要监听openflow消息,因此需要向FloodlightProviderprotected 注册,需要增加依赖关系,创建成员变量如下:

IFloodlightProviderService floodlightProvider;

然后将新增模块与模块加载相关联,通过完善getModuleDependencies() 告知模块加载器在floodlight启动时自己加载。

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

处理OpenFlow 消息 本部分实现对of packet_in消息的处理,利用一个buffer来存储近期收到的of消息,以备查询。 在startup()中注册监听器,告诉provider我们希望处理OF的PacketIn消息。

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

为OFMessage监听器提供id信息,需调用getName()。

@Override
public String getName() {
	return "PktInHistory";
}

对CallbackOrderingPrereq() 和 isCallbackOrderingPostreq()的调用,只需让它们返回false,packetin消息处理链的执行顺序并不重要。 作为类内部变量,创建circular buffer(import相关包),存储packet in消息。

protected ConcurrentCircularBuffer<SwitchMessagePair> buffer;

在初始化过程中初始化该变量。

@Override
public void init(FloodlightModuleContext context) throws FloodlightModuleException {
	floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
	buffer = new ConcurrentCircularBuffer<SwitchMessagePair>(SwitchMessagePair.class, 100);
}

最后实现模块接收到packetin消息时的处理动作。

@Override
public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
	switch(msg.getType()) {
		 case PACKET_IN:
			 buffer.add(new SwitchMessagePair(sw, msg));
			 break;
		default:
			break;
	 }
	 return Command.CONTINUE;
}

每次packetin发生,其相应消息都会增加相关的交换机消息。该方法返回 Command.CONTINUE 以告知 IFloodlightProvider能将packetin发给下一模块,若返回Command.STOP,则指消息就停在该模块不继续被处理。

添加rest API 在实现了一个完整的模块之后,我们可以实现一个rest api,来获取该模块的相关信息。需要完成两件事情:利用创建的模块导出一个服务,并把该服务绑到REST API模块。 具体说来,注册一个新的Restlet,包括

  1. 在net.floodlightcontroller.controller.internal.Controller中注册一个restlet。
  2. 实现一个*WebRoutable类。该类实现了RestletRoutable,并提供了getRestlet()和basePath()函数。
  3. 实现一个*Resource类,该类扩展了ServerResource(),并实现了@Get或@Put函数。

下面具体来看该如何实现。 创建并绑定接口IPktInHistoryService 首先在pktinhistory包中创建一个从IFloodlightService扩展出来的接口IPktInHistoryService(IPktInHistoryService.java),该服务拥有一个方法getBuffer(),来读取circular buffer中的信息。

package net.floodlightcontroller.pktinhistory; 
import net.floodlightcontroller.core.module.IFloodlightService; 
import net.floodlightcontroller.core.types.SwitchMessagePair; 
public interface IPktinHistoryService extends IFloodlightService { 
	public ConcurrentCircularBuffer<SwitchMessagePair> getBuffer(); 
} 

现在回到原先创建的PktInHistory.java。相应类定义修订如下,让它具体实现IpktInHistoryService接口,

public class PktInHistory implements IFloodlightModule, IPktinHistoryService, IOFMessageListener { 

并实现服务的getBuffer()方法。

@Override 
public ConcurrentCircularBuffer<SwitchMessagePair> getBuffer() { 
	return buffer; 
} 

通过修改PktInHistory模块中getModuleServices()和getServiceImpls()方法通知模块系统,我们提供了IPktInHistoryService。

@Override 
public Collection<Class<? extends IFloodlightService>> getModuleServices() { 
	Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>(); 
	l.add(IPktinHistoryService.class); 
	return l; 
} 
@Override 
public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() { 
	Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>(); 
	m.put(IPktinHistoryService.class, this); 
	return m; 
} 

getServiceImpls()会告诉模块系统,本类(PktInHistory)是提供服务的类。 添加变量引用REST API服务 之后,需要添加REST API服务的引用(需要import相关包)。 protected IRestApiService restApi; 并添加IRestApiService作为依赖,这需要修改init()和getModuleDependencies()。

@Override 
public Collection<Class<? extends IFloodlightService>> getModuleDependencies() { 
	Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>(); 
	l.add(IFloodlightProviderService.class); 
	l.add(IRestApiService.class); 
	return l; 
} 
@Override 
public void init(FloodlightModuleContext context) throws FloodlightModuleException { 
	floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class); 
	restApi = context.getServiceImpl(IRestApiService.class); 
	buffer = new ConcurrentCircularBuffer<SwitchMessagePair>(SwitchMessagePair.class, 100); 
} 

创建REST API相关的类PktInHistoryResource和PktInHistoryWebRoutable 现在创建用在REST API中的类,包括两部分,创建处理url call的类和注册到REST API的类。 首先创建处理REST API请求的类PktInHistoryResource(PktInHistoryResource.java)。当请求到达时,该类将返回circular buffer中的内容。

package net.floodlightcontroller.pktinhistory; 
 
import java.util.ArrayList; 
import java.util.List; 
import net.floodlightcontroller.core.types.SwitchMessagePair; 
import org.restlet.resource.Get; 
import org.restlet.resource.ServerResource; 
 
public class PktInHistoryResource extends ServerResource { 
	@Get("json") 
	public List<SwitchMessagePair> retrieve() { 
		IPktinHistoryService pihr = (IPktinHistoryService)getContext().getAttributes().get(IPktinHistoryService.class.getCanonicalName()); 
		List<SwitchMessagePair> l = new ArrayList<SwitchMessagePair>(); 
		l.addAll(java.util.Arrays.asList(pihr.getBuffer().snapshot())); 
		return l; 
	} 
} 

现在创建PktInHistoryWebRoutable类(PktInHistoryWebRoutable.java),负责告诉REST API我们注册了API并将它的URL绑定到指定的资源上。

package net.floodlightcontroller.pktinhistory; 
import org.restlet.Context; 
import org.restlet.Restlet; 
import org.restlet.routing.Router; 
import net.floodlightcontroller.restserver.RestletRoutable; 
public class PktInHistoryWebRoutable implements RestletRoutable { 
	@Override 
	public Restlet getRestlet(Context context) { 
		Router router = new Router(context); 
		router.attach("/history/json", PktInHistoryResource.class); 
		return router; 
	} 
	@Override 
	public String basePath() { 
		return "/wm/pktinhistory"; 
	} 
} 

并将Restlet PktInHistoryWebRoutable注册到REST API服务,这通过修改PktInHistory类中的startUp()方法来完成。

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

自定义序列化类 数据会被Jackson序列化为REST格式。如果需要指定部分序列化,需要自己实现序列化类OFSwitchImplJSONSerializer(OFSwitchImplJSONSerializer.java,位于net.floodlightcontroller.web.serialzers包中),并添加到net.floodlightcontroller.web.serialzers包。 package net.floodlightcontroller.core.web.serializers;

import java.io.IOException; 
import net.floodlightcontroller.core.internal.OFSwitchImpl; 
import org.codehaus.jackson.JsonGenerator; 
import org.codehaus.jackson.JsonProcessingException; 
import org.codehaus.jackson.map.JsonSerializer; 
import org.codehaus.jackson.map.SerializerProvider; 
import org.openflow.util.HexString; 
 
public class OFSwitchImplJSONSerializer extends JsonSerializer<OFSwitchImpl> { 
	/** 
	* Handles serialization for OFSwitchImpl 
	*/ 
	@Override 
	public void serialize(OFSwitchImpl switchImpl, JsonGenerator jGen, 
	SerializerProvider arg2) throws IOException, 
	JsonProcessingException { 
		jGen.writeStartObject(); 
		jGen.writeStringField("dpid", HexString.toHexString(switchImpl.getId())); 
		jGen.writeEndObject(); 
	} 
	/** 
	* Tells SimpleModule that we are the serializer for OFSwitchImpl 
	*/ 
	@Override 
	public Class<OFSwitchImpl> handledType() { 
		return OFSwitchImpl.class; 
	} 
} 

现在需要告诉Jackson使用我们的序列器。打开OFSwitchImpl.java >(位于net.floodlightcontroller.core.internal包),修改如下(需要import 我们创建的OFSwitchImplJSONSerializer包)

@JsonSerialize(using=OFSwitchImplJSONSerializer.class) 
public class OFSwitchImpl implements IOFSwitch { 

至此,新建模块基本完成,还需告诉loader我们的模块存在,添加模块名字到src/main/resources/META-INF/services/net.floodlight.core.module.IfloodlightModule

net.floodlightcontroller.pktinhistory.PktInHistory 

然后告知模块需要被加载。修改模块配置文件src/main/resources/floodlightdefault.properties中的floodlight.modules变量。

floodlight.modules = net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher,\ 
net.floodlightcontroller.forwarding.Forwarding,\ 
net.floodlightcontroller.pktinhistory.PktInHistory 

启动mininet。

mn --controller=remote --ip=[Your IP Address] --mac --topo=tree,2 
*** Adding controller 
*** Creating network 
*** Adding hosts: 
h1 h2 h3 h4 
*** Adding switches: 
s5 s6 s7 
*** Adding links: 
(h1, s6) (h2, s6) (h3, s7) (h4, s7) (s5, s6) (s5, s7) 
*** Configuring hosts 
h1 h2 h3 h4 
*** Starting controller 
*** Starting 3 switches 
s5 s6 s7 
*** Starting CLI: 
启动后,运行 
mininet> pingall 
*** Ping: testing ping reachability 
h1 -> h2 h3 h4 
h2 -> h1 h3 h4 
h3 -> h1 h2 h4 
h4 -> h1 h2 h3 
*** Results: 0% dropped (0/12 lost) 

利用REST URL拿到结果

$ curl -s http://localhost:8080/wm/pktinhistory/history/json | python -mjson.tool


[
	{
		"message": {
			"bufferId": 256,
			"inPort": 2,
			"length": 96,
			"lengthU": 96,
			"packetData": "MzP/Uk+PLoqIUk+Pht1gAAAAABg6/wAAAAAAAAAAAAAAAAAAAAD/AgAAAAAAAAAAAAH/Uk+PhwAo2gAAAAD+gAAAAAAAACyKiP/+Uk+P",
			"reason": "NO_MATCH",
			"totalLength": 78,
			"type": "PACKET_IN",
			"version": 1,
			"xid": 0
		},
		"switch": {
			"dpid": "00:00:00:00:00:00:00:06"
		}
	},
	{
		"message": {
			"bufferId": 260,
			"inPort": 1,
			"length": 96,
			"lengthU": 96,
			"packetData": "MzP/Uk+PLoqIUk+Pht1gAAAAABg6/wAAAAAAAAAAAAAAAAAAAAD/AgAAAAAAAAAAAAH/Uk+PhwAo2gAAAAD+gAAAAAAAACyKiP/+Uk+P",
			"reason": "NO_MATCH",
			"totalLength": 78,
			"type": "PACKET_IN",
			"version": 1,
			"xid": 0
		},
		"switch": {
			"dpid": "00:00:00:00:00:00:00:05"
		}
	},
etc....etc....