Add per-protocol flows, and track statistics for each protocol. Does not have the... 52/2752/1
authorKatrina LaCurts <katrina.lacurts@plexxi.com>
Thu, 14 Nov 2013 18:39:51 +0000 (13:39 -0500)
committerKatrina LaCurts <katrina.lacurts@plexxi.com>
Thu, 14 Nov 2013 18:39:51 +0000 (13:39 -0500)
Signed-off-by: Katrina LaCurts <katrina.lacurts@plexxi.com>
analytics/implementation/src/main/java/org/opendaylight/affinity/analytics/internal/HostStats.java
l2agent/src/main/java/org/opendaylight/affinity/l2agent/L2Agent.java

index 84c711b90e0ca085dd9b92bc3fa0989cfc1009ae..b0eb368207b9bcce6f0f1776d66a8235333b45d8 100644 (file)
@@ -8,44 +8,54 @@
 
 package org.opendaylight.affinity.analytics.internal;
 
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.opendaylight.controller.sal.match.MatchField;
+import org.opendaylight.controller.sal.match.MatchType;
 import org.opendaylight.controller.sal.reader.FlowOnNode;
+import org.opendaylight.controller.sal.utils.IPProtocols;
 
 public class HostStats {
 
-    private long byteCount;
-    private double duration;
+    private Map<Byte, Long> byteCounts;
+    private Map<Byte, Double> durations;
 
     public HostStats() {
-        this.byteCount = 0;
-        this.duration = 0;
+        this.byteCounts = new HashMap<Byte, Long>();
+        this.durations = new HashMap<Byte, Double>();
     }
 
     public long getByteCount() {
-        return this.byteCount;
-    }
-
-    public void setByteCount(long byteCount) {
-        this.byteCount = byteCount;
+        long totalByteCount = 0;
+        for (Byte protocol : this.byteCounts.keySet())
+            totalByteCount += this.byteCounts.get(protocol);
+        return totalByteCount;
     }
 
     public double getDuration() {
-        return this.duration;
-    }
-
-    public void setDuration(double duration) {
-        this.duration = duration;
+        return Collections.max(this.durations.values());
     }
 
     public void setStatsFromFlow(FlowOnNode flow) {
+        MatchField protocolField = flow.getFlow().getMatch().getField(MatchType.NW_PROTO);
+        Byte protocolNumber;
+        if (protocolField == null)
+            protocolNumber = IPProtocols.ANY.byteValue();
+        else
+            protocolNumber = (Byte) protocolField.getValue();
+
         // Prevent stats from getting overwritten by zero-byte flows.
-        // TODO: Figure out why this happens
-        if (flow.getByteCount() > this.byteCount) {
-            this.byteCount = flow.getByteCount();
+        Long currentByteCount = this.byteCounts.get(protocolNumber);
+        Long thisByteCount = flow.getByteCount();
+        if (thisByteCount > 0 && (currentByteCount == null || currentByteCount <= thisByteCount)) {
+            this.byteCounts.put(protocolNumber, thisByteCount);
+            this.durations.put(protocolNumber, flow.getDurationSeconds() + .000000001 * flow.getDurationNanoseconds());
         }
-        this.duration = flow.getDurationSeconds() + .000000001 * flow.getDurationNanoseconds();
     }
 
     public double getBitRate() {
-        return (this.byteCount * 8)/(this.duration);
+        return (getByteCount() * 8)/getDuration();
     }
 }
index 0d52c1ce66623c42dee194f94604a14f2685d3e4..b3b285b415bb30fd732de8f6bbae8a645ca90817 100644 (file)
  */
 package org.opendaylight.affinity.l2agent;
 
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.List;
+import java.util.Arrays;
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-import java.lang.String;
-import java.util.Map;
 import java.util.HashMap;
-import java.util.Timer;
-import java.util.TimerTask;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import org.opendaylight.controller.sal.action.Action;
 import org.opendaylight.controller.sal.action.Output;
-import org.opendaylight.controller.sal.action.Flood;
 import org.opendaylight.controller.sal.core.ConstructionException;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
-import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService;
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
+import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService;
 import org.opendaylight.controller.sal.match.Match;
 import org.opendaylight.controller.sal.match.MatchType;
 import org.opendaylight.controller.sal.match.MatchField;
-import org.opendaylight.controller.sal.packet.ARP;
 import org.opendaylight.controller.sal.packet.BitBufferHelper;
 import org.opendaylight.controller.sal.packet.Ethernet;
 import org.opendaylight.controller.sal.packet.IDataPacketService;
@@ -52,19 +43,16 @@ import org.opendaylight.controller.sal.packet.Packet;
 import org.opendaylight.controller.sal.packet.PacketResult;
 import org.opendaylight.controller.sal.packet.RawPacket;
 import org.opendaylight.controller.sal.utils.EtherTypes;
+import org.opendaylight.controller.sal.utils.IPProtocols;
 import org.opendaylight.controller.sal.utils.Status;
-import org.opendaylight.controller.sal.utils.NetUtils;
 import org.opendaylight.controller.switchmanager.ISwitchManager;
-import org.opendaylight.controller.switchmanager.Subnet;
 
 public class L2Agent implements IListenDataPacket, IfL2Agent {
-    private static final Logger logger = LoggerFactory
-            .getLogger(L2Agent.class);
+    private static final Logger logger = LoggerFactory.getLogger(L2Agent.class);
     private ISwitchManager switchManager = null;
     private IFlowProgrammerService programmer = null;
     private IDataPacketService dataPacketService = null;
     private Map<Node, Map<Long, NodeConnector>> mac_to_ports = new HashMap<Node, Map<Long, NodeConnector>>();
-    private String function = "switch";
 
     void setDataPacketService(IDataPacketService s) {
         this.dataPacketService = s;
@@ -102,7 +90,6 @@ public class L2Agent implements IListenDataPacket, IfL2Agent {
     /**
      * Function called by the dependency manager when all the required
      * dependencies are satisfied
-     *
      */
     void init() {
         logger.info("Initialized");
@@ -112,7 +99,6 @@ public class L2Agent implements IListenDataPacket, IfL2Agent {
      * Function called by the dependency manager when at least one
      * dependency become unsatisfied or when the component is shutting
      * down because for example bundle is being stopped.
-     *
      */
     void destroy() {
     }
@@ -121,7 +107,6 @@ public class L2Agent implements IListenDataPacket, IfL2Agent {
      * Function called by dependency manager after "init ()" is called
      * and after the services provided by the class are registered in
      * the service registry
-     *
      */
     void start() {
         logger.info("Started");
@@ -131,7 +116,6 @@ public class L2Agent implements IListenDataPacket, IfL2Agent {
      * Function called by the dependency manager before the services
      * exported by the component are unregistered, this will be
      * followed by a "destroy ()" calls
-     *
      */
     void stop() {
         logger.info("Stopped");
@@ -141,17 +125,7 @@ public class L2Agent implements IListenDataPacket, IfL2Agent {
         NodeConnector incoming_connector = inPkt.getIncomingNodeConnector();
         Node incoming_node = incoming_connector.getNode();
 
-        Packet formattedPak = this.dataPacketService.decodeDataPacket(inPkt);
-        if (formattedPak instanceof Ethernet) {
-            byte[] srcMAC = ((Ethernet)formattedPak).getSourceMACAddress();
-            byte[] dstMAC = ((Ethernet)formattedPak).getDestinationMACAddress();
-
-            long srcMAC_val = BitBufferHelper.toNumber(srcMAC);
-            long dstMAC_val = BitBufferHelper.toNumber(dstMAC);
-        }
-
-        Set<NodeConnector> nodeConnectors =
-                this.switchManager.getUpNodeConnectors(incoming_node);
+        Set<NodeConnector> nodeConnectors = this.switchManager.getUpNodeConnectors(incoming_node);
 
         for (NodeConnector p : nodeConnectors) {
             if (!p.equals(incoming_connector)) {
@@ -159,20 +133,33 @@ public class L2Agent implements IListenDataPacket, IfL2Agent {
                     RawPacket destPkt = new RawPacket(inPkt);
                     destPkt.setOutgoingNodeConnector(p);
                     this.dataPacketService.transmitDataPacket(destPkt);
-                } catch (ConstructionException e2) {
+                } catch (ConstructionException e) {
                     continue;
                 }
             }
         }
     }
 
+    private void installFlow(Match match, List<Action> actions, Node incoming_node, short priority) {
+        Flow f = new Flow(match, actions);
+        f.setPriority(priority);
+
+        // Modify the flow on the network node
+        Status status = programmer.addFlow(incoming_node, f);
+        if (!status.isSuccess()) {
+            logger.warn("SDN Plugin failed to program the flow: {}. The failure is: {}",
+                        f, status.getDescription());
+            return;
+        }
+        logger.info("Installed flow {} in node {}", f, incoming_node);
+    }
+
     @Override
     public PacketResult receiveDataPacket(RawPacket inPkt) {
         if (inPkt == null) {
             return PacketResult.IGNORED;
         }
-        logger.trace("Received a frame of size: {}",
-                        inPkt.getPacketData().length);
+        logger.trace("Received a frame of size: {}", inPkt.getPacketData().length);
 
         Packet formattedPak = this.dataPacketService.decodeDataPacket(inPkt);
         NodeConnector incoming_connector = inPkt.getIncomingNodeConnector();
@@ -182,63 +169,54 @@ public class L2Agent implements IListenDataPacket, IfL2Agent {
             byte[] srcMAC = ((Ethernet)formattedPak).getSourceMACAddress();
             byte[] dstMAC = ((Ethernet)formattedPak).getDestinationMACAddress();
 
-            // Hub implementation
-            if (function.equals("hub")) {
-                floodPacket(inPkt);
-                return PacketResult.CONSUME;
-            }
-
-            // Switch
-            else {
-                long srcMAC_val = BitBufferHelper.toNumber(srcMAC);
-                long dstMAC_val = BitBufferHelper.toNumber(dstMAC);
-
-                Match match = new Match();
-                match.setField( new MatchField(MatchType.IN_PORT, incoming_connector) );
-                match.setField( new MatchField(MatchType.DL_DST, dstMAC.clone()) );
-
-                // Set up the mapping: switch -> src MAC address -> incoming port
-                if (this.mac_to_ports.get(incoming_node) == null) {
-                    this.mac_to_ports.put(incoming_node, new HashMap<Long, NodeConnector>());
-                    logger.info("Added new node = {} to mac_to_ports", incoming_node);
-                }
-
-                // Only replace if we don't know the mapping.  This
-                // saves us from over-writing correct mappings with
-                // incorrect ones we get during flooding.
-                //
-                // TODO: this should never happen..
-                if (this.mac_to_ports.get(incoming_node).get(srcMAC_val) == null) {
-                    this.mac_to_ports.get(incoming_node).put(srcMAC_val, incoming_connector);
-                    logger.info("Added new learned MAC = {} on incoming connector = {} to mac_to_ports", srcMAC_val, incoming_connector);
-                }
-
-                NodeConnector dst_connector = this.mac_to_ports.get(incoming_node).get(dstMAC_val);
-
-                // Do I know the destination MAC?
-                if (dst_connector != null) {
-
-                    List<Action> actions = new ArrayList<Action>();
-                    actions.add(new Output(dst_connector));
+            long srcMAC_val = BitBufferHelper.toNumber(srcMAC);
+            long dstMAC_val = BitBufferHelper.toNumber(dstMAC);
 
-                    Flow f = new Flow(match, actions);
+            // Set up the mapping: switch -> src MAC address -> incoming port
+            if (this.mac_to_ports.get(incoming_node) == null) {
+                this.mac_to_ports.put(incoming_node, new HashMap<Long, NodeConnector>());
+                logger.info("Added new node = {} to mac_to_ports", incoming_node);
+            }
 
-                    // Modify the flow on the network node
-                    Status status = programmer.addFlow(incoming_node, f);
-                    if (!status.isSuccess()) {
-                        logger.warn(
-                                "SDN Plugin failed to program the flow: {}. The failure is: {}",
-                                f, status.getDescription());
-                        return PacketResult.IGNORED;
-                    }
-                    logger.info("Installed flow {} in node {}", f, incoming_node);
+            // Only replace if we don't know the mapping.  This
+            // saves us from over-writing correct mappings with
+            // incorrect ones we get during flooding.
+            //
+            // TODO: this should never happen..
+            if (this.mac_to_ports.get(incoming_node).get(srcMAC_val) == null) {
+                this.mac_to_ports.get(incoming_node).put(srcMAC_val, incoming_connector);
+                logger.info("Added new learned MAC = {} on incoming connector = {} to mac_to_ports", srcMAC_val, incoming_connector);
+            }
 
-                    // TODO: Testing.  What do the flows on this node look like now?
-                    //                    new FlowStatisticsConverter(flows).getFlowOnNodeList(node)
-                }
-                else {
-                    floodPacket(inPkt);
+            NodeConnector dst_connector = this.mac_to_ports.get(incoming_node).get(dstMAC_val);
+
+            // Do I know the destination MAC?
+            if (dst_connector != null) {
+                
+                List<Action> actions = new ArrayList<Action>();
+                actions.add(new Output(dst_connector));
+
+                // Install a high(er)-priority flow for each of the three protocols we care about
+                List<Byte> protocolList = Arrays.asList(IPProtocols.ICMP.byteValue(), IPProtocols.TCP.byteValue(), IPProtocols.UDP.byteValue());
+                for (byte protocol : protocolList) {
+                    Match match = new Match();
+                    match.setField(new MatchField(MatchType.IN_PORT, incoming_connector));
+                    match.setField(new MatchField(MatchType.DL_DST, dstMAC.clone()));
+                    // To get the actual protocol used in this packet, if it's an IPv4 packet:
+                    // ((IPv4) formattedPak.getPayload()).getProtocol();
+                    match.setField(new MatchField(MatchType.DL_TYPE, EtherTypes.IPv4.shortValue()));
+                    match.setField(new MatchField(MatchType.NW_PROTO, protocol));
+                    installFlow(match, actions, incoming_node, (short) 2);
                 }
+                
+                // Install a low-priority flow to catch everything else
+                Match match = new Match();
+                match.setField(new MatchField(MatchType.IN_PORT, incoming_connector));
+                match.setField(new MatchField(MatchType.DL_DST, dstMAC.clone()));
+                installFlow(match, actions, incoming_node, (short) 1);
+            }
+            else {
+                floodPacket(inPkt);
             }
         }
         return PacketResult.IGNORED;