SDN之QoS--3:网络基础信息的测量(Floodlight)

模块该部分承接上文,添加三个模块,来实现网络带宽使用、丢包率、链路时延等的测量。当然,读者也可以把他们三个木块合并,只是那样的话,每一个service就不单一了。

一、说在前面

一般来讲,我们在Floodlight中添加自定义的模块,最基础的需要实现以下两个步骤:

  1. 自定义一个interface,里面写上自定义的方法,当然,需要extends IFloodlightServcice.
  2. 自定义一个class,实现我们的那个interface,还需要实现IFloodlightModule。如果还需要处理OpenFlow消息还需要实现IOFMessageListener,其他类似;如果需要使用FL提供的线程池,那就需要添加改依赖。
在getModuleDependencies()中添加

接下来,我主要记录我们是如何采集到链路带宽使用情况,以及需要依赖那些service,另外两个模块与这个答题类似,就只贴上代码了。

二、链路带宽使用情况
定义的interface : IMonitorBandwidthService

public interface IMonitorBandwidthService extends IFloodlightService {
    //带宽使用情况
    public Map getBandwidthMap();
}

然后是定义的MonitorBandwidth

package aaa.net.floodlightcontroller.test;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.internal.IOFSwitchService;
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.statistics.IStatisticsService;
import net.floodlightcontroller.statistics.StatisticsCollector;
import net.floodlightcontroller.statistics.SwitchPortBandwidth;
import net.floodlightcontroller.threadpool.IThreadPoolService;
import net.floodlightcontroller.topology.NodePortTuple;

/**
 * 带宽获取模块
 * @author xjtu
 *
 */
public class MonitorBandwidth implements IFloodlightModule,IMonitorBandwidthService{

    //日志工具
    private static final Logger log = LoggerFactory.getLogger(StatisticsCollector.class);
    //Floodlight最核心的service类,其他service类需要该类提供
    protected static IFloodlightProviderService floodlightProvider;
    //链路数据分析模块,已经由Floodlight实现了,我们只需要调用一下就可以,然后对结果稍做加工,便于我们自己使用
    protected static IStatisticsService statisticsService;
    //Floodllight实现的线程池,当然我们也可以使用Java自带的,但推荐使用这个
    private static IThreadPoolService threadPoolService;
    //Future类,不明白的可以百度 Java现成future,其实C++11也有这个玩意了
    private static ScheduledFuture portBandwidthCollector;
    //交换机相关的service,通过这个服务,我们可以获取所有的交换机,即DataPath
    private static IOFSwitchService switchService;
    //存放每条俩路的带宽使用情况 
    private static Map bandwidth;
    //搜集数据的周期
    private static final int portBandwidthInterval = 4;

    //告诉FL,我们添加了一个模块,提供了IMonitorBandwidthService
    @Override
    public Collection> getModuleServices() {
        Collection> l = new ArrayList>();
        l.add(IMonitorBandwidthService.class);
        return l;
    }
    //我们前面声明了几个需要使用的service,在这里说明一下实现类
    @Override
    public Map, IFloodlightService> getServiceImpls() {
        Map, IFloodlightService> m = new HashMap, IFloodlightService>();
        m.put(IMonitorBandwidthService.class, this);
        return m;
    }

    //告诉FL我们以来那些服务,以便于加载
    @Override
    public Collection> getModuleDependencies() {
        Collection> l = new ArrayList>();
        l.add(IFloodlightProviderService.class);
        l.add(IStatisticsService.class);
        l.add(IOFSwitchService.class);
        l.add(IThreadPoolService.class);
        return l;
    }

    //初始化这些service,个人理解这个要早于startUp()方法的执行,验证很简单,在两个方法里打印当前时间就可以。
    @Override
    public void init(FloodlightModuleContext context) throws FloodlightModuleException {
        floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
        statisticsService = context.getServiceImpl(IStatisticsService.class);
        switchService = context.getServiceImpl(IOFSwitchService.class);
        threadPoolService = context.getServiceImpl(IThreadPoolService.class);
    }

