Added FatTree simulator, extended NullProviders.java and cli null control command

Change-Id: Ibfae78306fa8663af13770abe51d202453dd1474
diff --git a/providers/null/src/main/java/org/onosproject/provider/nil/FatTreeTopologySimulator.java b/providers/null/src/main/java/org/onosproject/provider/nil/FatTreeTopologySimulator.java
new file mode 100644
index 0000000..9a97c62
--- /dev/null
+++ b/providers/null/src/main/java/org/onosproject/provider/nil/FatTreeTopologySimulator.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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 org.onosproject.provider.nil;
+import java.util.Arrays;
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * Fat-tree topology simulator.
+ */
+public class FatTreeTopologySimulator extends TopologySimulator {
+
+    private static final int DEFAULT_NUMBER_OF_PORTS_PER_SWITCH = 4;
+    protected int kPorts;
+    protected int numberOfPods;
+    protected int numberOfAggLayerSwitches;
+    protected int numberOfCoreLayerSwitches;
+    protected int numberOfEdgeLayerSwitches;
+
+    @Override
+    protected void processTopoShape(String shape) {
+        super.processTopoShape(shape);
+
+        // If switch ports are not provided use a default value
+        int k = (topoShape.length == 1) ?
+                DEFAULT_NUMBER_OF_PORTS_PER_SWITCH :
+                Integer.parseInt(topoShape[1]);
+
+        // A fat-tree is parametrized by the total number of ports per switch.
+        // check top of page 4 of http://web.eecs.umich.edu/~mosharaf/Readings/Fat-Tree.pdf
+        kPorts = k;
+        numberOfPods = k;
+        numberOfCoreLayerSwitches = (k / 2) * (k / 2);
+        numberOfAggLayerSwitches = k * k / 2;
+        numberOfEdgeLayerSwitches = k * k / 2;
+
+        // need to also change hostCount variable of TopologySimulator
+        hostCount = kPorts / 2;
+    }
+
+
+    @Override
+    public void setUpTopology() {
+
+        checkArgument(kPorts > 1, "Fat Tree switches must " +
+                       "have at **least** 2 ports each!");
+
+        // this is the total number of **Switches**
+        // in a fat-tree topology
+        deviceCount = numberOfAggLayerSwitches +
+                      numberOfCoreLayerSwitches +
+                      numberOfEdgeLayerSwitches;
+
+        log.info("Booting a {} with {}-ports, {} switches in total {} pods",
+                  topoShape[0], kPorts, deviceCount,  numberOfPods);
+
+
+        prepareForDeviceEvents(deviceCount);
+        createDevices();
+        waitForDeviceEvents();
+
+        createLinks();
+        createHosts();
+    }
+
+    @Override
+    protected void createLinks() {
+
+        // For each switch keep a count of used ports
+        int[] portList = new int[deviceCount];
+        Arrays.fill(portList, 0);
+
+        // we assume that deviceIds stores all the fat tree switches in a flat list
+        int end = numberOfPods / 2;
+        // from [ 0, (k/2)^2 - 1] we store (k/2)^2 core switces
+        int startOfCore = 0;
+        // from [ (k/2)^2, (k/2)^2 + (k^2)/2 - 1] we store (k^2)/2 aggregation switches
+        int startOfAgg = (numberOfPods / 2) * (numberOfPods / 2);
+        // from [ (k/2)^2 + (k^2)/2, (k/2)^2 + (k^2)/2 + (k^2)/2 -1] we store (k^2)/2 edge switches
+        int startOfEdge = startOfAgg + (numberOfPods * numberOfPods) / 2;
+
+        log.debug("startOfCore = {}, startOfAgg = {}, startOfEdge = {}",
+                  startOfCore, startOfAgg, startOfEdge);
+
+        // Create links between core and aggregation switches
+        for (int x = 0; x < numberOfAggLayerSwitches; x += end) {
+
+            // each agg.switch will handle a group of k/2 core consecutive switches
+            for (int i = 0; i < end; i += 1) {
+                for (int j = 0; j < end; j += 1) {
+                    int coreSwitch = i * end + j;
+                    int aggSwitch = startOfAgg + x + i;
+
+                    createLink(coreSwitch,
+                               aggSwitch,
+                               portList[coreSwitch]++,
+                               portList[aggSwitch]++);
+                }
+            }
+        }
+
+        // Create links between aggregation and edge switches
+        for (int x = 0; x < numberOfAggLayerSwitches; x += end) {
+            for (int i = 0; i <  end; i += 1) {
+                for (int j = 0; j < end; j += 1) {
+                    int aggSwitch = startOfAgg + x + i;
+                    int edgeSwitch = startOfEdge + x + j;
+
+                    createLink(aggSwitch,
+                               edgeSwitch,
+                               portList[aggSwitch]++,
+                               portList[edgeSwitch]++);
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void createHosts() {
+
+        int firstEdgeSwitch = (numberOfPods / 2) * (numberOfPods / 2) +
+                              (numberOfPods * numberOfPods) / 2;
+
+        // hosts connect **only** to edge switches, each edge switch has k/2 ports free for hosts
+        for (int edgeSwitch = firstEdgeSwitch; edgeSwitch < deviceCount; edgeSwitch++) {
+
+           createHosts(deviceIds.get(edgeSwitch), kPorts / 2);
+        }
+    }
+}
diff --git a/providers/null/src/main/java/org/onosproject/provider/nil/NullProviders.java b/providers/null/src/main/java/org/onosproject/provider/nil/NullProviders.java
index b0ccf15..5d65caf 100644
--- a/providers/null/src/main/java/org/onosproject/provider/nil/NullProviders.java
+++ b/providers/null/src/main/java/org/onosproject/provider/nil/NullProviders.java
@@ -365,6 +365,8 @@
             return new MeshTopologySimulator();
         } else if (topoShape.matches("grid([,].*|$)")) {
             return new GridTopologySimulator();
+        } else if (topoShape.matches("fattree([,].*|$)")) {
+            return new FatTreeTopologySimulator();
         } else if (topoShape.matches("custom([,].*|$)")) {
             return new CustomTopologySimulator();
         } else {
diff --git a/providers/null/src/main/java/org/onosproject/provider/nil/cli/NullControlCommand.java b/providers/null/src/main/java/org/onosproject/provider/nil/cli/NullControlCommand.java
index 74fbbb1..6edf6e5 100644
--- a/providers/null/src/main/java/org/onosproject/provider/nil/cli/NullControlCommand.java
+++ b/providers/null/src/main/java/org/onosproject/provider/nil/cli/NullControlCommand.java
@@ -35,7 +35,8 @@
     String cmd = null;
 
     @Argument(index = 1, name = "topoShape",
-            description = "Topology shape: e.g. configured, linear, reroute, centipede, tree, spineleaf, mesh",
+            description = "Topology shape: e.g. configured, linear, reroute, centipede, tree, spineleaf, " +
+                    ", mesh, fattree",
             required = false, multiValued = false)
     String topoShape = null;