diff --git a/lib/openflowj-0.9.0-SNAPSHOT-javadoc.jar b/lib/openflowj-0.9.0-SNAPSHOT-javadoc.jar
index 9e685f2be1d758a4564fba5acf01bdbb4b237dac..0fa8cd6dac7eeb914fe77a9b0a89ea9145a3ee20 100644
Binary files a/lib/openflowj-0.9.0-SNAPSHOT-javadoc.jar and b/lib/openflowj-0.9.0-SNAPSHOT-javadoc.jar differ
diff --git a/lib/openflowj-0.9.0-SNAPSHOT-sources.jar b/lib/openflowj-0.9.0-SNAPSHOT-sources.jar
index bd732775843be73ff338598b296ecfb9510e40b1..b8ab5fcc55fca207c5bf2eb42f7267995f059836 100644
Binary files a/lib/openflowj-0.9.0-SNAPSHOT-sources.jar and b/lib/openflowj-0.9.0-SNAPSHOT-sources.jar differ
diff --git a/lib/openflowj-0.9.0-SNAPSHOT.jar b/lib/openflowj-0.9.0-SNAPSHOT.jar
index bef1d780013e3943927c357a4adb2173215e4753..2bd4f87c31d76c74891ec7f3c10d5e37d624da1e 100644
Binary files a/lib/openflowj-0.9.0-SNAPSHOT.jar and b/lib/openflowj-0.9.0-SNAPSHOT.jar differ
diff --git a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
index df2856c64f84834ee1737d93616cfe63298546d0..ccb68176f6086b187071cb4fc9fbf01e9e3df40d 100644
--- a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
+++ b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
@@ -34,10 +34,14 @@ import org.projectfloodlight.openflow.protocol.OFStatsReply;
 import org.projectfloodlight.openflow.protocol.OFStatsRequest;
 import org.projectfloodlight.openflow.types.DatapathId;
 import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.TableId;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.util.concurrent.ListenableFuture;
+
+import net.floodlightcontroller.core.internal.TableFeatures;
 import net.floodlightcontroller.core.web.serializers.IOFSwitchSerializer;
+
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 /**
  * An openflow switch connecting to the controller.  This interface offers
@@ -336,4 +340,15 @@ public interface IOFSwitch extends IOFMessageWriter {
      *         return a Future that immediately fails with a @link{SwitchDisconnectedException}.
      */
     <R extends OFMessage> ListenableFuture<R> writeRequest(OFRequest<R> request, LogicalOFMessageCategory category);
+    
+    /**
+     * Get the features of a particular switch table. The features are cached from
+     * the initial handshake, or, if applicable, from a more recent 
+     * OFTableFeaturesStatsRequest/Reply sent by a user module.
+     * 
+     * @param table, The table of which to get features.
+     * @return The table features or null if no features are known for the table requested.
+     */
+    public TableFeatures getTableFeatures(TableId table);
+    
 }
diff --git a/src/main/java/net/floodlightcontroller/core/IOFSwitchBackend.java b/src/main/java/net/floodlightcontroller/core/IOFSwitchBackend.java
index 75685c19a480c0bb4cb90bef48caa65d46023223..a14ca20199c549213544d85c73a4b7ade72058ed 100644
--- a/src/main/java/net/floodlightcontroller/core/IOFSwitchBackend.java
+++ b/src/main/java/net/floodlightcontroller/core/IOFSwitchBackend.java
@@ -18,6 +18,7 @@
 package net.floodlightcontroller.core;
 
 import java.util.Collection;
+import java.util.List;
 
 import org.projectfloodlight.openflow.protocol.OFBsnControllerConnectionsReply;
 import org.projectfloodlight.openflow.protocol.OFControllerRole;
@@ -26,6 +27,8 @@ import org.projectfloodlight.openflow.protocol.OFMessage;
 import org.projectfloodlight.openflow.protocol.OFPortDesc;
 import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
 import org.projectfloodlight.openflow.protocol.OFPortStatus;
+import org.projectfloodlight.openflow.protocol.OFTableFeatures;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturesStatsReply;
 
 import net.floodlightcontroller.util.OrderedCollection;
 