    @Override
    public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
        startCollectBandwidth();
    }

    //自定义的开始收集数据的方法,使用了线程池,定周期的执行
    private synchronized void startCollectBandwidth(){
        portBandwidthCollector = threadPoolService.getScheduledExecutor().scheduleAtFixedRate(new GetBandwidthThread(), portBandwidthInterval, portBandwidthInterval, TimeUnit.SECONDS);
        log.warn("Statistics collection thread(s) started");
    }

    //自定义的线程类,在上面的方法中实例化,并被调用
    /**
     * Single thread for collecting switch statistics and
     * containing the reply.
     */
    private class GetBandwidthThread extends Thread implements Runnable  {
        private Map bandwidth;

        public Map getBandwidth() {
            return bandwidth;
        }

//      public void setBandwidth(Map bandwidth) {
//          this.bandwidth = bandwidth;
//      }

        @Override
        public void run() {
            System.out.println("GetBandwidthThread run()....");
            bandwidth =getBandwidthMap(); 
            System.out.println("bandwidth.size():"+bandwidth.size());
        }
    }

    /**
     * 获取带宽使用情况
     * 需要简单的换算 
        根据 switchPortBand.getBitsPerSecondRx().getValue()/(8*1024) + switchPortBand.getBitsPerSecondTx().getValue()/(8*1024)
        计算带宽
     */
    public Map getBandwidthMap(){
        bandwidth = statisticsService.getBandwidthConsumption();
//      
//      for(NodePortTuple tuple:bandwidth.keySet()){
//          System.out.println(tuple.getNodeId().toString()+","+tuple.getPortId().getPortNumber());
//          System.out.println();
//      }
        Iterator> iter = bandwidth.entrySet().iterator();
        while (iter.hasNext()) {
            Entry entry = iter.next();
            NodePortTuple tuple  = entry.getKey();
            SwitchPortBandwidth switchPortBand = entry.getValue();
            System.out.print(tuple.getNodeId()+","+tuple.getPortId().getPortNumber()+",");
            System.out.println(switchPortBand.getBitsPerSecondRx().getValue()/(8*1024) + switchPortBand.getBitsPerSecondTx().getValue()/(8*1024));

        }


        return bandwidth;
    }

}

三、链路丢包率统计

import net.floodlightcontroller.core.module.IFloodlightService;

public interface IMonitorPkLossService extends IFloodlightService {
//  public Map<> getPkLoss(Object o1,Object o2);
}
package aaa.net.floodlightcontroller.test;

import java.lang.Thread.State;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFPortStatsEntry;
import org.projectfloodlight.openflow.protocol.OFPortStatsReply;
import org.projectfloodlight.openflow.protocol.OFStatsReply;
import org.projectfloodlight.openflow.protocol.OFStatsRequest;
import org.projectfloodlight.openflow.protocol.OFStatsType;
import org.projectfloodlight.openflow.protocol.OFType;
import org.projectfloodlight.openflow.protocol.OFVersion;
import org.projectfloodlight.openflow.protocol.match.Match;
import org.projectfloodlight.openflow.protocol.ver13.OFMeterSerializerVer13;
import org.projectfloodlight.openflow.types.DatapathId;
import org.projectfloodlight.openflow.types.OFPort;
import org.projectfloodlight.openflow.types.TableId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.primitives.UnsignedLong;
import com.google.common.util.concurrent.ListenableFuture;

import net.floodlightcontroller.core.FloodlightContext;
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IOFMessageListener;
import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.core.internal.IOFSwitchService;
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.statistics.IStatisticsService;
import net.floodlightcontroller.statistics.StatisticsCollector;
import net.floodlightcontroller.threadpool.IThreadPoolService;
import net.floodlightcontroller.topology.NodePortTuple;

/**
 * 获取丢包率模块
 * @author xjtu
 *
 */

public class MonitorPkLoss implements IMonitorPkLossService,IFloodlightModule,IOFMessageListener {
    private static final Logger log = LoggerFactory.getLogger(StatisticsCollector.class);

    private static  HashMap DPID_PK_LOSS = new HashMap();

