/* * 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.trafficgen; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import de.uniwuerzburg.info3.ofcprobe.vswitch.connection.IOFConnection; import de.uniwuerzburg.info3.ofcprobe.vswitch.main.config.Config; import de.uniwuerzburg.info3.ofcprobe.vswitch.runner.OFSwitchRunner; import de.uniwuerzburg.info3.ofcprobe.vswitch.trafficgen.arping.ARPManager; import de.uniwuerzburg.info3.ofcprobe.vswitch.trafficgen.arping.ArpPacket; import de.uniwuerzburg.info3.ofcprobe.vswitch.trafficgen.arping.TCPPacket; import de.uniwuerzburg.info3.ofcprobe.vswitch.trafficgen.ofevent.*; import de.uniwuerzburg.info3.ofcprobe.vswitch.trafficgen.PayLoadGen; /** * TrafficGenerator Event Based Traffic Generator Simulator * * @author Christopher Metter(christopher.metter@informatik.uni-wuerzburg.de) * */ public class TrafficGen implements Runnable { /** * Debugger */ private static final Logger logger = LoggerFactory.getLogger(TrafficGen.class); /** * Inter Arrival Time of two Events */ private int IAT; /** * List of Switches */ private List<IOFConnection> switches; /** * List of connected Switchs */ private List<IOFConnection> connectedSwitches; /** * The EventQueue */ private TreeMap<Date, List<IOFEvent>> eventQueue; /** * the PayloadGenerator */ private PayLoadGen payloadGen; /** * Map of switchStarters and their Switches */ private Map<OFSwitchRunner, List<IOFConnection>> switchstarters; /** * MasterTcp */ private byte[] tcpsyn; /** * Count of Packets Generated per Event */ private int countPerEvent; /** * Use Static Payload or randomly generate? */ private boolean staticPacket; /** * Threshold for QueueFilling */ private int fillThreshold; /** * The Config */ private Config config; /** * End Date of Simulation */ private Date endSim; /** * Doe ofSwitches have individual Settings? */ private boolean individualSwitchSettings; /** * Is IAT after distribution? */ private boolean iatDistributed; /** * IATGenerator */ private IATGen iatGen; /** * The ArpManager */ private ARPManager arpGen; /** * The scenario */ private String scenario; /** * Map of PCAPLoader for ofSwitchs */ private Map<Long, PCAPLoader> pcapLoaderMap; /** * Map of IATGens for ofSwitchs */ private Map<Long, IATGen> ofSwitchDistriMap; /** * Standard Constructor, initialized Stuff according to provided Config */ public TrafficGen(Config config) { this.config = config; this.scenario = config.getTrafficGenConfig().getScenario(); if (this.scenario.equals("TCP")) { } this.payloadGen = new PayLoadGen(config); this.switches = new ArrayList<>(); this.connectedSwitches = new ArrayList<>(); this.switchstarters = new HashMap<OFSwitchRunner, List<IOFConnection>>(); this.tcpsyn = this.payloadGen.generateTCPSyn(); this.staticPacket = config.getTrafficGenConfig().getStaticPayloadFlag(); this.fillThreshold = config.getTrafficGenConfig().getFillThreshold(); this.countPerEvent = config.getTrafficGenConfig().getCountPerEvent(); this.IAT = config.getTrafficGenConfig().getIAT(); this.individualSwitchSettings = config.getTrafficGenConfig().getSwitchHasIndividualSetting(); logger.trace("TrafficGen has Been Constructed"); this.pcapLoaderMap = new HashMap<Long, PCAPLoader>(); this.ofSwitchDistriMap = new HashMap<Long, IATGen>(); if (this.config.getTrafficGenConfig().getIatType() == 1) { this.iatDistributed = true; this.iatGen = new IATGen(config.getTrafficGenConfig().getDistribution(), config.getTrafficGenConfig().getDistributionPara1(), config.getTrafficGenConfig().getDistributionPara2()); } else { this.iatDistributed = false; } } /** * Registers OFSwitchStarter to this EventGen, so Events will be generated * for this OFSwitchStarter * * @param ofswitchRunner */ public void registerSwitchThread(OFSwitchRunner ofswitchRunner) { this.switches.addAll(ofswitchRunner.getSwitches()); this.switchstarters.put(ofswitchRunner, ofswitchRunner.getSwitches()); for (IOFConnection ofSwitch : ofswitchRunner.getSwitches()) { if (!ofSwitch.getPcapFileName().equals("notSet!")) { PCAPLoader loader = new PCAPLoader(ofSwitch); loader.load(); this.pcapLoaderMap.put(ofSwitch.getDpid(), loader); } if (!ofSwitch.getDistribution().equals("none!")) { IATGen iatGen = new IATGen(ofSwitch.getDistribution(), ofSwitch.getDistributionPara1(), ofSwitch.getDistributionPara2()); this.ofSwitchDistriMap.put(ofSwitch.getDpid(), iatGen); } } } /** * Initialises the EventQueue. */ private void initQueue() { this.eventQueue = new TreeMap<>(); eventQueue.clear(); Date now = new Date(); Date startSim = new Date(now.getTime() + 2 * config.getStartDelay()); // Schedule End of Simulation: Now + 2*StartDelay + SimTime + SafetyBuffer this.endSim = new Date(startSim.getTime() + config.getSimTime() + config.getStopDelay()); generateNext(this.endSim, EventType.GENERATION_END); for (IOFConnection ofSwitch : this.switches) { long connectDelay = ofSwitch.getConDelay(); IOFEvent connectEvent = generateEvent(ofSwitch, EventType.OFSWITCH_CONNECT_EVENT); Date connectDate = new Date(now.getTime() + connectDelay); queueEvent(connectDate, connectEvent); long disconnectDelay = ofSwitch.getStopDelay(); if (disconnectDelay != 0) { IOFEvent disconnectEvent = generateEvent(ofSwitch, EventType.OFSWITCH_DISCONNECT_EVENT); Date disconnectDate = new Date(startSim.getTime() + disconnectDelay); if (disconnectDate.before(this.endSim)) { queueEvent(disconnectDate, disconnectEvent); } } } if (this.config.getTrafficGenConfig().getArpFlag()) { // (trafficGenConfig.arpEnabled = true) this.arpGen = new ARPManager(config, this.switches); this.payloadGen = null; } } /** * Queue an Event into the Eventqueue * * @param targetDate targetDate * @param event the Event */ private void queueEvent(Date targetDate, IOFEvent event) { List<IOFEvent> eventList = eventQueue.get(targetDate); if (eventList == null) { eventList = new ArrayList<>(); } eventList.add(event); eventQueue.put(targetDate, eventList); logger.trace("Event has been Queued: Date: {} - Event: {}", targetDate.toString(), event.toString()); } /** * Generate a new Event and add it to the (existing) List of this Date * * @param targetDate Date when this event shall be executed */ private void generateNext(Date targetDate, EventType eventType) { List<IOFEvent> eventList = eventQueue.get(targetDate); if (eventList == null) { eventList = new ArrayList<IOFEvent>(); } for (int i = 0; i < this.countPerEvent; i++) { for (IOFConnection con : this.connectedSwitches) { eventList.add(generateEvent(con, eventType)); } } eventQueue.put(targetDate, eventList); logger.trace("{} PacketIns have been queued", eventList.size()); } /** * Generate a new Event and add it to the (existing) List of this Date * * @param now Date when this event shall be executed */ private void generateIndividualNext(Date now, IOFConnection ofSwitch, EventType eventType) { for (int i = 0; i < this.countPerEvent; i++) { long nextTime = now.getTime() + getIAT(ofSwitch); Date target = new Date(nextTime); List<IOFEvent> eventList = eventQueue.get(target); if (eventList == null) { eventList = new ArrayList<>(); } eventList.add(generateEvent(ofSwitch, eventType)); eventQueue.put(target, eventList); logger.trace("{} PacketIns have been queued for ofSwitch{}", eventList.size(), ofSwitch.getDpid()); } } /** * Actually generates the Event, currently only PacketIn supported * * @param ofSwitch the ofSwitch for this Event * @return the generated Event */ private IOFEvent generateEvent(IOFConnection ofSwitch, EventType eventType) { IOFEvent output = null; switch (eventType) { case GENERATION_END: output = new GenerationEndEvent(ofSwitch); break; case OFSWITCH_CONCHECK_EVENT: output = new OFSwitchConCheckEvent(ofSwitch); break; case OFSWITCH_CONNECT_EVENT: output = new OFSwitchConnectEvent(ofSwitch); break; case OFSWITCH_DISCONNECT_EVENT: output = new OFSwitchDisconnectEvent(ofSwitch); break; case OFSWITCH_QUEUESWITCH_EVENT: output = new OFSwitchQueueSwitchEvent(ofSwitch); break; case ARP_EVENT: output = new ARPEvent(ofSwitch); break; case TCP_AFTER_ARP: output = new TCPafterARP(ofSwitch); break; case PACKET_IN_EVENT: output = new PacketInEvent(ofSwitch); break; default: break; } return output; } /** * Calculates time Thread has to sleep between two Events * * @param d1 Date1 * @param d2 Date2 * @return sleepingTime (always >= 0) */ private long sleepingTime(Date d1, Date d2) { long sleeptime = d2.getTime() - d1.getTime(); if (sleeptime < 0) { return 0; } else { return sleeptime; } } /** * Run Method. */ @Override public void run() { initQueue(); Set<OFSwitchRunner> starters = new LinkedHashSet<>(); while (!Thread.interrupted()) { Date now = new Date(); // Get first Entry Entry<Date, List<IOFEvent>> currentEventEntry = this.eventQueue.pollFirstEntry(); if (currentEventEntry != null) { // Sleep till next Key/Event try { long stuff = sleepingTime(now, currentEventEntry.getKey()); Thread.sleep(stuff); } catch (InterruptedException e) { logger.error(e.getLocalizedMessage()); Thread.currentThread().interrupt(); } // List of events that have to be processed List<IOFEvent> nextEventList = (List<IOFEvent>) currentEventEntry.getValue(); Date eventTime = currentEventEntry.getKey(); // Generate new PacketIn for every 'connected' ofSwitch for (IOFEvent event : nextEventList) { logger.trace("Processing Event: {}", event.toString()); OFSwitchRunner ofRunner = event.getCon().getRunner(); IOFConnection ofSwitch = event.getCon(); switch (event.getType()) { case OFSWITCH_CONNECT_EVENT: // Connect Channel ofRunner.initOFSwitchConnections(event.getCon()); // Schedule con_check_event IOFEvent concheck = generateEvent(event.getCon(), EventType.OFSWITCH_CONCHECK_EVENT); queueEvent(new Date(eventTime.getTime() + config.getStartDelay()), concheck); break; case OFSWITCH_CONCHECK_EVENT: // wenn alles okay --> schedule ofswitch_queueswitch_event // + schedule ofswitch_disconnect_event mittels runtime - stopDelay ofRunner.alrdyOpenFlowed(event.getCon()); // Schedule queueSwitching Event IOFEvent queueSwitch = generateEvent(event.getCon(), EventType.OFSWITCH_QUEUESWITCH_EVENT); queueEvent(new Date(eventTime.getTime() + config.getStartDelay() + event.getCon().getStartDelay()), queueSwitch); break; case OFSWITCH_QUEUESWITCH_EVENT: // add ofSwitch to this.connectedSwitches this.connectedSwitches.add(event.getCon()); event.getCon().startSession(); if (this.individualSwitchSettings && !this.config.getTrafficGenConfig().getOnlyTopoPayloads()) { IOFEvent packet_in = generateEvent(event.getCon(), EventType.PACKET_IN_EVENT); queueEvent(eventTime, packet_in); } if (this.config.getTrafficGenConfig().getArpFlag()) { IOFEvent arping = generateEvent(event.getCon(), EventType.ARP_EVENT); queueEvent(new Date(eventTime.getTime() + 1000), arping); } break; case OFSWITCH_DISCONNECT_EVENT: // remove ofSwitch from this.connectedSwitches this.connectedSwitches.remove(event.getCon()); event.getCon().stopSession(); break; case ARP_EVENT: // Get ARPs for this ofSwitch List<ArpPacket> arps = this.arpGen.getArpsForIOFConnection(ofSwitch); // and Queue them on the ofSwitch for (ArpPacket arp : arps) { Short port = arp.getPort(); byte[] payload = arp.getPayload(); ofSwitch.queuePacketIn(payload, port, true); logger.trace("Queued ARP to Switch({})", ofSwitch.toString()); } // Schedule TCP Syn for this host after the ARPing IOFEvent tcpAfterArp = generateEvent(ofSwitch, EventType.TCP_AFTER_ARP); queueEvent(new Date(eventTime.getTime() + 2500), tcpAfterArp); break; case TCP_AFTER_ARP: event.getCon().packetInQueueLength(); List<TCPPacket> tcpSyns = this.arpGen.getTCPSynsForIOFConnection(ofSwitch); // and Queue them on the ofSwitch for (TCPPacket tcpSyn : tcpSyns) { Short port = tcpSyn.getPort(); byte[] payload = tcpSyn.getPayload(); ofSwitch.queuePacketIn(payload, port, true); logger.trace("Queued TCPSYN after ARP to ofSwitch({})", ofSwitch.toString()); } // Only Payloads from Topology 'Devices' if (this.config.getTrafficGenConfig().getOnlyTopoPayloads()) { IOFEvent tcpAfterTcps = generateEvent(ofSwitch, EventType.TCP_AFTER_ARP); queueEvent(new Date(eventTime.getTime() + getIAT(ofSwitch)), tcpAfterTcps); } break; case PACKET_IN_EVENT: if (ofRunner != null) { starters.add(ofRunner); // Calculate number of packets to queue in ofSwitch int packetsQueued = event.getCon().packetInQueueLength(); // by subtracting threshold - filling(now) int diff = this.fillThreshold - packetsQueued; if (this.individualSwitchSettings) { diff = event.getCon().getFillThreshold() - packetsQueued; } if (diff < 0) { diff = 0; } // Create a List of Payloads List<byte[]> payloads = new ArrayList<>(diff); // Check wether this ofSwitch will get PCAP payloads if (this.pcapLoaderMap.containsKey(ofSwitch.getDpid())) { logger.trace("Taking payload from pcap for {}", ofSwitch.toString()); // Get em PCAPLoader pcapL = this.pcapLoaderMap.get(ofSwitch.getDpid()); for (int i = 0; i < diff; i++) { // Add em payloads.add(pcapL.nextPayload()); } } else { for (int i = 0; i < diff; i++) { if (this.staticPacket) { // Get static payloads.add(this.tcpsyn); } else { // or generated Payload payloads.add(this.payloadGen.generateTCPSyn()); } } } // and add the List to the ofSwitch's queue event.getCon().queuePacketInS(payloads); if (this.individualSwitchSettings) { generateIndividualNext(eventTime, event.getCon(), EventType.PACKET_IN_EVENT); } } break; case GENERATION_END: event.getCon().stopSession(); this.connectedSwitches.remove(event.getCon()); break; default: break; } } // now wake up all Selectors for (OFSwitchRunner r : starters) { r.getSelector().wakeup(); } starters.clear(); // Generate new Date now = currentEventEntry.getKey(); if (now.before(this.endSim)) { if (!this.individualSwitchSettings && !this.config.getTrafficGenConfig().getOnlyTopoPayloads()) { int iat = getIAT(null); Date next = new Date(now.getTime() + iat); //Generate new Events for new Date generateNext(next, EventType.PACKET_IN_EVENT); } } } } } /** * Inter Arrival Time getter * * @param ofSwitch the ofSwitch * @return the IAT */ private int getIAT(IOFConnection ofSwitch) { int iat = 0; if (!this.individualSwitchSettings) { // Every ofSwitch gets Same stuff iat = this.IAT; if (this.iatDistributed) { iat = this.iatGen.nextIAT(); } } else { // Every ofSwitch has individual IAT if (this.iatDistributed) { if (this.ofSwitchDistriMap.containsKey(ofSwitch.getDpid())) { IATGen iatGen = this.ofSwitchDistriMap.get(ofSwitch.getDpid()); iat = iatGen.nextIAT(); } else { // get (standard) random genrated IAT iat = this.iatGen.nextIAT(); } } else { if (ofSwitch != null) { // get IAT set by ofSwitch.ini File iat = ofSwitch.getIAT(); } else { // Fallback iat = this.IAT; } } } return iat; } }