diff --git a/lib/netty-3.10.0.Final.jar b/lib/netty-3.10.0.Final.jar
deleted file mode 100644
index 5f8aa2e2eb08d43a1a8c90c13bafcec5fdd11d63..0000000000000000000000000000000000000000
Binary files a/lib/netty-3.10.0.Final.jar and /dev/null differ
diff --git a/lib/netty-all-4.0.31.Final.jar b/lib/netty-all-4.0.31.Final.jar
new file mode 100644
index 0000000000000000000000000000000000000000..ef9477a323af6de76bd1a0b4cda9c4da0e72860d
Binary files /dev/null and b/lib/netty-all-4.0.31.Final.jar differ
diff --git a/lib/openflowj-0.9.0-SNAPSHOT-sources.jar b/lib/openflowj-0.9.0-SNAPSHOT-sources.jar
deleted file mode 100644
index abdf436f91750e82a1e50f3376105bf590526477..0000000000000000000000000000000000000000
Binary files a/lib/openflowj-0.9.0-SNAPSHOT-sources.jar and /dev/null differ
diff --git a/lib/openflowj-0.9.0-SNAPSHOT-javadoc.jar b/lib/openflowj-2.0.0-SNAPSHOT-javadoc.jar
similarity index 53%
rename from lib/openflowj-0.9.0-SNAPSHOT-javadoc.jar
rename to lib/openflowj-2.0.0-SNAPSHOT-javadoc.jar
index 3b2cd87c8da1a2ba622894c2241b4321b59e6ce2..c914cdc2c508df534c5cbc0b0b68255b1691a3b1 100644
Binary files a/lib/openflowj-0.9.0-SNAPSHOT-javadoc.jar and b/lib/openflowj-2.0.0-SNAPSHOT-javadoc.jar differ
diff --git a/lib/openflowj-2.0.0-SNAPSHOT-sources.jar b/lib/openflowj-2.0.0-SNAPSHOT-sources.jar
new file mode 100644
index 0000000000000000000000000000000000000000..9702a84e6e38fdae39d6a01d8ffd651eea589ca7
Binary files /dev/null and b/lib/openflowj-2.0.0-SNAPSHOT-sources.jar differ
diff --git a/lib/openflowj-0.9.0-SNAPSHOT.jar b/lib/openflowj-2.0.0-SNAPSHOT.jar
similarity index 70%
rename from lib/openflowj-0.9.0-SNAPSHOT.jar
rename to lib/openflowj-2.0.0-SNAPSHOT.jar
index 2a2140a0038065ee1bc875723a42ae9b9cf8ece0..54a8ef28d0e28207ac2101ccc8f24bb752f25062 100644
Binary files a/lib/openflowj-0.9.0-SNAPSHOT.jar and b/lib/openflowj-2.0.0-SNAPSHOT.jar differ
diff --git a/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java b/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
index c91e55fc1720c5e36307cfb108084fe9f156da0e..ee182ef53b82014b5d737f9cf35996e9aa9abcf5 100644
--- a/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
+++ b/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
@@ -23,9 +23,7 @@ import java.util.Map;
 
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.packet.Ethernet;
-
-import org.jboss.netty.util.Timer;
-
+import io.netty.util.Timer;
 import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.HARole;
 import net.floodlightcontroller.core.IHAListener;
@@ -36,10 +34,12 @@ import net.floodlightcontroller.core.RoleInfo;
 import net.floodlightcontroller.core.internal.RoleManager;
 import net.floodlightcontroller.core.internal.Controller.IUpdate;
 import net.floodlightcontroller.core.internal.Controller.ModuleLoaderState;
-
 import net.floodlightcontroller.core.FloodlightContextStore;
+
 import org.projectfloodlight.openflow.protocol.OFMessage;
 import org.projectfloodlight.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.TransportPort;
 /**
  * The interface exposed by the core bundle that allows you to interact
  * with connected switches.
@@ -115,16 +115,16 @@ public interface IFloodlightProviderService extends
     public String getControllerId();
 
     /**
-     * Gets the controller hostname
-     * @return the controller hostname
+     * Gets the controller addresses
+     * @return the controller addresses
      */
-    public String getOFHostname();
+    public Set<IPv4Address> getOFAddresses();
 
     /**
      * Gets the controller's openflow port
      * @return the controller's openflow port
      */
-    public int getOFPort();
+    public TransportPort getOFPort();
 
     /**
      * Set the role of the controller
diff --git a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
index 4cc47498d8534a5cce3f24e78243f4cac7313394..9e51dd1f46124c8e8633c31df8d737c654f51054 100644
--- a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
+++ b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
@@ -40,6 +40,7 @@ import org.projectfloodlight.openflow.types.U64;
 import com.google.common.collect.ImmutableList;
 import com.google.common.util.concurrent.ListenableFuture;
 
+import net.floodlightcontroller.core.internal.OFConnection;
 import net.floodlightcontroller.core.internal.TableFeatures;
 import net.floodlightcontroller.core.web.serializers.IOFSwitchSerializer;
 
diff --git a/src/main/java/net/floodlightcontroller/core/internal/Controller.java b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
index 51c0dbc3232cff0944cf67771aad68fe1f6cfd1b..4e27cb95fa3b07a23f81ce77c5f066cb7d713881 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/Controller.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
@@ -22,6 +22,7 @@ import java.lang.management.RuntimeMXBean;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -34,9 +35,8 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.LinkedBlockingQueue;
 
-import org.jboss.netty.util.HashedWheelTimer;
-import org.jboss.netty.util.Timer;
-
+import io.netty.util.HashedWheelTimer;
+import io.netty.util.Timer;
 import net.floodlightcontroller.core.ControllerId;
 import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.HAListenerTypeMarker;
@@ -66,6 +66,8 @@ import org.projectfloodlight.openflow.protocol.OFPacketIn;
 import org.projectfloodlight.openflow.protocol.OFPortDesc;
 import org.projectfloodlight.openflow.protocol.OFType;
 import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.TransportPort;
 
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.perfmon.IPktInProcessingTimeService;
@@ -129,8 +131,8 @@ public class Controller implements IFloodlightProviderService, IStorageSourceLis
     private IShutdownService shutdownService;
 
     // Configuration options
-    protected int openFlowPort = 6653; // new registered OF port number
-    private String openFlowHostname = null;
+    private static TransportPort openFlowPort = TransportPort.of(6653); // new registered OF port number
+	private static Set<IPv4Address> openFlowAddresses = new HashSet<IPv4Address>();
     protected int workerThreads = 0;
     
     // The id for this controller node. Should be unique for each controller
@@ -513,11 +515,12 @@ public class Controller implements IFloodlightProviderService, IStorageSourceLis
     }
     
     @Override
-    public String getOFHostname() {
-        return openFlowHostname;
+    public Set<IPv4Address> getOFAddresses() {
+        return Collections.unmodifiableSet(openFlowAddresses);
     }
+    
     @Override
-    public int getOFPort() {
+    public TransportPort getOFPort() {
         return openFlowPort;
     }
 
@@ -677,22 +680,33 @@ public class Controller implements IFloodlightProviderService, IStorageSourceLis
     }
     
     private void setConfigParams(Map<String, String> configParams) throws FloodlightModuleException {
-        String ofPort = configParams.get("openflowPort");
+        String ofPort = configParams.get("openFlowPort");
         if (!Strings.isNullOrEmpty(ofPort)) {
             try {
-                this.openFlowPort = Integer.parseInt(ofPort);
-            } catch (NumberFormatException e) {
-                log.error("invalid openflow port specifier", e);
-                throw new FloodlightModuleException("invalid port specifier in cofig");
+                openFlowPort = TransportPort.of(Integer.parseInt(ofPort));
+            } catch (Exception e) {
+                log.error("Invalid OpenFlow port {}, {}", ofPort, e);
+                throw new FloodlightModuleException("Invalid OpenFlow port of " + ofPort + " in config");
             }
-            log.debug("OpenFlow port set to {}", this.openFlowPort);
         }
+        log.info("OpenFlow port set to {}", openFlowPort);
 
-        String threads = configParams.get("workerthreads");
+        String threads = configParams.get("workerThreads");
         if (!Strings.isNullOrEmpty(threads)) {
             this.workerThreads = Integer.parseInt(threads);
         }
-        log.debug("Number of worker threads set to {}", this.workerThreads);
+        log.info("Number of worker threads set to {}", this.workerThreads);
+        
+        String addresses = configParams.get("openFlowAddresses");
+        if (!Strings.isNullOrEmpty(ofPort)) {
+            try {
+                openFlowAddresses = Collections.singleton(IPv4Address.of(addresses)); //TODO support list of addresses for multi-honed controllers
+            } catch (Exception e) {
+                log.error("Invalid OpenFlow address {}, {}", addresses, e);
+                throw new FloodlightModuleException("Invalid OpenFlow address of " + addresses + " in config");
+            }
+            log.info("OpenFlow addresses set to {}", openFlowAddresses);
+        }
     }
 
     /**
diff --git a/src/main/java/net/floodlightcontroller/core/internal/ControllerCounters.java b/src/main/java/net/floodlightcontroller/core/internal/ControllerCounters.java
index de5b99255c8e2968a7d914b50dc7c0115f330d4c..d14e88d78e91a28fbe37e773cf5c684d4bda51f3 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/ControllerCounters.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/ControllerCounters.java
@@ -1,11 +1,9 @@
 package net.floodlightcontroller.core.internal;
 
 import net.floodlightcontroller.core.IOFSwitchBackend;
-import net.floodlightcontroller.core.OFConnectionCounters;
 import net.floodlightcontroller.debugcounter.IDebugCounter;
 import net.floodlightcontroller.debugcounter.IDebugCounterService;
 import net.floodlightcontroller.debugcounter.IDebugCounterService.MetaData;
-
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD",
diff --git a/src/main/java/net/floodlightcontroller/core/internal/HandshakeTimeoutHandler.java b/src/main/java/net/floodlightcontroller/core/internal/HandshakeTimeoutHandler.java
index 89ef68109bdc715eb2c16ea3f59f6c2c7b33fc67..2bf6a7c919072e5f6da9fa42cc85b00856b422bb 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/HandshakeTimeoutHandler.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/HandshakeTimeoutHandler.java
@@ -19,22 +19,18 @@ package net.floodlightcontroller.core.internal;
 
 import java.util.concurrent.TimeUnit;
 
-import org.jboss.netty.channel.ChannelHandlerContext;
-import org.jboss.netty.channel.ChannelStateEvent;
-import org.jboss.netty.channel.Channels;
-import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
-import org.jboss.netty.util.Timeout;
-import org.jboss.netty.util.Timer;
-import org.jboss.netty.util.TimerTask;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.util.Timeout;
+import io.netty.util.Timer;
+import io.netty.util.TimerTask;
 
 /**
  * Trigger a timeout if a switch fails to complete handshake soon enough
  */
-public class HandshakeTimeoutHandler
-    extends SimpleChannelUpstreamHandler {
+public class HandshakeTimeoutHandler extends ChannelInboundHandlerAdapter {
 
-    static final HandshakeTimeoutException EXCEPTION =
-            new HandshakeTimeoutException();
+    static final HandshakeTimeoutException EXCEPTION = new HandshakeTimeoutException();
 
     final OFChannelHandler handshakeHandler;
     final Timer timer;
@@ -52,22 +48,20 @@ public class HandshakeTimeoutHandler
     }
 
     @Override
-    public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e)
-            throws Exception {
+    public void channelActive(ChannelHandlerContext ctx) throws Exception {
         if (timeoutNanos > 0) {
-            timeout = timer.newTimeout(new HandshakeTimeoutTask(ctx),
-                                       timeoutNanos, TimeUnit.NANOSECONDS);
+            timeout = timer.newTimeout(new HandshakeTimeoutTask(ctx), timeoutNanos, TimeUnit.NANOSECONDS);
         }
-        ctx.sendUpstream(e);
+        super.channelActive(ctx);
     }
 
     @Override
-    public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e)
-            throws Exception {
+    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
         if (timeout != null) {
             timeout.cancel();
             timeout = null;
         }
+        super.channelInactive(ctx);
     }
 
     private final class HandshakeTimeoutTask implements TimerTask {
@@ -84,11 +78,11 @@ public class HandshakeTimeoutHandler
                 return;
             }
 
-            if (!ctx.getChannel().isOpen()) {
+            if (!ctx.channel().isOpen()) {
                 return;
             }
             if (!handshakeHandler.isSwitchHandshakeComplete())
-                Channels.fireExceptionCaught(ctx, EXCEPTION);
+                ctx.fireExceptionCaught(EXCEPTION);
         }
     }
-}
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/internal/NaiveSwitchDriverRegistry.java b/src/main/java/net/floodlightcontroller/core/internal/NaiveSwitchDriverRegistry.java
index b6bb90358f88b8c2fa38c6c478c2e8d9cbec64ac..04c68118d54f7e844e8e7988489e3277ee66c51f 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/NaiveSwitchDriverRegistry.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/NaiveSwitchDriverRegistry.java
@@ -11,7 +11,6 @@ import javax.annotation.Nonnull;
 import net.floodlightcontroller.core.IOFConnectionBackend;
 import net.floodlightcontroller.core.IOFSwitchBackend;
 import net.floodlightcontroller.core.IOFSwitchDriver;
-import net.floodlightcontroller.core.OFSwitch;
 import net.floodlightcontroller.core.SwitchDescription;
 
 import org.projectfloodlight.openflow.protocol.OFFactory;