@@ -82,6 +85,15 @@ public interface IOFSwitchBackend extends IOFSwitch {
      * conflicting appear before before events adding new ports
      */
     OrderedCollection<PortChangeEvent> processOFPortStatus(OFPortStatus ps);
+    
+    /**
+     * Add or modify a switch table.
+     * This is called by the core controller code in response to an OFTableFeaturesReply message.
+     * It should not typically be called by other Floodlight modules or applications.
+     * 
+     * @param tf, The table features to be updated.
+     */
+    void processOFTableFeatures(List<OFTableFeaturesStatsReply> replies);
 
     /**
      * Compute the changes that would be required to replace the old ports
diff --git a/src/main/java/net/floodlightcontroller/core/OFSwitch.java b/src/main/java/net/floodlightcontroller/core/OFSwitch.java
index f54f604597af07abec182c5ee5651b21c8a16c54..8b401dad680cdda48eccaa36fad5db0b987d08a3 100644
--- a/src/main/java/net/floodlightcontroller/core/OFSwitch.java
+++ b/src/main/java/net/floodlightcontroller/core/OFSwitch.java
@@ -39,6 +39,7 @@ import javax.annotation.Nonnull;
 
 import net.floodlightcontroller.core.annotations.LogMessageDoc;
 import net.floodlightcontroller.core.internal.IOFSwitchManager;
+import net.floodlightcontroller.core.internal.TableFeatures;
 import net.floodlightcontroller.core.util.AppCookie;
 import net.floodlightcontroller.core.util.URIUtil;
 
@@ -52,7 +53,6 @@ import org.projectfloodlight.openflow.protocol.OFFactory;
 import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
 import org.projectfloodlight.openflow.protocol.OFFlowWildcards;
 import org.projectfloodlight.openflow.protocol.OFMessage;
-
 import org.projectfloodlight.openflow.protocol.OFPortConfig;
 import org.projectfloodlight.openflow.protocol.OFPortDesc;
 import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
@@ -62,10 +62,13 @@ import org.projectfloodlight.openflow.protocol.OFPortStatus;
 import org.projectfloodlight.openflow.protocol.OFRequest;
 import org.projectfloodlight.openflow.protocol.OFStatsReply;
 import org.projectfloodlight.openflow.protocol.OFStatsRequest;
+import org.projectfloodlight.openflow.protocol.OFTableFeatures;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturesStatsReply;
 import org.projectfloodlight.openflow.protocol.OFVersion;
 import org.projectfloodlight.openflow.types.DatapathId;
 import org.projectfloodlight.openflow.types.OFAuxId;
 import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.TableId;
 
 import net.floodlightcontroller.util.LinkedHashSetWrapper;
 import net.floodlightcontroller.util.OrderedCollection;
@@ -76,6 +79,7 @@ import org.slf4j.LoggerFactory;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
@@ -96,6 +100,8 @@ public class OFSwitch implements IOFSwitchBackend {
 	protected short tables;
 	protected final DatapathId datapathId;
 
+	private Map<TableId, TableFeatures> tableFeaturesByTableId;
+
 	private boolean startDriverHandshakeCalled = false;
 	private final Map<OFAuxId, IOFConnectionBackend> connections;
 	private volatile Map<URI, Map<OFAuxId, OFBsnControllerConnection>> controllerConnections;
@@ -106,6 +112,8 @@ public class OFSwitch implements IOFSwitchBackend {
 	 */
 	private final PortManager portManager;
 
+	//private final TableManager tableManager;
+
 	private volatile boolean connected;
 
 	private volatile OFControllerRole role;
@@ -154,6 +162,8 @@ public class OFSwitch implements IOFSwitchBackend {
 		this.setAttribute(PROP_FASTWILDCARDS, EnumSet.allOf(OFFlowWildcards.class));
 		this.setAttribute(PROP_SUPPORTS_OFPP_FLOOD, Boolean.TRUE);
 		this.setAttribute(PROP_SUPPORTS_OFPP_TABLE, Boolean.TRUE);
+
+		this.tableFeaturesByTableId = new HashMap<TableId, TableFeatures>();
 	}
 
 	private static int ident(int i) {
@@ -847,6 +857,23 @@ public class OFSwitch implements IOFSwitchBackend {
 		return portManager.handlePortStatusMessage(ps);
 	}
 
+	@Override
+	public void processOFTableFeatures(List<OFTableFeaturesStatsReply> replies) {
+		/*
+		 * Parse out all the individual replies for each table.
+		 */
+		for (OFTableFeaturesStatsReply reply : replies) {
+			/*
+			 * Add or update the features for a particular table.
+			 */
+			List<OFTableFeatures> tfs = reply.getEntries();
+			for (OFTableFeatures tf : tfs) {
+				tableFeaturesByTableId.put(tf.getTableId(), TableFeatures.of(tf));
+				log.trace("Received TableFeatures for TableId {}, TableName {}", tf.getTableId().toString(), tf.getName());
+			}
+		}
+	}
+
 	@Override
 	public Collection<OFPortDesc> getSortedPorts() {
 		List<OFPortDesc> sortedPorts =
@@ -920,12 +947,69 @@ public class OFSwitch implements IOFSwitchBackend {
 
 	@Override
 	public <REPLY extends OFStatsReply> ListenableFuture<List<REPLY>> writeStatsRequest(OFStatsRequest<REPLY> request) {
-		return connections.get(OFAuxId.MAIN).writeStatsRequest(request);
+		return addInternalStatsReplyListener(connections.get(OFAuxId.MAIN).writeStatsRequest(request), request);
 	}
 
 	@Override
 	public <REPLY extends OFStatsReply> ListenableFuture<List<REPLY>> writeStatsRequest(OFStatsRequest<REPLY> request, LogicalOFMessageCategory category) {
-		return getConnection(category).writeStatsRequest(request);
+		return addInternalStatsReplyListener(getConnection(category).writeStatsRequest(request), request);
+	}	
+
+	/**
+	 * Append a listener to receive an OFStatsReply and update the 
+	 * internal OFSwitch data structures.
+	 * 
+	 * This presently taps into the following stats request 
+	 * messages to listen for the corresponding reply:
+	 * -- OFTableFeaturesStatsRequest
+	 * 
+	 * Extend this to tap into and update other OFStatsType messages.
+	 * 
+	 * @param future
+	 * @param request
+	 * @return
+	 */
+	private <REPLY extends OFStatsReply> ListenableFuture<List<REPLY>> addInternalStatsReplyListener(final ListenableFuture<List<REPLY>> future, OFStatsRequest<REPLY> request) {
+		switch (request.getStatsType()) {
+		case TABLE_FEATURES:
+		/* case YOUR_CASE_HERE */
+			future.addListener(new Runnable() {
+				/*
+				 * We know the reply will be a list of OFStatsReply.
+				 */
+				@SuppressWarnings("unchecked")
+				@Override
+				public void run() {
+					/*
+					 * The OFConnection handles REPLY_MORE for us in the case there
+					 * are multiple OFStatsReply messages with the same XID.
+					 */
+					try {
+						List<? extends OFStatsReply> replies = future.get();
+						if (!replies.isEmpty()) {
+							/*
+							 * By checking only the 0th element, we assume all others are the same type.
+							 * TODO If not, what then?
+							 */
+							switch (replies.get(0).getStatsType()) {
+							case TABLE_FEATURES:
+								processOFTableFeatures((List<OFTableFeaturesStatsReply>) future.get());
+								break;
+							/* case YOUR_CASE_HERE */
+							default:
+								throw new Exception("Received an invalid OFStatsReply of " 
+										+ replies.get(0).getStatsType().toString() + ". Expected TABLE_FEATURES.");
+							}
+						}
+					} catch (Exception e) {
+						e.printStackTrace();
+					}
+				}
+			}, MoreExecutors.sameThreadExecutor()); /* No need for another thread. */
+		default:
+			break;
+		}
+		return future; /* either unmodified or with an additional listener */
 	}
 
 	@Override
@@ -1119,4 +1203,9 @@ public class OFSwitch implements IOFSwitchBackend {
 		}
 		return false;
 	}
+
+	@Override
+	public TableFeatures getTableFeatures(TableId table) {
+		return tableFeaturesByTableId.get(table);
+	}
 }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java b/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java
index 3ce00d120738e332717836ba3729a301229e0487..6b165b5cab61b015996b90c3d9fd5af976e7bc38 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java
@@ -62,7 +62,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
 	private Channel channel;
 	private final Timer timer;
 	private volatile OFChannelState state;
-	private OFFactory factory = OFFactories.getFactory(OFVersion.OF_13);
+	private OFFactory factory = OFFactories.getFactory(OFVersion.OF_14);
 	private OFFeaturesReply featuresReply;
 	private volatile OFConnection connection;
 	private final IDebugCounterService debugCounters;
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandler.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandler.java
index b171312cacc4f54be88bd3dc9d906629f331e984..a17e7d5ae859978d5d7832ae10eed3273d7dc7b2 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandler.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandler.java
@@ -58,8 +58,11 @@ import org.projectfloodlight.openflow.protocol.OFRoleReply;
 import org.projectfloodlight.openflow.protocol.OFRoleRequest;
 import org.projectfloodlight.openflow.protocol.OFSetConfig;
 import org.projectfloodlight.openflow.protocol.OFStatsReply;
+import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
 import org.projectfloodlight.openflow.protocol.OFStatsRequestFlags;
 import org.projectfloodlight.openflow.protocol.OFStatsType;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturesStatsReply;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturesStatsRequest;
 import org.projectfloodlight.openflow.protocol.OFType;
 import org.projectfloodlight.openflow.protocol.OFVersion;
 import org.projectfloodlight.openflow.protocol.action.OFAction;
@@ -96,8 +99,8 @@ public class OFSwitchHandshakeHandler implements IOFConnectionListener {
 	private final Map<OFAuxId, IOFConnectionBackend> auxConnections;
 	private volatile OFSwitchHandshakeState state;
 	private RoleChanger roleChanger;
-	// Default to 1.3 - This is overwritten by the features reply
-	private OFFactory factory = OFFactories.getFactory(OFVersion.OF_13);
+	// Default to 1.4 - This is overwritten by the features reply
+	private OFFactory factory = OFFactories.getFactory(OFVersion.OF_14);
 	private final OFFeaturesReply featuresReply;
 	private final Timer timer;
 	
@@ -763,6 +766,28 @@ public class OFSwitchHandshakeHandler implements IOFConnectionListener {
 					switchManager.notifyPortChanged(sw, ev.port, ev.type);
 			}
 		}
+		
+		/**
+		 * Handle a table features message.
+		 *
+		 * Handle a table features message by updating the tables in the
+		 * IOFSwitch instance and notifying Controller about the change so
+		 * it can dispatch a switch update.
+		 *
+		 * @param h The OFChannelHandler that received the message
+		 * @param m The OFTableFeatures message we received
+		 * @param doNotify if true switch table changed events will be
+		 * dispatched
+		 */
+		protected void handleTableFeaturesMessage(List<OFTableFeaturesStatsReply> replies, boolean doNotify) {
+			if (sw == null) {
+				String msg = getSwitchStateMessage(!replies.isEmpty() ? replies.get(0) : null, "State machine error: switch is null. Should never happen");
+				throw new SwitchStateException(msg);
+			}
+			sw.processOFTableFeatures(replies);
+			//TODO like port status, might want to create an event and dispatch it. Not sure how useful this would be though...
+		}
+
 
 		/**
 		 * Process an OF message received on the channel and
@@ -1001,12 +1026,7 @@ public class OFSwitchHandshakeHandler implements IOFConnectionListener {
 			// Handle pending messages now that we have a sw object
 			handlePendingPortStatusMessages(description);
 
-			sw.startDriverHandshake();
-			if (sw.isDriverHandshakeComplete()) {
-				setState(new WaitAppHandshakeState());
-			} else {
-				setState(new WaitSwitchDriverSubHandshakeState());
-			}
+			setState(new WaitTableFeaturesReplyState());
 		}
 
 		void handlePendingPortStatusMessages(SwitchDescription description){
@@ -1022,6 +1042,77 @@ public class OFSwitchHandshakeHandler implements IOFConnectionListener {
 			sendHandshakeDescriptionStatsRequest();
 		}
 	}
+	
+	/*
+	 * New state: WaitSwitchTableFeaturesReplyState
+	 */
+	public class WaitTableFeaturesReplyState extends OFSwitchHandshakeState {
+
+		private ArrayList<OFTableFeaturesStatsReply> replies;
+		WaitTableFeaturesReplyState() {
+			super(false);
+			replies = new ArrayList<OFTableFeaturesStatsReply>();
+		}
+		
+		@Override
+		/**
+		 * Accumulate a list of the OFTableFeaturesStatsReply's until there 
+		 * are no more remaining. Then, pass the list to the switch for 
+		 * parsing and configuration.
+		 * 
+		 * The assumption is that the OFMessage dispatcher will call this each
+		 * time, which it does. We don't loop and receive here.
+		 * 
+		 * @param m, The potential OFTableFeaturesStatsReply message we want to include
+		 */
+		void processOFStatsReply(OFStatsReply m) {
+			if (m.getStatsType() == OFStatsType.TABLE_FEATURES) {
+				replies.add((OFTableFeaturesStatsReply) m);
+				if (!((OFTableFeaturesStatsReply)m).getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
+					handleTableFeaturesMessage(replies, false);
+					nextState();
+				} 
+			} else {
+				/* should only receive TABLE_FEATURES here */
+				log.error("Received {} message but expected TABLE_FEATURES.", m.getStatsType().toString());
+			}
+		
+		}
+		
+		@Override
+		void processOFError(OFErrorMsg m) {
+			if ((m.getErrType() == OFErrorType.BAD_REQUEST) &&
+					((((OFBadRequestErrorMsg)m).getCode() == OFBadRequestCode.MULTIPART_BUFFER_OVERFLOW)
+					|| ((OFBadRequestErrorMsg)m).getCode() == OFBadRequestCode.BAD_STAT)) { 
+				log.warn("Switch {} is {} but does not support OFTableFeaturesStats. Assuming all tables can perform any match, action, and instruction in the spec.", 
+						sw.getId().toString(), sw.getOFFactory().getVersion().toString());
+			} else {
+				log.error("Received unexpected OFErrorMsg {} on switch {}.", m.toString(), sw.getId().toString());
+			}
+			nextState();
+			
+		}
+		
+		private void nextState() {
+			/* move on to the next state */
+			sw.startDriverHandshake();
+			if (sw.isDriverHandshakeComplete()) {
+				setState(new WaitAppHandshakeState());
+			} else {
+				setState(new WaitSwitchDriverSubHandshakeState());
+			}
+		}
+		
+		@Override
+		void enterState() {
+			if (sw.getOFFactory().getVersion().compareTo(OFVersion.OF_13) < 0) {
+				nextState();
+			} else {
+				sendHandshakeTableFeaturesRequest();
+			}
+		}
+		
+	}
 
 	public class WaitSwitchDriverSubHandshakeState extends OFSwitchHandshakeState {
 
@@ -1348,6 +1439,12 @@ public class OFSwitchHandshakeHandler implements IOFConnectionListener {
 		void processOFFlowRemoved(OFFlowRemoved m) {
 			dispatchMessage(m);
 		}
+		
+		@Override
+		void processOFStatsReply(OFStatsReply m) {
+			// TODO Auto-generated method stub
+			super.processOFStatsReply(m);
+		}
 	}
 
 	/**
@@ -1665,6 +1762,17 @@ public class OFSwitchHandshakeHandler implements IOFConnectionListener {
 				.build();
 		mainConnection.write(descStatsRequest);
 	}
+	
+	/**
+	 * send a table features request
+	 */
+	private void sendHandshakeTableFeaturesRequest() {
+		OFTableFeaturesStatsRequest tfsr = factory.buildTableFeaturesStatsRequest()
+				/* leave entries blank --> just ask, don't set */
+				.setXid(handshakeTransactionIds--)
+				.build();
+		mainConnection.write(tfsr);
+	}
 
 	OFSwitchHandshakeState getStateForTesting() {
 		return state;
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchManager.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchManager.java
index 60c32deb2c9eaf50e0aa9bfadc8066d56cb936b3..3c5ea1085267f0e30bec55659d0bdd049e5052ec 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchManager.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchManager.java
@@ -715,6 +715,11 @@ public class OFSwitchManager implements IOFSwitchManager, INewOFConnectionListen
 			log.warn("Clear switch flow tables on each transition to master: TRUE");
 			OFSwitchManager.clearTablesOnEachTransitionToMaster = true;
 		}
+		
+		String tablesToGetFTCFlow = configParams.get("addDefaultSendToControllerFlowInTables");
+		if (tablesToGetFTCFlow == null || tablesToGetFTCFlow.isEmpty()) {
+			
+		}
 	}
 
 	@Override
diff --git a/src/main/java/net/floodlightcontroller/core/internal/TableFeatures.java b/src/main/java/net/floodlightcontroller/core/internal/TableFeatures.java
new file mode 100644
index 0000000000000000000000000000000000000000..35d12883df2dc3ca09017c458f7e680ea9a8d5b7
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/TableFeatures.java
@@ -0,0 +1,442 @@
+package net.floodlightcontroller.core.internal;
+
+import java.util.List;
+
+import org.projectfloodlight.openflow.protocol.OFTableFeatureProp;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturePropApplyActions;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturePropApplyActionsMiss;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturePropApplySetfield;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturePropApplySetfieldMiss;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturePropExperimenter;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturePropExperimenterMiss;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturePropInstructions;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturePropInstructionsMiss;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturePropMatch;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturePropNextTables;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturePropNextTablesMiss;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturePropTableSyncFrom;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturePropType;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturePropWildcards;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturePropWriteActions;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturePropWriteActionsMiss;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturePropWriteSetfield;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturePropWriteSetfieldMiss;
+import org.projectfloodlight.openflow.protocol.OFTableFeatures;
+import org.projectfloodlight.openflow.protocol.ver13.OFTableFeaturePropTypeSerializerVer13;
+import org.projectfloodlight.openflow.protocol.ver14.OFTableFeaturePropTypeSerializerVer14;
+import org.projectfloodlight.openflow.types.TableId;
+import org.projectfloodlight.openflow.types.U64;
+
+/**
+ * A small, immutable container for organizing the features of a
+ * particular table on a switch. OFTableFeatures is pretty much the 
+ * same, but it doesn't easily expose the properties for quick access.
+ * 
+ * This class will sacrifice the added time to instantiate instead
+ * of during each access to a particular property. Had the properties
+ * been in a Map of some sort, this might not be necessary. The
+ * assumption is that we won't ever change switch table properties
+ * frequently. It's more of a setup/initialization task. Otherwise,
+ * frequently making these would be quite inefficient considering
+ * the amount of data within and the number of tables switches can have.
+ * 
+ * <b> FIXME: OFTableFeatureProp types don't override equals in Loxi... </b>
+ * 
+ * @author Ryan Izard, rizard@g.clemson.edu, ryan.izard@bigswitch.com
+ *
+ */
+public class TableFeatures {
+	/* OF1.3+ */
+	private OFTableFeaturePropApplyActions aa;
+	private OFTableFeaturePropApplyActionsMiss aam;
+	private OFTableFeaturePropApplySetfield asf;
+	private OFTableFeaturePropApplySetfieldMiss asfm;
+	private OFTableFeaturePropExperimenter e;
+	private OFTableFeaturePropExperimenterMiss em;
+	private OFTableFeaturePropInstructions i;
+	private OFTableFeaturePropInstructionsMiss im;
+	private OFTableFeaturePropMatch m;
+	private OFTableFeaturePropNextTables nt;
+	private OFTableFeaturePropNextTablesMiss ntm;
+	private OFTableFeaturePropWildcards w;
+	private OFTableFeaturePropWriteActions wa;
+	private OFTableFeaturePropWriteActionsMiss wam;
+	private OFTableFeaturePropWriteSetfield wsf;
+	private OFTableFeaturePropWriteSetfieldMiss wsfm;
+	/* OF1.4+ */
+	private OFTableFeaturePropTableSyncFrom tsf;
+	
+	private long config;
+	private long maxEntries;
+	private U64 metadataMatch;
+	private U64 metadataWrite;
+	private String tableName;
+	private TableId tableId;
+	
+	/*
+	 * Loxi-style constructor for familiarity. Also eliminates
+	 * the need to use the new keyword.
+	 */
+	public static TableFeatures of(OFTableFeatures tableFeatures) {
+		return new TableFeatures(tableFeatures);
+	}
+	
+	/*
+	 * Make default constructor inaccessible. We don't set default
+	 * values so, we must start with an OFTableFeatures.
+	 */
+	private TableFeatures() {}
+	
+	/*
+	 * Called from of(OFTableFeatures tableFeatures) above.
+	 * Private to avoid confusion.
+	 */
+	private TableFeatures(OFTableFeatures tf) {
+		/*
+		 * First, get the properties.
+		 */
+		List<OFTableFeatureProp> properties = tf.getProperties();
+		for (OFTableFeatureProp p : properties) {
+			OFTableFeaturePropType pt = getTableFeaturePropType(p);
+			switch (pt) {
+			case APPLY_ACTIONS:
+				aa = (OFTableFeaturePropApplyActions) p;
+				break;
+			case APPLY_ACTIONS_MISS:
+				aam = (OFTableFeaturePropApplyActionsMiss) p;
+				break;
+			case APPLY_SETFIELD:
+				asf = (OFTableFeaturePropApplySetfield) p;
+				break;
+			case APPLY_SETFIELD_MISS:
+				asfm = (OFTableFeaturePropApplySetfieldMiss) p;
+				break;
+			case EXPERIMENTER:
+				e = (OFTableFeaturePropExperimenter) p;
+				break;
+			case EXPERIMENTER_MISS:
+				em = (OFTableFeaturePropExperimenterMiss) p;
+				break;
+			case INSTRUCTIONS:
+				i = (OFTableFeaturePropInstructions) p;
+				break;
+			case INSTRUCTIONS_MISS:
+				im = (OFTableFeaturePropInstructionsMiss) p;
+				break;
+			case MATCH:
+				m = (OFTableFeaturePropMatch) p;
+				break;
+			case NEXT_TABLES:
+				nt = (OFTableFeaturePropNextTables) p;
+				break;
+			case NEXT_TABLES_MISS:
+				ntm = (OFTableFeaturePropNextTablesMiss) p;
+				break;
+			case TABLE_SYNC_FROM:
+				tsf = (OFTableFeaturePropTableSyncFrom) p;
+				break;
+			case WILDCARDS:
+				w = (OFTableFeaturePropWildcards) p;
+				break;
+			case WRITE_ACTIONS:
+				wa = (OFTableFeaturePropWriteActions) p;
+				break;
+			case WRITE_ACTIONS_MISS:
+				wam = (OFTableFeaturePropWriteActionsMiss) p;
+				break;
+			case WRITE_SETFIELD:
+				wsf = (OFTableFeaturePropWriteSetfield) p;
+				break;
+			case WRITE_SETFIELD_MISS:
+				wsfm = (OFTableFeaturePropWriteSetfieldMiss) p;
+				break;
+			default:
+				throw new UnsupportedOperationException("OFTableFeaturePropType " + pt.toString() + " not accounted for in " + this.getClass().getCanonicalName());
+			}
+		}
+		
+		/*
+		 * Next, get the other info e.g. name, ID, etc.
+		 */
+		config = tf.getConfig();
+		maxEntries = tf.getMaxEntries();
+		metadataMatch = tf.getMetadataMatch();
+		metadataWrite = tf.getMetadataWrite();
+		tableId = tf.getTableId();
+		tableName = tf.getName();
+	}
+	
+	/*
+	 * Internal helper function to deserialize the property type in a version-agnostic way
+	 * from the perspective of the calling function.
+	 */
+	private static OFTableFeaturePropType getTableFeaturePropType(OFTableFeatureProp p) {
+		switch (p.getVersion()) {
+		case OF_13:
+			return OFTableFeaturePropTypeSerializerVer13.ofWireValue((short) p.getType());
+		case OF_14:
+			return OFTableFeaturePropTypeSerializerVer14.ofWireValue((short) p.getType());
+		default:
+			throw new IllegalArgumentException("OFVersion " + p.getVersion().toString() + " does not support OFTableFeature messages.");
+		}
+	}
+	
+	public long getConfig() {
+		return config;
+	}
+	
+	public long getMaxEntries() {
+		return maxEntries;
+	}
+	
+	public U64 getMetadataMatch() {
+		return metadataMatch;
+	}
+	
+	public U64 getMetadataWrite() {
+		return metadataWrite;
+	}
+	
+	public String getTableName() {
+		return tableName;
+	}
+	
+	public TableId getTableId() {
+		return tableId;
+	}
+	
+	public OFTableFeaturePropApplyActions getPropApplyActions() {
+		return aa;
+	}
+	
+	public OFTableFeaturePropApplyActionsMiss getPropApplyActionsMiss() {
+		return aam;
+	}
+	
+	public OFTableFeaturePropApplySetfield getPropApplySetField() {
+		return asf;
+	}
+	
+	public OFTableFeaturePropApplySetfieldMiss getPropApplySetFieldMiss() {
+		return asfm;
+	}
+	
+	public OFTableFeaturePropExperimenter getPropExperimenter() {
+		return e;
+	}
+	
+	public OFTableFeaturePropExperimenterMiss getPropExperimenterMiss() {
+		return em;
+	}
+	
+	public OFTableFeaturePropInstructions getPropInstructions() {
+		return i;
+	}
+	
+	public OFTableFeaturePropInstructionsMiss getPropInstructionsMiss() {
+		return im;
+	}
+	
+	public OFTableFeaturePropMatch getPropMatch() {
+		return m;
+	}
+
+	public OFTableFeaturePropNextTables getPropNextTables() {
+		return nt;
+	}
+	
+	public OFTableFeaturePropNextTablesMiss getPropNextTablesMiss() {
+		return ntm;
+	}
+	
+	public OFTableFeaturePropWildcards getPropWildcards() {
+		return w;
+	}
+	
+	public OFTableFeaturePropWriteActions getPropWriteActions() {
+		return wa;
+	}
+	
+	public OFTableFeaturePropWriteActionsMiss getPropWriteActionsMiss() {
+		return wam;
+	}
+	
+	public OFTableFeaturePropWriteSetfield getPropWriteSetField() {
+		return wsf;
+	}
+	
+	public OFTableFeaturePropWriteSetfieldMiss getPropWriteSetFieldMiss() {
+		return wsfm;
+	}
+	
+	public OFTableFeaturePropTableSyncFrom getPropTableSyncFrom() {
+		return tsf;
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + ((aa == null) ? 0 : aa.hashCode());
+		result = prime * result + ((aam == null) ? 0 : aam.hashCode());
+		result = prime * result + ((asf == null) ? 0 : asf.hashCode());
+		result = prime * result + ((asfm == null) ? 0 : asfm.hashCode());
+		result = prime * result + (int) (config ^ (config >>> 32));
+		result = prime * result + ((e == null) ? 0 : e.hashCode());
+		result = prime * result + ((em == null) ? 0 : em.hashCode());
+		result = prime * result + ((i == null) ? 0 : i.hashCode());
+		result = prime * result + ((im == null) ? 0 : im.hashCode());
+		result = prime * result + ((m == null) ? 0 : m.hashCode());
+		result = prime * result + (int) (maxEntries ^ (maxEntries >>> 32));
+		result = prime * result
+				+ ((metadataMatch == null) ? 0 : metadataMatch.hashCode());
+		result = prime * result
+				+ ((metadataWrite == null) ? 0 : metadataWrite.hashCode());
+		result = prime * result + ((nt == null) ? 0 : nt.hashCode());
+		result = prime * result + ((ntm == null) ? 0 : ntm.hashCode());
+		result = prime * result + ((tableId == null) ? 0 : tableId.hashCode());
+		result = prime * result
+				+ ((tableName == null) ? 0 : tableName.hashCode());
+		result = prime * result + ((tsf == null) ? 0 : tsf.hashCode());
+		result = prime * result + ((w == null) ? 0 : w.hashCode());
+		result = prime * result + ((wa == null) ? 0 : wa.hashCode());
+		result = prime * result + ((wam == null) ? 0 : wam.hashCode());
+		result = prime * result + ((wsf == null) ? 0 : wsf.hashCode());
+		result = prime * result + ((wsfm == null) ? 0 : wsfm.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		TableFeatures other = (TableFeatures) obj;
+		if (aa == null) {
+			if (other.aa != null)
+				return false;
+		} else if (!aa.equals(other.aa))
+			return false;
+		if (aam == null) {
+			if (other.aam != null)
+				return false;
+		} else if (!aam.equals(other.aam))
+			return false;
+		if (asf == null) {
+			if (other.asf != null)
+				return false;
+		} else if (!asf.equals(other.asf))
+			return false;
+		if (asfm == null) {
+			if (other.asfm != null)
+				return false;
+		} else if (!asfm.equals(other.asfm))
+			return false;
+		if (config != other.config)
+			return false;
+		if (e == null) {
+			if (other.e != null)
+				return false;
+		} else if (!e.equals(other.e))
+			return false;
+		if (em == null) {
+			if (other.em != null)
+				return false;
+		} else if (!em.equals(other.em))
+			return false;
+		if (i == null) {
+			if (other.i != null)
+				return false;
+		} else if (!i.equals(other.i))
+			return false;
+		if (im == null) {
+			if (other.im != null)
+				return false;
+		} else if (!im.equals(other.im))
+			return false;
+		if (m == null) {
+			if (other.m != null)
+				return false;
+		} else if (!m.equals(other.m))
+			return false;
+		if (maxEntries != other.maxEntries)
+			return false;
+		if (metadataMatch == null) {
+			if (other.metadataMatch != null)
+				return false;
+		} else if (!metadataMatch.equals(other.metadataMatch))
+			return false;
+		if (metadataWrite == null) {
+			if (other.metadataWrite != null)
+				return false;
+		} else if (!metadataWrite.equals(other.metadataWrite))
+			return false;
+		if (nt == null) {
+			if (other.nt != null)
+				return false;
+		} else if (!nt.equals(other.nt))
+			return false;
+		if (ntm == null) {
+			if (other.ntm != null)
+				return false;
+		} else if (!ntm.equals(other.ntm))
+			return false;
+		if (tableId == null) {
+			if (other.tableId != null)
+				return false;
+		} else if (!tableId.equals(other.tableId))
+			return false;
+		if (tableName == null) {
+			if (other.tableName != null)
+				return false;
+		} else if (!tableName.equals(other.tableName))
+			return false;
+		if (tsf == null) {
+			if (other.tsf != null)
+				return false;
+		} else if (!tsf.equals(other.tsf))
+			return false;
+		if (w == null) {
+			if (other.w != null)
+				return false;
+		} else if (!w.equals(other.w))
+			return false;
+		if (wa == null) {
+			if (other.wa != null)
+				return false;
+		} else if (!wa.equals(other.wa))
+			return false;
+		if (wam == null) {
+			if (other.wam != null)
+				return false;
+		} else if (!wam.equals(other.wam))
+			return false;
+		if (wsf == null) {
+			if (other.wsf != null)
+				return false;
+		} else if (!wsf.equals(other.wsf))
+			return false;
+		if (wsfm == null) {
+			if (other.wsfm != null)
+				return false;
+		} else if (!wsfm.equals(other.wsfm))
+			return false;
+		return true;
+	}
+	
+	@Override
+	public String toString() {
+		return "TableFeatures [TableName=" + tableName + ", TableId=" + tableId
+				+ ", Config=" + config + ", MaxEntries=" + maxEntries 
+				+ ", MetadataMatch=" + metadataMatch + ", MetadataWrite=" + metadataWrite
+				+ ", ApplyActions=" + aa + ", ApplyActionsMiss=" + aam + ", ApplySetField=" + asf
+				+ ", ApplySetFieldMiss=" + asfm + ", Experimenter=" + e + ", ExperimenterMiss=" + em + ", Instructions=" + i
+				+ ", InstructionsMiss=" + im + ", Match=" + m + ", NextTable=" + nt + ", NextTableMiss=" + ntm
+				+ ", Wildcards=" + w + ", WriteActions=" + wa + ", WriteActionsMiss=" + wam + ", WriteSetField=" + wsf
+				+ ", WriteSetFieldMiss=" + wsfm + ", TableSyncFrom=" + tsf 
+				+ "]";
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/testmodule/TestModule.java b/src/main/java/net/floodlightcontroller/testmodule/TestModule.java
index 5c2c1b02ae1a2346c51f123b2578959eca6c6cfe..85fbf0f46fa1fee79dda7f06e2ca590fb7c519cb 100644
--- a/src/main/java/net/floodlightcontroller/testmodule/TestModule.java
+++ b/src/main/java/net/floodlightcontroller/testmodule/TestModule.java
@@ -10,11 +10,13 @@ import java.util.Map;
 import org.projectfloodlight.openflow.protocol.OFFactories;
 import org.projectfloodlight.openflow.protocol.OFFactory;
 import org.projectfloodlight.openflow.protocol.OFFlowAdd;
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
 import org.projectfloodlight.openflow.protocol.OFMeterBandStats;
 import org.projectfloodlight.openflow.protocol.OFMeterBandType;
 import org.projectfloodlight.openflow.protocol.OFMeterConfig;
 import org.projectfloodlight.openflow.protocol.OFMeterMod;
 import org.projectfloodlight.openflow.protocol.OFMeterModCommand;
+import org.projectfloodlight.openflow.protocol.OFMeterStatsRequest;
 import org.projectfloodlight.openflow.protocol.OFOxmClass;
 import org.projectfloodlight.openflow.protocol.OFPortDesc;
 import org.projectfloodlight.openflow.protocol.OFSetConfig;
@@ -28,8 +30,10 @@ import org.projectfloodlight.openflow.protocol.OFTableModPropEvictionFlag;
 import org.projectfloodlight.openflow.protocol.OFVersion;
 import org.projectfloodlight.openflow.protocol.action.OFAction;
 import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
+import org.projectfloodlight.openflow.protocol.action.OFActionPushVlan;
 import org.projectfloodlight.openflow.protocol.action.OFActionSetField;
 import org.projectfloodlight.openflow.protocol.action.OFActionSetNwSrc;
+import org.projectfloodlight.openflow.protocol.action.OFActions;
 import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
 import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions;
 import org.projectfloodlight.openflow.protocol.instruction.OFInstructionClearActions;
@@ -37,12 +41,14 @@ import org.projectfloodlight.openflow.protocol.instruction.OFInstructionExperime
 import org.projectfloodlight.openflow.protocol.instruction.OFInstructionGotoTable;
 import org.projectfloodlight.openflow.protocol.instruction.OFInstructionMeter;
 import org.projectfloodlight.openflow.protocol.instruction.OFInstructionWriteActions;
+import org.projectfloodlight.openflow.protocol.instruction.OFInstructions;
 import org.projectfloodlight.openflow.protocol.match.Match;
 import org.projectfloodlight.openflow.protocol.match.MatchField;
 import org.projectfloodlight.openflow.protocol.meterband.OFMeterBand;
 import org.projectfloodlight.openflow.protocol.meterband.OFMeterBandDrop;
 import org.projectfloodlight.openflow.protocol.oxm.OFOxm;
 import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthSrc;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxms;
 import org.projectfloodlight.openflow.protocol.ver13.OFMeterModCommandSerializerVer13;
 import org.projectfloodlight.openflow.types.ArpOpcode;
 import org.projectfloodlight.openflow.types.DatapathId;
@@ -126,6 +132,42 @@ public class TestModule implements IFloodlightModule, IOFSwitchListener {
 	@Override
 	public void switchAdded(DatapathId switchId) {
 		OFFactory factory = switchService.getSwitch(switchId).getOFFactory();
+		
+		/*OFFlowAdd.Builder fab = factory.buildFlowAdd();
+		fab.setMatch(factory.buildMatch().setExact(MatchField.ETH_TYPE, EthType.IPv4)
+				.setMasked(MatchField.IPV4_SRC, IPv4Address.of("10.0.123.1"), IPv4Address.of("255.255.0.255"))
+				.build());
+		fab.setBufferId(OFBufferId.NO_BUFFER);
+		if (switchId.equals(DatapathId.of(1)))
+		switchService.getSwitch(switchId).write(fab.build());*/
+		
+		OFFactory f =factory;
+        Match.Builder mb =f.buildMatch();
+        mb.setExact(MatchField.ETH_SRC, MacAddress.of(2));
+        Match m=mb.build();
+        ArrayList<OFAction> actionList = new ArrayList<OFAction>();
+        OFActions actions = f.actions();
+        OFActionPushVlan vlan =actions.pushVlan(EthType.of(0x8100));
+        actionList.add(vlan);
+
+
+        OFOxms oxms =f.oxms();
+        OFActionSetField vlanid=actions.buildSetField().setField(oxms.buildVlanVid().setValue(OFVlanVidMatch.ofVlan(10)).build()).build();
+        actionList.add(vlanid);
+        OFInstructions inst=f.instructions(); 
+        OFInstructionApplyActions apply=inst.buildApplyActions().setActions(actionList).build();
+        ArrayList<OFInstruction> instList= new ArrayList<OFInstruction>();
+        instList.add(apply);
+        OFFlowMod.Builder fmb = factory.buildFlowAdd();
+        OFFlowMod msg = fmb.setPriority(32769)
+        .setMatch(m)
+        .setInstructions(instList)
+        .setOutPort(OFPort.of(1))
+        .build();
+
+        switchService.getSwitch(switchId).write(msg);
+		
+		
 		/*
 		 * An attempt at meters, but they aren't supported anywhere, yet... 
 		 * OFMeterBand mb = factory.meterBands().buildDrop()
diff --git a/src/main/resources/logback-test.xml b/src/main/resources/logback-test.xml
index 7c9e3ea4d5bc71b948ef8bbf6caf0cafaceccbfa..2c8ca28ccbefd41c21583decb480458dc076366a 100644
--- a/src/main/resources/logback-test.xml
+++ b/src/main/resources/logback-test.xml
@@ -20,5 +20,5 @@
   <logger name="net.floodlightcontroller.routing" level="INFO"></logger>
   <logger name="net.floodlightcontroller.core.internal" level="INFO"></logger>
   <logger level="INFO" name="net.floodlightcontroller.learningswitch"></logger>
-  <logger level="INFO" name="net.floodlightcontroller.staticflowentry"></logger>
+  <logger level="INFO" name="org.projectfloodlight.openflow"></logger>
 </configuration>
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandlerTestBase.java b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandlerTestBase.java
index f9ffc92559e556b1bf3613d7d3c6b06c79b3b903..e7590df1c838b059a9bdfc33f4387bfc8aecc66b 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandlerTestBase.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandlerTestBase.java
@@ -19,6 +19,7 @@ import static org.junit.Assert.fail;
 
 import java.io.IOException;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
@@ -62,11 +63,16 @@ import org.projectfloodlight.openflow.protocol.OFPortStatus;
 import org.projectfloodlight.openflow.protocol.OFSetConfig;
 import org.projectfloodlight.openflow.protocol.OFStatsRequest;
 import org.projectfloodlight.openflow.protocol.OFStatsType;
+import org.projectfloodlight.openflow.protocol.OFTableFeatureProp;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturesStatsReply;
 import org.projectfloodlight.openflow.protocol.OFType;
 import org.projectfloodlight.openflow.protocol.match.Match;
 import org.projectfloodlight.openflow.types.DatapathId;
 import org.projectfloodlight.openflow.types.OFAuxId;
 import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.TableId;
+import org.projectfloodlight.openflow.types.U32;
+import org.projectfloodlight.openflow.types.U64;
 
 import net.floodlightcontroller.util.LinkedHashSetWrapper;
 import net.floodlightcontroller.util.OrderedCollection;
@@ -307,6 +313,25 @@ public abstract class OFSwitchHandlerTestBase {
                 .build();
         return statsReply;
     }
+    
+    protected OFTableFeaturesStatsReply createTableFeaturesStatsReply() {
+    	OFTableFeaturesStatsReply statsReply = factory.buildTableFeaturesStatsReply()
+    			.setEntries(Collections.singletonList(factory.buildTableFeatures()
+    					.setConfig(0)
+    					.setMaxEntries(100)
+    					.setMetadataMatch(U64.NO_MASK)
+    					.setMetadataWrite(U64.NO_MASK)
+    					.setName("MyTable")
+    					.setTableId(TableId.of(1))
+    					.setProperties(Collections.singletonList((OFTableFeatureProp)factory.buildTableFeaturePropMatch()
+    							.setOxmIds(Collections.singletonList(U32.of(100)))
+    							.build())
+    				).build()
+    			)
+    			
+    		).build();
+    	return statsReply;
+    }
 
     /**
      * setup the expectations for the mock switch that are needed
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandlerVer10Test.java b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandlerVer10Test.java
index cefde88995600fc48eeda697301e801f89ff5dd7..be752d0246f9075751fae5d2f321a7ee4af85ac7 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandlerVer10Test.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandlerVer10Test.java
@@ -79,6 +79,7 @@ public class OFSwitchHandshakeHandlerVer10Test extends OFSwitchHandlerTestBase {
         setupSwitchForInstantiationWithReset();
         sw.startDriverHandshake();
         expectLastCall().once();
+        expect(sw.getOFFactory()).andReturn(factory).once();
         sw.isDriverHandshakeComplete();
         expectLastCall().andReturn(switchDriverComplete).once();
 
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandlerVer13Test.java b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandlerVer13Test.java
index b830915b6bac4cea5a21c0c039c84628ced42fe0..3d78ab6fc07bc836d32f96d1b000e6696ae5e337 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandlerVer13Test.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandlerVer13Test.java
@@ -11,6 +11,7 @@ import static org.hamcrest.CoreMatchers.equalTo;
 import static org.junit.Assert.assertThat;
 
 import java.util.EnumSet;
+import java.util.List;
 
 import org.hamcrest.CoreMatchers;
 import org.hamcrest.Matchers;
@@ -20,6 +21,7 @@ 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;
 
 import org.projectfloodlight.openflow.protocol.OFCapabilities;
 import org.projectfloodlight.openflow.protocol.OFControllerRole;
@@ -33,6 +35,8 @@ import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
 import org.projectfloodlight.openflow.protocol.OFPortDescStatsRequest;
 import org.projectfloodlight.openflow.protocol.OFRoleReply;
 import org.projectfloodlight.openflow.protocol.OFRoleRequest;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturesStatsReply;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturesStatsRequest;
 import org.projectfloodlight.openflow.protocol.OFVersion;
 import org.projectfloodlight.openflow.types.DatapathId;
 import org.projectfloodlight.openflow.types.OFAuxId;
@@ -93,7 +97,7 @@ public class OFSwitchHandshakeHandlerVer13Test extends OFSwitchHandlerTestBase {
         switchHandler.processOFMessage(getPortDescStatsReply());
     }
 
-    public void handleDescStatsAndCreateSwitch(boolean subHandShakeComplete) throws Exception {
+    public void handleDescStatsAndCreateSwitch() throws Exception {
         // build the stats reply
         OFDescStatsReply sr = createDescriptionStatsReply();
 
@@ -102,9 +106,8 @@ public class OFSwitchHandshakeHandlerVer13Test extends OFSwitchHandlerTestBase {
         setupSwitchForInstantiationWithReset();
         sw.setPortDescStats(anyObject(OFPortDescStatsReply.class));
         expectLastCall().once();
-        sw.startDriverHandshake();
-        expectLastCall().once();
-        expect(sw.isDriverHandshakeComplete()).andReturn(subHandShakeComplete).once();
+       
+        expect(sw.getOFFactory()).andReturn(factory).once();
         replay(sw);
 
         reset(switchManager);
@@ -122,14 +125,43 @@ public class OFSwitchHandshakeHandlerVer13Test extends OFSwitchHandlerTestBase {
         // send the description stats reply
         switchHandler.processOFMessage(sr);
 
+        OFMessage msg = connection.retrieveMessage();
+        assertThat(msg, CoreMatchers.instanceOf(OFTableFeaturesStatsRequest.class));
+        verifyUniqueXids(msg);
+        
         verify(sw, switchManager);
     }
+    
+    public void handleTableFeatures(boolean subHandShakeComplete) throws Exception {
+    	// build the table features stats reply
+    	OFTableFeaturesStatsReply tf = createTableFeaturesStatsReply();
+    	
+    	reset(sw);
+    	sw.startDriverHandshake();
+        expectLastCall().once();
+        expect(sw.isDriverHandshakeComplete()).andReturn(subHandShakeComplete).once();
+    	sw.processOFTableFeatures(anyObject(List.class));
+    	expectLastCall().once();
+    	expect(sw.getOFFactory()).andReturn(factory).anyTimes();
+    	replay(sw);
+    	
+    	switchHandler.processOFMessage(tf);
+    }
+    
+    @Test
+    public void moveToWaitTableFeaturesReplyState() throws Exception {
+    	moveToWaitDescriptionStatReply();
+    	handleDescStatsAndCreateSwitch();
+    	
+        assertThat(switchHandler.getStateForTesting(),
+                   CoreMatchers.instanceOf(WaitTableFeaturesReplyState.class));
+    }
 
     @Test
     @Override
     public void moveToWaitAppHandshakeState() throws Exception {
-    	moveToWaitDescriptionStatReply();
-    	handleDescStatsAndCreateSwitch(true);
+    	moveToWaitTableFeaturesReplyState();
+    	handleTableFeatures(true);
     	
         assertThat(switchHandler.getStateForTesting(),
                    CoreMatchers.instanceOf(WaitAppHandshakeState.class));
@@ -186,8 +218,8 @@ public class OFSwitchHandshakeHandlerVer13Test extends OFSwitchHandlerTestBase {
     @Override
     @Test
     public void moveToWaitSwitchDriverSubHandshake() throws Exception {
-        moveToWaitDescriptionStatReply();
-        handleDescStatsAndCreateSwitch(false);
+        moveToWaitTableFeaturesReplyState();
+        handleTableFeatures(false); //TODO
 
         assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitSwitchDriverSubHandshakeState.class));
         assertThat("Unexpected message captured", connection.getMessages(), Matchers.empty());
diff --git a/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java b/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java
index 338a013a064115eeffa11c7ab739ec38ad7ef72d..c11a14372eb33ad7d007e6d75c05bb2d1d68cc73 100644
--- a/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java
+++ b/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java
@@ -30,6 +30,7 @@ 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.TableFeatures;
 
 import org.projectfloodlight.openflow.protocol.OFActionType;
 import org.projectfloodlight.openflow.protocol.OFCapabilities;
@@ -42,6 +43,7 @@ import org.projectfloodlight.openflow.protocol.OFStatsReply;
 import org.projectfloodlight.openflow.protocol.OFStatsRequest;
 import org.projectfloodlight.openflow.types.DatapathId;
 import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.TableId;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.util.concurrent.ListenableFuture;
@@ -334,4 +336,10 @@ public class OFMessageDamperMockSwitch implements IOFSwitch {
 		// TODO Auto-generated method stub
 		return null;
 	}
+
+	@Override
+	public TableFeatures getTableFeatures(TableId table) {
+		// TODO Auto-generated method stub
+		return null;
+	}
 }