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/debugevent/DebugEvent.java b/src/main/java/net/floodlightcontroller/debugevent/DebugEvent.java
new file mode 100644
index 0000000..e167b26
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugevent/DebugEvent.java
@@ -0,0 +1,506 @@
+package net.floodlightcontroller.debugevent;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.core.module.FloodlightModuleException;
+import net.floodlightcontroller.core.module.IFloodlightModule;
+import net.floodlightcontroller.core.module.IFloodlightService;
+import net.floodlightcontroller.debugevent.web.DebugEventRoutable;
+import net.floodlightcontroller.restserver.IRestApiService;
+
+import com.google.common.collect.Sets;
+/**
+ * This class implements a central store for all events used for debugging the
+ * system. The basic idea is that given the functionality provided by this class,
+ * it should be unnecessary to resort to scraping through system DEBUG/TRACE logs
+ * to understand behavior in a running system.
+ *
+ * @author saurav
+ */
+public class DebugEvent implements IFloodlightModule, IDebugEventService {
+    protected static Logger log = LoggerFactory.getLogger(DebugEvent.class);
+
+    /**
+     *  Every registered event type gets an event id, the value for which is obtained
+     *  while holding the lock.
+     */
+    protected int eventIdCounter = 0;
+    protected Object eventIdLock = new Object();
+
+    private static final int PCT_LOCAL_CAP = 10; // % of global capacity
+    private static final int MIN_LOCAL_CAPACITY = 10; //elements
+
+    /**
+     * Event Information
+     */
+    public class EventInfo {
+        int eventId;
+        boolean enabled;
+        int bufferCapacity;
+        EventType etype;
+        String eventDesc;
+        String eventName;
+        String moduleName;
+        String moduleEventName;
+        Class<?> eventClass;
+        String[] metaData;
+
+        public EventInfo(int eventId, boolean enabled, int bufferCapacity,
+                         EventType etype, Class<?> eventClass, String eventDesc,
+                         String eventName, String moduleName, String... metaData) {
+            this.enabled = enabled;
+            this.eventId = eventId;
+            this.bufferCapacity = bufferCapacity;
+            this.etype = etype;
+            this.eventClass = eventClass;
+            this.eventDesc = eventDesc;
+            this.eventName = eventName;
+            this.moduleName = moduleName;
+            this.moduleEventName = moduleName + "/" + eventName;
+            this.metaData = metaData;
+        }
+
+        public int getEventId() { return eventId; }
+        public boolean isEnabled() { return enabled; }
+        public int getBufferCapacity() { return bufferCapacity; }
+        public EventType getEtype() { return etype; }
+        public String getEventDesc() { return eventDesc; }
+        public String getEventName() { return eventName; }
+        public String getModuleName() { return moduleName; }
+        public String getModuleEventName() { return moduleEventName; }
+        public String[] getMetaData() { return metaData; }
+    }
+
+    //******************
+    //   Global stores
+    //******************
+
+    /**
+     * Event history for a particular event-id is stored in a circular buffer
+     */
+    protected class DebugEventHistory {
+        EventInfo einfo;
+        CircularBuffer<Event> eventBuffer;
+
+        public DebugEventHistory(EventInfo einfo, int capacity) {
+            this.einfo = einfo;
+            this.eventBuffer = new CircularBuffer<Event>(capacity);
+        }
+    }
+
+    /**
+     * Global storage for all event types and their corresponding event buffers.
+     * A particular event type is accessed by directly indexing into the array
+     * with the corresponding event-id.
+     */
+    protected DebugEventHistory[] allEvents =
+                    new DebugEventHistory[MAX_EVENTS];
+
+    /**
+     * Global storage for all event ids registered for a module. The map is indexed
+     * by the module name and event name and returns the event-ids that correspond to the
+     * event types registered by that module (for example module 'linkdiscovery'
+     * may register events that have ids 0 and 1 that correspond to link up/down
+     * events, and receiving malformed LLDP packets, respectively).
+     */
+    protected ConcurrentHashMap<String, ConcurrentHashMap<String, Integer>>
+        moduleEvents = new ConcurrentHashMap<String,
+                                ConcurrentHashMap<String, Integer>>();
+
+    /**
+     * A collection of event ids that are currently enabled for logging
+     */
+    protected Set<Integer> currentEvents = Collections.newSetFromMap(
+                                       new ConcurrentHashMap<Integer,Boolean>());
+
+    //******************
+    // Thread local stores
+    //******************
+
+    /**
+     * Thread local storage for events
+     */
+    protected class LocalEventHistory {
+        int nextIndex;
+        int maxCapacity;
+        boolean enabled;
+        ArrayList<Event> eventList;
+
+        public LocalEventHistory(boolean enabled, int maxCapacity) {
+            this.nextIndex = 0;
+            this.maxCapacity = maxCapacity;
+            this.enabled = enabled;
+            this.eventList = new ArrayList<Event>();
+        }
+    }
+
+    /**
+     * Thread local event buffers used for maintaining event history local to
+     * a thread. Eventually this locally maintained information is flushed
+     * into the global event buffers.
+     */
+    protected final ThreadLocal<LocalEventHistory[]> threadlocalEvents =
+            new ThreadLocal<LocalEventHistory[]>() {
+        @Override
+        protected LocalEventHistory[] initialValue() {
+            return new LocalEventHistory[MAX_EVENTS];
+        }
+    };
+
+    /**
+     * Thread local cache for event-ids that are currently active.
+     */
+    protected final ThreadLocal<Set<Integer>> threadlocalCurrentEvents =
+            new ThreadLocal<Set<Integer>>() {
+        @Override
+        protected Set<Integer> initialValue() {
+            return new HashSet<Integer>();
+        }
+    };
+
+    //*******************************
+    //   IEventUpdater
+    //*******************************
+
+    protected class EventUpdaterImpl<T> implements IEventUpdater<T> {
+        private final int eventId;
+
+        public EventUpdaterImpl(int evId) {
+            this.eventId = evId;
+        }
+
+        @Override
+        public void updateEventNoFlush(Object event) {
+            if (!validEventId()) return;
+            updateEvent(eventId, false, event);
+        }
+
+        @Override
+        public void updateEventWithFlush(Object event) {
+            if (!validEventId()) return;
+            updateEvent(eventId, true, event);
+        }
+
+        private boolean validEventId() {
+            if (eventId < 0 || eventId >= MAX_EVENTS) {
+                throw new IllegalStateException();
+            }
+            return true;
+        }
+
+    }
+
+    //*******************************
+    //   IDebugEventService
+    //*******************************
+
+    @Override
+    public <T> IEventUpdater<T> registerEvent(String moduleName, String eventName,
+                                              String eventDescription, EventType et,
+                                              Class<T> eventClass, int bufferCapacity,
+                                              String... metaData) throws MaxEventsRegistered {
+        int eventId = -1;
+        synchronized (eventIdLock) {
+             eventId = Integer.valueOf(eventIdCounter++);
+        }
+        if (eventId > MAX_EVENTS-1) {
+            throw new MaxEventsRegistered();
+        }
+
+        // register event id for moduleName
+        if (!moduleEvents.containsKey(moduleName)) {
+            moduleEvents.put(moduleName, new ConcurrentHashMap<String, Integer>());
+        }
+        if (!moduleEvents.get(moduleName).containsKey(eventName)) {
+            moduleEvents.get(moduleName).put(eventName, new Integer(eventId));
+        } else {
+            int existingEventId = moduleEvents.get(moduleName).get(eventName);
+            log.error("Duplicate event registration for moduleName {} eventName {}",
+                      moduleName, eventName);
+            return new EventUpdaterImpl<T>(existingEventId);
+        }
+
+        // create storage for event-type
+        boolean enabled = (et == EventType.ALWAYS_LOG) ? true : false;
+        EventInfo ei = new EventInfo(eventId, enabled, bufferCapacity,
+                                     et, eventClass, eventDescription, eventName,
+                                     moduleName, metaData);
+        allEvents[eventId] = new DebugEventHistory(ei, bufferCapacity);
+        if (enabled) {
+            currentEvents.add(eventId);
+        }
+
+        return new EventUpdaterImpl<T>(eventId);
+    }
+
+    private void updateEvent(int eventId, boolean flushNow, Object eventData) {
+        if (eventId < 0 || eventId > MAX_EVENTS-1) return;
+
+        LocalEventHistory[] thishist = this.threadlocalEvents.get();
+        if (thishist[eventId] == null) {
+            // seeing this event for the first time in this thread - create local
+            // store by consulting global store
+            DebugEventHistory de = allEvents[eventId];
+            if (de != null) {
+                boolean enabled = de.einfo.enabled;
+                int localCapacity = de.einfo.bufferCapacity * PCT_LOCAL_CAP/ 100;
+                if (localCapacity < 10)  localCapacity = MIN_LOCAL_CAPACITY;
+                thishist[eventId] = new LocalEventHistory(enabled, localCapacity);
+                if (enabled) {
+                    Set<Integer> thisset = this.threadlocalCurrentEvents.get();
+                    thisset.add(eventId);
+                }
+            } else {
+                log.error("updateEvent seen locally for event {} but no global"
+                          + "storage exists for it yet .. not updating", eventId);
+                return;
+            }
+        }
+
+        // update local store if enabled locally for updating
+        LocalEventHistory le = thishist[eventId];
+        if (le.enabled) {
+            long timestamp = System.currentTimeMillis();
+            long thisthread = Thread.currentThread().getId();
+            String thisthreadname = Thread.currentThread().getName();
+            if (le.nextIndex < le.eventList.size()) {
+                if (le.eventList.get(le.nextIndex) == null) {
+                    le.eventList.set(le.nextIndex, new Event(timestamp, thisthread,
+                                                             thisthreadname,
+                                                             eventData));
+                } else {
+                    Event e = le.eventList.get(le.nextIndex);
+                    e.timestamp = timestamp;
+                    e.threadId = thisthread;
+                    e.threadName = thisthreadname;
+                    e.eventData = eventData;
+                    e.nullifyCachedFormattedEvent();
+                }
+            } else {
+                le.eventList.add(new Event(timestamp, thisthread, thisthreadname, eventData));
+            }
+            le.nextIndex++;
+
+            if (le.nextIndex >= le.maxCapacity || flushNow) {
+                // flush this buffer now
+                DebugEventHistory de = allEvents[eventId];
+                if (de.einfo.enabled) {
+                    le.eventList = de.eventBuffer.addAll(le.eventList, le.nextIndex);
+                } else {
+                    // global buffer is disabled - don't flush, disable locally
+                    le.enabled = false;
+                    Set<Integer> thisset = this.threadlocalCurrentEvents.get();
+                    thisset.remove(eventId);
+                }
+                le.nextIndex = 0;
+            }
+        }
+    }
+
+    @Override
+    public void flushEvents() {
+        LocalEventHistory[] thishist = this.threadlocalEvents.get();
+        Set<Integer> thisset = this.threadlocalCurrentEvents.get();
+        ArrayList<Integer> temp = new ArrayList<Integer>();
+
+        for (int eventId : thisset) {
+            LocalEventHistory le = thishist[eventId];
+            if (le != null && le.nextIndex > 0) {
+                // flush this buffer now
+                DebugEventHistory de = allEvents[eventId];
+                if (de.einfo.enabled) {
+                    le.eventList = de.eventBuffer.addAll(le.eventList, le.nextIndex);
+                } else {
+                    // global buffer is disabled - don't flush, disable locally
+                    le.enabled = false;
+                    temp.add(eventId);
+                }
+                le.nextIndex = 0;
+            }
+        }
+        for (int eId : temp)
+            thisset.remove(eId);
+
+        // sync thread local currently enabled set of eventIds with global set.
+        Sets.SetView<Integer> sv = Sets.difference(currentEvents, thisset);
+        for (int eventId : sv) {
+            if (thishist[eventId] != null) {
+                thishist[eventId].enabled = true;
+                thisset.add(eventId);
+            }
+        }
+
+    }
+
+    @Override
+    public boolean containsModuleEventName(String moduleName, String eventName) {
+        if (!moduleEvents.containsKey(moduleName)) return false;
+        if (moduleEvents.get(moduleName).containsKey(eventName)) return true;
+        return false;
+    }
+
+    @Override
+    public boolean containsModuleName(String moduleName) {
+        return moduleEvents.containsKey(moduleName);
+    }
+
+    @Override
+    public List<DebugEventInfo> getAllEventHistory() {
+        List<DebugEventInfo> moduleEventList = new ArrayList<DebugEventInfo>();
+        for (Map<String, Integer> modev : moduleEvents.values()) {
+            for (int eventId : modev.values()) {
+                DebugEventHistory de = allEvents[eventId];
+                if (de != null) {
+                    List<Map<String,String>> ret = new ArrayList<Map<String,String>>();
+                    for (Event e : de.eventBuffer) {
+                        ret.add(e.getFormattedEvent(de.einfo.eventClass,
+                                                    de.einfo.moduleEventName));
+                    }
+                    moduleEventList.add(new DebugEventInfo(de.einfo, ret));
+                }
+            }
+        }
+        return moduleEventList;
+    }
+
+    @Override
+    public List<DebugEventInfo> getModuleEventHistory(String moduleName) {
+        if (!moduleEvents.containsKey(moduleName)) return Collections.emptyList();
+        List<DebugEventInfo> moduleEventList = new ArrayList<DebugEventInfo>();
+        for (int eventId : moduleEvents.get(moduleName).values()) {
+            DebugEventHistory de = allEvents[eventId];
+            if (de != null) {
+                List<Map<String,String>> ret = new ArrayList<Map<String,String>>();
+                for (Event e : de.eventBuffer) {
+                    ret.add(e.getFormattedEvent(de.einfo.eventClass,
+                                                de.einfo.moduleEventName));
+                }
+                moduleEventList.add(new DebugEventInfo(de.einfo, ret));
+            }
+        }
+        return moduleEventList;
+    }
+
+    @Override
+    public DebugEventInfo getSingleEventHistory(String moduleName, String eventName,
+                                                int last) {
+        if (!moduleEvents.containsKey(moduleName)) return null;
+        Integer eventId = moduleEvents.get(moduleName).get(eventName);
+        if (eventId == null) return null;
+        DebugEventHistory de = allEvents[eventId];
+        if (de != null) {
+            int num = 1;
+            List<Map<String,String>> ret = new ArrayList<Map<String,String>>();
+            for (Event e : de.eventBuffer) {
+                if (num > last)
+                    break;
+                Map<String, String> temp = e.getFormattedEvent(de.einfo.eventClass,
+                                                               de.einfo.moduleEventName);
+                temp.put("#", String.valueOf(num++));
+                ret.add(temp);
+            }
+            return new DebugEventInfo(de.einfo, ret);
+        }
+        return null;
+    }
+
+    @Override
+    public void resetAllEvents() {
+        for (Map<String, Integer> eventMap : moduleEvents.values()) {
+            for (Integer evId : eventMap.values()) {
+                allEvents[evId].eventBuffer.clear();
+            }
+        }
+    }
+
+    @Override
+    public void resetAllModuleEvents(String moduleName) {
+        if (!moduleEvents.containsKey(moduleName)) return;
+        Map<String, Integer> modEvents = moduleEvents.get(moduleName);
+        for (Integer evId : modEvents.values()) {
+            allEvents[evId].eventBuffer.clear();
+        }
+    }
+
+    @Override
+    public void resetSingleEvent(String moduleName, String eventName) {
+        if (!moduleEvents.containsKey(moduleName)) return;
+        Integer eventId = moduleEvents.get(moduleName).get(eventName);
+        if (eventId == null) return;
+        DebugEventHistory de = allEvents[eventId];
+        if (de != null) {
+            de.eventBuffer.clear();
+        }
+    }
+
+    @Override
+    public List<String> getModuleList() {
+        List<String> el = new ArrayList<String>();
+        el.addAll(moduleEvents.keySet());
+        return el;
+    }
+
+    @Override
+    public List<String> getModuleEventList(String moduleName) {
+        if (!moduleEvents.containsKey(moduleName))
+            return Collections.emptyList();
+        List<String> el = new ArrayList<String>();
+        el.addAll(moduleEvents.get(moduleName).keySet());
+        return el;
+    }
+
+    //*******************************
+    //   IFloodlightModule
+    //*******************************
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+        Collection<Class<? extends IFloodlightService>> l =
+                new ArrayList<Class<? extends IFloodlightService>>();
+        l.add(IDebugEventService.class);
+        return l;
+    }
+
+    @Override
+    public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
+        Map<Class<? extends IFloodlightService>, IFloodlightService> m =
+                new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
+        m.put(IDebugEventService.class, this);
+        return m;
+    }
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
+        ArrayList<Class<? extends IFloodlightService>> deps =
+                new ArrayList<Class<? extends IFloodlightService>>();
+        deps.add(IRestApiService.class);
+        return deps;
+    }
+
+    @Override
+    public void init(FloodlightModuleContext context)
+            throws FloodlightModuleException {
+    }
+
+    @Override
+    public void startUp(FloodlightModuleContext context)
+            throws FloodlightModuleException {
+        IRestApiService restService =
+                context.getServiceImpl(IRestApiService.class);
+        restService.addRestletRoutable(new DebugEventRoutable());
+        DebugEventAppender.setDebugEventServiceImpl(this);
+    }
+
+}