Giant patch of changes to support OpenFlow 1.3

The following people have contributed to this patch:
- Ali Al-Shabibi <alshabibi.ali@gmail.com>
- Ayaka Koshibe <ayaka@onlab.us>
- Brian O'Connor <bocon@onlab.us>
- Jonathan Hart <jono@onlab.us>
- Matteo Gerola <mgerola@create-net.org>
- Michele Santuari <michele.santuari@create-net.org>
- Pavlin Radoslavov <pavlin@onlab.us>
- Saurav Das <sauravdas@alumni.stanford.edu>
- Toshio Koide <t-koide@onlab.us>
- Yuta HIGUCHI <y-higuchi@onlab.us>

The patch includes the following changes:
- New Floodlight I/O loop / state machine
- New switch/port handling
- New role management (incl. Role.EQUAL)
- Added Floodlight debug framework
- Updates to Controller.java
- Move to Loxigen's OpenflowJ library
- Added OF1.3 support
- Added support for different switches (via DriverManager)
- Updated ONOS modules to use new APIs
- Added and updated unit tests

Change-Id: Ic70a8d50f7136946193d2ba2e4dc0b4bfac5f599
diff --git a/src/main/java/net/floodlightcontroller/util/LoadMonitor.java b/src/main/java/net/floodlightcontroller/util/LoadMonitor.java
new file mode 100644
index 0000000..5b234cd
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/util/LoadMonitor.java
@@ -0,0 +1,275 @@
+/**
+ *    Copyright 2013, Big Switch Networks, Inc.
+ *
+ *    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 net.floodlightcontroller.util;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+
+import net.floodlightcontroller.core.annotations.LogMessageDocs;
+import net.floodlightcontroller.core.annotations.LogMessageDoc;
+
+public class LoadMonitor implements Runnable {
+
+    public enum LoadLevel {
+        OK,
+        HIGH,
+        VERYHIGH,
+    }
+
+    public LoadLevel getLoadLevel() {
+        return loadlevel ;
+    }
+
+    public double getLoad() {
+        return load ;
+    }
+
+    public static final int LOADMONITOR_SAMPLING_INTERVAL = 1000; // mili-sec
+    public static final double THRESHOLD_HIGH = 0.90;
+    public static final double THRESHOLD_VERYHIGH = 0.95;
+    public static final int MAX_LOADED_ITERATIONS = 5;
+    public static final int MAX_LOAD_HISTORY = 5;
+
+    protected volatile double load;
+    protected volatile LoadLevel loadlevel;
+    protected int itersLoaded;
+
+    protected boolean isLinux;
+    protected int numcores;
+    protected int jiffyNanos;
+    protected long[] lastNanos;
+    protected long[] lastIdle;
+    protected Logger log;
+
+    public LoadMonitor(Logger log_) {
+        log = log_;
+        loadlevel = LoadLevel.OK;
+        load = 0.0;
+        itersLoaded = 0;
+
+        lastNanos = new long[MAX_LOAD_HISTORY];
+        lastIdle = new long[MAX_LOAD_HISTORY];
+        for (int i=0 ; i<MAX_LOAD_HISTORY ; i++) {
+            lastNanos[i] = 0L;
+            lastIdle[i] = 0L;
+        }
+
+        isLinux = System.getProperty("os.name").equals("Linux");
+        numcores = 1;
+        jiffyNanos = 10 * 1000 * 1000;
+        if (isLinux) {
+            try {
+                numcores = Integer.parseInt(
+                        this.runcmd("/usr/bin/nproc"));
+                jiffyNanos = (1000 * 1000 * 1000) / Integer.parseInt(
+                        this.runcmd("/usr/bin/getconf CLK_TCK"));
+            }
+            catch (NumberFormatException ex) {
+                if (log != null) {
+                        // Log message documented on runcmd function
+                    log.error("Exception in inializing load monitor ", ex);
+                }
+                else {
+                    ex.printStackTrace();
+                }
+            }
+        }
+    }
+
+    @Override
+    @LogMessageDocs({
+        @LogMessageDoc(
+            message="System under very heavy load, dropping some packet-ins",
+            explanation="We detcted that the system was under very heavy" +
+                        "  load, dropping some packet-ins temporarily"),
+        @LogMessageDoc(
+            message="System under heavy load, dropping some new flows",
+            explanation="We detcted that the system was under heavy load," +
+                        " dropping some new flows temporarily")
+    })
+    public void run() {
+        if (!isLinux) return;
+
+        long currNanos = System.nanoTime();
+        long currIdle = this.readIdle();
+        for (int i=0 ; i < (MAX_LOAD_HISTORY - 1) ; i++) {
+            lastNanos[i] = lastNanos[i+1];
+            lastIdle[i] = lastIdle[i+1];
+        }
+        lastNanos[MAX_LOAD_HISTORY - 1] = currNanos;
+        lastIdle[MAX_LOAD_HISTORY - 1] = currIdle;
+
+        if (itersLoaded >= MAX_LOADED_ITERATIONS) {
+            loadlevel = LoadLevel.OK;
+            itersLoaded = 0;
+            return;
+        }
+
+        long nanos = lastNanos[MAX_LOAD_HISTORY - 1] - lastNanos[0];
+        long idle = lastIdle[MAX_LOAD_HISTORY - 1] - lastIdle[0];
+        load =
+            1.0 - ((double)(idle * jiffyNanos) / (double)(nanos * numcores));
+
+        if (load > THRESHOLD_VERYHIGH) {
+            loadlevel = LoadLevel.VERYHIGH;
+            itersLoaded += 1;
+            String msg = "System under very heavy load, dropping packet-ins.";
+
+            if (log != null) {
+                log.error(msg);
+            }
+            else {
+                System.out.println(msg);
+            }
+            return;
+        }
+
+        if (load > THRESHOLD_HIGH) {
+            loadlevel = LoadLevel.HIGH;
+            itersLoaded += 1;
+            String msg = "System under heavy load, dropping new flows.";
+
+            if (log != null) {
+                log.error(msg);
+            }
+            else {
+                System.out.println(msg);
+            }
+            return;
+        }
+
+        loadlevel = LoadLevel.OK;
+        itersLoaded = 0;
+        return;
+    }
+
+    @LogMessageDoc(
+        message="Exception in reading load monitor params, using defaults",
+        explanation="There was an error in inializing load monitor's props," +
+                    " using default parameters")
+    protected String runcmd(String cmd) {
+        String line;
+        StringBuilder ret = new StringBuilder();
+        try {
+            Process p = Runtime.getRuntime().exec(cmd);
+            BufferedReader input =
+                new BufferedReader(
+                new InputStreamReader(p.getInputStream()));
+            while ((line = input.readLine()) != null) {
+                ret.append(line);
+            }
+            input.close();
+            p.waitFor();
+        }
+        catch (InterruptedException ex) {
+            if (log != null) {
+                log.error("Exception in inializing load monitor ", ex);
+            }
+            else {
+                ex.printStackTrace();
+            }
+        }
+        catch (IOException ex) {
+            if (log != null) {
+                log.error("Exception in inializing load monitor ", ex);
+            }
+            else {
+                ex.printStackTrace();
+            }
+        }
+        return ret.toString();
+
+    }
+
+    protected long readIdle() {
+        long idle = 0;
+        FileInputStream fs = null;
+        BufferedReader reader = null;
+        try {
+            try {
+                fs = new FileInputStream("/proc/stat");
+                reader = new BufferedReader(new InputStreamReader(fs));
+                String line = reader.readLine();
+                if (line == null) throw new IOException("Empty file");
+                idle = Long.parseLong(line.split("\\s+")[4]);
+            } finally {
+                if (reader != null)
+                    reader.close();
+                if (fs != null)
+                    fs.close();
+            }
+        } catch (IOException ex) {
+            log.error("Error reading idle time from /proc/stat", ex);
+        }
+        return idle;
+
+    }
+
+    public ScheduledFuture<?> startMonitoring(ScheduledExecutorService ses)
+    {
+        ScheduledFuture<?> monitorTask =
+            ses.scheduleAtFixedRate(
+                this, 0,
+                LOADMONITOR_SAMPLING_INTERVAL, TimeUnit.MILLISECONDS);
+        return monitorTask;
+    }
+
+    /*
+     * For testing
+     */
+    public ScheduledFuture<?> printMonitoring(ScheduledExecutorService ses)
+    {
+        final LoadMonitor mon = this;
+        ScheduledFuture<?> monitorTask =
+            ses.scheduleAtFixedRate(
+                new Runnable() {
+                    public void run() {
+                        System.out.println(mon.getLoad());
+                    }
+                }, LOADMONITOR_SAMPLING_INTERVAL/2,
+                LOADMONITOR_SAMPLING_INTERVAL, TimeUnit.MILLISECONDS);
+        return monitorTask;
+    }
+
+    public static void main(String[] args) {
+        final LoadMonitor monitor = new LoadMonitor(null);
+        final ScheduledExecutorService scheduler =
+            Executors.newScheduledThreadPool(1);
+        final ScheduledFuture<?> monitorTask =
+            monitor.startMonitoring(scheduler);
+        final ScheduledFuture<?> printTask =
+            monitor.printMonitoring(scheduler);
+
+        // Run the tasks for 2 minutes
+        scheduler.schedule(
+            new Runnable() {
+                public void run() {
+                    monitorTask.cancel(true);
+                    printTask.cancel(true);
+                }
+            }, 5*60, TimeUnit.SECONDS);
+    }
+
+}