package edu.usc.enl.dynamicmeasurement.floodlight;
import edu.usc.enl.dynamicmeasurement.model.WildcardPattern;
import edu.usc.enl.dynamicmeasurement.model.monitorpoint.WildcardMonitorPoint;
import edu.usc.enl.dynamicmeasurement.util.ControlledBufferWriter;
import edu.usc.enl.dynamicmeasurement.util.Util;
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IOFSwitch;
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.FileNotFoundException;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* Created with IntelliJ IDEA.
* User: masoud
* Date: 10/18/13
* Time: 3:57 PM
* <br/>
* A class that bundles the data and functionalities of a switch in dREAM
*/
class SwitchData {
public static final List<WildcardPattern> NON_DEFAULT_DELETE_PATTERNS = Arrays.asList(new WildcardPattern(0, 31, 0), new WildcardPattern(1, 31, 0));
/**
* the corresponding OpenFlow switch
*/
private final IOFSwitch sw;
private final RuleFetcherThreadMethod ruleFetcherThreadMethod;
private final RuleSaverThreadMethod ruleSaverThreadMethod;
private final Map<Integer, CountDownLatch> observerMap;
/**
* The temporary datastructure to keep track of current rules
*/
private final Map<WildcardPattern, WildcardPattern> workingRules;
private final IFloodlightProviderService floodlightProvider;
private final int id;
/**
* The log is used to track the number of rules installed, deleted or kept untouched in this switch.
*/
private ControlledBufferWriter logWriter;
//to find the delay of the barrier
private CountDownLatch latch;
private long timeToReleaseLatch;
SwitchData(IOFSwitch aSwitch, IFloodlightProviderService floodlightProvider, WildcardMonitorPoint monitorPoint) {
this.sw = aSwitch;
this.floodlightProvider = floodlightProvider;
int capacity = monitorPoint.getCapacity();
workingRules = new ConcurrentHashMap<>(capacity);
Map<WildcardPattern, WildcardPattern> lastFetchedRules = new HashMap<>(capacity);
ruleFetcherThreadMethod = new RuleFetcherThreadMethod(aSwitch, capacity, workingRules, lastFetchedRules);
ruleSaverThreadMethod = new RuleSaverThreadMethod(this, capacity, workingRules, lastFetchedRules);
observerMap = new HashMap<>();
this.id = monitorPoint.getIntId();
try {
logWriter = Util.getNewWriter(Util.getRootFolder() + "/switch" + id + ".txt", false);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public IOFSwitch getSw() {
return sw;
}
public Map<WildcardPattern, WildcardPattern> getWorkingRules() {
return workingRules;
}
@Override
public String toString() {
return "SwitchData{" +
"sw=" + sw +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SwitchData that = (SwitchData) o;
if (sw != null ? !sw.equals(that.sw) : that.sw != null) return false;
return true;
}
@Override
public int hashCode() {
return sw != null ? sw.hashCode() : 0;
}
protected Runnable getStats(int epoch) {
ruleFetcherThreadMethod.setEpoch(epoch);
return ruleFetcherThreadMethod;
}
protected RuleSaverThreadMethod saveRules(int epoch) {
ruleSaverThreadMethod.setEpoch(epoch);
return ruleSaverThreadMethod;
}
public String getStringId() {
return sw.getStringId();
}
public int getIntId() {
return id;
}
public OFFlowMod getFlow() {
return (OFFlowMod) floodlightProvider.getOFMessageFactory().getMessage(OFType.FLOW_MOD);
}
public OFMessage getBarrier() throws IOException {
OFMessage barrierMsg = floodlightProvider.getOFMessageFactory().getMessage(OFType.BARRIER_REQUEST);
barrierMsg.setXid(sw.getNextTransactionId());
return barrierMsg;
}
/**
* Send the barrrier and setup the timer and latch
*
* @return
* @throws IOException
*/
public CountDownLatch sendBarrier() throws IOException {
OFMessage barrierMsg = getBarrier();
latch = new CountDownLatch(1);
observerMap.put(barrierMsg.getXid(), latch);
timeToReleaseLatch = System.nanoTime();
sw.write(barrierMsg, null);
return latch;
}
public void write(OFFlowMod flowMod) throws IOException {
sw.write(flowMod, null);
}
public void write(List<OFMessage> flowMod) throws IOException {
sw.write(flowMod, null);
}
public void flush() {
sw.flush();
}
/**
* The barrier is received. Stop the counter and release the latch so that thread can go through
*
* @param msg
*/
public void receiveBarrier(OFBarrierReply msg) {
// System.out.println("receive barrier msg " + msg);
CountDownLatch l = observerMap.get(msg.getXid());
if (l != null && l == latch) {
latch.countDown();
} else {
// PeriodicReport.log.warn("Unknown barrier reply received " + msg);
}
}
public long waitOnLastSend(int timeout) throws InterruptedException {
boolean await = latch.await(timeout, TimeUnit.MICROSECONDS);
if (await) {
return System.nanoTime() - timeToReleaseLatch;
} else {
return -1;
}
}
public Collection<OFFlowStatisticsReply> getLastFetchedFlows() {
return ruleFetcherThreadMethod.getStats();
}
public boolean isTrafficStarted(double threshold) {
for (WildcardPattern wildcardPattern : workingRules.keySet()) {
if (wildcardPattern.getWeight() > threshold) {
return true;
}
}
return false;
}
ControlledBufferWriter getLogWriter() {
return logWriter;
}
public void finish() {
logWriter.close();
}
}