FloodLight开发者文档四(译文)

添加模块

创建一个监听模块

在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中添加类

在floodlight项目中找到"src/main/java" 文件

在 "src/main/java"文件下选择 "New/Class."

在packet中输入"net.floodlightcontroller.pktinhistory" 

在name中输入 "PktInHistory"。

在"Interfaces"中选择choose "Add...",单击“choose interface”增加"IFloodlightListener"和"IFloodlightModule",然后单击“OK”

最后单击“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....

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值