First set of changes to the Cpqd driver to remove hardcoding
and adding ECMP group support

Change-Id: Id34ecd3336ce702e7c151b486c4dd02a28ef1c76
diff --git a/src/main/java/net/floodlightcontroller/core/FloodlightProvider.java b/src/main/java/net/floodlightcontroller/core/FloodlightProvider.java
index 0ee2904..5dbdb3e 100644
--- a/src/main/java/net/floodlightcontroller/core/FloodlightProvider.java
+++ b/src/main/java/net/floodlightcontroller/core/FloodlightProvider.java
@@ -30,6 +30,7 @@
 import net.floodlightcontroller.debugevent.IDebugEventService;
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
+import net.onrc.onos.core.configmanager.INetworkConfigService;
 import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
 import net.onrc.onos.core.registry.IControllerRegistryService;
 
@@ -83,6 +84,8 @@
                context.getServiceImpl(IControllerRegistryService.class));
        controller.setLinkDiscoveryService(
                context.getServiceImpl(ILinkDiscoveryService.class));
+        controller.setNetworkConfigService(
+                context.getServiceImpl(INetworkConfigService.class));
 
        controller.init(context.getConfigParams(this));
     }
diff --git a/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java b/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
index 5f73d9a..4447b75 100644
--- a/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
+++ b/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
@@ -23,6 +23,7 @@
 
 import net.floodlightcontroller.core.internal.Controller.Counters;
 import net.floodlightcontroller.core.module.IFloodlightService;
+import net.onrc.onos.core.configmanager.INetworkConfigService;
 import net.onrc.onos.core.packet.Ethernet;
 import net.onrc.onos.core.util.OnosInstanceId;
 
@@ -186,6 +187,28 @@
     public void removeOFSwitchListener(IOFSwitchListener listener);
 
 
+    Set<Long> getAllSwitchDpids();
+
+    IOFSwitch getSwitch(long dpid);
+
+    /**
+     * Record a switch event in in-memory debug-event
+     * 
+     * @param switchDPID
+     * @param reason Reason for this event
+     * @param flushNow see debug-event flushing in IDebugEventService
+     */
+    public void addSwitchEvent(long switchDPID, String reason, boolean flushNow);
+
+    Set<Long> getAllMasterSwitchDpids();
+
+    Set<Long> getAllEqualSwitchDpids();
+
+    IOFSwitch getMasterSwitch(long dpid);
+
+    IOFSwitch getEqualSwitch(long dpid);
+
+    void setAlwaysClearFlowsOnSwActivate(boolean value);
 
     //************************
     //  Utility methods
@@ -235,29 +258,12 @@
      */
     public Counters getCounters();
 
-    void setAlwaysClearFlowsOnSwActivate(boolean value);
+
 
     Map<String, Long> getMemory();
 
     Long getUptime();
 
-    Set<Long> getAllSwitchDpids();
 
-    IOFSwitch getSwitch(long dpid);
-
-    /**
-     * Record a switch event in in-memory debug-event
-     * @param switchDPID
-     * @param reason Reason for this event
-     * @param flushNow see debug-event flushing in IDebugEventService
-     */
-    public void addSwitchEvent(long switchDPID, String reason, boolean flushNow);
-
-    Set<Long> getAllMasterSwitchDpids();
-
-    Set<Long> getAllEqualSwitchDpids();
-
-    IOFSwitch getMasterSwitch(long dpid);
-
-    IOFSwitch getEqualSwitch(long dpid);
+    public INetworkConfigService getNetworkConfigService();
 }
diff --git a/src/main/java/net/floodlightcontroller/core/IOF13Switch.java b/src/main/java/net/floodlightcontroller/core/IOF13Switch.java
index 425c6a9..8ac2912 100644
--- a/src/main/java/net/floodlightcontroller/core/IOF13Switch.java
+++ b/src/main/java/net/floodlightcontroller/core/IOF13Switch.java
@@ -1,5 +1,6 @@
 package net.floodlightcontroller.core;
 
+import java.io.IOException;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Set;
@@ -22,17 +23,20 @@
      * by a switch implementing this interface. It is up to the implementation
      * to translate the 'matchActionOp' into a match-instruction with actions,
      * as expected by OF 1.3 switches.
-     *
+     * 
      * @param matchActionOp
+     * @throws IOException
      */
-    public void pushFlow(MatchActionOperationEntry matchActionOp);
+    public void pushFlow(MatchActionOperationEntry matchActionOp) throws IOException;
 
     /**
      * Pushes a collection of flows to the switch.
-     * 
+     *
      * @param matchActionOps
+     * @throws IOException
      */
-    public void pushFlows(Collection<MatchActionOperationEntry> matchActionOps);
+    public void pushFlows(Collection<MatchActionOperationEntry> matchActionOps)
+            throws IOException;
 
     // ****************************
     // Group related
diff --git a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
index 40aa530..72ec404 100644
--- a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
+++ b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
@@ -624,4 +624,9 @@
      */
     public void setTableFull(boolean isFull);
 
+    /**
+     * Get the switch driver hanshake state
+     */
+    public String getSwitchDriverState();
+
 }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/Controller.java b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
index 3550297..72c536f 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/Controller.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
@@ -68,6 +68,7 @@
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
 import net.floodlightcontroller.util.LoadMonitor;
+import net.onrc.onos.core.configmanager.INetworkConfigService;
 import net.onrc.onos.core.drivermanager.DriverManager;
 import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
 import net.onrc.onos.core.packet.Ethernet;
@@ -136,6 +137,7 @@
     protected IDebugEventService debugEvents;
 
     protected ILinkDiscoveryService linkDiscovery;
+    protected INetworkConfigService networkConfig;
 
     // Configuration options
     protected int openFlowPort = 6633;
@@ -483,6 +485,10 @@
         this.linkDiscovery = linkDiscovery;
     }
 
+    public void setNetworkConfigService(INetworkConfigService networkConfigService) {
+        this.networkConfig = networkConfigService;
+    }
+
     public void setDebugCounter(IDebugCounterService debugCounters) {
         this.debugCounters = debugCounters;
     }
@@ -993,6 +999,10 @@
         }
     }
 
+    public INetworkConfigService getNetworkConfigService() {
+        return networkConfig;
+    }
+
     // **************
     // Initialization
     // **************
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java b/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java
index d2e4156..b011e6b 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java
@@ -1069,7 +1069,7 @@
          * controller. Next State: depends on the role of this controller for
          * this switch - either MASTER or EQUAL.
          */