    protected static IFloodlightProviderService floodlightProvider;
    protected static IStatisticsService statisticsService;
    private static IOFSwitchService switchService;
    private static IThreadPoolService threadPoolService;
    private static ScheduledFuture portStatsCollector;

    private static int portStatsInterval = 4;


    @Override
    public Collection> getModuleServices() {
        Collection> l = new ArrayList>();
        l.add(IMonitorPkLossService.class);
        return l;
    }

    @Override
    public Map, IFloodlightService> getServiceImpls() {
        Map, IFloodlightService> m = new HashMap, IFloodlightService>();
        m.put(IMonitorPkLossService.class, this);
        return m;
    }

    @Override
    public Collection> getModuleDependencies() {
        Collection> l = new ArrayList>();
        l.add(IFloodlightProviderService.class);
        l.add(IStatisticsService.class);
        l.add(IOFSwitchService.class);
        l.add(IThreadPoolService.class);
        return l;
    }

    @Override
    public void init(FloodlightModuleContext context) throws FloodlightModuleException {
        floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
        statisticsService = context.getServiceImpl(IStatisticsService.class);
        switchService = context.getServiceImpl(IOFSwitchService.class);
        threadPoolService = context.getServiceImpl(IThreadPoolService.class);

    }

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

    @Override
    public String getName() {

        return "monitorpkloss";
    }

    @Override
    public boolean isCallbackOrderingPrereq(OFType type, String name) {

        return false;
    }

    @Override
    public boolean isCallbackOrderingPostreq(OFType type, String name) {

        return false;
    }

    @Override
    public Command receive(IOFSwitch sw, OFMessage msg,FloodlightContext cntx) {
//      Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
//      Long sourceMACHash = eth.getSourceMACAddress().getLong();
//      OFFactory factory = sw.getOFFactory();
        /**
         * 获取丢包率
         */
//      if(msg.getType() == OFType.STATS_REPLY){
//          OFStatsReply reply = (OFStatsReply) msg;
//          OFPortStatsReply psr = (OFPortStatsReply) reply;
//          OFPortStatsEntry pse = (OFPortStatsEntry) psr;
//          System.out.println("rx bytes:"+pse.getRxBytes().getValue());
//          System.out.println("rx_dropped bytes:"+pse.getRxDropped().getValue());
//          System.out.println("tx bytes:"+pse.getTxBytes().getValue());
//          System.out.println("tx_dropped bytes:"+pse.getTxDropped().getValue());
//      }









        return Command.CONTINUE;
    }

    /**
     * Start all stats threads.
     */
    private synchronized void startStatisticsCollection() {
        portStatsCollector = threadPoolService.getScheduledExecutor().scheduleAtFixedRate(new PortStatsCollector(), portStatsInterval, portStatsInterval, TimeUnit.SECONDS);
        log.warn("Statistics collection thread(s) started");
    }


    /**
     * Single thread for collecting switch statistics and
     * containing the reply.
     */
    private class GetStatisticsThread extends Thread {
        private List statsReply;
        private DatapathId switchId;
        private OFStatsType statType;

        public GetStatisticsThread(DatapathId switchId, OFStatsType statType) {
            this.switchId = switchId;
            this.statType = statType;
            this.statsReply = null;
        }

        public List getStatisticsReply() {
            return statsReply;
        }

        public DatapathId getSwitchId() {
            return switchId;
        }

        @Override
        public void run() {
//          System.out.println("run............");
            statsReply = getSwitchStatistics(switchId, statType);
        }
    }