diff --git a/src/main/java/net/floodlightcontroller/core/NullConnection.java b/src/main/java/net/floodlightcontroller/core/internal/NullConnection.java
similarity index 92%
rename from src/main/java/net/floodlightcontroller/core/NullConnection.java
rename to src/main/java/net/floodlightcontroller/core/internal/NullConnection.java
index 34f225e1343a1f32953f786a61555cf053438f8d..2db236e45f64a6e475e4729d3e0653604f6d918a 100644
--- a/src/main/java/net/floodlightcontroller/core/NullConnection.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/NullConnection.java
@@ -1,10 +1,12 @@
-package net.floodlightcontroller.core;
+package net.floodlightcontroller.core.internal;
 
 import java.net.SocketAddress;
 import java.util.List;
 import java.util.Date;
 
-import net.floodlightcontroller.core.internal.IOFConnectionListener;
+import net.floodlightcontroller.core.IOFConnectionBackend;
+import net.floodlightcontroller.core.IOFMessageWriter;
+import net.floodlightcontroller.core.SwitchDisconnectedException;
 
 import org.projectfloodlight.openflow.protocol.OFFactories;
 import org.projectfloodlight.openflow.protocol.OFFactory;
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java b/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java
index 7d45c1ee862f08dea0111bed7a63c37d94caf15e..0611648a5252cd623f1ade599777b3a9151c0067 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java
@@ -10,25 +10,19 @@ import java.util.concurrent.RejectedExecutionException;
 
 import javax.annotation.Nonnull;
 
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.channel.ChannelHandlerContext;
-import org.jboss.netty.channel.ChannelPipeline;
-import org.jboss.netty.channel.ChannelStateEvent;
-import org.jboss.netty.channel.Channels;
-import org.jboss.netty.channel.ExceptionEvent;
-import org.jboss.netty.channel.MessageEvent;
-import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;
-import org.jboss.netty.handler.timeout.IdleStateEvent;
-import org.jboss.netty.handler.timeout.IdleStateHandler;
-import org.jboss.netty.handler.timeout.ReadTimeoutException;
-import org.jboss.netty.util.Timer;
-
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.handler.timeout.IdleStateHandler;
+import io.netty.handler.timeout.ReadTimeoutException;
+import io.netty.util.AttributeKey;
+import io.netty.util.Timer;
 import net.floodlightcontroller.core.IOFConnectionBackend;
-import net.floodlightcontroller.core.OFConnection;
-import net.floodlightcontroller.core.internal.OpenflowPipelineFactory.PipelineHandler;
-import net.floodlightcontroller.core.internal.OpenflowPipelineFactory.PipelineHandshakeTimeout;
-import net.floodlightcontroller.core.internal.OpenflowPipelineFactory.PipelineIdleReadTimeout;
-import net.floodlightcontroller.core.internal.OpenflowPipelineFactory.PipelineIdleWriteTimeout;
+import net.floodlightcontroller.core.internal.OFChannelInitializer.PipelineHandler;
+import net.floodlightcontroller.core.internal.OFChannelInitializer.PipelineHandshakeTimeout;
+import net.floodlightcontroller.core.internal.OFChannelInitializer.PipelineIdleReadTimeout;
+import net.floodlightcontroller.core.internal.OFChannelInitializer.PipelineIdleWriteTimeout;
 import net.floodlightcontroller.debugcounter.IDebugCounterService;
 
 import org.projectfloodlight.openflow.exceptions.OFParseError;
@@ -62,10 +56,12 @@ import com.google.common.base.Preconditions;
  *  messages to the higher orders of control.
  * @author Jason Parraga <Jason.Parraga@Bigswitch.com>
  */
