/** * Copyright (c) <2013> <Radware Ltd.> and others. All rights reserved. * * This program and the accompanying materials are made available under the terms of the Eclipse Public License * v1.0 which accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html * @author Gera Goft * @author Konstantin Pozdeev * @version 0.1 */ package org.opendaylight.defense4all.core; import java.lang.IllegalArgumentException; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import org.opendaylight.defense4all.core.Traffic.TrafficDirection; import org.opendaylight.defense4all.core.interactionstructures.Bandwidth; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class TrafficTuple { protected static final String TUPLE_SERIALIZATION_DELIMITER = "::"; protected static final String TRAFFIC_DATA_SERIALIZATION_DELIMITER = ":"; public static Logger log = LoggerFactory.getLogger(TrafficTuple.class); public class TrafficData { public int protocol; // 6-tcp, 17-udp, 1-icmp, 0- other public int port; // Relevant only for tcp and udp public float bytes; public float packets; public boolean forTrafficLearning; public TrafficDirection direction; public TrafficData() { this.protocol = 0; this.port = 0; this.bytes = 0; this.packets = 0; this.forTrafficLearning = false; direction = TrafficDirection.INVALID; } public TrafficData(TrafficData other) { this.protocol = other.protocol; this.port = other.port; this.bytes = other.bytes; this.packets = other.packets; this.forTrafficLearning = other.forTrafficLearning; this.direction = other.direction; } public String toPrintableString () { return ( ProtocolPort.DFProtocol.getProtocol(protocol).name() + " bytes: "+bytes+ " packets: "+packets); } } protected Hashtable<Integer,TrafficData> tuple; public Hashtable<Integer,TrafficData> getTuple() { return tuple; } public static int generateTrafficDataKey(int protocol, int port) { return (protocol<<16) + port; } public TrafficData getTrafficData(int protocol, int port) { int key = generateTrafficDataKey(protocol, port); return tuple.get(key); } public TrafficData getTrafficData(int key) { return tuple.get(key); } public float getTrafficBytes(int protocol, int port) { int key = generateTrafficDataKey(protocol, port); return tuple.get(key).bytes; } public float getTrafficPackets(int protocol, int port) { int key = generateTrafficDataKey(protocol, port); return tuple.get(key).packets; } public boolean isForTrafficLearning () { Iterator<Map.Entry<Integer,TrafficData>> iter = tuple.entrySet().iterator(); while(iter.hasNext()) { if ( iter.next().getValue().forTrafficLearning ) return true; } return false; } public void setTrafficData(int protocol, int port, float bytes, float packets, boolean forTrafficLearning, TrafficDirection direction) { TrafficData trafficData = new TrafficData(); trafficData.protocol = protocol; trafficData.port = port; trafficData.bytes = bytes > 0 ? bytes : 0; trafficData.packets = packets > 0 ? packets : 0; trafficData.forTrafficLearning = forTrafficLearning; trafficData.direction = direction; tuple.put(generateTrafficDataKey(protocol, port), trafficData); } public void setTrafficData(TrafficData trafficData ) { tuple.put(generateTrafficDataKey(trafficData.protocol, trafficData.port), new TrafficData(trafficData)); } public TrafficTuple() { tuple = new Hashtable<Integer,TrafficData>(); } public void zero() { Iterator<Map.Entry<Integer,TrafficData>> iter = tuple.entrySet().iterator(); TrafficData trafficData; while(iter.hasNext()) { trafficData = iter.next().getValue(); trafficData.bytes = trafficData.packets = 0; } } public boolean isZero() { Iterator<Map.Entry<Integer,TrafficData>> iter = tuple.entrySet().iterator(); TrafficData trafficData; while(iter.hasNext()) { trafficData = iter.next().getValue(); if(trafficData.bytes > 0 || trafficData.packets > 0) return false; } return true; } /* Inflate from concatinated thresholds string. Use the structure from Spring: * tcpsynportbytes:tcpsynportpackets:tcpportbytes:tcpportpackets:tcpbytes:tcppackets: * udpportbytes:udpportpackets:udpbytes:udppackets:icmpbytes:icmppackets:otherbytes:otherpackets */ public TrafficTuple(String trafficTupleStr) throws IllegalArgumentException { this(); if(trafficTupleStr == null || trafficTupleStr.length() == 0) return; String[] split1 = trafficTupleStr.split(TUPLE_SERIALIZATION_DELIMITER); String[] split2; TrafficData trafficData; for(String trafficDataStr : split1) { if(trafficDataStr.length() == 0) continue; split2 = trafficDataStr.split(TRAFFIC_DATA_SERIALIZATION_DELIMITER); if(split2.length < 6) continue; trafficData = new TrafficData(); try { trafficData.protocol = Short.valueOf(split2[0]); trafficData.port = Short.valueOf(split2[1]); trafficData.bytes = Float.valueOf(split2[2]); trafficData.packets = Float.valueOf(split2[3]); trafficData.forTrafficLearning = Boolean.valueOf(split2[4]); trafficData.direction = TrafficDirection.valueOf(split2[5]); } catch (NumberFormatException e) { log.error("Failed to construct TrafficTuple from string." + e.getLocalizedMessage()); throw new IllegalArgumentException("Could not parse trafficTupleStr. + " + e.getLocalizedMessage()); } tuple.put(generateTrafficDataKey(trafficData.protocol, trafficData.port), trafficData); } } @Override public TrafficTuple clone() { TrafficTuple tt = new TrafficTuple(); Iterator<Map.Entry<Integer,TrafficData>> iter = tuple.entrySet().iterator(); TrafficData trafficData; while(iter.hasNext()) { trafficData = new TrafficData(iter.next().getValue()); tt.tuple.put(generateTrafficDataKey(trafficData.protocol, trafficData.port), trafficData); } return tt; } @Override public String toString() { return serialize(); } public String toPrintableString() { if ( tuple == null || tuple.isEmpty()) return ""; StringBuilder sb = new StringBuilder(); TrafficData trafficData; int[] traceOrder = {6,17,1,0}; for ( int tr:traceOrder) { trafficData = getTrafficData( tr, 0); if (trafficData == null ) continue; sb.append( trafficData.toPrintableString()); sb.append(" "); } return sb.toString(); } /** * #### * @return */ public String serialize() { if ( tuple == null || tuple.isEmpty()) return ""; StringBuilder sb = new StringBuilder(); TrafficData trafficData; Iterator<Map.Entry<Integer,TrafficData>> iter = tuple.entrySet().iterator(); while(iter.hasNext()) { trafficData = iter.next().getValue(); sb.append(trafficData.protocol); sb.append(TRAFFIC_DATA_SERIALIZATION_DELIMITER); sb.append(trafficData.port); sb.append(TRAFFIC_DATA_SERIALIZATION_DELIMITER); sb.append(trafficData.bytes); sb.append(TRAFFIC_DATA_SERIALIZATION_DELIMITER); sb.append(trafficData.packets); sb.append(TRAFFIC_DATA_SERIALIZATION_DELIMITER); sb.append(trafficData.forTrafficLearning); sb.append(TRAFFIC_DATA_SERIALIZATION_DELIMITER); sb.append(trafficData.direction); sb.append(TUPLE_SERIALIZATION_DELIMITER); } sb.setLength(sb.length() - TUPLE_SERIALIZATION_DELIMITER.length()); return sb.toString(); } public Object toString(int protocol) { if ( tuple == null || tuple.isEmpty()) return ""; float trafficBytes = getTrafficBytes(protocol, 0); return Float.toString(trafficBytes); } public TrafficTuple delta(TrafficTuple lower, float timePeriod) { if(lower == null) return this; TrafficTuple tt = new TrafficTuple(); if(timePeriod == 0) return tt ; Iterator<Map.Entry<Integer,TrafficData>> iter = tuple.entrySet().iterator(); TrafficData trafficData; TrafficData trafficDelta; while(iter.hasNext()) { trafficData = iter.next().getValue(); if(trafficData == null) continue; TrafficData lowerTrafficData = lower.getTrafficData(trafficData.protocol, trafficData.port); if ( lowerTrafficData == null ) lowerTrafficData = new TrafficData(); /* port, protocol and flag are same as source. bytes and packets should be calculated in terms of rates */ trafficDelta = new TrafficData(trafficData); trafficDelta.bytes = ( trafficData.bytes - lowerTrafficData.bytes ) / timePeriod; trafficDelta.packets = ( trafficData.packets - lowerTrafficData.packets ) / timePeriod; tt.tuple.put(generateTrafficDataKey(trafficDelta.protocol, trafficDelta.port), trafficDelta); } return tt; } public void add(TrafficTuple other) { if(other == null) return; // Update traffic data for received protocol/port data Iterator<Map.Entry<Integer,TrafficData>> iter = other.tuple.entrySet().iterator(); TrafficData otherTrafficData; while(iter.hasNext()) { otherTrafficData = iter.next().getValue(); int key = generateTrafficDataKey(otherTrafficData.protocol, otherTrafficData.port); if ( ! tuple.containsKey(key)) { tuple.put(key, new TrafficData (otherTrafficData)); } else if ( otherTrafficData.direction == tuple.get(key).direction ) { // Add for same direction only tuple.get(key).bytes = tuple.get(key).bytes + otherTrafficData.bytes ; tuple.get(key).packets = tuple.get(key).packets + otherTrafficData.packets ; } } } public void setNonNegative(TrafficTuple other) { if(other == null) return; // Update traffic data for received protocol/port data Iterator<Map.Entry<Integer,TrafficData>> iter = other.tuple.entrySet().iterator(); TrafficData otherTrafficData; while(iter.hasNext()) { otherTrafficData = iter.next().getValue(); // Copy only positive values. In case of negative keep current if ( otherTrafficData.bytes < 0 ||otherTrafficData.packets < 0 ) continue; int key = generateTrafficDataKey(otherTrafficData.protocol, otherTrafficData.port); if ( ! tuple.containsKey(key)) { tuple.put(key, new TrafficData (otherTrafficData)); } else if ( otherTrafficData.direction == tuple.get(key).direction ) { // Add for same direction only tuple.get(key).bytes = otherTrafficData.bytes ; tuple.get(key).packets = otherTrafficData.packets ; } } } /* Return string containing bytes and packets. */ public String getBandwidth(TrafficDirection direction) { long bytes = 0; long packets = 0; Iterator<Map.Entry<Integer,TrafficData>> iter = tuple.entrySet().iterator(); TrafficData trafficData; while(iter.hasNext()) { trafficData = iter.next().getValue(); if(trafficData.direction == direction) { bytes += trafficData.bytes; packets += trafficData.packets; } } Bandwidth bandwidth = new Bandwidth(bytes, packets); return bandwidth.toString(); } }