    /**
     * Get statistics from a switch.
     * @param switchId
     * @param statsType
     * @return
     */
    @SuppressWarnings("unchecked")
    protected List getSwitchStatistics(DatapathId switchId, OFStatsType statsType) {
        IOFSwitch sw = switchService.getSwitch(switchId);
//      System.out.println("getSwitchStatistics............");
        ListenableFuture future;
        List values = null;
        Match match;
        if (sw != null) {
            OFStatsRequest req = null;
            switch (statsType) {
            case FLOW:
                match = sw.getOFFactory().buildMatch().build();
                req = sw.getOFFactory().buildFlowStatsRequest()
                        .setMatch(match)
                        .setOutPort(OFPort.ANY)
                        .setTableId(TableId.ALL)
                        .build();
                break;
            case AGGREGATE:
                match = sw.getOFFactory().buildMatch().build();
                req = sw.getOFFactory().buildAggregateStatsRequest()
                        .setMatch(match)
                        .setOutPort(OFPort.ANY)
                        .setTableId(TableId.ALL)
                        .build();
                break;
            case PORT:
                req = sw.getOFFactory().buildPortStatsRequest()
                .setPortNo(OFPort.ANY)
                .build();
                break;
            case QUEUE:
                req = sw.getOFFactory().buildQueueStatsRequest()
                .setPortNo(OFPort.ANY)
                .setQueueId(UnsignedLong.MAX_VALUE.longValue())
                .build();
                break;
            case DESC:
                req = sw.getOFFactory().buildDescStatsRequest()
                .build();
                break;
            case GROUP:
                if (sw.getOFFactory().getVersion().compareTo(OFVersion.OF_10) > 0) {
                    req = sw.getOFFactory().buildGroupStatsRequest()                
                            .build();
                }
                break;

            case METER:
                if (sw.getOFFactory().getVersion().compareTo(OFVersion.OF_13) >= 0) {
                    req = sw.getOFFactory().buildMeterStatsRequest()
                            .setMeterId(OFMeterSerializerVer13.ALL_VAL)
                            .build();
                }
                break;

            case GROUP_DESC:            
                if (sw.getOFFactory().getVersion().compareTo(OFVersion.OF_10) > 0) {
                    req = sw.getOFFactory().buildGroupDescStatsRequest()            
                            .build();
                }
                break;

            case GROUP_FEATURES:
                if (sw.getOFFactory().getVersion().compareTo(OFVersion.OF_10) > 0) {
                    req = sw.getOFFactory().buildGroupFeaturesStatsRequest()
                            .build();
                }
                break;

            case METER_CONFIG:
                if (sw.getOFFactory().getVersion().compareTo(OFVersion.OF_13) >= 0) {
                    req = sw.getOFFactory().buildMeterConfigStatsRequest()
                            .build();
                }
                break;

            case METER_FEATURES:
                if (sw.getOFFactory().getVersion().compareTo(OFVersion.OF_13) >= 0) {
                    req = sw.getOFFactory().buildMeterFeaturesStatsRequest()
                            .build();
                }
                break;

            case TABLE:
                if (sw.getOFFactory().getVersion().compareTo(OFVersion.OF_10) > 0) {
                    req = sw.getOFFactory().buildTableStatsRequest()
                            .build();
                }
                break;

            case TABLE_FEATURES:    
                if (sw.getOFFactory().getVersion().compareTo(OFVersion.OF_10) > 0) {
                    req = sw.getOFFactory().buildTableFeaturesStatsRequest()
                            .build();       
                }
                break;
            case PORT_DESC:
                if (sw.getOFFactory().getVersion().compareTo(OFVersion.OF_13) >= 0) {
                    req = sw.getOFFactory().buildPortDescStatsRequest()
                            .build();
                }
                break;
            case EXPERIMENTER:      
            default:
                log.error("Stats Request Type {} not implemented yet", statsType.name());
                break;
            }
            try {
                if (req != null) {
                    future = sw.writeStatsRequest(req); 
                    values = (List) future.get(portStatsInterval / 2, TimeUnit.SECONDS);
                }
            } catch (Exception e) {
                log.error("Failure retrieving statistics from switch {}. {}", sw, e);
            }
        }
        return values;
    }
    /**
     * Retrieve the statistics from all switches in parallel.
     * @param dpids
     * @param statsType
     * @return
     */
    private Map> getSwitchStatistics(Set dpids, OFStatsType statsType) {
        HashMap> model = new HashMap>();

        List activeThreads = new ArrayList(dpids.size());
        List pendingRemovalThreads = new ArrayList();
        GetStatisticsThread t;
        for (DatapathId d : dpids) {
            t = new GetStatisticsThread(d, statsType);
            activeThreads.add(t);
            t.start();
        }

        /* Join all the threads after the timeout. Set a hard timeout
         * of 12 seconds for the threads to finish. If the thread has not
         * finished the switch has not replied yet and therefore we won't
         * add the switch's stats to the reply.
         */
        for (int iSleepCycles = 0; iSleepCycles < portStatsInterval; iSleepCycles++) {
            for (GetStatisticsThread curThread : activeThreads) {
                if (curThread.getState() == State.TERMINATED) {
                    model.put(curThread.getSwitchId(), curThread.getStatisticsReply());
                    pendingRemovalThreads.add(curThread);
                }
            }

            /* remove the threads that have completed the queries to the switches */
            for (GetStatisticsThread curThread : pendingRemovalThreads) {
                activeThreads.remove(curThread);
            }

            /* clear the list so we don't try to double remove them */
            pendingRemovalThreads.clear();

            /* if we are done finish early */
            if (activeThreads.isEmpty()) {
                break;
            }

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                log.error("Interrupted while waiting for statistics", e);
            }
        }

