Rebase changes from recent demo work. 87/5487/1
authorSuchi Raman <suchi.raman@plexxi.com>
Thu, 27 Feb 2014 14:49:58 +0000 (09:49 -0500)
committerSuchi Raman <suchi.raman@plexxi.com>
Thu, 27 Feb 2014 14:49:58 +0000 (09:49 -0500)
Signed-off-by: Suchi Raman <suchi.raman@plexxi.com>
affinity/api/pom.xml
affinity/api/src/main/java/org/opendaylight/affinity/affinity/AffinityAttributeType.java
affinity/api/src/main/java/org/opendaylight/affinity/affinity/AffinityLink.java
affinity/api/src/main/java/org/opendaylight/affinity/affinity/AffinityPath.java [new file with mode: 0644]
affinity/api/src/main/java/org/opendaylight/affinity/affinity/SetMaxTputPath.java [new file with mode: 0644]
flatl2/src/main/java/org/opendaylight/affinity/flatl2/FlatL2AffinityImpl.java
scripts/affinity.py
scripts/demo.py
scripts/stats.py

index 3385151d98390337fbc61b299e7afe8eb5832a1a..c45ddf1201da8358530a8711aa3d2c29e3f5e5cf 100644 (file)
@@ -47,6 +47,7 @@
               org.opendaylight.controller.sal.packet,
               org.opendaylight.controller.sal.inventory,
               org.opendaylight.controller.sal.flowprogrammer,
+              org.opendaylight.controller.hosttracker.hostAware,
               com.fasterxml.jackson.jaxrs.base,
               com.fasterxml.jackson.jaxrs.json,
               com.fasterxml.jackson.annotation,
       <artifactId>configuration</artifactId>
       <version>0.4.1</version>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>hosttracker</artifactId>
