package edu.usc.enl.dynamicmeasurement.floodlight;
import edu.usc.enl.dynamicmeasurement.algorithms.tasks.hhh.NeedInitHHHAlgorithm;
import edu.usc.enl.dynamicmeasurement.algorithms.tasks.hhh.flow.FlowHHHAlgorithm;
import edu.usc.enl.dynamicmeasurement.model.WildcardPattern;
import edu.usc.enl.dynamicmeasurement.model.monitorpoint.WildcardMonitorPoint;
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.threadpool.IThreadPoolService;
import org.openflow.protocol.OFBarrierReply;
import org.openflow.protocol.OFFlowMod;
import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFType;
import org.openflow.protocol.statistics.OFFlowStatisticsReply;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* Created with IntelliJ IDEA.
* User: masoud
* Date: 1/25/14
* Time: 8:05 AM <br/>
* A simple floodlight module to install rules, an delete rules from switches to calculate the delay of that
* using the profiler class
*/
public class SwitchTest implements IFloodlightModule, IOFSwitchListener, IOFMessageListener {
protected IFloodlightProviderService floodlightProvider;
protected IThreadPoolService threadPool;
private SwitchData switchData;
private int rulesNum;
private MyRunnable task;
@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(IThreadPoolService.class);
return l;
}
@Override
public void init(FloodlightModuleContext context) throws FloodlightModuleException {
floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
threadPool = context.getServiceImpl(IThreadPoolService.class);
Map<String, String> configParams = context.getConfigParams(this);
rulesNum = Integer.parseInt(configParams.get("rulesNum"));
}
@Override
public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
floodlightProvider.addOFSwitchListener(this);
floodlightProvider.addOFMessageListener(OFType.BARRIER_REPLY, this);
floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
}
@Override
public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
if (msg.getType().equals(OFType.BARRIER_REPLY)) {
if (this.switchData != null) {
this.switchData.receiveBarrier(((OFBarrierReply) msg));
}
} else {
System.out.println(sw + "-->" + msg);
}
return Command.CONTINUE;
}
@Override
public String getName() {
return "BarrierTest";
}
@Override
public boolean isCallbackOrderingPrereq(OFType type, String name) {
return false;
}
@Override
public boolean isCallbackOrderingPostreq(OFType type, String name) {
return false;
}
@Override
public void switchAdded(long switchId) {
}
@Override
public void switchRemoved(long switchId) {
if (switchData != null && switchId == switchData.getIntId()) {
switchData = null;
System.out.println("switch " + switchId + " removed");
task.cancel();
}
}
@Override
public void switchActivated(long switchId) {
if (switchData != null) { //just one switch
return;
}
System.out.println("switch " + switchId + " wants to connect");
if (switchId > 100 || switchId == 1) {//just to ignore other switches except the switch with mac 1
final IOFSwitch sw = floodlightProvider.getSwitch(switchId);
ScheduledExecutorService ses = threadPool.getScheduledExecutor();
this.switchData = new SwitchData(sw, floodlightProvider,
new WildcardMonitorPoint(rulesNum, new HashSet<>(Arrays.asList(new WildcardPattern(0, WildcardPattern.TOTAL_LENGTH, 0)))));
task = new MyRunnable(this.switchData, rulesNum);
SingletonTask flowInfoTask = new SingletonTask(ses, task);
task.setFlowInfoTask(flowInfoTask);
flowInfoTask.reschedule(5, TimeUnit.SECONDS);
}
}
@Override
public void switchPortChanged(long switchId, ImmutablePort port, IOFSwitch.PortChangeType type) {
}
@Override
public void switchChanged(long switchId) {
}
private enum State {INIT, SAVE, DELETE}
private class MyRunnable implements Runnable {
private final SwitchData sw;
private final ArrayList<OFFlowStatisticsReply> stats;
private SingletonTask flowInfoTask;
private List<OFMessage> rules;
private List<OFMessage> deleteRules;
private State state;
private boolean cancel = false;
private int epoch = 0;
public MyRunnable(SwitchData sw, int rulesToInstall) {
this.sw = sw;
rules = new ArrayList<>();
OFFlowMod defaultFlowMod = RuleSaverThreadMethod.getOfFlowMod(RuleSaverThreadMethod.DEFAULT_PATTERN, sw, false);
rules.add(defaultFlowMod);
final List<WildcardPattern> patterns = new ArrayList<>();
try {
FlowHHHAlgorithm.initMonitors(rulesToInstall, new NeedInitHHHAlgorithm() {
@Override
public void addMonitor(WildcardPattern wildcardPattern) {
patterns.add(wildcardPattern);
}
@Override
public WildcardPattern pollAMonitor() {
return patterns.remove(patterns.size() - 1);
}
}, RuleSaverThreadMethod.DEFAULT_PATTERN.clone().goDown(true));
} catch (WildcardPattern.InvalidWildCardValue invalidWildCardValue) {
invalidWildCardValue.printStackTrace();
}
for (WildcardPattern pattern : patterns) {
rules.add(RuleSaverThreadMethod.getOfFlowMod(pattern, sw, true));
}
deleteRules = new ArrayList<>();
for (WildcardPattern pattern : patterns) {
deleteRules.add(RuleSaverThreadMethod.getDeleteRule(pattern, sw.getFlow()));
}
stats = new ArrayList<>();
state = State.INIT;
}
private void setFlowInfoTask(SingletonTask flowInfoTask) {
this.flowInfoTask = flowInfoTask;
}
@Override
public void run() {
if (cancel) {
return;
}
if (state == State.DELETE || state == State.SAVE) {
stats.clear();
long time = System.nanoTime();
RuleFetcherThreadMethod.fetch(sw.getSw(), stats);
long fetchDelay = System.nanoTime() - time;
int size = stats.size();
System.out.println("Fetch, " + epoch + "," + fetchDelay / 1e6);
}
try {
Long time = System.nanoTime();
if (state == State.SAVE) {
sw.write(deleteRules);
state = State.DELETE;
System.out.print("Delete, ");
} else if (state == State.INIT || state == State.DELETE) {
sw.write(rules);
state = State.SAVE;
System.out.print("Save, ");
}
sw.sendBarrier();
sw.flush();
long nanoDelay = -1;
while (System.nanoTime() - time < 600e9) {
nanoDelay = sw.waitOnLastSend(10);//wait 10us
if (nanoDelay >= 0) {
System.out.println(epoch + "," + (System.nanoTime() - time) / 1e6);
break;
}
}
if (nanoDelay < 0) {
System.out.println(epoch + ",-1");
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
epoch++;
flowInfoTask.reschedule(5, TimeUnit.SECONDS);
}
public void cancel() {
cancel = true;
}
}
}