-        WAIT_SWITCH_DRIVER_SUB_HANDSHAKE(true) {
+        WAIT_SWITCH_DRIVER_SUB_HANDSHAKE(false) {
 
             @Override
             void processOFError(OFChannelHandler h, OFErrorMsg m)
@@ -1871,7 +1871,14 @@
 
         void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
                 throws SwitchStateException, IOException {
-            unhandledMessageReceived(h, m);
+            // A role reply message received by the default handler implies
+            // that the channel state-machine is in a state where it does not
+            // expect a role message. That in turn implies that role-request was
+            // sent out by this controller, as a result of a callback
+            // from the registry service, because the chosen master (some other
+            // instance) died, while this controller instance has not completed
+            // handshake yet. Best to disconnect switch and start over.
+            illegalMessageReceived(h, m);
         }
 
         void processOFGetAsyncReply(OFChannelHandler h,
@@ -1925,15 +1932,17 @@
          * controller that wins mastership. Once the registry API changes to
          * reply to every request, we would not need to wait for a timeout to
          * move to Role.EQUAL (or SLAVE).
-         * 
+         *
          * @param h the channel handler for this switch
          * @param ctx the netty channel handler context for the channel 'h'
          * @throws IOException
          */
         public void handleTimedOutHandshake(OFChannelHandler h,
                 ChannelHandlerContext ctx) throws IOException {
-            log.error("Disconnecting switch {}: failed to complete handshake",
-                    h.getSwitchInfoString());
+            log.error("Disconnecting switch {}: failed to complete handshake " +
+                    "in state {} (with driverState: {})",
+                    h.getSwitchInfoString(), h.getStateForTesting(),
+                    h.sw.getSwitchDriverState());
             h.counters.switchDisconnectHandshakeTimeout.updateCounterWithFlush();
             ctx.getChannel().close();
         }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImplBase.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImplBase.java
index 3e6d7b2..254e658 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImplBase.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImplBase.java
@@ -1286,4 +1286,9 @@
     public Lock getListenerWriteLock() {
         return listenerLock.writeLock();
     }
+
+    public String getSwitchDriverState() {
+        return "";
+    }
+
 }
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java
index 60cf0b1..961a913 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java
@@ -36,7 +36,7 @@
 import net.onrc.onos.core.matchaction.action.PopMplsAction;
 import net.onrc.onos.core.matchaction.action.PushMplsAction;
 import net.onrc.onos.core.matchaction.action.SetMplsIdAction;
-import net.onrc.onos.core.matchaction.match.Ipv4PacketMatch;
+import net.onrc.onos.core.matchaction.match.Ipv4Match;
 import net.onrc.onos.core.matchaction.match.Match;
 import net.onrc.onos.core.matchaction.match.MplsMatch;
 import net.onrc.onos.core.packet.ARP;
@@ -432,7 +432,7 @@
     private void setIpTableRouter(Switch sw, String subnetIp, String mplsLabel,
             List<String> fwdToSws) {
 
-        Ipv4PacketMatch ipMatch = new Ipv4PacketMatch(subnetIp);
+        Ipv4Match ipMatch = new Ipv4Match(subnetIp);
         List<Action> actions = new ArrayList<>();
 
         // If destination SW is the same as the fwd SW, then do not push MPLS label
@@ -537,9 +537,9 @@
         Match m = ma.getMatch();
         List<Action> actions = ma.getActions();
 
-        if (m instanceof Ipv4PacketMatch) {
+        if (m instanceof Ipv4Match) {
             logStr.append("If the IP matches with ");
-            IPv4Net ip = ((Ipv4PacketMatch) m).getDestination();
+            IPv4Net ip = ((Ipv4Match) m).getDestination();
             logStr.append(ip.toString());
             logStr.append(" then ");
         }
diff --git a/src/main/java/net/onrc/onos/core/configmanager/NetworkConfigManager.java b/src/main/java/net/onrc/onos/core/configmanager/NetworkConfigManager.java
index b1d3836..d7c0ac4 100644
--- a/src/main/java/net/onrc/onos/core/configmanager/NetworkConfigManager.java
+++ b/src/main/java/net/onrc/onos/core/configmanager/NetworkConfigManager.java
@@ -46,13 +46,13 @@
      * JSON Config file needs to use one of the following types for defining the
      * kind of switch or link it wishes to configure.
      */
-    private static final String SEGMENT_ROUTER = "Router_SR";
-    private static final String ROADM = "Roadm";
-    private static final String OF10SWITCH = "Switch_OF10";
+    public static final String SEGMENT_ROUTER = "Router_SR";
+    public static final String ROADM = "Roadm";
+    public static final String OF10SWITCH = "Switch_OF10";
 
-    private static final String PKT_LINK = "pktLink";
-    private static final String WDM_LINK = "wdmLink";
-    private static final String PKT_OPT_LINK = "pktOptLink";
+    public static final String PKT_LINK = "pktLink";
+    public static final String WDM_LINK = "wdmLink";
+    public static final String PKT_OPT_LINK = "pktOptLink";
 
     NetworkConfig networkConfig;
     private ConcurrentMap<Long, SwitchConfig> configuredSwitches;
diff --git a/src/main/java/net/onrc/onos/core/configmanager/PktLinkConfig.java b/src/main/java/net/onrc/onos/core/configmanager/PktLinkConfig.java
index f205686..e205e77 100644
--- a/src/main/java/net/onrc/onos/core/configmanager/PktLinkConfig.java
+++ b/src/main/java/net/onrc/onos/core/configmanager/PktLinkConfig.java
@@ -132,6 +132,7 @@
     private void validateParams() {
         // TODO - wrong-names, duplicate links,
         // duplicate use of port, is switch-allowed for which link is allowed?
+        // valid port numbers
     }
 
     public static class PktLinkParamsNotSpecified extends RuntimeException {
diff --git a/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplCPqD13.java b/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplCPqD13.java
index 2e80c3b..d722da8 100644
--- a/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplCPqD13.java
+++ b/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplCPqD13.java
@@ -2,16 +2,51 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import net.floodlightcontroller.core.IFloodlightProviderService.Role;
+import net.floodlightcontroller.core.IOF13Switch;
+import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.SwitchDriverSubHandshakeAlreadyStarted;
 import net.floodlightcontroller.core.SwitchDriverSubHandshakeCompleted;
 import net.floodlightcontroller.core.SwitchDriverSubHandshakeNotStarted;
 import net.floodlightcontroller.core.internal.OFSwitchImplBase;
+import net.onrc.onos.core.configmanager.INetworkConfigService;
+import net.onrc.onos.core.configmanager.INetworkConfigService.NetworkConfigState;
+import net.onrc.onos.core.configmanager.INetworkConfigService.SwitchConfigStatus;
+import net.onrc.onos.core.configmanager.NetworkConfig.LinkConfig;
+import net.onrc.onos.core.configmanager.NetworkConfigManager;
+import net.onrc.onos.core.configmanager.PktLinkConfig;
+import net.onrc.onos.core.configmanager.SegmentRouterConfig;
+import net.onrc.onos.core.matchaction.MatchAction;
+import net.onrc.onos.core.matchaction.MatchActionOperationEntry;
+import net.onrc.onos.core.matchaction.MatchActionOperations.Operator;
+import net.onrc.onos.core.matchaction.action.Action;
+import net.onrc.onos.core.matchaction.action.CopyTtlInAction;
+import net.onrc.onos.core.matchaction.action.CopyTtlOutAction;
+import net.onrc.onos.core.matchaction.action.DecMplsTtlAction;
+import net.onrc.onos.core.matchaction.action.DecNwTtlAction;
+import net.onrc.onos.core.matchaction.action.GroupAction;
+import net.onrc.onos.core.matchaction.action.ModifyDstMacAction;
+import net.onrc.onos.core.matchaction.action.ModifySrcMacAction;
+import net.onrc.onos.core.matchaction.action.OutputAction;
+import net.onrc.onos.core.matchaction.action.PopMplsAction;
+import net.onrc.onos.core.matchaction.action.PushMplsAction;
+import net.onrc.onos.core.matchaction.action.SetMplsIdAction;
+import net.onrc.onos.core.matchaction.match.Ipv4Match;
+import net.onrc.onos.core.matchaction.match.Match;
+import net.onrc.onos.core.matchaction.match.MplsMatch;
+import net.onrc.onos.core.matchaction.match.PacketMatch;
+import net.onrc.onos.core.util.Dpid;
+import net.onrc.onos.core.util.IPv4Net;
+import net.onrc.onos.core.util.PortNumber;
 
 import org.projectfloodlight.openflow.protocol.OFAsyncGetReply;
 import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
@@ -48,15 +83,18 @@
 import org.projectfloodlight.openflow.types.U64;
 import org.projectfloodlight.openflow.util.HexString;
 
+import com.google.common.collect.Sets;
+
 /**
  * OFDescriptionStatistics Vendor (Manufacturer Desc.): Stanford University,
  * Ericsson Research and CPqD Research. Make (Hardware Desc.) : OpenFlow 1.3
  * Reference Userspace Switch Model (Datapath Desc.) : None Software : Serial :
  * None
  */
-public class OFSwitchImplCPqD13 extends OFSwitchImplBase {
+public class OFSwitchImplCPqD13 extends OFSwitchImplBase implements IOF13Switch {
     private static final int VLAN_ID_OFFSET = 16;
     private AtomicBoolean driverHandshakeComplete;
+    private AtomicBoolean haltStateMachine;
     private OFFactory factory;
     private static final int OFPCML_NO_BUFFER = 0xffff;
     // Configuration of asynch messages to controller. We need different
@@ -73,7 +111,6 @@
     private static final long TEST_FLOW_REMOVED_MASK = 0xf;
     private static final long TEST_PACKET_IN_MASK = 0x7;
     private static final long TEST_PORT_STATUS_MASK = 0x7;
-    private long barrierXidToWaitFor = -1;
 
     private static final int TABLE_VLAN = 0;
     private static final int TABLE_TMAC = 1;
@@ -83,25 +120,38 @@
     private static final int TABLE_ACL = 5;
 
     private static final short MAX_PRIORITY = (short) 0xffff;
-    private static final short SLASH_24_PRIORITY = (short) 0xfff0;
-    private static final short SLASH_16_PRIORITY = (short) 0xff00;
-    private static final short SLASH_8_PRIORITY = (short) 0xf000;
+    private static final short PRIORITY_MULTIPLIER = (short) 2046;
     private static final short MIN_PRIORITY = 0x0;
     private static final U64 METADATA_MASK = U64.of(Long.MAX_VALUE << 1 | 0x1);
 
     ConcurrentHashMap<Integer, OFGroup> l2groups;
 
+    private long barrierXidToWaitFor = -1;
+    private DriverState driverState;
     private final boolean usePipeline13;
+    private SegmentRouterConfig srConfig;
+    private ConcurrentMap<Dpid, Set<PortNumber>> neighbors;
+    private ConcurrentMap<NeighborSet, EcmpInfo> ecmpGroups;
+
+
 
     public OFSwitchImplCPqD13(OFDescStatsReply desc, boolean usePipeline13) {
         super();
+        haltStateMachine = new AtomicBoolean(false);
+        driverState = DriverState.INIT;
         driverHandshakeComplete = new AtomicBoolean(false);
         l2groups = new ConcurrentHashMap<Integer, OFGroup>();
         setSwitchDescription(desc);
-
+        neighbors = new ConcurrentHashMap<Dpid, Set<PortNumber>>();
+        ecmpGroups = new ConcurrentHashMap<NeighborSet, EcmpInfo>();
         this.usePipeline13 = usePipeline13;
     }
 
+    // *****************************
+    // OFSwitchImplBase
+    // *****************************
+
+
     /* (non-Javadoc)
      * @see java.lang.Object#toString()
      */
@@ -123,10 +173,10 @@
         if (!usePipeline13) {
             // Send packet-in to controller if a packet misses the first table
             populateTableMissEntry(0, true, false, false, 0);
+            driverHandshakeComplete.set(true);
         } else {
-           configureSwitch();
+            nextDriverState();
         }
-        sendBarrier(true);
     }
 
 
@@ -141,64 +191,759 @@
     public void processDriverHandshakeMessage(OFMessage m) {
         if (!startDriverHandshakeCalled)
             throw new SwitchDriverSubHandshakeNotStarted();
-        if (driverHandshakeComplete.get())
+        if (isDriverHandshakeComplete())
             throw new SwitchDriverSubHandshakeCompleted(m);
+        try {
+            processOFMessage(this, m);
+        } catch (IOException e) {
+            log.error("Error generated when processing OFMessage", e.getCause());
+        }
+    }
 
+    @Override
+    public String getSwitchDriverState() {
+        return driverState.toString();
+    }
+
+    // *****************************
+    // Driver handshake state-machine
+    // *****************************
+
+    enum DriverState {
+        INIT,
+        SET_TABLE_MISS_ENTRIES,
+        SET_TABLE_VLAN_TMAC,
+        SET_GROUPS,
+        VERIFY_GROUPS,
+        SET_ADJACENCY_LABELS,
+        EXIT
+    }
+
+    protected void nextDriverState() throws IOException {
+        DriverState currentState = driverState;
+        if (haltStateMachine.get())
+            return;
+        switch (currentState) {
+        case INIT:
+            driverState = DriverState.SET_TABLE_MISS_ENTRIES;
+            setTableMissEntries();
+            sendBarrier();
+            break;
+        case SET_TABLE_MISS_ENTRIES:
+            driverState = DriverState.SET_TABLE_VLAN_TMAC;
+            getNetworkConfig();
+            populateTableVlan();
+            populateTableTMac();
+            sendBarrier();
+            break;
+        case SET_TABLE_VLAN_TMAC:
+            driverState = DriverState.SET_GROUPS;
+            createGroups();
+            sendBarrier();
+            break;
+        case SET_GROUPS:
+            driverState = DriverState.VERIFY_GROUPS;
+            verifyGroups();
+            break;
+        case VERIFY_GROUPS:
+            driverState = DriverState.SET_ADJACENCY_LABELS;
+            assignAdjacencyLabels();
+            break;
+        case SET_ADJACENCY_LABELS:
+            driverState = DriverState.EXIT;
+            driverHandshakeComplete.set(true);
+            break;
+        case EXIT:
+        default:
+            driverState = DriverState.EXIT;
+            log.error("Driver handshake has exited for sw: {}", getStringId());
+        }
+    }
+
+    void processOFMessage(IOFSwitch sw, OFMessage m) throws IOException {
         switch (m.getType()) {
         case BARRIER_REPLY:
-            if (m.getXid() == barrierXidToWaitFor)
-                driverHandshakeComplete.set(true);
+            processBarrierReply(m);
             break;
 
         case ERROR:
-            log.error("Switch {} Error {}", getStringId(), (OFErrorMsg) m);
+            processErrorMessage(m);
             break;
 
-        case FEATURES_REPLY:
-            break;
-        case FLOW_REMOVED:
-            break;
         case GET_ASYNC_REPLY:
             OFAsyncGetReply asrep = (OFAsyncGetReply) m;
             decodeAsyncGetReply(asrep);
             break;
 
         case PACKET_IN:
+            // not ready to handle packet-ins
             break;
-        case PORT_STATUS:
-            break;
+
         case QUEUE_GET_CONFIG_REPLY:
-            break;
-        case ROLE_REPLY:
+            // not doing queue config yet
             break;
 
         case STATS_REPLY:
             processStatsReply((OFStatsReply) m);
             break;
 
+        case ROLE_REPLY: // channelHandler should handle this
+        case PORT_STATUS: // channelHandler should handle this
+        case FEATURES_REPLY: // don't care
+        case FLOW_REMOVED: // don't care
         default:
             log.debug("Received message {} during switch-driver subhandshake "
-                    + "from switch {} ... Ignoring message", m, getStringId());
+                    + "from switch {} ... Ignoring message", m, sw.getStringId());
+        }
+    }
+
+    private void processStatsReply(OFStatsReply sr) {
+        switch (sr.getStatsType()) {
+        case AGGREGATE:
+            break;
+        case DESC:
+            break;
+        case EXPERIMENTER:
+            break;
+        case FLOW:
+            break;
+        case GROUP_DESC:
+            processGroupDesc((OFGroupDescStatsReply) sr);
+            break;
+        case GROUP_FEATURES:
+            processGroupFeatures((OFGroupFeaturesStatsReply) sr);
+            break;
+        case METER_CONFIG:
+            break;
+        case METER_FEATURES:
+            break;
+        case PORT_DESC:
+            break;
+        case TABLE_FEATURES:
+            break;
+        default:
+            break;
 
         }
     }
 
+    private void processErrorMessage(OFMessage m) {
+        log.error("Switch {} Error {} in DriverState", getStringId(),
+                (OFErrorMsg) m, driverState);
+    }
+
+    private void processBarrierReply(OFMessage m) throws IOException {
+        if (m.getXid() == barrierXidToWaitFor) {
+            // Driver state-machine progresses to the next state.
+            // If Barrier messages is not received, then eventually
+            // the ChannelHandler state machine will timeout, and the switch
+            // will be disconnected.
+            nextDriverState();
+        } else {
+            log.error("Received incorrect barrier-message xid {} (expected: {}) in "
+                    + "switch-driver state {} for switch {}", m, barrierXidToWaitFor,
+                    driverState, getStringId());
+        }
+    }
+
+    private void processGroupDesc(OFGroupDescStatsReply gdsr) {
+        log.info("Sw: {} Group Desc {}", getStringId(), gdsr);
+        try {
+            nextDriverState();
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+
+    // *****************************
+    // Utility methods
+    // *****************************
+
+    void setTableMissEntries() throws IOException {
+        // set all table-miss-entries
+        populateTableMissEntry(TABLE_VLAN, true, false, false, -1);
+        populateTableMissEntry(TABLE_TMAC, true, false, false, -1);
+        populateTableMissEntry(TABLE_IPv4_UNICAST, false, true, true,
+                TABLE_ACL);
+        populateTableMissEntry(TABLE_MPLS, false, true, true,
+                TABLE_ACL);
+        populateTableMissEntry(TABLE_ACL, false, false, false, -1);
+    }
+
+    private void sendBarrier() throws IOException {
+        long xid = getNextTransactionId();
+        barrierXidToWaitFor = xid;
+        OFBarrierRequest br = getFactory()
+                .buildBarrierRequest()
+                .setXid(xid)
+                .build();
+        write(br, null);
+    }
+
+    /**
+     * Adds a table-miss-entry to a pipeline table.
+     * <p>
+     * The table-miss-entry can be added with 'write-actions' or
+     * 'apply-actions'. It can also add a 'goto-table' instruction. By default
+     * if none of the booleans in the call are set, then the table-miss entry is
+     * added with no instructions, which means that if a packet hits the
+     * table-miss-entry, pipeline execution will stop, and the action set
+     * associated with the packet will be executed.
+     *
+     * @param tableToAdd the table to where the table-miss-entry will be added
+     * @param toControllerNow as an APPLY_ACTION instruction
+     * @param toControllerWrite as a WRITE_ACTION instruction
+     * @param toTable as a GOTO_TABLE instruction
+     * @param tableToSend the table to send as per the GOTO_TABLE instruction it
+     *        needs to be set if 'toTable' is true. Ignored of 'toTable' is
+     *        false.
+     * @throws IOException
+     */
+    @SuppressWarnings("unchecked")
+    private void populateTableMissEntry(int tableToAdd, boolean toControllerNow,
+            boolean toControllerWrite,
+            boolean toTable, int tableToSend) throws IOException {
+        OFOxmList oxmList = OFOxmList.EMPTY;
+        OFMatchV3 match = factory.buildMatchV3()
+                .setOxmList(oxmList)
+                .build();
+        OFAction outc = factory.actions()
+                .buildOutput()
+                .setPort(OFPort.CONTROLLER)
+                .setMaxLen(OFPCML_NO_BUFFER)
+                .build();
+        List<OFInstruction> instructions = new ArrayList<OFInstruction>();
+        if (toControllerNow) {
+            // table-miss instruction to send to controller immediately
+            OFInstruction instr = factory.instructions()
+                    .buildApplyActions()
+                    .setActions(Collections.singletonList(outc))
+                    .build();
+            instructions.add(instr);
+        }
+
+        if (toControllerWrite) {
+            // table-miss instruction to write-action to send to controller
+            // this will be executed whenever the action-set gets executed
+            OFInstruction instr = factory.instructions()
+                    .buildWriteActions()
+                    .setActions(Collections.singletonList(outc))
+                    .build();
+            instructions.add(instr);
+        }
+
+        if (toTable) {
+            // table-miss instruction to goto-table x
+            OFInstruction instr = factory.instructions()
+                    .gotoTable(TableId.of(tableToSend));
+            instructions.add(instr);
+        }
+
+        if (!toControllerNow && !toControllerWrite && !toTable) {
+            // table-miss has no instruction - at which point action-set will be
+            // executed - if there is an action to output/group in the action
+            // set
+            // the packet will be sent there, otherwise it will be dropped.
+            instructions = (List<OFInstruction>) Collections.EMPTY_LIST;
+        }
+
+        OFMessage tableMissEntry = factory.buildFlowAdd()
+                .setTableId(TableId.of(tableToAdd))
+                .setMatch(match) // match everything
+                .setInstructions(instructions)
+                .setPriority(MIN_PRIORITY)
+                .setBufferId(OFBufferId.NO_BUFFER)
+                .setIdleTimeout(0)
+                .setHardTimeout(0)
+                .setXid(getNextTransactionId())
+                .build();
+        write(tableMissEntry, null);
+    }
+
+    private void getNetworkConfig() {
+        INetworkConfigService ncs = floodlightProvider.getNetworkConfigService();
+        SwitchConfigStatus scs = ncs.checkSwitchConfig(new Dpid(getId()));
+        if (scs.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
+            srConfig = (SegmentRouterConfig) scs.getSwitchConfig();
+        } else {
+            log.error("Switch not configured as Segment-Router");
+        }
+
+        List<LinkConfig> linkConfigList = ncs.getConfiguredAllowedLinks();
+        setNeighbors(linkConfigList);
+    }
+
+    private void populateTableVlan() throws IOException {
+        List<OFMessage> msglist = new ArrayList<OFMessage>();
+        for (OFPortDesc p : getPorts()) {
+            int pnum = p.getPortNo().getPortNumber();
+            if (U32.of(pnum).compareTo(U32.of(OFPort.MAX.getPortNumber())) < 1) {
+                OFOxmInPort oxp = factory.oxms().inPort(p.getPortNo());
+                OFOxmVlanVid oxv = factory.oxms()
+                        .vlanVid(OFVlanVidMatch.UNTAGGED);
+                OFOxmList oxmList = OFOxmList.of(oxp, oxv);
+                OFMatchV3 match = factory.buildMatchV3()
+                        .setOxmList(oxmList).build();
+
+                // TODO: match on vlan-tagged packets for vlans configured on
+                // subnet ports and strip-vlan
+
+                // Do not need to add vlans
+                /*int vlanid = getVlanConfig(pnum);
+                OFOxmVlanVid vidToSet = factory.oxms()
+                        .vlanVid(OFVlanVidMatch.ofVlan(vlanid));
+                OFAction pushVlan = factory.actions().pushVlan(EthType.VLAN_FRAME);
+                OFAction setVlan = factory.actions().setField(vidToSet);
+                List<OFAction> actionlist = new ArrayList<OFAction>();
+                actionlist.add(pushVlan);
+                actionlist.add(setVlan);
+                OFInstruction appAction = factory.instructions().buildApplyActions()
+                        .setActions(actionlist).build();*/
+
+                OFInstruction gotoTbl = factory.instructions().buildGotoTable()
+                        .setTableId(TableId.of(TABLE_TMAC)).build();
+                List<OFInstruction> instructions = new ArrayList<OFInstruction>();
+                // instructions.add(appAction);
+                instructions.add(gotoTbl);
+                OFMessage flowEntry = factory.buildFlowAdd()
+                        .setTableId(TableId.of(TABLE_VLAN))
+                        .setMatch(match)
+                        .setInstructions(instructions)
+                        .setPriority(1000) // does not matter - all rules
+                                           // exclusive
+                        .setBufferId(OFBufferId.NO_BUFFER)
+                        .setIdleTimeout(0)
+                        .setHardTimeout(0)
+                        .setXid(getNextTransactionId())
+                        .build();
+                msglist.add(flowEntry);
+            }
+        }
+        write(msglist);
+        log.debug("Adding {} port/vlan-rules in sw {}", msglist.size(), getStringId());
+    }
+
+    private void populateTableTMac() throws IOException {
+        // match for router-mac and ip-packets
+        OFOxmEthType oxe = factory.oxms().ethType(EthType.IPv4);
+        OFOxmEthDst dmac = factory.oxms().ethDst(getRouterMacAddr());
+        OFOxmList oxmListIp = OFOxmList.of(dmac, oxe);
+        OFMatchV3 matchIp = factory.buildMatchV3()
+                .setOxmList(oxmListIp).build();
+        OFInstruction gotoTblIp = factory.instructions().buildGotoTable()
+                .setTableId(TableId.of(TABLE_IPv4_UNICAST)).build();
+        List<OFInstruction> instructionsIp = Collections.singletonList(gotoTblIp);
+        OFMessage ipEntry = factory.buildFlowAdd()
+                .setTableId(TableId.of(TABLE_TMAC))
+                .setMatch(matchIp)
+                .setInstructions(instructionsIp)
+                .setPriority(1000) // strict priority required lower than
+                                   // multicastMac
+                .setBufferId(OFBufferId.NO_BUFFER)
+                .setIdleTimeout(0)
+                .setHardTimeout(0)
+                .setXid(getNextTransactionId())
+                .build();
+
+        // match for router-mac and mpls packets
+        OFOxmEthType oxmpls = factory.oxms().ethType(EthType.MPLS_UNICAST);
+        OFOxmList oxmListMpls = OFOxmList.of(dmac, oxmpls);
+        OFMatchV3 matchMpls = factory.buildMatchV3()
+                .setOxmList(oxmListMpls).build();
+        OFInstruction gotoTblMpls = factory.instructions().buildGotoTable()
+                .setTableId(TableId.of(TABLE_MPLS)).build();
+        List<OFInstruction> instructionsMpls = Collections.singletonList(gotoTblMpls);
+        OFMessage mplsEntry = factory.buildFlowAdd()
+                .setTableId(TableId.of(TABLE_TMAC))
+                .setMatch(matchMpls)
+                .setInstructions(instructionsMpls)
+                .setPriority(1001) // strict priority required lower than
+                                   // multicastMac
+                .setBufferId(OFBufferId.NO_BUFFER)
+                .setIdleTimeout(0)
+                .setHardTimeout(0)
+                .setXid(getNextTransactionId())
+                .build();
+
+        log.debug("Adding termination-mac-rules in sw {}", getStringId());
+        List<OFMessage> msglist = new ArrayList<OFMessage>(2);
+        msglist.add(ipEntry);
+        msglist.add(mplsEntry);
+        write(msglist);
+    }
+
+    private MacAddress getRouterMacAddr() {
+        if (srConfig != null) {
+            return MacAddress.of(srConfig.getRouterMac());
+        } else {
+            // return a dummy mac address - it will not be used
+            return MacAddress.of("00:00:00:00:00:00");
+        }
+    }
+
+    private MacAddress getNeighborRouterMacAddress(Dpid ndpid) {
+        INetworkConfigService ncs = floodlightProvider.getNetworkConfigService();
+        SwitchConfigStatus scs = ncs.checkSwitchConfig(ndpid);
+        if (scs.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
+            return MacAddress.of(((SegmentRouterConfig) scs.getSwitchConfig())
+                    .getRouterMac());
+        } else {
+            // return a dummy mac address - it will not be used
+            return MacAddress.of("00:00:00:00:00:00");
+        }
+    }
+
+    private void setNeighbors(List<LinkConfig> linkConfigList) {
+        List<PortNumber> portlist = new ArrayList<PortNumber>();
+        for (LinkConfig lg : linkConfigList) {
+            if (!lg.getType().equals(NetworkConfigManager.PKT_LINK)) {
+                return;
+            }
+            PktLinkConfig plg = (PktLinkConfig) lg;
+            if (plg.getDpid1() == getId()) {
+                addNeighborAtPort(new Dpid(plg.getDpid2()),
+                        PortNumber.uint32(plg.getPort1()));
+            } else if (plg.getDpid2() == getId()) {
+                addNeighborAtPort(new Dpid(plg.getDpid1()),
+                        PortNumber.uint32(plg.getPort2()));
+            }
+        }
+    }
+
+    private void addNeighborAtPort(Dpid neighborDpid, PortNumber portToNeighbor) {
+        if (neighbors.get(neighborDpid) != null) {
+            neighbors.get(neighborDpid).add(portToNeighbor);
+        } else {
+            Set<PortNumber> ports = new HashSet<PortNumber>();
+            ports.add(portToNeighbor);
+            neighbors.put(neighborDpid, ports);
+        }
+    }
+
+    /**
+     * createGroups creates ECMP groups for all ports on this router connected
+     * to other routers (in the OF network). The information for ports is
+     * gleaned from the configured links. If no links are configured no groups
+     * will be created, and it is up to the caller of the IOF13Switch API to
+     * create groups.
+     * <p>
+     * By default all ports connected to the same neighbor router will be part
+     * of the same ECMP group. In addition, groups will be created for all
+     * possible combinations of neighbor routers.
+     * <p>
+     * For example, consider this router (R0) connected to 3 neighbors (R1, R2,
+     * and R3). The following groups will be created in R0:
+     * <li>1) all ports to R1,
+     * <li>2) all ports to R2,
+     * <li>3) all ports to R3,
+     * <li>4) all ports to R1 and R2
+     * <li>5) all ports to R1 and R3
+     * <li>6) all ports to R2 and R3
+     * <li>7) all ports to R1, R2, and R3
+     */
+    private void createGroups() {
+        Set<Dpid> dpids = neighbors.keySet();
+        if (dpids == null || dpids.isEmpty()) {
+            return;
+        }
+        // temp map of ecmp groupings
+        /*        Map<NeighborSet, List<BucketInfo>> temp =
+                        new HashMap<NeighborSet, List<BucketInfo>>();
+        */
+        // get all combinations of neighbors
+        Set<Set<Dpid>> powerSet = Sets.powerSet(dpids);
+        int groupid = 1;
+        for (Set<Dpid> combo : powerSet) {
+            if (combo.isEmpty()) {
+                // eliminate the empty set in the power set
+                continue;
+            }
+            List<BucketInfo> buckets = new ArrayList<BucketInfo>();
+            NeighborSet ns = new NeighborSet();
+            for (Dpid d : combo) {
+                ns.addDpid(d);
+                for (PortNumber sp : neighbors.get(d)) {
+                    BucketInfo b = new BucketInfo(d,
+                            MacAddress.of(srConfig.getRouterMac()),
+                            getNeighborRouterMacAddress(d), sp);
+                    buckets.add(b);
+                }
+            }
+            EcmpInfo ecmpInfo = new EcmpInfo(groupid++, buckets);
+            setEcmpGroup(ecmpInfo);
+            ecmpGroups.put(ns, ecmpInfo);
+            log.debug("Creating ecmp group in sw {}: {}", getStringId(), ecmpInfo);
+        }
+    }
+
+    private class EcmpInfo {
+        int groupId;
+        List<BucketInfo> buckets;
+
+        EcmpInfo(int gid, List<BucketInfo> bucketInfos) {
+            groupId = gid;
+            buckets = bucketInfos;
+        }
+
+        @Override
+        public String toString() {
+            return "groupId: " + groupId + ", buckets: " + buckets;
+        }
+    }
+
+    private class BucketInfo {
+        Dpid neighborDpid;
+        MacAddress srcMac;
+        MacAddress dstMac;
+        PortNumber outport;
+
+        BucketInfo(Dpid nDpid, MacAddress smac, MacAddress dmac, PortNumber p) {
+            neighborDpid = nDpid;
+            srcMac = smac;
+            dstMac = dmac;
+            outport = p;
+        }
+
+        @Override
+        public String toString() {
+            return " {neighborDpid: " + neighborDpid + ", dstMac: " + dstMac +
+                    ", srcMac: " + srcMac + ", outport: " + outport + "}";
+        }
+    }
+
+    private void setEcmpGroup(EcmpInfo ecmpInfo) {
+        List<OFMessage> msglist = new ArrayList<OFMessage>();
+        OFGroup group = OFGroup.of(ecmpInfo.groupId);
+
+        List<OFBucket> buckets = new ArrayList<OFBucket>();
+        for (BucketInfo b : ecmpInfo.buckets) {
+            OFOxmEthDst dmac = factory.oxms()
+                    .ethDst(b.dstMac);
+            OFAction setDA = factory.actions().buildSetField()
+                    .setField(dmac).build();
+            OFOxmEthDst smac = factory.oxms()
+                    .ethDst(b.srcMac);
+            OFAction setSA = factory.actions().buildSetField()
+                    .setField(smac).build();
+            OFAction outp = factory.actions().buildOutput()
+                    .setPort(OFPort.of(b.outport.shortValue()))
+                    .build();
+            List<OFAction> actions = new ArrayList<OFAction>();
+            actions.add(setSA);
+            actions.add(setDA);
+            actions.add(outp);
+            OFBucket ofb = factory.buildBucket()
+                    .setWeight(1)
+                    .setActions(actions)
+                    .build();
+            buckets.add(ofb);
+        }
+
+        OFMessage gm = factory.buildGroupAdd()
+                .setGroup(group)
+                .setBuckets(buckets)
+                .setGroupType(OFGroupType.SELECT)
+                .setXid(getNextTransactionId())
+                .build();
+        msglist.add(gm);
+        try {
+            write(msglist);
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+
+    private void verifyGroups() throws IOException {
+        sendGroupDescRequest();
+    }
+
+    private void sendGroupDescRequest() throws IOException {
+        OFMessage gdr = factory.buildGroupDescStatsRequest()
+                .setXid(getNextTransactionId())
+                .build();
+        write(gdr, null);
+    }
+
+    private void assignAdjacencyLabels() {
+        // TODO
+        try {
+            nextDriverState();
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+
+    private void pushIpEntry(MatchActionOperationEntry mao) throws IOException {
+        MatchAction ma = mao.getTarget();
+        Operator op = mao.getOperator();
+        Ipv4Match ipm = (Ipv4Match) ma.getMatch();
+
+        // set match
+        IPv4Net ipdst = ipm.getDestination();
+        OFOxmEthType ethTypeIp = factory.oxms()
+                .ethType(EthType.IPv4);
+        OFOxmIpv4DstMasked ipPrefix = factory.oxms()
+                .ipv4DstMasked(
+                        IPv4Address.of(ipdst.address().value()),
+                        IPv4Address.ofCidrMaskLength(ipdst.prefixLen())
+                );
+        OFOxmList oxmList = OFOxmList.of(ethTypeIp, ipPrefix);
+        OFMatchV3 match = factory.buildMatchV3()
+                .setOxmList(oxmList).build();
+
+        // set actions
+        List<OFAction> writeActions = new ArrayList<OFAction>();
+        for (Action action : ma.getActions()) {
+            OFAction ofAction = null;
+            if (action instanceof OutputAction) {
+                OutputAction outputAction = (OutputAction) action;
+                OFPort port = OFPort.of((int) outputAction.getPortNumber().value());
+                ofAction = factory.actions().output(port, Short.MAX_VALUE);
+            } else if (action instanceof ModifyDstMacAction) {
+                long dstMac = ((ModifyDstMacAction) action).getDstMac().toLong();
+                OFOxmEthDst dmac = factory.oxms()
+                        .ethDst(MacAddress.of(dstMac));
+                ofAction = factory.actions().buildSetField()
+                        .setField(dmac).build();
+            } else if (action instanceof ModifySrcMacAction) {
+                long srcMac = ((ModifySrcMacAction) action).getSrcMac().toLong();
+                OFOxmEthSrc smac = factory.oxms()
+                        .ethSrc(MacAddress.of(srcMac));
+                ofAction = factory.actions().buildSetField()
+                        .setField(smac).build();
+            } else if (action instanceof PushMplsAction) {
+                ofAction = factory.actions().pushMpls(EthType.MPLS_UNICAST);
+            } else if (action instanceof SetMplsIdAction) {
+                int labelid = ((SetMplsIdAction) action).getMplsId();
+                OFOxmMplsLabel lid = factory.oxms()
+                        .mplsLabel(U32.of(labelid));
+                ofAction = factory.actions().buildSetField()
+                        .setField(lid).build();
+            } else if (action instanceof PopMplsAction) {
+
+            } else if (action instanceof GroupAction) {
+                ofAction = factory.actions().buildGroup()
+                        .setGroup(OFGroup.of(0)) // TODO fail
+                        .build();
+            } else if (action instanceof DecNwTtlAction) {
+
+            } else if (action instanceof DecMplsTtlAction) {
+
+            } else if (action instanceof CopyTtlInAction) {
+
+            } else if (action instanceof CopyTtlOutAction) {
+                ofAction = factory.actions().copyTtlOut();
+            } else {
+                log.warn("Unsupported Action type: {}", action.getClass().getName());
+                continue;
+            }
+            writeActions.add(ofAction);
+        }
+
+        // OFAction setBos =
+        // factory.actions().buildSetField().setField(bos).build();
+
+        // set instructions
+        OFInstruction writeInstr = factory.instructions().buildWriteActions()
+                .setActions(writeActions).build();
+        OFInstruction gotoInstr = factory.instructions().buildGotoTable()
+                .setTableId(TableId.of(TABLE_ACL)).build();
+        List<OFInstruction> instructions = new ArrayList<OFInstruction>();
+        instructions.add(writeInstr);
+        instructions.add(gotoInstr);
+
+        // set flow priority
+        int priority = ipdst.prefixLen() * PRIORITY_MULTIPLIER;
+        if (ipdst.prefixLen() == (short) 32) {
+            priority = MAX_PRIORITY;
+        }
+
+        // set flow-mod XXX - This is only ADD (not doing DELETE yet)
+        OFMessage ipFlow = factory.buildFlowAdd()
+                .setTableId(TableId.of(TABLE_IPv4_UNICAST))
+                .setMatch(match)
+                .setInstructions(instructions)
+                .setPriority(priority)
+                .setBufferId(OFBufferId.NO_BUFFER)
+                .setIdleTimeout(0)
+                .setHardTimeout(0)
+                .setXid(getNextTransactionId())
+                .build();
+
+        write(ipFlow, null);
+        log.debug("Adding ip-rule {}-{} in sw {}", match, writeActions,
+                getStringId());
+    }
+
+    private void pushMplsEntry(MatchActionOperationEntry mao) {
+
+    }
+
+    private void pushAclEntry(MatchActionOperationEntry mao) {
+
+    }
+
+    // *****************************
+    // IOF13Switch
+    // *****************************
+
+    @Override
+    public void pushFlow(MatchActionOperationEntry matchActionOp) throws IOException {
+        final MatchAction matchAction = matchActionOp.getTarget();
+        final Match match = matchAction.getMatch();
+        if (match instanceof Ipv4Match) {
+            pushIpEntry(matchActionOp);
+        } else if (match instanceof MplsMatch) {
+            pushMplsEntry(matchActionOp);
+        } else if (match instanceof PacketMatch) {
+            pushAclEntry(matchActionOp);
+        } else {
+            log.error("Unknown match type {} pushed to switch {}", match,
+                    getStringId());
+        }
+    }
+
+    @Override
+    public void pushFlows(Collection<MatchActionOperationEntry> matchActionOps)
+            throws IOException {
+        for (MatchActionOperationEntry matchActionOp : matchActionOps) {
+            pushFlow(matchActionOp);
+        }
+    }
+
+    @Override
+    public int getEcmpGroupId(NeighborSet ns) {
+        EcmpInfo ei = ecmpGroups.get(ns);
+        if (ei == null) {
+            return -1;
+        } else {
+            return ei.groupId;
+        }
+    }
+
+    // *****************************
+    // Old Hardcoded Stuff
+    // *****************************
+
     private void configureSwitch() throws IOException {
         // setAsyncConfig();
         // getTableFeatures();
         sendGroupFeaturesRequest();
         setL2Groups();
-        sendBarrier(false);
+        sendBarrier();
         setL3Groups();
         setL25Groups();
-        setEcmpGroup();
+        // setEcmpGroup();
         sendGroupDescRequest();
         populateTableVlan();
         populateTableTMac();
         populateIpTable();
         populateMplsTable();
         populateTableMissEntry(TABLE_ACL, false, false, false, -1);
-        sendBarrier(true);
+        sendBarrier();
     }
 
     private void setAsyncConfig() throws IOException {
@@ -271,12 +1016,6 @@
         write(gfr, null);
     }
 
-    private void sendGroupDescRequest() throws IOException {
-        OFMessage gdr = factory.buildGroupDescStatsRequest()
-                .setXid(getNextTransactionId())
-                .build();
-        write(gdr, null);
-    }
 
     /*Create L2 interface groups for all physical ports
      Naming convention followed is the same as OF-DPA spec
@@ -324,14 +1063,6 @@
         return portVlan;
     }
 
-    private MacAddress getRouterMacAddr() {
-        if (getId() == 0x3)
-            return MacAddress.of("00:00:07:07:07:80"); // router mac
-        if (getId() == 0x1)
-            return MacAddress.of("00:00:01:01:01:80");
-        // switch 0x2
-        return MacAddress.of("00:00:02:02:02:80");
-    }
 
     // only for ports connected to other routers
     private OFAction getDestAction(int portnum) {
@@ -469,181 +1200,12 @@
         log.debug("Creating {} MPLS groups in sw {}", msglist.size(), getStringId());
     }
 
-    private void setEcmpGroup() throws IOException {
-        if (getId() != 0x1)
-            return;
-        List<OFMessage> msglist = new ArrayList<OFMessage>();
-        OFGroup group47 = OFGroup.of(47);
-
-        OFAction outg1 = factory.actions().buildGroup()
-                .setGroup(OFGroup.of(0xa0000000 | // mpls group id
-                        6))
-                .build();
-        OFBucket buc47_1 = factory.buildBucket()
-                .setWeight(1)
-                .setActions(Collections.singletonList(outg1))
-                .build();
-
-        OFAction outg2 = factory.actions().buildGroup()
-                .setGroup(OFGroup.of(0xa0000000 | // mpls group id
-                        7))
-                .build();
-        OFBucket buc47_2 = factory.buildBucket()
-                .setWeight(1)
-                .setActions(Collections.singletonList(outg2))
-                .build();
-
-        List<OFBucket> buckets47 = new ArrayList<OFBucket>();
-        buckets47.add(buc47_1);
-        buckets47.add(buc47_2);
-        OFMessage gmS12 = factory.buildGroupAdd()
-                .setGroup(group47)
-                .setBuckets(buckets47)
-                .setGroupType(OFGroupType.SELECT)
-                .setXid(getNextTransactionId())
-                .build();
-        msglist.add(gmS12);
-        write(msglist);
-        log.debug("Creating {} ECMP groups in sw {}", msglist.size(), getStringId());
-    }
-
-    private void processStatsReply(OFStatsReply sr) {
-        switch (sr.getStatsType()) {
-        case AGGREGATE:
-            break;
-        case DESC:
-            break;
-        case EXPERIMENTER:
-            break;
-        case FLOW:
-            break;
-        case GROUP_DESC:
-            processGroupDesc((OFGroupDescStatsReply) sr);
-            break;
-        case GROUP_FEATURES:
-            processGroupFeatures((OFGroupFeaturesStatsReply) sr);
-            break;
-        case METER_CONFIG:
-            break;
-        case METER_FEATURES:
-            break;
-        case PORT_DESC:
-            break;
-        case TABLE_FEATURES:
-            break;
-        default:
-            break;
-
-        }
-    }
 
     private void processGroupFeatures(OFGroupFeaturesStatsReply gfsr) {
         log.info("Sw: {} Group Features {}", getStringId(), gfsr);
     }
 
-    private void processGroupDesc(OFGroupDescStatsReply gdsr) {
-        log.info("Sw: {} Group Desc {}", getStringId(), gdsr);
-    }
 
-    private void populateTableVlan() throws IOException {
-        // for all incoming ports assign configured port-vlans
-        // currently assign portnum*10 -> vlanid to access ports
-        // and vlan 192 to router to router ports
-        List<OFMessage> msglist = new ArrayList<OFMessage>();
-        for (OFPortDesc p : getPorts()) {
-            int pnum = p.getPortNo().getPortNumber();
-            if (U32.of(pnum).compareTo(U32.of(OFPort.MAX.getPortNumber())) < 1) {
-                int vlanid = getVlanConfig(pnum);
-                OFOxmInPort oxp = factory.oxms().inPort(p.getPortNo());
-                OFOxmVlanVid oxv = factory.oxms()
-                        .vlanVid(OFVlanVidMatch.UNTAGGED);
-                OFOxmList oxmList = OFOxmList.of(oxp, oxv);
-                OFMatchV3 match = factory.buildMatchV3()
-                        .setOxmList(oxmList).build();
-                OFOxmVlanVid vidToSet = factory.oxms()
-                        .vlanVid(OFVlanVidMatch.ofVlan(vlanid));
-                OFAction pushVlan = factory.actions().pushVlan(EthType.VLAN_FRAME);
-                OFAction setVlan = factory.actions().setField(vidToSet);
-                List<OFAction> actionlist = new ArrayList<OFAction>();
-                actionlist.add(pushVlan);
-                actionlist.add(setVlan);
-                OFInstruction appAction = factory.instructions().buildApplyActions()
-                        .setActions(actionlist).build();
-                OFInstruction gotoTbl = factory.instructions().buildGotoTable()
-                        .setTableId(TableId.of(TABLE_TMAC)).build();
-                List<OFInstruction> instructions = new ArrayList<OFInstruction>();
-                // instructions.add(appAction);
-                instructions.add(gotoTbl);
-                OFMessage flowEntry = factory.buildFlowAdd()
-                        .setTableId(TableId.of(TABLE_VLAN))
-                        .setMatch(match)
-                        .setInstructions(instructions)
-                        .setPriority(1000) // does not matter - all rules
-                                           // exclusive
-                        .setBufferId(OFBufferId.NO_BUFFER)
-                        .setIdleTimeout(0)
-                        .setHardTimeout(0)
-                        .setXid(getNextTransactionId())
-                        .build();
-                msglist.add(flowEntry);
-            }
-        }
-        // table-vlan has no table-miss entry, and so packets that miss are
-        // essentially dropped
-        write(msglist);
-        log.debug("Adding {} vlan-rules in sw {}", msglist.size(), getStringId());
-    }
-
-    private void populateTableTMac() throws IOException {
-        // match for ip packets
-        OFOxmEthType oxe = factory.oxms().ethType(EthType.IPv4);
-        OFOxmList oxmListIp = OFOxmList.of(oxe);
-        OFMatchV3 matchIp = factory.buildMatchV3()
-                .setOxmList(oxmListIp).build();
-        OFInstruction gotoTblIp = factory.instructions().buildGotoTable()
-                .setTableId(TableId.of(TABLE_IPv4_UNICAST)).build();
-        List<OFInstruction> instructionsIp = Collections.singletonList(gotoTblIp);
-        OFMessage ipEntry = factory.buildFlowAdd()
-                .setTableId(TableId.of(TABLE_TMAC))
-                .setMatch(matchIp)
-                .setInstructions(instructionsIp)
-                .setPriority(1000) // strict priority required lower than
-                                   // multicastMac
-                .setBufferId(OFBufferId.NO_BUFFER)
-                .setIdleTimeout(0)
-                .setHardTimeout(0)
-                .setXid(getNextTransactionId())
-                .build();
-
-        // match for mpls packets
-        OFOxmEthType oxmpls = factory.oxms().ethType(EthType.MPLS_UNICAST);
-        OFOxmList oxmListMpls = OFOxmList.of(oxmpls);
-        OFMatchV3 matchMpls = factory.buildMatchV3()
-                .setOxmList(oxmListMpls).build();
-        OFInstruction gotoTblMpls = factory.instructions().buildGotoTable()
-                .setTableId(TableId.of(TABLE_MPLS)).build();
-        List<OFInstruction> instructionsMpls = Collections.singletonList(gotoTblMpls);
-        OFMessage mplsEntry = factory.buildFlowAdd()
-                .setTableId(TableId.of(TABLE_TMAC))
-                .setMatch(matchMpls)
-                .setInstructions(instructionsMpls)
-                .setPriority(1001) // strict priority required lower than
-                                   // multicastMac
-                .setBufferId(OFBufferId.NO_BUFFER)
-                .setIdleTimeout(0)
-                .setHardTimeout(0)
-                .setXid(getNextTransactionId())
-                .build();
-
-        // match for everything else to send to controller. Essentially
-        // the table miss flow entry
-        populateTableMissEntry(TABLE_TMAC, true, false, false, -1);
-        log.debug("Adding termination-mac-rules in sw {}", getStringId());
-        List<OFMessage> msglist = new ArrayList<OFMessage>(2);
-        msglist.add(ipEntry);
-        msglist.add(mplsEntry);
-        write(msglist);
-    }
 
     private List<String> getMyIps() { // send to controller
         List<String> myIps = new ArrayList<String>();
@@ -828,7 +1390,7 @@
                     .setTableId(TableId.of(TABLE_IPv4_UNICAST))
                     .setMatch(match)
                     .setInstructions(instructions)
-                    .setPriority(SLASH_24_PRIORITY)
+                    .setPriority((short) 0xfff0)
                     .setBufferId(OFBufferId.NO_BUFFER)
                     .setIdleTimeout(0)
                     .setHardTimeout(0)
@@ -918,7 +1480,7 @@
             if (routerNextHopIps.get(i).mask.equals("255.255.255.255"))
                 priority = MAX_PRIORITY;
             else
-                priority = SLASH_24_PRIORITY;
+                priority = (short) 0xfff0;
             OFMessage myIpEntry = factory.buildFlowAdd()
                     .setTableId(TableId.of(TABLE_IPv4_UNICAST))
                     .setMatch(match)
@@ -1133,90 +1695,5 @@
 
     }
 
-    /**
-     * By default if none of the booleans in the call are set, then the
-     * table-miss entry is added with no instructions, which means that pipeline
-     * execution will stop, and the action set associated with the packet will
-     * be executed.
-     *
-     * @param tableToAdd
-     * @param toControllerNow as an APPLY_ACTION instruction
-     * @param toControllerWrite as a WRITE_ACITION instruction
-     * @param toTable as a GOTO_TABLE instruction
-     * @param tableToSend
-     * @throws IOException
-     */
-    @SuppressWarnings("unchecked")
-    private void populateTableMissEntry(int tableToAdd, boolean toControllerNow,
-            boolean toControllerWrite,
-            boolean toTable, int tableToSend) throws IOException {
-        OFOxmList oxmList = OFOxmList.EMPTY;
-        OFMatchV3 match = factory.buildMatchV3()
-                .setOxmList(oxmList)
-                .build();
-        OFAction outc = factory.actions()
-                .buildOutput()
-                .setPort(OFPort.CONTROLLER)
-                .setMaxLen(OFPCML_NO_BUFFER)
-                .build();
-        List<OFInstruction> instructions = new ArrayList<OFInstruction>();
-        if (toControllerNow) {
-            // table-miss instruction to send to controller immediately
-            OFInstruction instr = factory.instructions()
-                    .buildApplyActions()
-                    .setActions(Collections.singletonList(outc))
-                    .build();
-            instructions.add(instr);
-        }
-
-        if (toControllerWrite) {
-            // table-miss instruction to write-action to send to controller
-            // this will be executed whenever the action-set gets executed
-            OFInstruction instr = factory.instructions()
-                    .buildWriteActions()
-                    .setActions(Collections.singletonList(outc))
-                    .build();
-            instructions.add(instr);
-        }
-
-        if (toTable) {
-            // table-miss instruction to goto-table x
-            OFInstruction instr = factory.instructions()
-                    .gotoTable(TableId.of(tableToSend));
-            instructions.add(instr);
-        }
-
-        if (!toControllerNow && !toControllerWrite && !toTable) {
-            // table-miss has no instruction - at which point action-set will be
-            // executed - if there is an action to output/group in the action
-            // set
-            // the packet will be sent there, otherwise it will be dropped.
-            instructions = (List<OFInstruction>) Collections.EMPTY_LIST;
-        }
-
-        OFMessage tableMissEntry = factory.buildFlowAdd()
-                .setTableId(TableId.of(tableToAdd))
-                .setMatch(match) // match everything
-                .setInstructions(instructions)
-                .setPriority(MIN_PRIORITY)
-                .setBufferId(OFBufferId.NO_BUFFER)
-                .setIdleTimeout(0)
-                .setHardTimeout(0)
-                .setXid(getNextTransactionId())
-                .build();
-        write(tableMissEntry, null);
-    }
-
-    private void sendBarrier(boolean finalBarrier) throws IOException {
-        int xid = getNextTransactionId();
-        if (finalBarrier) {
-            barrierXidToWaitFor = xid;
-        }
-        OFBarrierRequest br = factory
-                .buildBarrierRequest()
-                .setXid(xid)
-                .build();
-        write(br, null);
-    }
 
 }
diff --git a/src/main/java/net/onrc/onos/core/matchaction/match/Ipv4PacketMatch.java b/src/main/java/net/onrc/onos/core/matchaction/match/Ipv4PacketMatch.java
deleted file mode 100644
index 7182ca1..0000000
--- a/src/main/java/net/onrc/onos/core/matchaction/match/Ipv4PacketMatch.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package net.onrc.onos.core.matchaction.match;
-
-import net.onrc.onos.core.util.IPv4Net;
-
-public class Ipv4PacketMatch implements Match {
-
-    IPv4Net dstIp;
-
-    public Ipv4PacketMatch(String ipAddressSlash) {
-        this.dstIp = new IPv4Net(ipAddressSlash);
-    }
-
-    public IPv4Net getDestination() {
-        return dstIp;
-    }
-
-}