        return model;
    }


    /**
     * Run periodically to collect all port statistics. This only collects
     * bandwidth stats right now, but it could be expanded to record other
     * information as well. The difference between the most recent and the
     * current RX/TX bytes is used to determine the "elapsed" bytes. A 
     * timestamp is saved each time stats results are saved to compute the
     * bits per second over the elapsed time. There isn't a better way to
     * compute the precise bandwidth unless the switch were to include a
     * timestamp in the stats reply message, which would be nice but isn't
     * likely to happen. It would be even better if the switch recorded 
     * bandwidth and reported bandwidth directly.
     * 
     * Stats are not reported unless at least two iterations have occurred
     * for a single switch's reply. This must happen to compare the byte 
     * counts and to get an elapsed time.
     *
     */
    private class PortStatsCollector implements Runnable {
        @Override
        public void run() {
//          System.out.println("Runnable run()....");
            Map> replies = getSwitchStatistics(switchService.getAllSwitchDpids(), OFStatsType.PORT);
//          System.out.println("replies.size():"+replies.size());
            for (Entry> e : replies.entrySet()) {
                for (OFStatsReply r : e.getValue()) {
                    OFPortStatsReply psr = (OFPortStatsReply) r;
                    for (OFPortStatsEntry pse : psr.getEntries()) {
//                      System.out.println("dpid:"+e.getKey().toString());
//                      System.out.println("for (OFPortStatsEntry pse : psr.getEntries())");

                        long pk_loss = 0;

                        if(e.getKey().toString().equals("") || e.getKey() == null){
//                          System.out.println("e.getKey() is null....");
                        }
//                      System.out.println("--------------------------------------------");
                        NodePortTuple npt = new NodePortTuple(e.getKey(), pse.getPortNo());
//                      System.out.println("--------------------------------------------");
//                      System.out.println(pse.getRxDropped().getValue() + pse.getTxDropped().getValue());
//                      System.out.println(pse.getRxBytes().getValue() + pse.getTxBytes().getValue());
                        if((pse.getRxBytes().getValue() + pse.getTxBytes().getValue()) != 0l){
                            pk_loss = (pse.getRxDropped().getValue() + pse.getTxDropped().getValue())/(pse.getRxBytes().getValue() + pse.getTxBytes().getValue()) ;
                        }else{
                            pk_loss = 0;
                        }

//                      System.out.println("PK_LOSS:"+pk_loss+",dpid:"+e.getKey().toString());
                        DPID_PK_LOSS.put(npt, pk_loss);
                    }
                }
            }
        }
    }


}

四、链路时延

public interface IMonitorDelayService extends IFloodlightService{
    /**
     * 获取链路之间的时间延迟
     * @return Map,Integer> 链路:时延
     */
//  public Map,Integer> getLinkDelay(); 
}
package aaa.net.floodlightcontroller.test;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFPortDesc;
import org.projectfloodlight.openflow.protocol.OFType;
import org.projectfloodlight.openflow.types.DatapathId;

