package edu.usc.enl.dynamicmeasurement.floodlight;
import edu.usc.enl.dynamicmeasurement.algorithms.taskhandler.TaskHandler;
import edu.usc.enl.dynamicmeasurement.data.ConfigReader;
import edu.usc.enl.dynamicmeasurement.data.FinishPacket;
import edu.usc.enl.dynamicmeasurement.model.Packet;
import edu.usc.enl.dynamicmeasurement.model.WildcardPattern;
import edu.usc.enl.dynamicmeasurement.model.event.Event;
import edu.usc.enl.dynamicmeasurement.model.event.EventRunner;
import edu.usc.enl.dynamicmeasurement.model.event.TaskEvent;
import edu.usc.enl.dynamicmeasurement.model.monitorpoint.MonitorPoint;
import edu.usc.enl.dynamicmeasurement.model.monitorpoint.WildcardMonitorPoint;
import edu.usc.enl.dynamicmeasurement.process.PacketUser;
import edu.usc.enl.dynamicmeasurement.util.Util;
import net.floodlightcontroller.core.*;
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.util.SingletonTask;
import net.floodlightcontroller.counter.ICounterStoreService;
import net.floodlightcontroller.threadpool.IThreadPoolService;
import org.openflow.protocol.OFBarrierReply;
import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* Created with IntelliJ IDEA.
* User: masoud
* Date: 10/8/13
* Time: 9:59 PM <br/>
* The main module of DREAM on Floodlight.
* The experiment starts in the following way:
* In the beginning the controller waits for all switches to register.
* Once all switches register, it initiates a periodic configure-fetch algorithm in EpochProcedure class
*/
public class PeriodicReport implements IFloodlightModule, IOFSwitchListener, IOFMessageListener {
protected static Logger log = LoggerFactory.getLogger(PeriodicReport.class);
// Module dependencies
protected IFloodlightProviderService floodlightProvider;
protected IThreadPoolService threadPool;
protected ICounterStoreService counterStore;
//
protected Map<String, SwitchData> registeredSwitches;
private Map<String, MonitorPoint> toRegisterSwitches;
/**
* The number of seconds of an epoch
*/
private int epochSize;
/**
* The actual periodical algorithm
*/
private EpochProcedure doEachEpoch;
/**
* The folder that contains the experiment configuration.
*/
private String configFolder;
@Override
public Collection<Class<? extends IFloodlightService>> getModuleServices() {
return null;
}
@Override
public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
return null;
}
@Override
public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Collection<Class<? extends IFloodlightService>> l = new ArrayList<>();
l.add(IFloodlightProviderService.class);
l.add(ICounterStoreService.class);
l.add(IThreadPoolService.class);
return l;
}
@Override
public void init(FloodlightModuleContext context) throws FloodlightModuleException {
WildcardPattern.TOTAL_LENGTH = 32;
floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
counterStore = context.getServiceImpl(ICounterStoreService.class);
threadPool = context.getServiceImpl(IThreadPoolService.class);
registeredSwitches = new HashMap<>();
Map<String, String> configParams = context.getConfigParams(this);
epochSize = Integer.parseInt(configParams.get("epochSize"));
configFolder = configParams.get("configFolder");
loadConfigFile(configFolder);
}
public String getConfigFolder() {
return configFolder;
}
private void loadConfigFile(String filename) throws FloodlightModuleException {
try {
File file = new File(filename);
if (file.isDirectory()) {
filename = file.getAbsolutePath() + "/config.xml";
}
ConfigReader configReader = new ConfigReader();
configReader.read(filename);
log.info("Load config file " + filename);
//get list of switches
toRegisterSwitches = new HashMap<>();
for (MonitorPoint monitorPoint : Util.getNetwork().getMonitorPoints()) {
toRegisterSwitches.put(monitorPoint.getStringId(), monitorPoint);
}
TaskHandler taskHandler = configReader.getTaskHandler();
for (Event event : configReader.getEvents()) {
event.setEpoch(event.getEpoch() / epochSize); // the traffic generation is based on per second epochs, but run is different
if (event instanceof TaskEvent) {
((TaskEvent) event).setHandler(taskHandler);
}
}
// wrap it by event runner
EventRunner eventRunner = new EventRunner(new PacketUser() {
@Override
public void process(Packet p) {
}
@Override
public void finish(FinishPacket p) {
}
}, configReader.getEvents());
RuntimeTaskHandler runtimeTaskHandler = new RuntimeTaskHandler(taskHandler, eventRunner, epochSize);
doEachEpoch = new EpochProcedure(runtimeTaskHandler, epochSize);
} catch (Exception e) {
throw new FloodlightModuleException(e);
}
}
@Override
public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
floodlightProvider.addOFSwitchListener(this);
floodlightProvider.addOFMessageListener(OFType.BARRIER_REPLY, this);
}
@Override
public void switchAdded(long switchId) {
IOFSwitch sw = floodlightProvider.getSwitch(switchId);
if (sw == null)
return;
registeredSwitches.put(sw.getStringId(), new SwitchData(sw, floodlightProvider, (WildcardMonitorPoint) toRegisterSwitches.get(sw.getStringId())));
if (registeredSwitches.size() >= toRegisterSwitches.size()) {
log.info("All switches are connected.");
ScheduledExecutorService ses = threadPool.getScheduledExecutor();
SingletonTask flowInfoTask = new SingletonTask(ses, doEachEpoch);
doEachEpoch.init(registeredSwitches, flowInfoTask);
flowInfoTask.reschedule(0, TimeUnit.SECONDS);
} else {
log.info("Still waiting for " + (toRegisterSwitches.size() - registeredSwitches.size()) + " more switches");
}
}
@Override
public void switchRemoved(long switchId) {
registeredSwitches.remove("" + switchId);
}
@Override
public void switchActivated(long switchId) {
}
@Override
public void switchPortChanged(long switchId, ImmutablePort port, IOFSwitch.PortChangeType type) {
}
@Override
public void switchChanged(long switchId) {
}
@Override
public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
if (msg.getType().equals(OFType.BARRIER_REPLY)) {
SwitchData switchData = registeredSwitches.get(sw.getStringId());
if (switchData != null) {
switchData.receiveBarrier(((OFBarrierReply) msg));
}
} else {
doEachEpoch.receive(sw, msg);
}
return Command.CONTINUE;
}
@Override
public String getName() {
return "PeriodicReport";
}
@Override
public boolean isCallbackOrderingPrereq(OFType type, String name) {
return false;
}
@Override
public boolean isCallbackOrderingPostreq(OFType type, String name) {
return false;
}
}