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);
+ }
+
+}