+      <version>0.5.1</version>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>sal</artifactId>
index f322d4ce9f99688c176e4016d74f372e43634546..b92cdbdf95815a352e903d63c47ea7bce245445d 100644 (file)
@@ -14,7 +14,8 @@ public enum AffinityAttributeType {
     SET_DENY("deny"),
     SET_TAP("set_tap"),
     SET_PATH_ISOLATE("set_path_isolate"),
-    SET_PATH_REDIRECT("set_path_redirect");
+    SET_PATH_REDIRECT("set_path_redirect"),
+    SET_MAX_TPUT_PATH("set_path_max_tput");
 
     String id;
 
index 041bf2f5e951712745610472a382f7d80446aaf9..f93875a70f5a32732c1946d3dc2f6bc55190bf84 100644 (file)
@@ -177,6 +177,8 @@ public class AffinityLink implements Cloneable, Serializable {
     public void setIsolate() {
         SetPathIsolate iso = new SetPathIsolate();
         addAttribute(iso);
+        SetMaxTputPath mtp = new SetMaxTputPath();
+        addAttribute(mtp);
     }
     public void unsetIsolate() {
         attrlist.remove(AffinityAttributeType.SET_PATH_ISOLATE);
diff --git a/affinity/api/src/main/java/org/opendaylight/affinity/affinity/AffinityPath.java b/affinity/api/src/main/java/org/opendaylight/affinity/affinity/AffinityPath.java
new file mode 100644 (file)
index 0000000..22a9938
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2013 Plexxi, Inc. 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
+ */
+package org.opendaylight.affinity.affinity;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.InetAddress;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ArrayList;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.Path;
+import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
+
+/**
+ * Represents the attribute associated with an affinity link. 
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class AffinityPath implements Serializable {
+    private static final long serialVersionUID = 1L;
+    private static final Logger logger = LoggerFactory.getLogger(AffinityPath.class);
+    @XmlElement
+    private transient boolean isValid = true;
+    
+    // Default path, leading to the destination. Each element is a sub-path of the total default path. 
+    HostNodeConnector src;
+    HostNodeConnector dst;
+    List<Path> defaultPath;
+    HashMap<HostNodeConnector, Path> tapPaths;
+
+    /* Dummy constructor for JAXB */
+    public AffinityPath(HostNodeConnector src, HostNodeConnector dst) {
+        this.src = src;
+        this.dst = dst;
+        this.defaultPath = new ArrayList<Path>();
+        this.tapPaths = new HashMap<HostNodeConnector, Path>();
+    }
+
+    public HostNodeConnector getSrc() {
+        return this.src;
+    }
+    public HostNodeConnector getDst() {
+        return this.dst;
+    }
+    public List<Path> getDefaultPath() {
+        return defaultPath;
+    }
+    public void setDefaultPath(List<Path> subpaths) {
+        defaultPath = subpaths;
+    }
+    
+    public void setTapPath(HostNodeConnector dst, Path path) {
+        tapPaths.put(dst, path);
+    }
+
+    public HashMap<HostNodeConnector, Path> getTapPaths() {
+        return tapPaths;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        AffinityPath other = (AffinityPath) obj;
+        if (this.src != other.src || this.dst != other.dst) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        String string = "affinity-path: \n";
+        string = string + "src: " + src.toString() + "\n" + "dst: " + dst.toString() + "\n";
+        string = string + "defPath: " + defaultPath.toString() + "\n";
+        for (HostNodeConnector k: tapPaths.keySet()) {
+            string = string + "tapdst: " + k.toString() + "\n" + "path: " + tapPaths.get(k).toString() + "\n";
+        }
+        return string;
+    }
+
+}
diff --git a/affinity/api/src/main/java/org/opendaylight/affinity/affinity/SetMaxTputPath.java b/affinity/api/src/main/java/org/opendaylight/affinity/affinity/SetMaxTputPath.java
new file mode 100644 (file)
index 0000000..b4bc70e
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013 Plexxi, Inc. 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
+ */
+package org.opendaylight.affinity.affinity;
+
+import java.net.InetAddress;
+import java.util.List;
+import java.util.ArrayList;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class SetMaxTputPath extends AffinityAttribute {
+    private static final long serialVersionUID = 1L;
+
+    public SetMaxTputPath() {
+        type = AffinityAttributeType.SET_MAX_TPUT_PATH;
+    }
+}
+
+
+
index 4b12704c75ad08aacff7898e772eb6b718ddaf90..8a22953150e0e5f46cb559651bff38700dfc8d7b 100644 (file)
@@ -54,6 +54,7 @@ import org.opendaylight.controller.sal.utils.IPProtocols;
 
 import org.opendaylight.controller.sal.core.IContainer;
 import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.Edge;
 import org.opendaylight.controller.sal.core.Host;
 import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.core.NodeTable;
@@ -92,6 +93,7 @@ import org.opendaylight.controller.sal.routing.IRouting;
 import org.opendaylight.affinity.affinity.IAffinityManager;
 import org.opendaylight.affinity.affinity.AffinityAttributeType;
 import org.opendaylight.affinity.affinity.AffinityAttribute;
+import org.opendaylight.affinity.affinity.AffinityPath;
 import org.opendaylight.affinity.affinity.SetDeny;
 import org.opendaylight.affinity.affinity.SetPathIsolate;
 import org.opendaylight.affinity.affinity.SetPathRedirect;
@@ -205,6 +207,8 @@ public class FlatL2AffinityImpl implements IfNewHostNotify {
     }
     public void setRouting(IRouting routing) {
         this.routing = routing;
+        // Init max throughput edge weights
+        this.routing.initMaxThroughput(null);
     }
 
     public void unsetRouting(IRouting routing) {
@@ -289,13 +293,179 @@ public class FlatL2AffinityImpl implements IfNewHostNotify {
         // Get all flow groups and attribs from the affinity manager. 
         this.allfgroups = am.getAllFlowGroups();
         this.attribs = am.getAllAttributes();
+        
+
+        // New implementation using AffintyPath. 
+        HashMap<Flow, AffinityPath> flowpaths = calcAffinityPathsForAllFlows(mergeAffinityAttributesPerFlow());
+        for (Flow f: flowpaths.keySet()) {
+            HashMap<Node, List<Action>> flowActions = calcForwardingActions(flowpaths.get(f));
+            InetAddress srcIp = (InetAddress) f.getMatch().getField(MatchType.NW_SRC).getValue();
+            InetAddress dstIp = (InetAddress) f.getMatch().getField(MatchType.NW_DST).getValue();
+            printActionMap(srcIp, dstIp, flowActions);
+            for (Node n: flowActions.keySet()) {
+                programFlows(n, f, flowActions.get(n));
+            }
+        }
 
+        /** Old implementation that does per-node programming. Demo-only.
         for (Node node: this.nodelist) {
             programFlowGroupsOnNode(this.allfgroups, this.attribs, node);
         }
+        */
         return true;
     }
+
+    public void programFlows(Node n, Flow f, List<Action> actions) {
+        
+        // Update flow with actions. 
+        if (actions.size() > 0) {
+            log.info("Adding actions {} to flow {}", actions, f);
+            f.setActions(actions);
+            // Make a flowEntry object. groupName is the policy name, 
+            // from the affinity link name. Same for all flows in this bundle. 
+            InetAddress srcIp = (InetAddress) f.getMatch().getField(MatchType.NW_SRC).getValue();
+            InetAddress dstIp = (InetAddress) f.getMatch().getField(MatchType.NW_DST).getValue();
+            String flowName = "[" + srcIp + "->" + dstIp + "]";
+            
+            FlowEntry fEntry = new FlowEntry("affinity", flowName, f, n);
+            log.info("Install flow entry {} on node {}", fEntry.toString(), n.toString());
+            installFlowEntry(fEntry);
+        }
+    }
+
+    public HashMap<Node, List<Action>> mergeActions(HashMap<Node, List<Action>> a, HashMap<Node, List<Action>> b) {
+        HashMap<Node, List<Action>> result = new HashMap<Node, List<Action>>();
+
+        if (a == null) {
+            return b;
+        }
+        if (b == null) {
+            return a;
+        }
+        // Initialize with all elements of a.
+        result = a;
+        // Add elements from b, merging when necessary. 
+        ArrayList<Action> allActions = new ArrayList<Action>();
+        for (Node n: b.keySet()) {
+            // This node is listed in both maps, merge the actions. 
+            if (a.get(n) != null) {
+                allActions.addAll(a.get(n));
+                allActions.addAll(b.get(n));
+                result.put(n, allActions);
+            }
+        }
+        return result;
+    }
+
+    // Merge all affinity links into a single result. This result is a
+    // collection that maps Flow (src-dst pair) -> combined set of all
+    // attribs applied to that src-dst pair.
+    public HashMap<Flow, HashMap<AffinityAttributeType, AffinityAttribute>> mergeAffinityAttributesPerFlow() {
+        // per-flow attributes
+        HashMap<Flow, HashMap<AffinityAttributeType, AffinityAttribute>> pfa = new HashMap<Flow, HashMap<AffinityAttributeType, AffinityAttribute>>();
+
+        for (String linkname: this.allfgroups.keySet()) {
+            log.debug("Adding new affinity link", linkname);
+            List<Flow> newflows = this.allfgroups.get(linkname);
+            HashMap<AffinityAttributeType, AffinityAttribute> newattribs = this.attribs.get(linkname);
+            
+            for (Flow f: newflows) {
+                if (!pfa.containsKey(f)) {
+                    // Create the initial record for this flow (src-dst pair). 
+                    pfa.put(f, newattribs);
+                } else {
+                    // Merge attribs to the key that already exists. 
+                    pfa.put(f, merge(pfa.get(f), newattribs));
+                }
+            }
+        }
+        return pfa;
+    }
+
+    // tbd: This attribute map should become a class. 
+    // Overwriting merge of two atribute HashMaps. 
+    public HashMap<AffinityAttributeType, AffinityAttribute> merge(HashMap<AffinityAttributeType, AffinityAttribute> a, 
+                                                                   HashMap<AffinityAttributeType, AffinityAttribute> b) {
+        HashMap<AffinityAttributeType, AffinityAttribute> result = new HashMap<AffinityAttributeType, AffinityAttribute>();
+
+        for (AffinityAttributeType at: a.keySet()) {
+            result.put(at, a.get(at));
+        }
+        for (AffinityAttributeType at: b.keySet()) {
+            result.put(at, b.get(at));
+        }
+        return result;
+    }
+
+    // A "Flow" here is used to represent the source-destination pair. 
+    // Function returns an affinity path object per src-dest pair. 
+    public HashMap<Flow, AffinityPath> calcAffinityPathsForAllFlows(HashMap<Flow, HashMap<AffinityAttributeType, AffinityAttribute>>perFlowAttribs) {
+        HashMap<Flow, AffinityPath> perFlowPaths = new HashMap<Flow, AffinityPath>();
+        
+        for (Flow f: perFlowAttribs.keySet()) {
+            InetAddress srcIp = (InetAddress) f.getMatch().getField(MatchType.NW_SRC).getValue();
+            InetAddress dstIp = (InetAddress) f.getMatch().getField(MatchType.NW_DST).getValue();
+            String flowName = "[" + srcIp + "->" + dstIp + "]";
+            AffinityPath ap = calcAffinityPath(srcIp, dstIp, perFlowAttribs.get(f));
+            perFlowPaths.put(f, ap);
+        }
+        return perFlowPaths;
+    }
+
+    // xxx Compute the set of output actions for each node in this AffinityPath. 
+    public HashMap<Node, List<Action>> calcForwardingActions(AffinityPath ap) {
+
+        HashMap<Node, List<Action>> actionMap;
+        actionMap = new HashMap<Node, List<Action>>();
+        
+        // Add nodes in default path into the hash map.
+        // Default path has subpaths, created by redirects. xxx for now, just get one of these. 
+        Path p = ap.getDefaultPath().get(0);
+        addrules(ap.getDst(), p, actionMap);
+
+        // Add output ports for each node in the tapPath list. Include
+        // the host node connector of the destination server too.
+        HashMap<HostNodeConnector, Path> tapPaths = ap.getTapPaths();
+        for (HostNodeConnector tapDest: tapPaths.keySet()) {
+            Path tp = tapPaths.get(tapDest);
+            actionMap = addrules(tapDest, tp, actionMap);
+        }
+        return actionMap;
+    }
+
+    // Translate the path (edges + nodes) into a set of per-node forwarding actions. 
+    // Coalesce them with the existing set of rules for this affinity path. 
+    public HashMap<Node, List<Action>> addrules(HostNodeConnector hnc, Path p, HashMap<Node, List<Action>> actionMap) {
+        HashMap<Node, List<Action>> rules = actionMap;
+        
+        Edge lastedge = null;
+        for (Edge e: p.getEdges()) {
+            NodeConnector op = e.getTailNodeConnector();
+            Node node = e.getTailNodeConnector().getNode();
+            List<Action> actions = rules.get(node);
+            rules.put(node, merge(actions, new Output(op)));
+            lastedge = e;
+        }
+        // Add the edge from the lastnode to the destination host. 
+        NodeConnector dstNC = hnc.getnodeConnector();
+        Node lastnode = lastedge.getHeadNodeConnector().getNode();
+        // lastnode is also the same as hnc.getnodeConnectorNode();
+        List<Action> actions = rules.get(lastnode);
+        rules.put(lastnode, merge(actions, new Output(dstNC)));
+        return rules;
+    }
     
+    public void printActionMap(InetAddress src, InetAddress dst, HashMap<Node, List<Action>> aMap) {
+        log.debug("source: {}, destination: {}", src, dst);
+        for (Node n: aMap.keySet()) {
+            String astr = " ";
+            for (Action a: aMap.get(n)) {
+                astr = astr + "; " + a.toString();
+            }
+            log.debug("Node: {}, Output: {}", n, astr);
+        }
+    }
+
     /** 
      * Add flow groups to forwarding rules manager as FlowEntry
      * objects. Each flow group corresponds to a policy group in the
@@ -304,8 +474,9 @@ public class FlatL2AffinityImpl implements IfNewHostNotify {
      * may be REDIRECT, DROP, or TAP. 
      */
     public boolean programFlowGroupsOnNode(HashMap<String, List<Flow>>flowgroups, 
-                                          HashMap<String, HashMap<AffinityAttributeType, AffinityAttribute>>attribs, 
-                                          Node node) {
+                                           HashMap<String, HashMap<AffinityAttributeType, 
+                                           AffinityAttribute>>attribs, 
+                                           Node node) {
         for (String groupName: flowgroups.keySet()) {
             List<Flow> flowlist = flowgroups.get(groupName);
             log.info("flatl2: {} (#flows={})", groupName, flowgroups.get(groupName).size());
@@ -321,7 +492,8 @@ public class FlatL2AffinityImpl implements IfNewHostNotify {
                 if (actions.size() > 0) {
                     log.info("Adding actions {} to flow {}", actions, f);
                     f.setActions(actions);
-                    // Make a flowEntry object. groupName is the policy name, from the affinity link name. Same for all flows in this bundle. 
+                    // Make a flowEntry object. groupName is the policy name, 
+                    // from the affinity link name. Same for all flows in this bundle. 
                     FlowEntry fEntry = new FlowEntry(groupName, flowName, f, node);
                     log.info("Install flow entry {} on node {}", fEntry.toString(), node.toString());
                     installFlowEntry(fEntry);
@@ -335,7 +507,8 @@ public class FlatL2AffinityImpl implements IfNewHostNotify {
      * (switch) and the list of configured actions.
      */
 
-    public List<Action> calcForwardingActions(Node node, InetAddress src, InetAddress dst, HashMap<AffinityAttributeType, AffinityAttribute> attribs) {
+    public List<Action> calcForwardingActions(Node node, InetAddress src, InetAddress dst, 
+                                              HashMap<AffinityAttributeType, AffinityAttribute> attribs) {
         List<Action> fwdactions = new ArrayList<Action>();
 
         AffinityAttributeType aatype;
@@ -357,6 +530,17 @@ public class FlatL2AffinityImpl implements IfNewHostNotify {
             log.info("Found a path isolate setting.");
         }
 
+        // Apply MTP path.
+        aatype = AffinityAttributeType.SET_MAX_TPUT_PATH;
+
+        if (attribs.get(aatype) != null) {
+            log.info("Found a max tput setting.");
+            Output output = getOutputPort(node, dst, true);
+            if (output != null) {
+                fwdactions.add(output);
+            }
+        }
+
         // Apply redirect 
         aatype = AffinityAttributeType.SET_PATH_REDIRECT;
 
@@ -373,6 +557,8 @@ public class FlatL2AffinityImpl implements IfNewHostNotify {
 
                 // Using L2agent
                 Output output = getOutputPortL2Agent(node, wp);
+                // Using routing service. 
+                // Output output = getOutputPort(node, wp, false);
                 if (output != null) {
                     fwdactions.add(output);
                 }
@@ -396,11 +582,15 @@ public class FlatL2AffinityImpl implements IfNewHostNotify {
                 for (InetAddress tapip: taplist) {
                     log.info("tap information = {}", tapip);
                     Output output1 = getOutputPortL2Agent(node, tapip);
+                    // Not using L2 agent, using routing service. 
+                    // Output output1 = getOutputPort(node, tapip, false);
                     if (output1 != null) {
                         fwdactions = merge(fwdactions, output1);
                     }
                 }
                 Output output2 = getOutputPortL2Agent(node, dst);
+                // Not using L2 agent, using routing service. 
+                // Output output2 = getOutputPort(node, dst, false);
                 if (output2 != null) {
                     fwdactions = merge(fwdactions, output2);
                 }
@@ -415,8 +605,128 @@ public class FlatL2AffinityImpl implements IfNewHostNotify {
         return fwdactions;
     }
     
+
+
+    /** 
+     * Calculate paths for this src-dst pair after applying: 
+     *  -- default routing and exception/waypoint routing
+     *  -- tap destinations.
+     * Return a list of Paths.
+     */
+    
+    public AffinityPath calcAffinityPath(InetAddress src, InetAddress dst, 
+                                         HashMap<AffinityAttributeType, AffinityAttribute> attribs) {
+
+        boolean maxTputPath = false;
+        AffinityPath ap;
+
+        log.info("calc paths: src = {}, dst = {}", src, dst);
+
+        AffinityAttributeType aatype;
+
+        // Apply drop
+        aatype = AffinityAttributeType.SET_DENY;
+        if (attribs.get(aatype) != null) {
+            return null;
+        }
+
+        // Apply isolate (no-op now), and continue to add other affinity types to the forwarding actions list.
+        aatype = AffinityAttributeType.SET_PATH_ISOLATE;
+        if (attribs.get(aatype) != null) {
+            log.info("Found a path isolate setting.");
+        }
+
+        // Apply MTP path, set the type of default path to compute.
+        aatype = AffinityAttributeType.SET_MAX_TPUT_PATH;
+        if (attribs.get(aatype) != null) {
+            log.info("Found a max tput setting.");
+            maxTputPath = true;
+        }
+        // Compute the default path, after applying waypoints and add it to the list. 
+        List<Path> subpaths = new ArrayList<Path>();
+        HostNodeConnector srcNC, dstNC;
+        srcNC = getHostNodeConnector(src);
+        dstNC = getHostNodeConnector(dst);
+        if (srcNC == null || dstNC == null) {
+            log.info("src or destination does not have a HostNodeConnector. src={}, dst={}", src, dst);
+            return null;
+        }
+        Node srcNode = srcNC.getnodeconnectorNode();
+        Node dstNode = dstNC.getnodeconnectorNode();
+        ap = new AffinityPath(srcNC, dstNC);
+
+        log.debug("from node: {}", srcNC.toString());
+        log.debug("dst node: {}", dstNC.toString());
+        
+        // Apply redirect 
+        aatype = AffinityAttributeType.SET_PATH_REDIRECT;
+
+        SetPathRedirect rdrct = (SetPathRedirect) attribs.get(aatype);
+
+        // No redirects were added, so calculate the defaultPath by
+        // looking up the appropriate type of route in the routing
+        // service.
+        List<Path> route = new ArrayList<Path>();
+        if (rdrct == null) {
+            Path defPath;
+            if (maxTputPath == true) {
+                defPath = this.routing.getMaxThroughputRoute(srcNode, dstNode);
+            } else {
+                defPath = this.routing.getRoute(srcNode, dstNode);
+            }
+            route.add(defPath);
+        } else {
+            log.info("Found a path redirect setting. Calculating subpaths 1, 2");
+            List<InetAddress> wplist = rdrct.getWaypointList();
+            if (wplist != null) {
+                // Only one waypoint server in list. 
+                InetAddress wp = wplist.get(0);
+                log.info("waypoint information = {}", wplist.get(0));
+                HostNodeConnector wpNC = getHostNodeConnector(wp);
+                Node wpNode = wpNC.getnodeconnectorNode();
+                Path subpath1;
+                Path subpath2;
+                subpath1 = this.routing.getRoute(srcNode, wpNode);
+                subpath2 = this.routing.getRoute(wpNode, dstNode);
+                route.add(subpath1);
+                route.add(subpath2);
+            }
+        }
+        if (route.size() > 0) {
+            ap.setDefaultPath(route);
+        }
+            
+        // Apply tap, calculate paths to each tap destination and add to AffinityPath.
+        aatype = AffinityAttributeType.SET_TAP;
+
+        SetTap tap = (SetTap) attribs.get(aatype);
+
+        if (tap != null) {
+            log.info("Applying tap affinity.");
+            List<InetAddress> taplist = tap.getTapList();
+            if (taplist != null) {
+                // Add a new rule with original destination + tap destinations. 
+                for (InetAddress tapip: taplist) {
+                    log.info("Adding tap path to destination = {}", tapip);
+
+                    Path tapPath;
+                    HostNodeConnector tapNC = getHostNodeConnector(tapip);
+                    Node tapNode = tapNC.getnodeconnectorNode();
+                    tapPath = this.routing.getRoute(srcNode, tapNode);
+                    ap.setTapPath(tapNC, tapPath);
+                }
+            }
+        }
+
+        log.debug("calcAffinityPath: {}", ap.toString());
+        return ap;
+    }
+    
     public List<Action> merge(List<Action> fwdactions, Action a) {
-        if (!fwdactions.contains(a)) {
+        if (fwdactions == null) {
+            fwdactions = new ArrayList<Action>();
+            fwdactions.add(a);
+        } else if (!fwdactions.contains(a)) {
             fwdactions.add(a);
         }
         return fwdactions;
@@ -447,7 +757,7 @@ public class FlatL2AffinityImpl implements IfNewHostNotify {
         // and not known to the l2agent which relies on learning.
         if (op == null && isHostInactive(ip)) {
             // Use routing.
-            op = getOutputPort(node, ip);
+            op = getOutputPort(node, ip, false);
         }
         return op;
     }
@@ -522,7 +832,7 @@ public class FlatL2AffinityImpl implements IfNewHostNotify {
         return hnConnector;
     }
 
-    public Output getOutputPort(Node node, InetAddress ipaddr) {
+    public Output getOutputPort(Node node, InetAddress ipaddr, boolean mtp) {
         HostNodeConnector hnConnector;
         hnConnector = getHostNodeConnector(ipaddr);
         if (hnConnector != null) {
@@ -538,17 +848,23 @@ public class FlatL2AffinityImpl implements IfNewHostNotify {
                 log.info("Both source and destination are connected to same switch nodes. output port is {}",
                          forwardPort);
             } else {
-                Path route = this.routing.getRoute(node, destNode);
+                Path route;
+                if (mtp == true) {
+                    log.info("Lookup max throughput route {} -> {}", node, destNode);
+                    route = this.routing.getMaxThroughputRoute(node, destNode);
+                } else {
+                    route = this.routing.getRoute(node, destNode);
+                }
+
                 log.info("Path between source and destination switch nodes : {}",
                          route.toString());
-                forwardPort = route.getEdges().get(0).getTailNodeConnector();
+                forwardPort = route.getEdges().get(0).getTailNodeConnector();                
             }
             log.info("output port {} on node {} toward host {}", forwardPort, node, hnConnector);
             return(new Output(forwardPort));
         } 
         return null;
     }
-
     /**
      * Install this flow entry object. 
      */
index e702235d9ad225f1128875ec0a757bb2984c8932..c950f15cd67aae2d84caa7a63c28b3cf3fb82142 100644 (file)
@@ -213,7 +213,7 @@ def add_waypoint():
 def test_tap_1(): 
     tap_example()
     set_tap('a_to_b', '10.0.0.4')
-    add_static_host_tap('a_to_b', '10.0.0.20')
+#    add_static_host_tap('a_to_b', '10.0.0.20')
     get_affinity_link('a_to_b')
     enable_affinity() # Tap to '10.0.0.4'.
 
@@ -236,19 +236,20 @@ def main():
 
     # Create two affinity groups and a link between them. 
     # Assign attributes. 
-    client_ws_example()
-    repeat_add_link()
+#    client_ws_example()
+#    repeat_add_link()
 
-    get_affinity_group('webservers')
-    get_affinity_group('clients')
-    get_affinity_link('inflows')
+#    get_affinity_group('webservers')
+#    get_affinity_group('clients')
+#    get_affinity_link('inflows')
+
+    test_tap()
 
     print "get_all_affinity_groups..."
     get_all_affinity_groups()
     print "get_all_affinity_links..."
     get_all_affinity_links()
 
-#    test_tap_2()
     list_all_hosts()
     return
 
index 3e748cca43e2219dd0fa2f3fe3d82b74993193bf..fa6d7ba1dc8eaaa887ee2aac1d660bb974de4f8f 100644 (file)
@@ -93,7 +93,7 @@ class WaypointMonitor(Thread):
                 # AL: Between them
                 link_name = "inflows"
                 ac.add_affinity_link(link_name, src_ag_name, dst_ag_name)
-                ac.add_waypoint(link_name, self.waypoint_address)
+#                ac.add_waypoint(link_name, self.waypoint_address)
                 ac.add_isolate(link_name)
 #                ac.enable_waypoint(link_name)
                 ac.enable_affinity()
@@ -129,14 +129,14 @@ class WaypointMonitor(Thread):
                 if (self.stat_type == Stats.TYPE_SUBNET):
                     ac.add_affinity_group(dst_ag_name, subnet=self.stat.subnet)
                 elif (self.stat_type == Stats.TYPE_HOST):
-                    pass
+                    ac.add_affinity_group(dst_ag_name, ips=self.dst)
                 else:
                     print "type", self.stat_type, "not supported for redirection"
 
                 # AL: Between them
                 link_name = "inflows"
                 ac.add_affinity_link(link_name, src_ag_name, dst_ag_name)
-                ac.add_waypoint(link_name, self.waypoint_address)
+#                ac.add_waypoint(link_name, self.waypoint_address)
                 ac.add_isolate(link_name)
                 ac.enable_affinity()
                 did_waypoint = True
@@ -163,7 +163,7 @@ def main():
     if (not x):
         print "Unable to add per-protocol flows"
 
-    m = WaypointMonitor(Stats.TYPE_SUBNET, subnet="10.0.0.0/31")
+    m = WaypointMonitor(Stats.TYPE_SUBNET, subnet="10.0.0.1/32")
     m.set_waypoint("10.0.0.2")
     m.set_large_flow_threshold(2000) # 2000 bytes
     m.start()
index a72e233010f89adf81eba303f9502d785b029f9b..d6671b236692cfb37c7f20b91d61e429bf2b6d80 100644 (file)
@@ -30,7 +30,7 @@ class Stats:
         self.prev_bytes = None
 
         self.large_flow_threshold = 5 * 10**6 # in bytes
-        self.rate_threshold = 1 * 10**6 # bits/sec
+        self.rate_threshold = 1 * 10**5 # bits/sec
 
     def __str__(self):
         if (self.stat_type == Stats.TYPE_HOST):