import net.floodlightcontroller.core.FloodlightContext;
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IOFMessageListener;
import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.core.IOFSwitchListener;
import net.floodlightcontroller.core.PortChangeType;
import net.floodlightcontroller.core.internal.IOFSwitchService;
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.linkdiscovery.ILinkDiscoveryService;
import net.floodlightcontroller.linkdiscovery.internal.LinkInfo;
import net.floodlightcontroller.routing.Link;
import net.floodlightcontroller.threadpool.IThreadPoolService;
import net.floodlightcontroller.topology.NodePortTuple;

public class MonitorDelay implements IFloodlightModule, IOFMessageListener, IMonitorDelayService,IOFSwitchListener {

    private IThreadPoolService threadPoolServcie;
    private IOFSwitchService switchService;
    private ILinkDiscoveryService linkDiscoveryService;
    private IFloodlightProviderService floodlightProviderService;

    @Override
    public String getName() {

        return "LinkDelay";
    }

    @Override
    public boolean isCallbackOrderingPrereq(OFType type, String name) {
        return false;
    }

    @Override
    public boolean isCallbackOrderingPostreq(OFType type, String name) {
        return false;
    }

    @Override
    public Command receive(IOFSwitch sw, OFMessage msg,
            FloodlightContext cntx) {

        return null;
    }

    @Override
    public Collection> getModuleServices() {

        Collection> l = new ArrayList>();
        l.add(IMonitorDelayService.class);
        return l;
    }

    @Override
    public Map, IFloodlightService> getServiceImpls() {
        Map, IFloodlightService> l = new HashMap<>();
        l.put(IMonitorDelayService.class, this);
        return l;
    }

    @Override
    public Collection> getModuleDependencies() {
        Collection> l = new ArrayList>();
        l.add(IFloodlightProviderService.class);
        l.add(IThreadPoolService.class);
        l.add(IOFSwitchService.class);
        l.add(ILinkDiscoveryService.class);
        return l;
    }

    @Override
    public void init(FloodlightModuleContext context) throws FloodlightModuleException {
        floodlightProviderService = context.getServiceImpl(IFloodlightProviderService.class);
        switchService = context.getServiceImpl(IOFSwitchService.class);
        linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
        threadPoolServcie = context.getServiceImpl(IThreadPoolService.class);
    }


    @Override
    public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {


    }

    @Override
    public void switchAdded(DatapathId switchId) {

    }

    @Override
    public void switchRemoved(DatapathId switchId) {

    }

    @Override
    public void switchActivated(DatapathId switchId) {

    }

    @Override
    public void switchPortChanged(DatapathId switchId, OFPortDesc port, PortChangeType type) {

    }

    @Override
    public void switchChanged(DatapathId switchId) {

    }


    public void testFunc(){
        Map linkInfo = linkDiscoveryService.getLinks();
        Iterator> iter = linkInfo.entrySet().iterator();
        while(iter.hasNext()){
            Entry node = iter.next();
            System.out.println("源交换机:"+node.getKey().getSrc().toString()+",源端口:"+node.getKey().getSrcPort());
            System.out.println("目的交换机:"+node.getKey().getDst().toString()+",目的端口:"+node.getKey().getDstPort());
            System.out.println("链路时延:"+node.getKey().getLatency());
            System.out.println("当前时延:"+node.getValue().getCurrentLatency());
        }
    }


}

五、要记得,在配置文件中需要添加上我们添加的service。如果不熟悉的话,可以参考官网的指南,还是挺不错。
链接如下:https://floodlight.atlassian.net/wiki/display/floodlightcontroller/How+to+Write+a+Module

六、改变我们的路由规则
待续~~
也欢迎各位批评指正。!!

美好的2017年已经开始,祝福天下有情人终成眷属,祝愿所有人身体健康,事事如意。

SDN之QoS--3:网络基础信息的测量(Floodlight)_第1张图片

你可能感兴趣的:(计算机网络)