-class OFChannelHandler extends IdleStateAwareChannelHandler {
+class OFChannelHandler extends SimpleChannelInboundHandler<Iterable<OFMessage>> {
 
 	private static final Logger log = LoggerFactory.getLogger(OFChannelHandler.class);
 
+	public static final AttributeKey<OFChannelInfo> ATTR_CHANNEL_INFO = AttributeKey.valueOf("channelInfo");
+
 	private final ChannelPipeline pipeline;
 	private final INewOFConnectionListener newConnectionListener;
 	private final SwitchManagerCounters counters;
@@ -83,10 +79,10 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
 	 * We will count down
 	 */
 	private long handshakeTransactionIds = 0x00FFFFFFFFL;
-	
-    private volatile long echoSendTime;
-    private volatile long featuresLatency;
-    
+
+	private volatile long echoSendTime;
+	private volatile long featuresLatency;
+
 	/**
 	 * Default implementation for message handlers in any OFChannelState.
 	 *
@@ -336,11 +332,11 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
 				/* Lookup highest, common supported OpenFlow version */
 				commonVersion = computeOFVersionFromBitmap(bitmaps);
 				if (commonVersion == null) {
-					log.error("Could not negotiate common OpenFlow version for {} with greatest version bitmap algorithm.", channel.getRemoteAddress());
+					log.error("Could not negotiate common OpenFlow version for {} with greatest version bitmap algorithm.", channel.remoteAddress());
 					channel.disconnect();
 					return;
 				} else {
-					log.info("Negotiated OpenFlow version of {} for {} with greatest version bitmap algorithm.", commonVersion.toString(), channel.getRemoteAddress());
+					log.info("Negotiated OpenFlow version of {} for {} with greatest version bitmap algorithm.", commonVersion.toString(), channel.remoteAddress());
 					factory = OFFactories.getFactory(commonVersion);
 					OFMessageDecoder decoder = pipeline.get(OFMessageDecoder.class);
 					decoder.setVersion(commonVersion);
@@ -348,16 +344,16 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
 			}
 			/* If there's not a bitmap present, choose the lower of the two supported versions. */
 			else if (theirVersion.compareTo(factory.getVersion()) < 0) {
-				log.info("Negotiated down to switch OpenFlow version of {} for {} using lesser hello header algorithm.", theirVersion.toString(), channel.getRemoteAddress());
+				log.info("Negotiated down to switch OpenFlow version of {} for {} using lesser hello header algorithm.", theirVersion.toString(), channel.remoteAddress());
 				factory = OFFactories.getFactory(theirVersion);
 				OFMessageDecoder decoder = pipeline.get(OFMessageDecoder.class);
 				decoder.setVersion(theirVersion);
 			} /* else The controller's version is < or = the switch's, so keep original controller factory. */
 			else if (theirVersion.equals(factory.getVersion())) {
-				log.info("Negotiated equal OpenFlow version of {} for {} using lesser hello header algorithm.", factory.getVersion().toString(), channel.getRemoteAddress());
+				log.info("Negotiated equal OpenFlow version of {} for {} using lesser hello header algorithm.", factory.getVersion().toString(), channel.remoteAddress());
 			}
 			else {
-				log.info("Negotiated down to controller OpenFlow version of {} for {} using lesser hello header algorithm.", factory.getVersion().toString(), channel.getRemoteAddress());
+				log.info("Negotiated down to controller OpenFlow version of {} for {} using lesser hello header algorithm.", factory.getVersion().toString(), channel.remoteAddress());
 			}
 
 			setState(new WaitFeaturesReplyState());
@@ -382,7 +378,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
 		void processOFFeaturesReply(OFFeaturesReply  m)
 				throws IOException {
 			featuresReply = m;
-			
+
 			featuresLatency = (System.currentTimeMillis() - featuresLatency) / 2;
 
 			// Mark handshake as completed
@@ -409,7 +405,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
 			 * we are.
 			 */
 			if (m.getVersion().equals(factory.getVersion())) {
-				log.warn("Ignoring second hello from {} in state {}. Might be a Brocade.", channel.getRemoteAddress(), state.toString());
+				log.warn("Ignoring second hello from {} in state {}. Might be a Brocade.", channel.remoteAddress(), state.toString());
 			} else {
 				super.processOFHello(m); /* Versions don't match as they should; abort */
 			}
@@ -417,7 +413,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
 
 		@Override
 		void processOFPortStatus(OFPortStatus m) {
-			log.warn("Ignoring PORT_STATUS message from {} during OpenFlow channel establishment. Ports will be explicitly queried in a later state.", channel.getRemoteAddress());
+			log.warn("Ignoring PORT_STATUS message from {} during OpenFlow channel establishment. Ports will be explicitly queried in a later state.", channel.remoteAddress());
 		}
 
 		@Override
@@ -429,7 +425,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
 		@Override
 		void processOFMessage(OFMessage m) throws IOException {
 			if (m.getType().equals(OFType.PACKET_IN)) {
-				log.warn("Ignoring PACKET_IN message from {} during OpenFlow channel establishment.", channel.getRemoteAddress());
+				log.warn("Ignoring PACKET_IN message from {} during OpenFlow channel establishment.", channel.remoteAddress());
 			} else {
 				super.processOFMessage(m);
 			}
@@ -453,11 +449,11 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
 			setSwitchHandshakeTimeout();
 
 			// Handle non 1.3 connections
-			if(featuresReply.getVersion().compareTo(OFVersion.OF_13) < 0){
+			if (featuresReply.getVersion().compareTo(OFVersion.OF_13) < 0){
 				connection = new OFConnection(featuresReply.getDatapathId(), factory, channel, OFAuxId.MAIN, debugCounters, timer);
 			}
 			// Handle 1.3 connections
-			else{
+			else {
 				connection = new OFConnection(featuresReply.getDatapathId(), factory, channel, featuresReply.getAuxiliaryId(), debugCounters, timer);
 
 				// If this is an aux connection, we set a longer echo idle time
@@ -465,10 +461,10 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
 					setAuxChannelIdle();
 				}
 			}
-			
+
 			connection.updateLatency(U64.of(featuresLatency));
 			echoSendTime = 0;
-			
+
 			// Notify the connection broker
 			notifyConnectionOpened(connection);
 		}
@@ -588,21 +584,18 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
 	}
 
 	@Override
-	public void channelConnected(ChannelHandlerContext ctx,
-			ChannelStateEvent e) throws Exception {
+	public void channelActive(ChannelHandlerContext ctx) throws Exception {
 		log.debug("channelConnected on OFChannelHandler {}", String.format("%08x", System.identityHashCode(this)));
 		counters.switchConnected.increment();
-		channel = e.getChannel();
-		log.info("New switch connection from {}",
-				channel.getRemoteAddress());
+		channel = ctx.channel();
+		log.info("New switch connection from {}", channel.remoteAddress());
 		setState(new WaitHelloState());
 	}
 
 	@Override
-	public void channelDisconnected(ChannelHandlerContext ctx,
-			ChannelStateEvent e) throws Exception {
+	public void channelInactive(ChannelHandlerContext ctx) {
 		// Only handle cleanup connection is even known
-		if(this.connection != null){
+		if (this.connection != null) {
 			// Alert the connection object that the channel has been disconnected
 			this.connection.disconnected();
 			// Punt the cleanup to the Switch Manager
@@ -612,19 +605,19 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
 	}
 
 	@Override
-	public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
+	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
 			throws Exception {
-		if (e.getCause() instanceof ReadTimeoutException) {
+		if (cause instanceof ReadTimeoutException) {
 
 			if (featuresReply.getVersion().compareTo(OFVersion.OF_13) < 0) {
 				log.error("Disconnecting switch {} due to read timeout on main cxn.",
 						getConnectionInfoString());
-				ctx.getChannel().close();
+				ctx.channel().close();
 			} else {
 				if (featuresReply.getAuxiliaryId().equals(OFAuxId.MAIN)) {
 					log.error("Disconnecting switch {} due to read timeout on main cxn.",
 							getConnectionInfoString());
-					ctx.getChannel().close();
+					ctx.channel().close();
 				} else {
 					// We only don't disconnect on aux connections
 					log.warn("Switch {} encountered read timeout on aux cxn.",
@@ -634,95 +627,84 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
 			// Increment counters
 			counters.switchDisconnectReadTimeout.increment();
 
-		} else if (e.getCause() instanceof HandshakeTimeoutException) {
+		} else if (cause instanceof HandshakeTimeoutException) {
 			log.error("Disconnecting switch {}: failed to complete handshake. Channel handshake complete : {}",
 					getConnectionInfoString(),
 					this.state.channelHandshakeComplete);
 			counters.switchDisconnectHandshakeTimeout.increment();
-			ctx.getChannel().close();
-		} else if (e.getCause() instanceof ClosedChannelException) {
+			ctx.channel().close();
+		} else if (cause instanceof ClosedChannelException) {
 			log.debug("Channel for sw {} already closed", getConnectionInfoString());
-		} else if (e.getCause() instanceof IOException) {
+		} else if (cause instanceof IOException) {
 			log.error("Disconnecting switch {} due to IO Error: {}",
-					getConnectionInfoString(), e.getCause().getMessage());
+					getConnectionInfoString(), cause.getMessage());
 			if (log.isDebugEnabled()) {
 				// still print stack trace if debug is enabled
-				log.debug("StackTrace for previous Exception: ", e.getCause());
+				log.debug("StackTrace for previous Exception: ", cause);
 			}
 			counters.switchDisconnectIOError.increment();
-			ctx.getChannel().close();
-		} else if (e.getCause() instanceof SwitchStateException) {
+			ctx.channel().close();
+		} else if (cause instanceof SwitchStateException) {
 			log.error("Disconnecting switch {} due to switch state error: {}",
-					getConnectionInfoString(), e.getCause().getMessage());
+					getConnectionInfoString(), cause.getMessage());
 			if (log.isDebugEnabled()) {
 				// still print stack trace if debug is enabled
-				log.debug("StackTrace for previous Exception: ", e.getCause());
+				log.debug("StackTrace for previous Exception: ", cause);
 			}
 			counters.switchDisconnectSwitchStateException.increment();
-			ctx.getChannel().close();
-		} else if (e.getCause() instanceof OFAuxException) {
+			ctx.channel().close();
+		} else if (cause instanceof OFAuxException) {
 			log.error("Disconnecting switch {} due to OF Aux error: {}",
-					getConnectionInfoString(), e.getCause().getMessage());
+					getConnectionInfoString(), cause.getMessage());
 			if (log.isDebugEnabled()) {
 				// still print stack trace if debug is enabled
-				log.debug("StackTrace for previous Exception: ", e.getCause());
+				log.debug("StackTrace for previous Exception: ", cause);
 			}
 			counters.switchDisconnectSwitchStateException.increment();
-			ctx.getChannel().close();
-		} else if (e.getCause() instanceof OFParseError) {
+			ctx.channel().close();
+		} else if (cause instanceof OFParseError) {
 			log.error("Disconnecting switch "
 					+ getConnectionInfoString() +
 					" due to message parse failure",
-					e.getCause());
+					cause);
 			counters.switchDisconnectParseError.increment();
-			ctx.getChannel().close();
-		} else if (e.getCause() instanceof RejectedExecutionException) {
+			ctx.channel().close();
+		} else if (cause instanceof RejectedExecutionException) {
 			log.warn("Could not process message: queue full");
 			counters.rejectedExecutionException.increment();
-		} else if (e.getCause() instanceof IllegalArgumentException) {
-			log.error("Illegal argument exception with switch {}. {}", getConnectionInfoString(), e.getCause());
+		} else if (cause instanceof IllegalArgumentException) {
+			log.error("Illegal argument exception with switch {}. {}", getConnectionInfoString(), cause);
 			counters.switchSslConfigurationError.increment();
-			ctx.getChannel().close();
+			ctx.channel().close();
 		} else {
 			log.error("Error while processing message from switch "
 					+ getConnectionInfoString()
-					+ "state " + this.state, e.getCause());
+					+ "state " + this.state, cause);
 			counters.switchDisconnectOtherException.increment();
-			ctx.getChannel().close();
+			ctx.channel().close();
 		}
 	}
 
 	@Override
-	public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e)
-			throws Exception {
-
+	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
 		log.debug("channelIdle on OFChannelHandler {}", String.format("%08x", System.identityHashCode(this)));
-		OFChannelHandler handler = ctx.getPipeline().get(OFChannelHandler.class);
+		OFChannelHandler handler = ctx.pipeline().get(OFChannelHandler.class);
 		handler.sendEchoRequest();
 	}
 
 	@Override
-	public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
-			throws Exception {
-		if (e.getMessage() instanceof List) {
-			@SuppressWarnings("unchecked")
-			List<OFMessage> msglist = (List<OFMessage>)e.getMessage();
-			for (OFMessage ofm : msglist) {
-				try {
-					// Do the actual packet processing
-					state.processOFMessage(ofm);
-				}
-				catch (Exception ex) {
-					// We are the last handler in the stream, so run the
-					// exception through the channel again by passing in
-					// ctx.getChannel().
-					Channels.fireExceptionCaught(ctx.getChannel(), ex);
-				}
+	public void channelRead0(ChannelHandlerContext ctx, Iterable<OFMessage> msgList) throws Exception {
+		for (OFMessage ofm : msgList) {
+			try {
+				// Do the actual packet processing
+				state.processOFMessage(ofm);
+			}
+			catch (Exception ex) {
+				// We are the last handler in the stream, so run the
+				// exception through the channel again by passing in
+				// ctx.getChannel().
+				ctx.fireExceptionCaught(ex);
 			}
-		}
-		else {
-			Channels.fireExceptionCaught(ctx.getChannel(),
-					new AssertionError("Message received from channel is not a list"));
 		}
 	}
 
@@ -731,9 +713,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
 	 * This is specifically for aux channels.
 	 */
 	private void setAuxChannelIdle() {
-
 		IdleStateHandler idleHandler = new IdleStateHandler(
-				this.timer,
 				PipelineIdleReadTimeout.AUX,
 				PipelineIdleWriteTimeout.AUX,
 				0);
@@ -765,10 +745,10 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
 	private String getConnectionInfoString() {
 
 		String channelString;
-		if (channel == null || channel.getRemoteAddress() == null) {
+		if (channel == null || channel.remoteAddress() == null) {
 			channelString = "?";
 		} else {
-			channelString = channel.getRemoteAddress().toString();
+			channelString = channel.remoteAddress().toString();
 			if(channelString.startsWith("/"))
 				channelString = channelString.substring(1);
 		}
@@ -807,7 +787,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
 		OFFeaturesRequest m = factory.buildFeaturesRequest()
 				.setXid(handshakeTransactionIds--)
 				.build();
-		channel.write(Collections.singletonList(m));
+		write(m);
 	}
 
 	/**
@@ -830,8 +810,8 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
 
 		OFHello m = builder.setXid(handshakeTransactionIds--)
 				.build();
-		
-		channel.write(Collections.singletonList(m));
+
+		write(m);
 		log.debug("Send hello: {}", m); 
 	}
 
@@ -841,7 +821,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
 				.build();
 		/* Record for latency calculation */
 		echoSendTime = System.currentTimeMillis();
-		channel.write(Collections.singletonList(request));
+		write(request);
 	}
 
 	private void sendEchoReply(OFEchoRequest request) {
@@ -849,7 +829,11 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
 				.setXid(request.getXid())
 				.setData(request.getData())
 				.build();
-		channel.write(Collections.singletonList(reply));
+		write(reply);
+	}
+	
+	private void write(OFMessage m) {
+		channel.writeAndFlush(Collections.singletonList(m));
 	}
 
 	OFChannelState getStateForTesting() {
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFChannelInfo.java b/src/main/java/net/floodlightcontroller/core/internal/OFChannelInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..e4a347e18dafccc9a90f90d48c6e287f1908da02
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFChannelInfo.java
@@ -0,0 +1,59 @@
+package net.floodlightcontroller.core.internal;
+
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+
+import javax.annotation.Nonnull;
+
+import io.netty.channel.Channel;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.IPAddress;
+import org.projectfloodlight.openflow.types.OFAuxId;
+
+import com.google.common.base.Preconditions;
+
+/** Basic information that {@link OFChannelHandler} attaches to the
+ *  netty channel via {@link Channel#setAttachment(Object)}, mainly
+ *  for the purpose of being able to log the connection information.
+ *
+ * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
+ */
+public class OFChannelInfo {
+    private final DatapathId id;
+    private final OFAuxId auxId;
+    private final IPAddress<?> address;
+    private final int port;
+
+    public OFChannelInfo(@Nonnull DatapathId id, @Nonnull OFAuxId auxId, @Nonnull SocketAddress address) {
+        Preconditions.checkNotNull(id, "id should not be null");
+        Preconditions.checkNotNull(auxId, "auxId should not be null");
+        Preconditions.checkNotNull(address, "address should not be null");
+
+        this.id = id;
+        this.auxId = auxId;
+        InetSocketAddress socketAddress = (InetSocketAddress) address;
+        this.address = IPAddress.of(socketAddress.getHostString());
+        this.port = socketAddress.getPort();
+    }
+
+    public DatapathId getId() {
+        return id;
+    }
+
+    public OFAuxId getAuxId() {
+        return auxId;
+    }
+
+    public IPAddress<?> getAddress() {
+       return address;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    @Override
+    public String toString() {
+        return id + "/" + auxId + "@" + address + ":" + port;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OpenflowPipelineFactory.java b/src/main/java/net/floodlightcontroller/core/internal/OFChannelInitializer.java
similarity index 54%
rename from src/main/java/net/floodlightcontroller/core/internal/OpenflowPipelineFactory.java
rename to src/main/java/net/floodlightcontroller/core/internal/OFChannelInitializer.java
index 11827d02fb50a490c7661179bab38e9b2b46292a..3b3709c2e288c5e3fbd31911c7f6248cded12185 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OpenflowPipelineFactory.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFChannelInitializer.java
@@ -21,7 +21,6 @@ import java.io.FileInputStream;
 import java.security.KeyStore;
 import java.util.List;
 
-import javax.annotation.Nonnull;
 import javax.net.ssl.KeyManager;
 import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.SSLContext;
@@ -29,85 +28,64 @@ import javax.net.ssl.SSLEngine;
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.TrustManagerFactory;
 
-import org.jboss.netty.channel.ChannelPipeline;
-import org.jboss.netty.channel.ChannelPipelineFactory;
-import org.jboss.netty.channel.Channels;
-import org.jboss.netty.handler.ssl.SslHandler;
-import org.jboss.netty.handler.timeout.IdleStateHandler;
-import org.jboss.netty.handler.timeout.ReadTimeoutHandler;
-import org.jboss.netty.util.ExternalResourceReleasable;
-import org.jboss.netty.util.Timer;
 import org.projectfloodlight.openflow.protocol.OFFactory;
 import org.projectfloodlight.openflow.types.U32;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import net.floodlightcontroller.core.internal.IOFSwitchManager;
+import net.floodlightcontroller.core.internal.HandshakeTimeoutHandler;
+import net.floodlightcontroller.core.internal.INewOFConnectionListener;
+import net.floodlightcontroller.core.internal.OFChannelHandler;
 import net.floodlightcontroller.debugcounter.IDebugCounterService;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.handler.ssl.SslHandler;
+import io.netty.handler.timeout.IdleStateHandler;
+import io.netty.handler.timeout.ReadTimeoutHandler;
+import io.netty.util.Timer;
 
 /**
  * Creates a ChannelPipeline for a server-side openflow channel
- * @author readams, sovietaced
+ * @author readams, sovietaced, rizard, andi-bigswitch
  */
-public class OpenflowPipelineFactory
-implements ChannelPipelineFactory, ExternalResourceReleasable {
-	private static final Logger log = LoggerFactory.getLogger(OpenflowPipelineFactory.class);
-	protected IOFSwitchManager switchManager;
-	protected INewOFConnectionListener connectionListener;
-	protected Timer timer;
-	protected IdleStateHandler idleHandler;
-	protected ReadTimeoutHandler readTimeoutHandler;
-	protected IDebugCounterService debugCounters;
+public class OFChannelInitializer extends ChannelInitializer<Channel> {
+	private static final Logger log = LoggerFactory.getLogger(OFChannelInitializer.class);
+
+	private IOFSwitchManager switchManager;
+	private INewOFConnectionListener connectionListener;
+	private Timer timer;
+	private IDebugCounterService debugCounters;
 	private String keyStore;
 	private String keyStorePassword;
 	private OFFactory defaultFactory;
 	private List<U32> ofBitmaps;
 
-	private void init(IOFSwitchManager switchManager, Timer timer,
+	public OFChannelInitializer(IOFSwitchManager switchManager,
 			INewOFConnectionListener connectionListener,
 			IDebugCounterService debugCounters,
-			@Nonnull List<U32> ofBitmaps,
-			@Nonnull OFFactory defaultFactory) {
+			Timer timer,
+			List<U32> ofBitmaps,
+			OFFactory defaultFactory,
+			String keyStore, 
+			String keyStorePassword) {
+		super();
 		this.switchManager = switchManager;
 		this.connectionListener = connectionListener;
 		this.timer = timer;
 		this.debugCounters = debugCounters;
 		this.defaultFactory = defaultFactory;
 		this.ofBitmaps = ofBitmaps;
-		this.idleHandler = new IdleStateHandler(
-				timer,
-				PipelineIdleReadTimeout.MAIN,
-				PipelineIdleWriteTimeout.MAIN,
-				0);
-		this.readTimeoutHandler = new ReadTimeoutHandler(timer, 30);
-	}
-
-	public OpenflowPipelineFactory(IOFSwitchManager switchManager, Timer timer,
-			INewOFConnectionListener connectionListener,
-			IDebugCounterService debugCounters,
-			@Nonnull List<U32> ofBitmaps,
-			@Nonnull OFFactory defaultFactory) {
-		super();
-		init(switchManager,timer, connectionListener, debugCounters, ofBitmaps, defaultFactory);
-		this.keyStore = null;
-		this.keyStorePassword = null;
-	}
-
-	public OpenflowPipelineFactory(IOFSwitchManager switchManager, Timer timer,
-			INewOFConnectionListener connectionListener,
-			IDebugCounterService debugCounters,
-			@Nonnull List<U32> ofBitmaps,
-			@Nonnull OFFactory defaultFactory,
-			@Nonnull String keyStore, @Nonnull String keyStorePassword) {
-		super();
-		init(switchManager,timer, connectionListener, debugCounters, ofBitmaps, defaultFactory);   
 		this.keyStore = keyStore;
 		this.keyStorePassword = keyStorePassword;
 	}
 
 	@Override
-	public ChannelPipeline getPipeline() throws Exception {
-		ChannelPipeline pipeline = Channels.pipeline();
-		OFChannelHandler handler = new OFChannelHandler(switchManager,
+	protected void initChannel(Channel ch) throws Exception {
+		ChannelPipeline pipeline = ch.pipeline();
+		OFChannelHandler handler = new OFChannelHandler(
+				switchManager,
 				connectionListener,
 				pipeline,
 				debugCounters,
@@ -153,61 +131,57 @@ implements ChannelPipelineFactory, ExternalResourceReleasable {
 				throw e; /* If we wanted secure but didn't get it, we should bail. */
 			}
 		}
-
-		/* SSL handler will have been added first if we're using it. */
+		
 		pipeline.addLast(PipelineHandler.OF_MESSAGE_DECODER,
 				new OFMessageDecoder());
 		pipeline.addLast(PipelineHandler.OF_MESSAGE_ENCODER,
 				new OFMessageEncoder());
-		pipeline.addLast(PipelineHandler.MAIN_IDLE, idleHandler);
-		pipeline.addLast(PipelineHandler.READ_TIMEOUT, readTimeoutHandler);
+		pipeline.addLast(PipelineHandler.MAIN_IDLE,
+				new IdleStateHandler(PipelineIdleReadTimeout.MAIN,
+						PipelineIdleWriteTimeout.MAIN,
+						0));
+		pipeline.addLast(PipelineHandler.READ_TIMEOUT, new ReadTimeoutHandler(30));
 		pipeline.addLast(PipelineHandler.CHANNEL_HANDSHAKE_TIMEOUT,
 				new HandshakeTimeoutHandler(
 						handler,
 						timer,
 						PipelineHandshakeTimeout.CHANNEL));
-		pipeline.addLast(PipelineHandler.CHANNEL_HANDLER, handler);
-		return pipeline;
-	}
 
-	@Override
-	public void releaseExternalResources() {
-		timer.stop();
+		pipeline.addLast(PipelineHandler.CHANNEL_HANDLER, handler);
 	}
 
 	public static class PipelineHandler {
-		final static String CHANNEL_HANDSHAKE_TIMEOUT = "channelhandshaketimeout";
-		final static String SWITCH_HANDSHAKE_TIMEOUT = "switchhandshaketimeout";
-		final static String CHANNEL_HANDLER = "channelhandler";
-		final static String MAIN_IDLE = "mainidle";
-		final static String AUX_IDLE = "auxidle";
-		final static String OF_MESSAGE_DECODER = "ofmessagedecoder";
-		final static String OF_MESSAGE_ENCODER = "ofmessageencoder";
-		final static String READ_TIMEOUT = "readtimeout";
-		final static String SSL_TLS_ENCODER_DECODER = "ofsecurechannelencoderdecoder";
-	}
+		public final static String CHANNEL_HANDSHAKE_TIMEOUT = "channelhandshaketimeout";
+		public final static String SWITCH_HANDSHAKE_TIMEOUT = "switchhandshaketimeout";
+		public final static String CHANNEL_HANDLER = "channelhandler";
+		public final static String MAIN_IDLE = "mainidle";
+		public final static String AUX_IDLE = "auxidle";
+		public final static String OF_MESSAGE_DECODER = "ofmessagedecoder";
+		public final static String OF_MESSAGE_ENCODER = "ofmessageencoder";
+		public final static String READ_TIMEOUT = "readtimeout";
+		public final static String SSL_TLS_ENCODER_DECODER = "ofsecurechannelencoderdecoder";    }
 
 	/**
 	 * Timeouts for parts of the handshake, in seconds
 	 */
-	public static class PipelineHandshakeTimeout {
-		final static int CHANNEL = 10;
-		final static int SWITCH = 30;
-	}
-
-	/**
-	 * Timeouts for writes on connections, in seconds
-	 */
-	public static class PipelineIdleWriteTimeout {
-		final static int MAIN = 2;
-		final static int AUX = 15;
-	}
-
-	/**
-	 * Timeouts for reads on connections, in seconds
-	 */
-	public static class PipelineIdleReadTimeout {
-		final static int MAIN = 3 * PipelineIdleWriteTimeout.MAIN;
-		final static int AUX = 3 * PipelineIdleWriteTimeout.AUX;
-	}
-}
+	 public static class PipelineHandshakeTimeout {
+		 final static int CHANNEL = 10;
+		 public final static int SWITCH = 30;
+	 }
+
+	 /**
+	  * Timeouts for writes on connections, in seconds
+	  */
+	 public static class PipelineIdleWriteTimeout {
+		 final static int MAIN = 2;
+		 public final static int AUX = 15;
+	 }
+
+	 /**
+	  * Timeouts for reads on connections, in seconds
+	  */
+	 public static class PipelineIdleReadTimeout {
+		 final static int MAIN = 3 * PipelineIdleWriteTimeout.MAIN;
+		 public final static int AUX = 3 * PipelineIdleWriteTimeout.AUX;
+	 }
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/OFConnection.java b/src/main/java/net/floodlightcontroller/core/internal/OFConnection.java
similarity index 95%
rename from src/main/java/net/floodlightcontroller/core/OFConnection.java
rename to src/main/java/net/floodlightcontroller/core/internal/OFConnection.java
index c72c618c6d2073cd1738baa0d35c7a3c95a3b5e6..791ced36bf710eb2a59f2d2def57a1f68f5539a7 100644
--- a/src/main/java/net/floodlightcontroller/core/OFConnection.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFConnection.java
@@ -15,7 +15,7 @@
  *    under the License.
  **/
 
-package net.floodlightcontroller.core;
+package net.floodlightcontroller.core.internal;
 
 import java.net.SocketAddress;
 import java.util.ArrayList;
@@ -29,15 +29,18 @@ import java.util.concurrent.TimeoutException;
 
 import javax.annotation.Nonnull;
 
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.util.Timeout;
-import org.jboss.netty.util.Timer;
-import org.jboss.netty.util.TimerTask;
+import io.netty.channel.Channel;
+import io.netty.util.Timeout;
+import io.netty.util.Timer;
+import io.netty.util.TimerTask;
 
 import java.util.Date;
 
-import net.floodlightcontroller.core.internal.Controller;
-import net.floodlightcontroller.core.internal.IOFConnectionListener;
+import net.floodlightcontroller.core.Deliverable;
+import net.floodlightcontroller.core.DeliverableListenableFuture;
+import net.floodlightcontroller.core.IOFConnection;
+import net.floodlightcontroller.core.IOFConnectionBackend;
+import net.floodlightcontroller.core.SwitchDisconnectedException;
 import net.floodlightcontroller.debugcounter.IDebugCounterService;
 
 import org.projectfloodlight.openflow.protocol.OFErrorMsg;
@@ -164,7 +167,7 @@ public class OFConnection implements IOFConnection, IOFConnectionBackend{
                 logger.trace("{}: send {}", this, m);
             counters.updateWriteStats(m);
         }
-        this.channel.write(msglist);
+        this.channel.writeAndFlush(msglist);
     }
 
     // Notifies the connection object that the channel has been disconnected
@@ -188,7 +191,7 @@ public class OFConnection implements IOFConnection, IOFConnectionBackend{
 
     @Override
     public String toString() {
-        String channelString = (channel != null) ? String.valueOf(channel.getRemoteAddress()): "?";
+        String channelString = (channel != null) ? String.valueOf(channel.remoteAddress()): "?";
         return "OFConnection [" + getDatapathId() + "(" + getAuxId() + ")" + "@" + channelString + "]";
     }
 
@@ -279,7 +282,7 @@ public class OFConnection implements IOFConnection, IOFConnectionBackend{
 
     @Override
     public boolean isConnected() {
-        return channel.isConnected();
+        return channel.isActive();
     }
 
     @Override
@@ -293,12 +296,12 @@ public class OFConnection implements IOFConnection, IOFConnectionBackend{
 
     @Override
     public SocketAddress getRemoteInetAddress() {
-        return channel.getRemoteAddress();
+        return channel.remoteAddress();
     }
 
     @Override
     public SocketAddress getLocalInetAddress() {
-        return channel.getLocalAddress();
+        return channel.localAddress();
     }
 
     public boolean deliverResponse(OFMessage m) {
diff --git a/src/main/java/net/floodlightcontroller/core/OFConnectionCounters.java b/src/main/java/net/floodlightcontroller/core/internal/OFConnectionCounters.java
similarity index 99%
rename from src/main/java/net/floodlightcontroller/core/OFConnectionCounters.java
rename to src/main/java/net/floodlightcontroller/core/internal/OFConnectionCounters.java
index aef32b24d9743be5bf8528d3c02714cfdf425eb4..b92ab9ed71a031376f0805b0723c55ea6dcd7570 100644
--- a/src/main/java/net/floodlightcontroller/core/OFConnectionCounters.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFConnectionCounters.java
@@ -1,6 +1,5 @@
-package net.floodlightcontroller.core;
+package net.floodlightcontroller.core.internal;
 
-import net.floodlightcontroller.core.internal.OFSwitchManager;
 import net.floodlightcontroller.debugcounter.IDebugCounter;
 import net.floodlightcontroller.debugcounter.IDebugCounterService;
 
diff --git a/src/main/java/net/floodlightcontroller/core/OFErrorMsgException.java b/src/main/java/net/floodlightcontroller/core/internal/OFErrorMsgException.java
similarity index 95%
rename from src/main/java/net/floodlightcontroller/core/OFErrorMsgException.java
rename to src/main/java/net/floodlightcontroller/core/internal/OFErrorMsgException.java
index f990f0a451052dfac060673e5bca7b20d6e802ad..bdb526153ac5cc2ce6b9ebf7d0aac2d6d4bfc276 100644
--- a/src/main/java/net/floodlightcontroller/core/OFErrorMsgException.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFErrorMsgException.java
@@ -1,4 +1,4 @@
-package net.floodlightcontroller.core;
+package net.floodlightcontroller.core.internal;
 
 import org.projectfloodlight.openflow.protocol.OFErrorMsg;
 import org.projectfloodlight.openflow.protocol.OFRequest;
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFMessageDecoder.java b/src/main/java/net/floodlightcontroller/core/internal/OFMessageDecoder.java
index 12faa3be6b49a43d70a8d8fbffec769184524b77..40e6434baeef2c7538437f02ca674b70894f1487 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFMessageDecoder.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFMessageDecoder.java
@@ -1,29 +1,30 @@
 /**
-*    Copyright 2011, Big Switch Networks, Inc.
-*    Originally created by David Erickson, Stanford University
-*
-*    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.
-**/
+ *    Copyright 2011, Big Switch Networks, Inc.
+ *    Originally created by David Erickson, Stanford University
+ *
+ *    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.core.internal;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.channel.ChannelHandlerContext;
-import org.jboss.netty.handler.codec.frame.FrameDecoder;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.ByteToMessageDecoder;
+
 import org.projectfloodlight.openflow.protocol.OFFactories;
 import org.projectfloodlight.openflow.protocol.OFFactory;
 import org.projectfloodlight.openflow.protocol.OFMessage;
@@ -33,49 +34,71 @@ import org.projectfloodlight.openflow.protocol.OFVersion;
 /**
  * Decode an openflow message from a channel, for use in a netty pipeline.
  *
- * @author readams
+ * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
  */
-public class OFMessageDecoder extends FrameDecoder {
+public class OFMessageDecoder extends ByteToMessageDecoder {
+
+	private OFMessageReader<OFMessage> reader;
 
-    private OFMessageReader<OFMessage> reader;
+	public OFMessageDecoder() {
+		setReader();
+	}
 
-    public OFMessageDecoder() {
-        reader = OFFactories.getGenericReader();
-    }
+	public OFMessageDecoder(OFVersion version) {
+		setVersion(version);
+		setReader();
+	}
 
-    public OFMessageDecoder(OFVersion version) {
-        setVersion(version);
-    }
+	private void setReader() {
+		reader = OFFactories.getGenericReader();
+	}
 
-    public void setVersion(OFVersion version) {
-        OFFactory factory = OFFactories.getFactory(version);
-        this.reader = factory.getReader();
-    }
+	public void setVersion(OFVersion version) {
+		OFFactory factory = OFFactories.getFactory(version);
+		this.reader = factory.getReader();
+	}
 
-    @Override
-    protected Object decode(ChannelHandlerContext ctx, Channel channel,
-                            ChannelBuffer buffer) throws Exception {
-        if (!channel.isConnected()) {
-            // In testing, I see decode being called AFTER decode last.
-            // This check avoids that from reading corrupted frames
-            return null;
-        }
+	@Override
+	protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
+		if (!ctx.channel().isActive()) {
+			// In testing, I see decode being called AFTER decode last.
+			// This check avoids that from reading corrupted frames
+			return;
+		}
 
-        List<OFMessage> messageList = new ArrayList<OFMessage>();
-        for (;;) {
-            OFMessage message = reader.readFrom(buffer);
-            if (message == null)
-                break;
-            messageList.add(message);
-        }
-        return messageList.isEmpty() ? null : messageList;
-    }
+		// Note(andiw): netty4 adds support for more efficient handling of lists messages in the
+		// pipeline itself.
+		// Instead of constructing a list of messages here, we could also just add the individual
+		// messages to the "out" list provided by netty. This would require changing all the handlers
+		// in the pipeline to accept "OFMessage" instead of "Iterable<OFMessage>". Probably
+		// a good idea, but left for a future cleanup.
 
-    @Override
-    protected Object decodeLast(ChannelHandlerContext ctx, Channel channel,
-                            ChannelBuffer buffer) throws Exception {
-        // This is not strictly needed at this time. It is used to detect
-        // connection reset detection from netty (for debug)
-        return null;
-    }
-}
+		OFMessage singleMessage = null;
+		List<OFMessage> list = null;
+		boolean first = true;
+		for (;;) {
+			OFMessage message = reader.readFrom(in);
+			if (message == null) {
+				break;
+			}
+			if (first) {
+				// first message read
+				singleMessage = message;
+				first = false;
+			} else {
+				// more messages read, use the list
+				if (list == null) {
+					list = new ArrayList<>();
+					list.add(singleMessage);
+					singleMessage = null;
+				}
+				list.add(message);
+			}
+		}
+		if (list != null) {
+			out.add(list);
+		} else if (singleMessage != null) {
+			out.add(Collections.singletonList(singleMessage));
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFMessageEncoder.java b/src/main/java/net/floodlightcontroller/core/internal/OFMessageEncoder.java
index 4d6912ad69a9246da975063127fca3b8d97fe0b0..09ca7bd4441b89150d1417c508080243cd98765f 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFMessageEncoder.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFMessageEncoder.java
@@ -17,33 +17,24 @@
 
 package net.floodlightcontroller.core.internal;
 
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.buffer.ChannelBuffers;
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.channel.ChannelHandlerContext;
-import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;
 import org.projectfloodlight.openflow.protocol.OFMessage;
 
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.MessageToByteEncoder;
+
+
 /**
- * Encode an openflow message for output into a ChannelBuffer, for use in a
+ * Encode an iterable of openflow messages for output into a ByteBuf, for use in a
  * netty pipeline
- * @author readams
+ *
+ * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
  */
-public class OFMessageEncoder extends OneToOneEncoder {
-
+public class OFMessageEncoder extends MessageToByteEncoder<Iterable<OFMessage>> {
     @Override
-    protected Object encode(ChannelHandlerContext ctx, Channel channel,
-                            Object msg) throws Exception {
-        if (!(msg instanceof Iterable))
-            return msg;
-
-        @SuppressWarnings("unchecked")
-        Iterable<OFMessage> msgList = (Iterable<OFMessage>)msg;
-
-        ChannelBuffer buf = ChannelBuffers.dynamicBuffer();
+    protected void encode(ChannelHandlerContext ctx, Iterable<OFMessage> msgList, ByteBuf out) throws Exception {
         for (OFMessage ofm :  msgList) {
-            ofm.writeTo(buf);
+            ofm.writeTo(out);
         }
-        return buf;
     }
-}
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/OFSwitch.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitch.java
similarity index 98%
rename from src/main/java/net/floodlightcontroller/core/OFSwitch.java
rename to src/main/java/net/floodlightcontroller/core/internal/OFSwitch.java
index 1b72fef170fd0a8b3b5827dd1ce39bc747dad533..1c95a2bfe2ff9e84fde91d75daa025d826b095e8 100644
--- a/src/main/java/net/floodlightcontroller/core/OFSwitch.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitch.java
@@ -15,7 +15,7 @@
  *    under the License.
  **/
 
-package net.floodlightcontroller.core;
+package net.floodlightcontroller.core.internal;
 
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
@@ -37,8 +37,18 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 import javax.annotation.Nonnull;
 
-import net.floodlightcontroller.core.internal.IOFSwitchManager;
-import net.floodlightcontroller.core.internal.TableFeatures;
+import net.floodlightcontroller.core.IOFConnection;
+import net.floodlightcontroller.core.IOFConnectionBackend;
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.IOFSwitchBackend;
+import net.floodlightcontroller.core.LogicalOFMessageCategory;
+import net.floodlightcontroller.core.PortChangeEvent;
+import net.floodlightcontroller.core.PortChangeType;
+import net.floodlightcontroller.core.SwitchDescription;
+import net.floodlightcontroller.core.SwitchDriverSubHandshakeAlreadyStarted;
+import net.floodlightcontroller.core.SwitchDriverSubHandshakeCompleted;
+import net.floodlightcontroller.core.SwitchDriverSubHandshakeNotStarted;
+import net.floodlightcontroller.core.IOFSwitch.SwitchStatus;
 import net.floodlightcontroller.core.util.AppCookie;
 import net.floodlightcontroller.core.util.URIUtil;
 
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchAppHandshakePlugin.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchAppHandshakePlugin.java
index ddfd008720a6853262905afeb7072cf91c99c3f5..9652f4ac64d60b1e5f31bb2e31b1023fd12120c7 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchAppHandshakePlugin.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchAppHandshakePlugin.java
@@ -2,9 +2,9 @@ package net.floodlightcontroller.core.internal;
 
 import java.util.concurrent.TimeUnit;
 
-import org.jboss.netty.util.Timeout;
-import org.jboss.netty.util.Timer;
-import org.jboss.netty.util.TimerTask;
+import io.netty.util.Timeout;
+import io.netty.util.Timer;
+import io.netty.util.TimerTask;
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler.WaitAppHandshakeState;
 import org.projectfloodlight.openflow.protocol.OFMessage;
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandler.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandler.java
index b6bed6556164633f3e169f377d2dc6c3276f7963..b17eec619fd6a67c10f55aea8bca85e2e414925a 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandler.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandler.java
@@ -11,7 +11,7 @@ import java.util.concurrent.TimeUnit;
 
 import javax.annotation.Nonnull;
 
-import org.jboss.netty.util.Timer;
+import io.netty.util.Timer;
 
 import net.floodlightcontroller.core.HARole;
 import net.floodlightcontroller.core.IOFConnection;
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchManager.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchManager.java
index dbf9cc2449c9cfe77cf562296071662f5f478c61..e0f30158c5862a0a48813744d965e70de1204660 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchManager.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchManager.java
@@ -1,6 +1,7 @@
 package net.floodlightcontroller.core.internal;
 
 import java.io.IOException;
+import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -16,13 +17,6 @@ import java.util.TreeSet;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CopyOnWriteArraySet;
-import java.util.concurrent.Executors;
-
-import org.jboss.netty.bootstrap.ServerBootstrap;
-import org.jboss.netty.channel.ChannelPipelineFactory;
-import org.jboss.netty.channel.group.ChannelGroup;
-import org.jboss.netty.channel.group.DefaultChannelGroup;
-import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
 
 import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.HAListenerTypeMarker;
@@ -60,6 +54,7 @@ import org.projectfloodlight.openflow.protocol.OFMessage;
 import org.projectfloodlight.openflow.protocol.OFPortDesc;
 import org.projectfloodlight.openflow.protocol.OFVersion;
 import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.IPv4Address;
 import org.projectfloodlight.openflow.types.OFAuxId;
 import org.projectfloodlight.openflow.types.TableId;
 import org.projectfloodlight.openflow.types.U32;
@@ -80,6 +75,13 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.group.DefaultChannelGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.util.concurrent.GlobalEventExecutor;
+
 /**
  * The Switch Manager class contains most of the code involved with dealing
  * with switches. The Switch manager keeps track of the switches known to the controller,
@@ -102,7 +104,6 @@ public class OFSwitchManager implements IOFSwitchManager, INewOFConnectionListen
 
 	private static String keyStorePassword;
 	private static String keyStore;
-	private static boolean useSsl = false;
 
 	protected static boolean clearTablesOnInitialConnectAsMaster = false;
 	protected static boolean clearTablesOnEachTransitionToMaster = false;
@@ -112,7 +113,7 @@ public class OFSwitchManager implements IOFSwitchManager, INewOFConnectionListen
 
 	protected static List<U32> ofBitmaps;
 	protected static OFFactory defaultFactory;
-	
+
 	private ConcurrentHashMap<DatapathId, OFSwitchHandshakeHandler> switchHandlers;
 	private ConcurrentHashMap<DatapathId, IOFSwitchBackend> switches;
 	private ConcurrentHashMap<DatapathId, IOFSwitch> syncedSwitches;
@@ -129,9 +130,13 @@ public class OFSwitchManager implements IOFSwitchManager, INewOFConnectionListen
 	protected Set<IOFSwitchListener> switchListeners;
 
 	// Module Dependencies
-	IFloodlightProviderService floodlightProvider;
-	IDebugEventService debugEventService;
-	IDebugCounterService debugCounterService;
+	private IFloodlightProviderService floodlightProvider;
+	private IDebugEventService debugEventService;
+	private IDebugCounterService debugCounterService;
+
+	private NioEventLoopGroup bossGroup;
+	private NioEventLoopGroup workerGroup;
+	private DefaultChannelGroup cg;
 
 	/** IHAListener Implementation **/
 	@Override
@@ -181,7 +186,7 @@ public class OFSwitchManager implements IOFSwitchManager, INewOFConnectionListen
 			addUpdateToQueue(new SwitchUpdate(dpid, SwitchUpdateType.REMOVED));
 			oldSw.disconnect();
 		}
-		
+
 		/*
 		 * Set some other config options for this switch.
 		 */
@@ -480,7 +485,7 @@ public class OFSwitchManager implements IOFSwitchManager, INewOFConnectionListen
 	public IOFSwitchBackend getOFSwitchInstance(IOFConnectionBackend connection,
 			SwitchDescription description,
 			OFFactory factory, DatapathId datapathId) {
-		
+
 		return this.driverRegistry.getOFSwitchInstance(connection, description, factory, datapathId);
 	}
 
@@ -488,7 +493,7 @@ public class OFSwitchManager implements IOFSwitchManager, INewOFConnectionListen
 	public void handleMessage(IOFSwitchBackend sw, OFMessage m, FloodlightContext bContext) {
 		floodlightProvider.handleMessage(sw, m, bContext);
 	}
-	
+
 	@Override
 	public void handleOutgoingMessage(IOFSwitch sw, OFMessage m) {
 		floodlightProvider.handleOutgoingMessage(sw, m);
@@ -653,7 +658,7 @@ public class OFSwitchManager implements IOFSwitchManager, INewOFConnectionListen
 		driverRegistry = new NaiveSwitchDriverRegistry(this);
 
 		this.switchListeners = new CopyOnWriteArraySet<IOFSwitchListener>();
-		
+
 		/* TODO @Ryan
 		try {
 			this.storeClient = this.syncService.getStoreClient(
@@ -685,13 +690,11 @@ public class OFSwitchManager implements IOFSwitchManager, INewOFConnectionListen
 						)
 				) {
 			log.warn("SSL disabled. Using unsecure connections between Floodlight and switches.");
-			OFSwitchManager.useSsl = false;
 			OFSwitchManager.keyStore = null;
 			OFSwitchManager.keyStorePassword = null;
 		} else {
 			log.info("SSL enabled. Using secure connections between Floodlight and switches.");
 			log.info("SSL keystore path: {}, password: {}", path, (pass == null ? "" : pass)); 
-			OFSwitchManager.useSsl = true;
 			OFSwitchManager.keyStore = path;
 			OFSwitchManager.keyStorePassword = (pass == null ? "" : pass);
 		}
@@ -762,7 +765,7 @@ public class OFSwitchManager implements IOFSwitchManager, INewOFConnectionListen
 			maxPerDpid = configParams.get("maxTableToReceiveTableMissFlowPerDpid");
 		}
 		forwardToControllerFlowsUpToTableByDpid = jsonToSwitchTableIdMap(maxPerDpid);
-	
+
 		/*
 		 * Get config to determine what versions of OpenFlow we will
 		 * support. The versions will determine the hello's header
@@ -809,7 +812,7 @@ public class OFSwitchManager implements IOFSwitchManager, INewOFConnectionListen
 		defaultFactory = computeInitialFactory(ofVersions);
 		ofBitmaps = computeOurVersionBitmaps(ofVersions);
 	}
-	
+
 	/**
 	 * Find the max version supplied in the supported
 	 * versions list and use it as the default, which
@@ -845,7 +848,7 @@ public class OFSwitchManager implements IOFSwitchManager, INewOFConnectionListen
 		 */
 		return OFFactories.getFactory(highest);
 	}
-	
+
 	/**
 	 * Based on the list of OFVersions provided as input (or from Loxi),
 	 * create a list of bitmaps for use in version negotiation during a
@@ -862,7 +865,7 @@ public class OFSwitchManager implements IOFSwitchManager, INewOFConnectionListen
 		if (ofVersions == null || ofVersions.isEmpty()) {
 			throw new IllegalStateException("OpenFlow version list should never be null or empty at this point. Make sure it's set in the OFSwitchManager.");
 		}
-		
+
 		int pos = 1; /* initial bitmap in list */
 		int size = 32; /* size of a U32 */
 		int tempBitmap = 0; /* maintain the current bitmap we're working on */
@@ -978,45 +981,51 @@ public class OFSwitchManager implements IOFSwitchManager, INewOFConnectionListen
 	 */
 	public void bootstrapNetty() {
 		try {
-			final ServerBootstrap bootstrap = createServerBootStrap();
-
-			bootstrap.setOption("reuseAddr", true);
-			bootstrap.setOption("child.keepAlive", true);
-			bootstrap.setOption("child.tcpNoDelay", true);
-			bootstrap.setOption("child.sendBufferSize", Controller.SEND_BUFFER_SIZE);
-			
-			ChannelPipelineFactory pfact = useSsl ? new OpenflowPipelineFactory(this, floodlightProvider.getTimer(), this, debugCounterService, ofBitmaps, defaultFactory, keyStore, keyStorePassword) :
-				new OpenflowPipelineFactory(this, floodlightProvider.getTimer(), this, debugCounterService, ofBitmaps, defaultFactory);
+			bossGroup = new NioEventLoopGroup();
+			workerGroup = new NioEventLoopGroup();
+
+			ServerBootstrap bootstrap = new ServerBootstrap()
+			.group(bossGroup, workerGroup)
+			.channel(NioServerSocketChannel.class)
+			.option(ChannelOption.SO_REUSEADDR, true)
+			.option(ChannelOption.SO_KEEPALIVE, true)
+			.option(ChannelOption.TCP_NODELAY, true)
+			.option(ChannelOption.SO_SNDBUF, Controller.SEND_BUFFER_SIZE);
+
+
+			OFChannelInitializer initializer = new OFChannelInitializer(
+					this, 
+					this, 
+					debugCounterService, 
+					floodlightProvider.getTimer(), 
+					ofBitmaps, 
+					defaultFactory, 
+					keyStore, 
+					keyStorePassword);
+
+			bootstrap.childHandler(initializer);
+
+			cg = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
+
+			Set<InetSocketAddress> addrs = new HashSet<InetSocketAddress>();
+			if (floodlightProvider.getOFAddresses().isEmpty()) {
+				cg.add(bootstrap.bind(addrs.iterator().next()).channel());
+			} else {
+				for (IPv4Address ip : floodlightProvider.getOFAddresses()) {
+					addrs.add(new InetSocketAddress(InetAddress.getByAddress(ip.getBytes()), floodlightProvider.getOFPort().getPort()));
+				}
+			}
 			
-			bootstrap.setPipelineFactory(pfact);
-			InetSocketAddress sa = new InetSocketAddress(floodlightProvider.getOFPort());
-			final ChannelGroup cg = new DefaultChannelGroup();
-			cg.add(bootstrap.bind(sa));
+			for (InetSocketAddress sa : addrs) {
+				cg.add(bootstrap.bind(sa).channel());
+				log.info("Listening for switch connections on {}", sa);
+			}
 
-			log.info("Listening for switch connections on {}", sa);
 		} catch (Exception e) {
 			throw new RuntimeException(e);
 		}
 	}
 
-	/**
-	 * Helper that bootstrapNetty.
-	 * @return
-	 */
-	private ServerBootstrap createServerBootStrap() {
-		if (floodlightProvider.getWorkerThreads() == 0) {
-			return new ServerBootstrap(
-					new NioServerSocketChannelFactory(
-							Executors.newCachedThreadPool(),
-							Executors.newCachedThreadPool()));
-		} else {
-			return new ServerBootstrap(
-					new NioServerSocketChannelFactory(
-							Executors.newCachedThreadPool(),
-							Executors.newCachedThreadPool(), floodlightProvider.getWorkerThreads()));
-		}
-	}
-
 	/**
 	 * Performs startup related actions for logical OF message categories.
 	 * Setting the categories list to immutable ensures that unsupported operation
diff --git a/src/main/java/net/floodlightcontroller/core/util/NettyUtils.java b/src/main/java/net/floodlightcontroller/core/util/NettyUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..88e5a1b9e927f6fbb7c730c3427f6f08ad265c99
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/util/NettyUtils.java
@@ -0,0 +1,105 @@
+package net.floodlightcontroller.core.util;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.netty.channel.EventLoopGroup;
+import io.netty.util.concurrent.Future;
+
+/** Collection of static utilitiy functions for netty.
+ *
+ * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
+ */
+public class NettyUtils {
+	private static final Logger logger = LoggerFactory.getLogger(NettyUtils.class);
+
+	private static final long SHUTDOWN_TIMEOUT = 20;
+	private static final TimeUnit SHUTDOWN_TIMEOUT_UNIT = TimeUnit.SECONDS;
+
+	private NettyUtils() {}
+
+	/**
+	 * Shuts down an event group gracefully and waits for the corresponding Future to complete. Logs
+	 * any exceptions.
+	 *
+	 * TODO: may want to force a shutdown if the graceful shutdown fails
+	 *
+	 * @param name - name of the even group to be shut down (for logging)
+	 * @param group to be shut down
+	 * @throws InterruptedException - if the thread is interrupted while shutting down
+	 */
+	public static void shutdownAndWait(String name, EventLoopGroup group) throws InterruptedException {
+		try {
+			logger.debug("Shutting down {}", name);
+			Future<?> shutdownFuture = group.shutdownGracefully();
+			shutdownFuture.get(SHUTDOWN_TIMEOUT, SHUTDOWN_TIMEOUT_UNIT);
+			logger.debug("Done shutting down {}", name);
+		} catch (ExecutionException e) {
+			/***
+			 * @id      NETTYUTIL4001
+			 * @desc    A netty event loop group failed to shutdown
+			 * @action  #support if encountered repeatedly
+			 * @param   name the name of the event loop group
+			 * @param   e the exception
+			 */
+			logger.warn("NETTYUTIL4001: Error during shutdown of {}: {}", name, e);
+		} catch (TimeoutException e) {
+			/***
+			 * @id      NETTYUTIL4002
+			 * @desc    A netty event loop group failed to shutdown
+			 * @action  #support if encountered repeatedly
+			 * @param   name the name of the event loop group
+			 * @param   e the exception
+			 */
+			logger.warn("NETTYUTIL4002: Graceful shutdown of {} timed out: {}", name, e);
+		}
+	}
+
+	/** Wait for the supplied set of futures to complete. Logs any exceptions occur.
+	 *
+	 * @param name name of futures to wait on for logging
+	 * @param shutdownFutures futures to wait on
+	 * @throws InterruptedException if process is interrupted
+	 */
+	public static void waitOrLog(String name, Future<?>... shutdownFutures)
+			throws InterruptedException {
+		logger.debug("Shutting down {}", name);
+		long limit = System.nanoTime() + SHUTDOWN_TIMEOUT_UNIT.toNanos(SHUTDOWN_TIMEOUT);
+
+		for(Future<?> f: shutdownFutures) {
+			try {
+				long wait = limit - System.nanoTime();
+				if(wait > 0) {
+					f.get(wait, TimeUnit.NANOSECONDS);
+					logger.debug("Done shutting down {}", name);
+				} else {
+					throw new TimeoutException("timed out waiting for shutdown");
+				}
+			} catch (ExecutionException e) {
+				/***
+				 * @id      NETTYUTIL4003
+				 * @desc    An error was encountered waiting for completion of future.
+				 * @action  #support if encountered repeatedly
+				 * @param   name the name of the future
+				 * @param   e the exception
+				 */
+				logger.warn("Error during completion of {}: {}", name, e);
+			} catch (TimeoutException e) {
+				/***
+				 * @id      NETTYUTIL4004
+				 * @desc    A timeout was encountered waiting for completion of future.
+				 * @action  #support if encountered repeatedly
+				 * @param   name the name of the future
+				 * @param   e the exception
+				 */
+				logger.warn("Graceful shutdown of {} timed out: {}", name, e);
+				break;
+			}
+
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/web/serializers/StatsReplySerializer.java b/src/main/java/net/floodlightcontroller/core/web/serializers/StatsReplySerializer.java
index 3481e974505c4bcdfe50801a60a40848796c6ecd..0c6a520e3161a05f6589f09b1e152ebf78ff5b9c 100644
--- a/src/main/java/net/floodlightcontroller/core/web/serializers/StatsReplySerializer.java
+++ b/src/main/java/net/floodlightcontroller/core/web/serializers/StatsReplySerializer.java
@@ -409,7 +409,7 @@ public class StatsReplySerializer extends JsonSerializer<StatsReply> {
 		jGen.writeStringField("version", meterConfigReply.getVersion().toString()); //return the enum name
 		jGen.writeFieldName("meterConfig");
 		jGen.writeStartArray();
-		for(OFMeterBand band : meterConfigReply.getEntries()) {
+		for (OFMeterBand band : meterConfigReply.getEntries()) {
 			jGen.writeStartObject();
 			short type = (short)band.getType();
 			jGen.writeNumberField("bandType",type);
diff --git a/src/test/java/net/floodlightcontroller/core/internal/MockOFSwitchImpl.java b/src/test/java/net/floodlightcontroller/core/internal/MockOFSwitchImpl.java
index 846f4f7b82ad89a557f6b30aaf0b1ddacd6f1675..0fcbc88c19b217e6d67141acc9f44b5f093c8046 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/MockOFSwitchImpl.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/MockOFSwitchImpl.java
@@ -7,7 +7,6 @@ import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 import org.easymock.EasyMock;
-import net.floodlightcontroller.core.OFSwitch;
 import org.projectfloodlight.openflow.protocol.OFCapabilities;
 import org.projectfloodlight.openflow.protocol.OFFactories;
 import org.projectfloodlight.openflow.protocol.OFStatsReply;
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerVer10Test.java b/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerVer10Test.java
index 96147b02eb52b4323be4f804ffad6014c552809b..2460b3a7687c93ba64c32af6779ea7517847e031 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerVer10Test.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerVer10Test.java
@@ -24,22 +24,20 @@ import org.easymock.Capture;
 import org.easymock.CaptureType;
 import org.easymock.EasyMock;
 import org.hamcrest.CoreMatchers;
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.channel.ChannelHandlerContext;
-import org.jboss.netty.channel.ChannelPipeline;
-import org.jboss.netty.channel.ChannelStateEvent;
-import org.jboss.netty.channel.ExceptionEvent;
-import org.jboss.netty.channel.MessageEvent;
-import org.jboss.netty.util.HashedWheelTimer;
-import org.jboss.netty.util.Timer;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelPipeline;
+import io.netty.util.HashedWheelTimer;
+import io.netty.util.Timer;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
 import net.floodlightcontroller.core.IOFConnectionBackend;
-import net.floodlightcontroller.core.OFConnectionCounters;
-import net.floodlightcontroller.core.internal.OpenflowPipelineFactory.PipelineHandler;
-import net.floodlightcontroller.core.internal.OpenflowPipelineFactory.PipelineHandshakeTimeout;
+import net.floodlightcontroller.core.internal.OFChannelInitializer.PipelineHandler;
+import net.floodlightcontroller.core.internal.OFChannelInitializer.PipelineHandshakeTimeout;
 import net.floodlightcontroller.debugcounter.DebugCounterServiceImpl;
 import net.floodlightcontroller.debugcounter.IDebugCounterService;
 
@@ -67,6 +65,7 @@ import org.projectfloodlight.openflow.types.DatapathId;
 import org.projectfloodlight.openflow.types.OFPort;
 import org.projectfloodlight.openflow.types.U32;
 
+import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableList;
 
 
@@ -78,13 +77,10 @@ public class OFChannelHandlerVer10Test {
     private Channel channel;
     private Timer timer;
     private ChannelHandlerContext ctx;
-    private MessageEvent messageEvent;
-    private ChannelStateEvent channelStateEvent;
     private ChannelPipeline pipeline;
-    // FIXME:LOJI: Currently only use OF 1.0
     private final OFFactory factory = OFFactories.getFactory(OFVersion.OF_10);
 
-    private Capture<ExceptionEvent> exceptionEventCapture;
+    private Capture<Throwable> exceptionEventCapture;
     private Capture<List<OFMessage>> writeCapture;
 
     private OFPortDesc portDesc;
@@ -121,11 +117,9 @@ public class OFChannelHandlerVer10Test {
         newFeaturesReply = new Capture<OFFeaturesReply>();
 
         ctx = createMock(ChannelHandlerContext.class);
-        channelStateEvent = createMock(ChannelStateEvent.class);
         channel = createMock(Channel.class);
         timer = new HashedWheelTimer();
-        messageEvent = createMock(MessageEvent.class);
-        exceptionEventCapture = new Capture<ExceptionEvent>(CaptureType.ALL);
+        exceptionEventCapture = new Capture<Throwable>(CaptureType.ALL);
         pipeline = createMock(ChannelPipeline.class);
         writeCapture = new Capture<List<OFMessage>>(CaptureType.ALL);
         seenXids = null;
@@ -150,16 +144,14 @@ public class OFChannelHandlerVer10Test {
         replay(switchManager);
 
         // Mock ctx and channelStateEvent
-        expect(ctx.getChannel()).andReturn(channel).anyTimes();
-        expect(channelStateEvent.getChannel()).andReturn(channel).anyTimes();
-        replay(ctx, channelStateEvent);
+        expect(ctx.channel()).andReturn(channel).anyTimes();
+        expect(ctx.fireExceptionCaught(capture(exceptionEventCapture))).andReturn(ctx).anyTimes();
+        replay(ctx);
 
         /* Setup an exception event capture on the channel. Right now
          * we only expect exception events to be send up the channel.
          * However, it's easy to extend to other events if we need it
          */
-        pipeline.sendUpstream(capture(exceptionEventCapture));
-        expectLastCall().anyTimes();
         expect(pipeline.get(OFMessageDecoder.class)).andReturn(new OFMessageDecoder()).anyTimes();
         replay(pipeline);
     }
@@ -168,40 +160,26 @@ public class OFChannelHandlerVer10Test {
     public void tearDown() {
         /* ensure no exception was thrown */
         if (exceptionEventCapture.hasCaptured()) {
-            Throwable ex = exceptionEventCapture.getValue().getCause();
+            Throwable ex = exceptionEventCapture.getValue();
             ex.printStackTrace();
-            throw new AssertionError("Unexpected exception: " +
-                       ex.getClass().getName() + "(" + ex + ")");
+            Throwables.propagate(ex);
         }
         assertFalse("Unexpected messages have been captured",
                     writeCapture.hasCaptured());
         // verify all mocks.
         verify(channel);
-        verify(messageEvent);
         verify(switchManager);
         verify(ctx);
-        verify(channelStateEvent);
         verify(pipeline);
     }
 
     /** Reset the channel mock and set basic method call expectations */
     void resetChannel() {
         reset(channel);
-        expect(channel.getPipeline()).andReturn(pipeline).anyTimes();
-        expect(channel.getRemoteAddress()).andReturn(InetSocketAddress.createUnresolved("1.1.1.1", 80)).anyTimes();
-    }
-
-
-    /** reset, setup, and replay the messageEvent mock for the given
-     * messages
-     */
-    void setupMessageEvent(List<OFMessage> messages) {
-        reset(messageEvent);
-        expect(messageEvent.getMessage()).andReturn(messages).atLeastOnce();
-        replay(messageEvent);
+        expect(channel.pipeline()).andReturn(pipeline).anyTimes();
+        expect(channel.remoteAddress()).andReturn(InetSocketAddress.createUnresolved("1.1.1.1", 80)).anyTimes();
     }
 
-
     /** reset, setup, and replay the messageEvent mock for the given
      * messages, mock controller  send message to channel handler
      *
@@ -209,7 +187,6 @@ public class OFChannelHandlerVer10Test {
      */
     void sendMessageToHandlerWithControllerReset(List<OFMessage> messages)
             throws Exception {
-
         sendMessageToHandlerNoControllerReset(messages);
     }
 
@@ -220,9 +197,7 @@ public class OFChannelHandlerVer10Test {
      */
     void sendMessageToHandlerNoControllerReset(List<OFMessage> messages)
             throws Exception {
-        setupMessageEvent(messages);
-
-        handler.messageReceived(ctx, messageEvent);
+        handler.channelRead(ctx, messages);
     }
 
     /**
@@ -256,7 +231,7 @@ public class OFChannelHandlerVer10Test {
             Class<? extends Throwable> expectedExceptionClass) {
         assertTrue("Excpected exception not thrown",
                    exceptionEventCapture.hasCaptured());
-        Throwable caughtEx = exceptionEventCapture.getValue().getCause();
+        Throwable caughtEx = exceptionEventCapture.getValue();
         assertEquals(expectedExceptionClass, caughtEx.getClass());
         exceptionEventCapture.reset();
     }
@@ -277,16 +252,21 @@ public class OFChannelHandlerVer10Test {
             seenXids.add(xid);
         }
     }
-
+    
+    @Test
+    public void testNullMsg() throws Exception {
+    	reset(ctx);
+    	expect(ctx.fireChannelRead(null)).andReturn(ctx).once();
+    	replay(ctx, channel);
+    	
+    	// null message is not passed to the handler
+    	handler.channelRead(ctx, null);
+    	verify(channel, ctx);
+    }
 
     @Test
     public void testInitState() throws Exception {
-        // Message event needs to be list
-        expect(messageEvent.getMessage()).andReturn(null);
-        replay(channel, messageEvent);
-        handler.messageReceived(ctx, messageEvent);
-        verify(channel, messageEvent);
-        verifyExceptionCaptured(AssertionError.class);
+        replay(channel);
 
         // We don't expect to receive /any/ messages in init state since
         // channelConnected moves us to a different state
@@ -302,13 +282,10 @@ public class OFChannelHandlerVer10Test {
     public void moveToWaitHello() throws Exception {
 
         resetChannel();
-        channel.write(capture(writeCapture));
-        expectLastCall().andReturn(null).once();
+        expect(channel.writeAndFlush(capture(writeCapture))).andReturn(null).once();
         replay(channel);
-        // replay unused mocks
-        replay(messageEvent);
 
-        handler.channelConnected(ctx, channelStateEvent);
+        handler.channelActive(ctx);
 
         List<OFMessage> msgs = getMessagesFromCapture();
         assertEquals(1, msgs.size());
@@ -327,8 +304,7 @@ public class OFChannelHandlerVer10Test {
         moveToWaitHello();
 
         resetChannel();
-        channel.write(capture(writeCapture));
-        expectLastCall().andReturn(null).atLeastOnce();
+        expect(channel.writeAndFlush(capture(writeCapture))).andReturn(null).atLeastOnce();
         replay(channel);
 
         OFMessage hello = factory.buildHello().build();
@@ -387,8 +363,7 @@ public class OFChannelHandlerVer10Test {
         newConnection.getValue().setListener(connectionListener);
 
         resetChannel();
-        channel.write(capture(writeCapture));
-        expectLastCall().andReturn(null).atLeastOnce();
+        expect(channel.writeAndFlush(capture(writeCapture))).andReturn(null).atLeastOnce();
         replay(channel);
 
         // Send echo request. expect reply
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerVer13Test.java b/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerVer13Test.java
index 9b9b6ce897bf00c210326fed7d49e315500e11eb..6764bdef866c9d61dd65628e8ca0eb9413cfc9a7 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerVer13Test.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerVer13Test.java
@@ -24,22 +24,20 @@ import org.easymock.Capture;
 import org.easymock.CaptureType;
 import org.easymock.EasyMock;
 import org.hamcrest.CoreMatchers;
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.channel.ChannelHandlerContext;
-import org.jboss.netty.channel.ChannelPipeline;
-import org.jboss.netty.channel.ChannelStateEvent;
-import org.jboss.netty.channel.ExceptionEvent;
-import org.jboss.netty.channel.MessageEvent;
-import org.jboss.netty.util.HashedWheelTimer;
-import org.jboss.netty.util.Timer;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelPipeline;
+import io.netty.util.HashedWheelTimer;
+import io.netty.util.Timer;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
 import net.floodlightcontroller.core.IOFConnectionBackend;
-import net.floodlightcontroller.core.OFConnectionCounters;
-import net.floodlightcontroller.core.internal.OpenflowPipelineFactory.PipelineHandler;
-import net.floodlightcontroller.core.internal.OpenflowPipelineFactory.PipelineHandshakeTimeout;
+import net.floodlightcontroller.core.internal.OFChannelInitializer.PipelineHandler;
+import net.floodlightcontroller.core.internal.OFChannelInitializer.PipelineHandshakeTimeout;
 import net.floodlightcontroller.debugcounter.DebugCounterServiceImpl;
 import net.floodlightcontroller.debugcounter.IDebugCounterService;
 
@@ -68,6 +66,7 @@ import org.projectfloodlight.openflow.types.OFAuxId;
 import org.projectfloodlight.openflow.types.OFPort;
 import org.projectfloodlight.openflow.types.U32;
 
+import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableList;
 
 
@@ -82,12 +81,10 @@ public class OFChannelHandlerVer13Test {
     private Channel channel;
     private Timer timer;
     private ChannelHandlerContext ctx;
-    private MessageEvent messageEvent;
-    private ChannelStateEvent channelStateEvent;
     private ChannelPipeline pipeline;
     private final OFFactory factory = OFFactories.getFactory(OFVersion.OF_13);
 
-    private Capture<ExceptionEvent> exceptionEventCapture;
+    private Capture<Throwable> exceptionEventCapture;
     private Capture<List<OFMessage>> writeCapture;
 
     private OFFeaturesReply featuresReply;
@@ -123,11 +120,9 @@ public class OFChannelHandlerVer13Test {
         newFeaturesReply = new Capture<OFFeaturesReply>();
 
         ctx = createMock(ChannelHandlerContext.class);
-        channelStateEvent = createMock(ChannelStateEvent.class);
         channel = createMock(Channel.class);
         timer = new HashedWheelTimer();
-        messageEvent = createMock(MessageEvent.class);
-        exceptionEventCapture = new Capture<ExceptionEvent>(CaptureType.ALL);
+        exceptionEventCapture = new Capture<Throwable>(CaptureType.ALL);
         pipeline = createMock(ChannelPipeline.class);
         writeCapture = new Capture<List<OFMessage>>(CaptureType.ALL);
         seenXids = null;
@@ -154,16 +149,14 @@ public class OFChannelHandlerVer13Test {
         replay(switchManager);
 
         // Mock ctx and channelStateEvent
-        expect(ctx.getChannel()).andReturn(channel).anyTimes();
-        expect(channelStateEvent.getChannel()).andReturn(channel).anyTimes();
-        replay(ctx, channelStateEvent);
+        expect(ctx.channel()).andReturn(channel).anyTimes();
+        expect(ctx.fireExceptionCaught(capture(exceptionEventCapture))).andReturn(ctx).anyTimes();
+        replay(ctx);
 
         /* Setup an exception event capture on the channel. Right now
          * we only expect exception events to be send up the channel.
          * However, it's easy to extend to other events if we need it
          */
-        pipeline.sendUpstream(capture(exceptionEventCapture));
-        expectLastCall().anyTimes();
         expect(pipeline.get(OFMessageDecoder.class)).andReturn(new OFMessageDecoder()).anyTimes();
         replay(pipeline);
     }
@@ -172,40 +165,26 @@ public class OFChannelHandlerVer13Test {
     public void tearDown() {
         /* ensure no exception was thrown */
         if (exceptionEventCapture.hasCaptured()) {
-            Throwable ex = exceptionEventCapture.getValue().getCause();
+            Throwable ex = exceptionEventCapture.getValue();
             ex.printStackTrace();
-            throw new AssertionError("Unexpected exception: " +
-                       ex.getClass().getName() + "(" + ex + ")");
+            Throwables.propagate(ex);
         }
         assertFalse("Unexpected messages have been captured",
                     writeCapture.hasCaptured());
         // verify all mocks.
         verify(channel);
-        verify(messageEvent);
         verify(switchManager);
         verify(ctx);
-        verify(channelStateEvent);
         verify(pipeline);
     }
 
     /** Reset the channel mock and set basic method call expectations */
     void resetChannel() {
         reset(channel);
-        expect(channel.getPipeline()).andReturn(pipeline).anyTimes();
-        expect(channel.getRemoteAddress()).andReturn(null).anyTimes();
+        expect(channel.pipeline()).andReturn(pipeline).anyTimes();
+        expect(channel.remoteAddress()).andReturn(null).anyTimes();
     }
 
-
-    /** reset, setup, and replay the messageEvent mock for the given
-     * messages
-     */
-    void setupMessageEvent(List<OFMessage> messages) {
-        reset(messageEvent);
-        expect(messageEvent.getMessage()).andReturn(messages).atLeastOnce();
-        replay(messageEvent);
-    }
-
-
     /** reset, setup, and replay the messageEvent mock for the given
      * messages, mock controller  send message to channel handler
      *
@@ -213,7 +192,6 @@ public class OFChannelHandlerVer13Test {
      */
     void sendMessageToHandlerWithControllerReset(List<OFMessage> messages)
             throws Exception {
-
         sendMessageToHandlerNoControllerReset(messages);
     }
 
@@ -224,9 +202,7 @@ public class OFChannelHandlerVer13Test {
      */
     void sendMessageToHandlerNoControllerReset(List<OFMessage> messages)
             throws Exception {
-        setupMessageEvent(messages);
-
-        handler.messageReceived(ctx, messageEvent);
+        handler.channelRead(ctx, messages);
     }
 
     /**
@@ -256,11 +232,9 @@ public class OFChannelHandlerVer13Test {
      * expectedExceptionClass.
      * Resets the capture
      */
-    void verifyExceptionCaptured(
-            Class<? extends Throwable> expectedExceptionClass) {
-        assertTrue("Excpected exception not thrown",
-                   exceptionEventCapture.hasCaptured());
-        Throwable caughtEx = exceptionEventCapture.getValue().getCause();
+    void verifyExceptionCaptured(Class<? extends Throwable> expectedExceptionClass) {
+        assertTrue("Excpected exception not thrown", exceptionEventCapture.hasCaptured());
+        Throwable caughtEx = exceptionEventCapture.getValue();
         assertEquals(expectedExceptionClass, caughtEx.getClass());
         exceptionEventCapture.reset();
     }
@@ -282,15 +256,20 @@ public class OFChannelHandlerVer13Test {
         }
     }
 
+    @Test
+    public void testNullMsg() throws Exception {
+    	reset(ctx);
+    	expect(ctx.fireChannelRead(null)).andReturn(ctx).once();
+    	replay(ctx, channel);
+    	
+    	// null message is not passed to the handler
+    	handler.channelRead(ctx, null);
+    	verify(channel, ctx);
+    }
 
     @Test
     public void testInitState() throws Exception {
-        // Message event needs to be list
-        expect(messageEvent.getMessage()).andReturn(null);
-        replay(channel, messageEvent);
-        handler.messageReceived(ctx, messageEvent);
-        verify(channel, messageEvent);
-        verifyExceptionCaptured(AssertionError.class);
+        replay(channel);
 
         // We don't expect to receive /any/ messages in init state since
         // channelConnected moves us to a different state
@@ -305,13 +284,10 @@ public class OFChannelHandlerVer13Test {
     @Test
     public void moveToWaitHello() throws Exception {
         resetChannel();
-        channel.write(capture(writeCapture));
-        expectLastCall().andReturn(null).once();
+        expect(channel.writeAndFlush(capture(writeCapture))).andReturn(null).once();
         replay(channel);
-        // replay unused mocks
-        replay(messageEvent);
 
-        handler.channelConnected(ctx, channelStateEvent);
+        handler.channelActive(ctx);
 
         List<OFMessage> msgs = getMessagesFromCapture();
         assertEquals(1, msgs.size());
@@ -328,8 +304,7 @@ public class OFChannelHandlerVer13Test {
     public void moveToWaitFeaturesReply() throws Exception {
         moveToWaitHello();
         resetChannel();
-        channel.write(capture(writeCapture));
-        expectLastCall().andReturn(null).atLeastOnce();
+        expect(channel.writeAndFlush(capture(writeCapture))).andReturn(null).once();
         replay(channel);
 
         OFMessage hello = factory.buildHello().build();
@@ -388,8 +363,7 @@ public class OFChannelHandlerVer13Test {
         newConnection.getValue().setListener(connectionListener);
 
         resetChannel();
-        channel.write(capture(writeCapture));
-        expectLastCall().andReturn(null).atLeastOnce();
+        expect(channel.writeAndFlush(capture(writeCapture))).andReturn(null).once();
         replay(channel);
 
         // Send echo request. expect reply
diff --git a/src/test/java/net/floodlightcontroller/core/OFConnectionTest.java b/src/test/java/net/floodlightcontroller/core/internal/OFConnectionTest.java
similarity index 94%
rename from src/test/java/net/floodlightcontroller/core/OFConnectionTest.java
rename to src/test/java/net/floodlightcontroller/core/internal/OFConnectionTest.java
index d65788b36a3cff928e09301fdeb1362f3f78121d..24d39515c6b8dd9d93208959632e7fe1da1249d7 100644
--- a/src/test/java/net/floodlightcontroller/core/OFConnectionTest.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/OFConnectionTest.java
@@ -1,4 +1,4 @@
-package net.floodlightcontroller.core;
+package net.floodlightcontroller.core.internal;
 
 import static org.easymock.EasyMock.capture;
 import static org.easymock.EasyMock.expect;
@@ -13,12 +13,18 @@ import org.easymock.Capture;
 import org.easymock.EasyMock;
 import org.hamcrest.CoreMatchers;
 import org.hamcrest.Matchers;
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.util.HashedWheelTimer;
-import org.jboss.netty.util.Timer;
+
+import io.netty.channel.Channel;
+import io.netty.util.HashedWheelTimer;
+import io.netty.util.Timer;
+
 import org.junit.Before;
 import org.junit.Test;
 
+import net.floodlightcontroller.core.SwitchDisconnectedException;
+import net.floodlightcontroller.core.internal.OFConnection;
+import net.floodlightcontroller.core.internal.OFConnectionCounters;
+import net.floodlightcontroller.core.internal.OFErrorMsgException;
 import net.floodlightcontroller.debugcounter.DebugCounterServiceImpl;
 import net.floodlightcontroller.debugcounter.IDebugCounterService;
 
@@ -142,9 +148,9 @@ public class OFConnectionTest {
     }
 
     private Capture<List<OFMessage>> prepareChannelForWriteList() {
-        EasyMock.expect(channel.isConnected()).andReturn(Boolean.TRUE).anyTimes();
+        EasyMock.expect(channel.isActive()).andReturn(Boolean.TRUE).anyTimes();
         Capture<List<OFMessage>> cMsgList = new Capture<>();
-        expect(channel.write(capture(cMsgList))).andReturn(null).once();
+        expect(channel.writeAndFlush(capture(cMsgList))).andReturn(null).once();
         replay(channel);
         return cMsgList;
     }
@@ -181,7 +187,7 @@ public class OFConnectionTest {
     @Test(timeout = 5000)
     public void testWriteRequestNotConnectedFailure() throws InterruptedException,
             ExecutionException {
-        EasyMock.expect(channel.isConnected()).andReturn(Boolean.FALSE).anyTimes();
+        EasyMock.expect(channel.isActive()).andReturn(Boolean.FALSE).anyTimes();
         replay(channel);
 
         OFEchoRequest echoRequest = factory.echoRequest(new byte[] {});
diff --git a/src/test/java/net/floodlightcontroller/core/OFSwitchBaseTest.java b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchBaseTest.java
similarity index 98%
rename from src/test/java/net/floodlightcontroller/core/OFSwitchBaseTest.java
rename to src/test/java/net/floodlightcontroller/core/internal/OFSwitchBaseTest.java
index 24db287af6da5c28214280f1a240991dafc27e55..8fefbfbf162c7dd51533f23b4e51ff36f229a627 100644
--- a/src/test/java/net/floodlightcontroller/core/OFSwitchBaseTest.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchBaseTest.java
@@ -14,7 +14,7 @@
  *    under the License.
  **/
 
-package net.floodlightcontroller.core;
+package net.floodlightcontroller.core.internal;
 
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.expect;
@@ -41,7 +41,17 @@ import org.easymock.EasyMock;
 import org.junit.Before;
 import org.junit.Test;
 
+import net.floodlightcontroller.core.IOFConnectionBackend;
+import net.floodlightcontroller.core.IOFSwitchBackend;
+import net.floodlightcontroller.core.LogicalOFMessageCategory;
+import net.floodlightcontroller.core.PortChangeEvent;
+import net.floodlightcontroller.core.PortChangeType;
+import net.floodlightcontroller.core.SwitchDescription;
+import net.floodlightcontroller.core.SwitchDriverSubHandshakeAlreadyStarted;
+import net.floodlightcontroller.core.SwitchDriverSubHandshakeCompleted;
+import net.floodlightcontroller.core.SwitchDriverSubHandshakeNotStarted;
 import net.floodlightcontroller.core.internal.IOFSwitchManager;
+import net.floodlightcontroller.core.internal.OFSwitch;
 import net.floodlightcontroller.core.internal.SwitchManagerCounters;
 import net.floodlightcontroller.debugcounter.DebugCounterServiceImpl;
 import net.floodlightcontroller.debugcounter.IDebugCounterService;
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandlerTestBase.java b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandlerTestBase.java
index 675873a5eeac46c7e8db6cef30e31ea02680fd08..23cc4f12e661dc4043e9a85509464201179470e3 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandlerTestBase.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandlerTestBase.java
@@ -27,9 +27,9 @@ import java.util.concurrent.TimeUnit;
 import org.easymock.EasyMock;
 import org.hamcrest.CoreMatchers;
 import org.hamcrest.Matchers;
-import org.jboss.netty.util.Timeout;
-import org.jboss.netty.util.Timer;
-import org.jboss.netty.util.TimerTask;
+import io.netty.util.Timeout;
+import io.netty.util.Timer;
+import io.netty.util.TimerTask;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandlerVer10Test.java b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandlerVer10Test.java
index be752d0246f9075751fae5d2f321a7ee4af85ac7..d940ed4d55ee6da5e922d871a8319a6ce2437457 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandlerVer10Test.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandlerVer10Test.java
@@ -16,11 +16,12 @@ import java.util.EnumSet;
 import org.hamcrest.CoreMatchers;
 import org.hamcrest.Matchers;
 import org.junit.Test;
+
 import net.floodlightcontroller.core.IOFSwitchBackend;
-import net.floodlightcontroller.core.OFConnection;
 import net.floodlightcontroller.core.SwitchDescription;
 import net.floodlightcontroller.core.internal.OFSwitchAppHandshakePlugin.PluginResultType;
 import net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler.WaitAppHandshakeState;
+
 import org.projectfloodlight.openflow.protocol.OFActionType;
 import org.projectfloodlight.openflow.protocol.OFCapabilities;
 import org.projectfloodlight.openflow.protocol.OFControllerRole;
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandlerVer13Test.java b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandlerVer13Test.java
index 9cb4c82167651f09f48588bc085e460103220e23..7f8393f65b704c26e3b865c93a2518494439e7f3 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandlerVer13Test.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandlerVer13Test.java
@@ -18,7 +18,6 @@ import org.hamcrest.Matchers;
 import org.junit.Test;
 
 import net.floodlightcontroller.core.IOFSwitchBackend;
-import net.floodlightcontroller.core.OFConnection;
 import net.floodlightcontroller.core.SwitchDescription;
 import net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler.WaitAppHandshakeState;
 import net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler.WaitTableFeaturesReplyState;
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchManagerTest.java b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchManagerTest.java
index 62d43ab96a1305cb89e0df40ae14df5ee9f89fd2..6f5312ae2670344d91791bd4b87292a4ee5078e1 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchManagerTest.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchManagerTest.java
@@ -35,7 +35,7 @@ import static org.junit.Assert.fail;
 
 import java.util.List;
 
-import org.jboss.netty.util.Timer;
+import io.netty.util.Timer;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -50,8 +50,6 @@ import net.floodlightcontroller.core.IOFSwitchListener;
 import net.floodlightcontroller.core.IShutdownListener;
 import net.floodlightcontroller.core.IShutdownService;
 import net.floodlightcontroller.core.LogicalOFMessageCategory;
-import net.floodlightcontroller.core.NullConnection;
-import net.floodlightcontroller.core.OFSwitch;
 import net.floodlightcontroller.core.PortChangeType;
 import net.floodlightcontroller.core.SwitchDescription;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchTest.java b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchTest.java
index b5ca01ed6884656e520c40ccd5cc284e88eae5f9..4ddef9978888e2c77763e9fb95a9362453cf9656 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchTest.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchTest.java
@@ -29,12 +29,13 @@ import java.util.List;
 import org.easymock.EasyMock;
 import org.junit.Before;
 import org.junit.Test;
+
 import net.floodlightcontroller.core.IOFSwitchBackend;
-import net.floodlightcontroller.core.OFSwitch;
 import net.floodlightcontroller.core.SwitchDriverSubHandshakeAlreadyStarted;
 import net.floodlightcontroller.core.SwitchDriverSubHandshakeCompleted;
 import net.floodlightcontroller.core.SwitchDriverSubHandshakeNotStarted;
 import net.floodlightcontroller.core.util.URIUtil;
+
 import org.projectfloodlight.openflow.protocol.OFBsnControllerConnection;
 import org.projectfloodlight.openflow.protocol.OFBsnControllerConnectionState;
 import org.projectfloodlight.openflow.protocol.OFBsnControllerConnectionsReply;
diff --git a/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java b/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java
index f5f89350abb048234cd368bc773f45187ff98f05..adab6d540995123d559b59b84e0bdc879ef621a2 100644
--- a/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java
+++ b/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java
@@ -35,8 +35,7 @@ import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 
-import org.jboss.netty.util.Timer;
-
+import io.netty.util.Timer;
 import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.HAListenerTypeMarker;
 import net.floodlightcontroller.core.HARole;
@@ -59,6 +58,8 @@ import net.floodlightcontroller.core.util.ListenerDispatcher;
 import org.projectfloodlight.openflow.protocol.OFMessage;
 import org.projectfloodlight.openflow.protocol.OFPacketIn;
 import org.projectfloodlight.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.TransportPort;
 
 import net.floodlightcontroller.packet.Ethernet;
 
@@ -74,8 +75,8 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro
     protected ConcurrentMap<OFType, ListenerDispatcher<OFType,IOFMessageListener>> listeners;
     protected ListenerDispatcher<HAListenerTypeMarker, IHAListener> haListeners;
     private HARole role;
-    private final String openFlowHostname = "127.0.0.1";
-    private final int openFlowPort = 6653;
+    private final Set<IPv4Address> openFlowHostname = Collections.singleton(IPv4Address.of("127.0.0.1"));
+    private final TransportPort openFlowPort = TransportPort.of(6653);
     private final boolean useAsyncUpdates;
     private volatile ExecutorService executorService;
     private volatile Future<?> mostRecentUpdateFuture;
@@ -378,12 +379,12 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro
     }
 
     @Override
-    public String getOFHostname() {
+    public Set<IPv4Address> getOFAddresses() {
         return openFlowHostname;
     }
 
     @Override
-    public int getOFPort() {
+    public TransportPort getOFPort() {
         return openFlowPort;
     }
 
diff --git a/src/test/java/net/floodlightcontroller/debugcounter/OFConnectionCountersTest.java b/src/test/java/net/floodlightcontroller/debugcounter/OFConnectionCountersTest.java
index c82eb132c050eef6b9acedc0cde5936dd2545154..46984522e60e9af43a471a42e8cc5c6f759c3deb 100644
--- a/src/test/java/net/floodlightcontroller/debugcounter/OFConnectionCountersTest.java
+++ b/src/test/java/net/floodlightcontroller/debugcounter/OFConnectionCountersTest.java
@@ -7,7 +7,7 @@ import java.util.ArrayList;
 import org.junit.Before;
 import org.junit.Test;
 
-import net.floodlightcontroller.core.OFConnectionCounters;
+import net.floodlightcontroller.core.internal.OFConnectionCounters;
 
 import org.projectfloodlight.openflow.protocol.OFAsyncGetReply;
 import org.projectfloodlight.openflow.protocol.OFAsyncGetRequest;
diff --git a/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java b/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java
index c4005b32aaec719cfd0f4f43732bacc941f75bb3..119b7acf8dcba7ca15ca9d5bf89a92ce798c5483 100644
--- a/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java
+++ b/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java
@@ -28,8 +28,8 @@ import java.util.Set;
 import net.floodlightcontroller.core.IOFConnection;
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.LogicalOFMessageCategory;
-import net.floodlightcontroller.core.OFConnection;
 import net.floodlightcontroller.core.SwitchDescription;
+import net.floodlightcontroller.core.internal.OFConnection;
 import net.floodlightcontroller.core.internal.TableFeatures;
 
 import org.projectfloodlight.openflow.protocol.OFActionType;