/* * 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; } }