/*
* Copyright 2016 christopher.metter.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.uniwuerzburg.info3.ofcprobe.vswitch.statistics;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import de.uniwuerzburg.info3.ofcprobe.vswitch.main.config.Config;
import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFPacketIn;
import org.openflow.protocol.OFPacketOut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* RoundTripTime Logger - Analyzes the Buffid of PacketIn and tries to match to
* BuffID of PacketOut If found Pair -> RTT= Date(PACKET_OUT) - Date(PACKET_IN)
*
* @author Christopher Metter(christopher.metter@informatik.uni-wuerzburg.de)
*
*/
public class RoundTripTime implements IStatistics {
/**
* The Logger
*/
private static final Logger logger = LoggerFactory.getLogger(RoundTripTime.class);
/**
* List of rtts
*/
private List<Long> rtt;
/**
* Map of Buffids and Dates
*/
private Map<Integer, Date> packIns;
/**
* Output File
*/
private String file;
/**
* Session Running?
*/
private boolean running;
/**
* The Dppid
*/
private String dpid;
/**
* Constructor
*/
public RoundTripTime(Config config) {
this.rtt = new ArrayList<Long>();
this.packIns = new HashMap<Integer, Date>();
this.running = false;
NumberFormat formatter = new DecimalFormat("#000");
this.dpid = formatter.format(config.getSwitchConfig().getDpid());
}
/**
* Process incoming Packets of this Switch Only interested in OFPacketOut
* (Response from Controller to OFPacketIn)
*/
public void packetIn(OFMessage in) {
if (!this.running) {
return;
}
switch (in.getType()) {
case BARRIER_REPLY:
break;
case BARRIER_REQUEST:
break;
case ECHO_REPLY:
break;
case ECHO_REQUEST:
break;
case ERROR:
break;
case FEATURES_REPLY:
break;
case FEATURES_REQUEST:
break;
case FLOW_MOD:
break;
case FLOW_REMOVED:
break;
case GET_CONFIG_REPLY:
break;
case GET_CONFIG_REQUEST:
break;
case HELLO:
break;
case PACKET_IN:
break;
case PACKET_OUT:
OFPacketOut packOut = (OFPacketOut) in;
packOut(packOut);
break;
case PORT_MOD:
break;
case PORT_STATUS:
break;
case QUEUE_CONFIG_REPLY:
break;
case QUEUE_CONFIG_REQUEST:
break;
case SET_CONFIG:
break;
case STATS_REPLY:
break;
case STATS_REQUEST:
break;
case VENDOR:
break;
default:
break;
}
}
/**
* Process outgoing packets of this switch Only interested in OFPacketIn
* (Generated by TrafficGen)
*/
public void packetOut(OFMessage out) {
if (!this.running) {
return;
}
switch (out.getType()) {
case BARRIER_REPLY:
break;
case BARRIER_REQUEST:
break;
case ECHO_REPLY:
break;
case ECHO_REQUEST:
break;
case ERROR:
break;
case FEATURES_REPLY:
break;
case FEATURES_REQUEST:
break;
case FLOW_MOD:
break;
case FLOW_REMOVED:
break;
case GET_CONFIG_REPLY:
break;
case GET_CONFIG_REQUEST:
break;
case HELLO:
break;
case PACKET_IN:
OFPacketIn packIn = (OFPacketIn) out;
this.packIns.put(packIn.getBufferId(), new Date());
break;
case PACKET_OUT:
break;
case PORT_MOD:
break;
case PORT_STATUS:
break;
case QUEUE_CONFIG_REPLY:
break;
case QUEUE_CONFIG_REQUEST:
break;
case SET_CONFIG:
break;
case STATS_REPLY:
break;
case STATS_REQUEST:
break;
case VENDOR:
break;
default:
break;
}
}
/**
* Process PacketOut, RTT is computed here. Basically look if there is a
* OFPacketInMsg with the same BufferID and then just subtract the Times:
* Date(Now) - DatePacketInHasArrived
*
* @param packOut packet to Process
*/
private void packOut(OFPacketOut packOut) {
for (Iterator<Map.Entry<Integer, Date>> i = this.packIns.entrySet().iterator(); i.hasNext();) {
Map.Entry<Integer, Date> entry = i.next();
if (entry.getKey() == packOut.getBufferId()) {
this.rtt.add(new Date().getTime() - entry.getValue().getTime());
logger.trace("RoundTripTime of this Packet: {}ms", this.rtt.get(this.rtt.size() - 1));
i.remove();
}
}
}
/**
* Ends this Session.
*/
public void report() {
double rttSum = 0;
for (long rtt : this.rtt) {
rttSum += rtt;
}
double rttMean = rttSum / this.rtt.size();
if (Double.isNaN(rttMean)) {
rttMean = 0;
}
logger.info("[Switch#{}]: RTT Mean in this Session: {}", this.dpid, rttMean);
writeToFile(rttMean);
}
private void writeToFile(double rttMean) {
try {
File filou = new File(this.file);
if (!filou.getParentFile().exists()) {
filou.getParentFile().mkdirs();
}
PrintWriter out = new PrintWriter(this.file);
if (!this.rtt.isEmpty()) {
for (long rtt : this.rtt) {
out.print(rtt + ";");
}
} else {
out.print("0;");
}
out.print("\n");
if (Double.isNaN(rttMean)) {
out.println(0);
} else {
out.println(rttMean);
}
out.close();
} catch (FileNotFoundException e) {
logger.error("[Switch#{}]: {}", this.dpid, e);
}
}
@Override
public void setReportFile(String file) {
this.file = file;
}
@Override
public void evaluate() {
// Auto-generated method stub
}
@Override
public void start() {
this.running = true;
this.rtt.clear();
}
@Override
public void stop() {
this.running = false;
}
}