Makefile and nss_qdisc modifications to enable qdiscs via the new APIs
Fix debug statements in nss_phys_if and nss_virt_if
Fix bugs in nss_if.[c|h] files

Change-Id: I7d383cb88997bf60eeb002e987fd8ec12d512600
Signed-off-by: Sakthi Vignesh Radhakrishnan <sradhakr@codeaurora.org>
diff --git a/nss_qdisc.c b/nss_qdisc.c
index cbb0ef2..9bf67b2 100755
--- a/nss_qdisc.c
+++ b/nss_qdisc.c
@@ -94,17 +94,18 @@
 	void *nss_shaping_ctx;			/* NSS context for general operations */
 	int32_t nss_interface_number;		/* NSS Interface number we are shaping on */
 	nss_shaper_node_type_t type;		/* Type of shaper node */
+	bool is_class;				/* True if this represents a class and not a qdisc */
 	bool is_root;				/* True if root qdisc on a net device */
 	bool is_bridge;				/* True when qdisc is a bridge */
-	bool is_virtual;			/* True when this is a non-bridge qdisc BUT
-						 * the device is represented as a virtual in
-						 * the NSS e.g. perhaps operating on a wifi interface.
+	bool is_virtual;			/* True when the device is represented as a virtual in
+						 * the NSS e.g. perhaps operating on a wifi interface
+						 * or bridge.
 						 */
 	bool destroy_virtual_interface;		/* Set if the interface is first registered in NSS by
 						 * us. This means it needs to be un-regisreted when the
 						 * module goes down.
 						 */
-	volatile atomic_t state;		/* < 0: Signal that qdisc has 'failed'. 0
+	atomic_t state;				/* < 0: Signal that qdisc has 'failed'. 0
 						 * indicates 'pending' setup.  > 0 is READY.
 						 * NOTE: volatile AND atomic - this is polled
 						 * AND is used for syncronisation.
@@ -126,13 +127,20 @@
 						 * shaping purposes, and is returned to
 						 * Linux for transmit.
 						 */
-	void (*stats_update_callback)(void *, struct nss_shaper_response *);
-						/* Stats update callback function for qdisc specific
-						 * stats update
+	spinlock_t bounce_protection_lock;	/* Lock to protect the enqueue and dequeue
+						 * operation on skb lists triggeret by bounce
+						 * callbacks.
 						 */
+	void (*stats_update_callback)(void *, struct nss_shaper_configure *);
+						/* Stats update callback function for qdisc specific
+						 * stats update. Currently unused.
+						 */
+	struct gnet_stats_basic_packed bstats;	/* Basic class statistics */
+	struct gnet_stats_queue qstats;		/* Qstats for use by classes */
+	atomic_t refcnt;			/* Reference count for class use */
 	struct timer_list stats_get_timer;	/* Timer used to poll for stats */
 	atomic_t pending_stat_requests;		/* Number of pending stats responses */
-	struct nss_shaper_response_shaper_node_basic_stats_get_success basic_stats_latest;
+	struct nss_shaper_shaper_node_basic_stats_get basic_stats_latest;
 						/* Latest stats obtained */
 };
 
@@ -146,61 +154,109 @@
 };
 
 /*
- * nssqdisc bridge task types
+ * Task types for bridge scanner.
  */
 enum nssqdisc_bshaper_tasks {
-	NSSQDISC_ASSIGN_BSHAPER,
-	NSSQDISC_UNASSIGN_BSHAPER,
+	NSSQDISC_SCAN_AND_ASSIGN_BSHAPER,
+	NSSQDISC_SCAN_AND_UNASSIGN_BSHAPER,
 };
 
 /*
+ * Types of messages sent down to NSS interfaces
+ */
+enum nssqdisc_interface_msgs {
+	NSSQDISC_IF_SHAPER_ASSIGN,
+	NSSQDISC_IF_SHAPER_UNASSIGN,
+	NSSQDISC_IF_SHAPER_CONFIG,
+};
+
+/*
+ * nssqdisc_get_interface_msg()
+ *	Returns the correct message that needs to be sent down to the NSS interface.
+ */
+static inline int nssqdisc_get_interface_msg(bool is_bridge, uint32_t msg_type)
+{
+	/*
+	 * We re-assign the message based on whether this is for the I shaper
+	 * or the B shaper. The is_bridge flag tells if we are on a bridge interface.
+	 */
+	if (is_bridge) {
+		switch(msg_type) {
+		case NSSQDISC_IF_SHAPER_ASSIGN:
+			return NSS_IF_BSHAPER_ASSIGN;
+		case NSSQDISC_IF_SHAPER_UNASSIGN:
+			return NSS_IF_BSHAPER_UNASSIGN;
+		case NSSQDISC_IF_SHAPER_CONFIG:
+			return NSS_IF_BSHAPER_CONFIG;
+		default:
+			nssqdisc_info("%s: Unknown message type for a bridge - type %d", __func__, msg_type);
+			return -1;
+		}
+	} else {
+		switch(msg_type) {
+		case NSSQDISC_IF_SHAPER_ASSIGN:
+			return NSS_IF_ISHAPER_ASSIGN;
+		case NSSQDISC_IF_SHAPER_UNASSIGN:
+			return NSS_IF_ISHAPER_UNASSIGN;
+		case NSSQDISC_IF_SHAPER_CONFIG:
+			return NSS_IF_ISHAPER_CONFIG;
+		default:
+			nssqdisc_info("%s: Unknown message type for an interface - type %d", __func__, msg_type);
+			return -1;
+		}
+	}
+}
+
+/*
  * nssqdisc_get_br_port()
  * 	Returns the bridge port structure of the bridge to which the device is attached to.
  */
 static inline struct net_bridge_port *nssqdisc_get_br_port(const struct net_device *dev)
 {
-        struct net_bridge_port *br_port;
+	struct net_bridge_port *br_port;
 
-        if (!dev)
-                return NULL;
+	if (!dev) {
+		return NULL;
+	}
 
-        rcu_read_lock();
+	rcu_read_lock();
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
-        br_port = br_port_get_rcu(dev);
+	br_port = br_port_get_rcu(dev);
 #else
 	br_port = rcu_dereference(dev->br_port);
 #endif
-        rcu_read_unlock();
+	rcu_read_unlock();
 
-        return br_port;
+	return br_port;
 }
 
 /*
  * nssqdisc_attach_bshaper_callback()
  *	Call back funtion for bridge shaper attach to an interface.
  */
-static void nssqdisc_attach_bshaper_callback(void *app_data, struct nss_shaper_response *response)
+static void nssqdisc_attach_bshaper_callback(void *app_data, struct nss_if_msg *nim)
 {
 	struct Qdisc *sch = (struct Qdisc *)app_data;
 	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
 
-	if (response->type < 0) {
-		nssqdisc_info("%s: B-shaper attach FAILED - response: %d\n", __func__, response->type);
+	if (nim->cm.response != NSS_CMN_RESPONSE_ACK) {
+		nssqdisc_warning("%s: B-shaper attach FAILED - response: %d\n", __func__,
+				nim->cm.error);
 		atomic_set(&nq->state, NSSQDISC_STATE_FAILED_RESPONSE);
 		return;
 	}
 
-	nssqdisc_info("%s: B-shaper attach SUCCESS - response %d\n", __func__, response->type);
+	nssqdisc_info("%s: B-shaper attach SUCCESS\n", __func__);
 	atomic_set(&nq->state, NSSQDISC_STATE_READY);
 }
 
 /*
  * nssqdisc_attach_bridge()
- *	Attaches a given bridge shaper to a given interface.
+ *	Attaches a given bridge shaper to a given interface (Different from shaper_assign)
  */
 static int nssqdisc_attach_bshaper(struct Qdisc *sch, uint32_t if_num)
 {
-	struct nss_shaper_configure shaper_assign;
+	struct nss_if_msg nim;
 	struct nssqdisc_qdisc *nq = (struct nssqdisc_qdisc *)qdisc_priv(sch);
 	int32_t state, rc;
 
@@ -219,18 +275,22 @@
 	 */
 	atomic_set(&nq->state, NSSQDISC_STATE_IDLE);
 
-	shaper_assign.interface_num = if_num;
-	shaper_assign.i_shaper = false;
-	shaper_assign.cb = nssqdisc_attach_bshaper_callback;
-	shaper_assign.app_data = sch;
-	shaper_assign.owner = THIS_MODULE;
-	shaper_assign.type = NSS_SHAPER_CONFIG_TYPE_ASSIGN_SHAPER;
-	shaper_assign.mt.unassign_shaper.shaper_num = nq->shaper_id;
+	/*
+	 * Populate the message and send it down
+	 */
+	nss_cmn_msg_init(&nim.cm, if_num, NSS_IF_BSHAPER_ASSIGN,
+				sizeof(struct nss_if_msg), nssqdisc_attach_bshaper_callback, sch);
+	/*
+	 * Assign the ID of the Bshaper that needs to be assigned to the interface recognized
+	 * by if_num.
+	 */
+	nim.msg.shaper_assign.shaper_id = nq->shaper_id;
+	rc = nss_if_tx_msg(nq->nss_shaping_ctx, &nim);
 
-	rc = nss_shaper_config_send(nq->nss_shaping_ctx, &shaper_assign);
 	if (rc != NSS_TX_SUCCESS) {
 		nssqdisc_warning("%s: Failed to send bshaper (id: %u) attach for "
 				"interface(if_num: %u)\n", __func__, nq->shaper_id, if_num);
+		atomic_set(&nq->state, NSSQDISC_STATE_READY);
 		return -1;
 	}
 
@@ -241,11 +301,13 @@
 	if (state == NSSQDISC_STATE_FAILED_RESPONSE) {
 		nssqdisc_error("%s: Failed to attach B-shaper %u to interface %u\n",
 				__func__, nq->shaper_id, if_num);
+		atomic_set(&nq->state, NSSQDISC_STATE_READY);
 		return -1;
 	}
 
 	nssqdisc_info("%s: Attach of B-shaper %u to interface %u is complete\n",
 			__func__, nq->shaper_id, if_num);
+	atomic_set(&nq->state, NSSQDISC_STATE_READY);
 	return 0;
 }
 
@@ -253,14 +315,14 @@
  * nssqdisc_detach_bshaper_callback()
  *	Call back function for bridge shaper detach
  */
-static void nssqdisc_detach_bshaper_callback(void *app_data, struct nss_shaper_response *response)
+static void nssqdisc_detach_bshaper_callback(void *app_data, struct nss_if_msg *nim)
 {
 	struct Qdisc *sch = (struct Qdisc *)app_data;
 	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
 
-	if (response->type < 0) {
-		nssqdisc_info("%s: B-shaper detach FAILED - response: %d\n",
-				__func__, response->type);
+	if (nim->cm.response != NSS_CMN_RESPONSE_ACK) {
+		nssqdisc_error("%s: B-shaper detach FAILED - response: %d\n",
+				__func__, nim->cm.error);
 		atomic_set(&nq->state, NSSQDISC_STATE_FAILED_RESPONSE);
 		return;
 	}
@@ -271,11 +333,11 @@
 
 /*
  * nssqdisc_detach_bridge()
- *	Detaches a given bridge shaper from a given interface
+ *	Detaches a given bridge shaper from a given interface (different from shaper unassign)
  */
 static int nssqdisc_detach_bshaper(struct Qdisc *sch, uint32_t if_num)
 {
-	struct nss_shaper_configure shaper_assign;
+	struct nss_if_msg nim;
 	struct nssqdisc_qdisc *nq = (struct nssqdisc_qdisc *)qdisc_priv(sch);
 	int32_t state, rc;
 
@@ -294,18 +356,18 @@
 	 */
 	atomic_set(&nq->state, NSSQDISC_STATE_IDLE);
 
-	shaper_assign.interface_num = if_num;
-	shaper_assign.i_shaper = false;
-	shaper_assign.cb = nssqdisc_detach_bshaper_callback;
-	shaper_assign.app_data = sch;
-	shaper_assign.owner = THIS_MODULE;
-	shaper_assign.type = NSS_SHAPER_CONFIG_TYPE_UNASSIGN_SHAPER;
-	shaper_assign.mt.unassign_shaper.shaper_num = nq->shaper_id;
+	/*
+	 * Create and send shaper unassign message to the NSS interface
+	 */
+	nss_cmn_msg_init(&nim.cm, if_num, NSS_IF_BSHAPER_UNASSIGN,
+				sizeof(struct nss_if_msg), nssqdisc_detach_bshaper_callback, sch);
+	nim.msg.shaper_unassign.shaper_id = nq->shaper_id;
+	rc = nss_if_tx_msg(nq->nss_shaping_ctx, &nim);
 
-	rc = nss_shaper_config_send(nq->nss_shaping_ctx, &shaper_assign);
 	if (rc != NSS_TX_SUCCESS) {
 		nssqdisc_warning("%s: Failed to send B-shaper (id: %u) detach "
 			"for interface(if_num: %u)\n", __func__, nq->shaper_id, if_num);
+		atomic_set(&nq->state, NSSQDISC_STATE_READY);
 		return -1;
 	}
 
@@ -370,7 +432,7 @@
 			goto nextdev;
 		}
 
-		nssqdisc_info("%s: Will be linking %s to bridge %s\n", __func__,
+		nssqdisc_info("%s: Will be linking/unlinking %s to/from bridge %s\n", __func__,
 				dev->name, br_dev->name);
 		br_update.port_list[br_update.port_list_count++] = nss_if_num;
 nextdev:
@@ -380,7 +442,7 @@
 
 	nssqdisc_info("%s: List count %d\n", __func__, br_update.port_list_count);
 
-	if (task == NSSQDISC_ASSIGN_BSHAPER) {
+	if (task == NSSQDISC_SCAN_AND_ASSIGN_BSHAPER) {
 		/*
 		 * Loop through the ports and assign them with B-shapers.
 		 */
@@ -416,7 +478,7 @@
 
 		nssqdisc_info("%s: Failed to link interfaces to bridge\n", __func__);
 		return -1;
-	} else if (task == NSSQDISC_UNASSIGN_BSHAPER) {
+	} else if (task == NSSQDISC_SCAN_AND_UNASSIGN_BSHAPER) {
 		/*
 		 * Loop through the ports and assign them with B-shapers.
 		 */
@@ -441,10 +503,8 @@
  *	Performs final cleanup of a root shaper node after all other
  *	shaper node cleanup is complete.
  */
-static void nssqdisc_root_cleanup_final(struct Qdisc *sch)
+static void nssqdisc_root_cleanup_final(struct nssqdisc_qdisc *nq)
 {
-	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
-
 	nssqdisc_info("%s: Root qdisc %p (type %d) final cleanup\n", __func__,
 				nq->qdisc, nq->type);
 
@@ -458,7 +518,7 @@
 	 	 */
 		nssqdisc_info("%s: Unregister for bridge bouncing: %p\n", __func__,
 				nq->bounce_context);
-		nss_unregister_shaper_bounce_bridge(nq->nss_interface_number);
+		nss_shaper_unregister_shaper_bounce_bridge(nq->nss_interface_number);
 
 		/*
 		 * Unregister the virtual interface we use to act as shaper
@@ -470,23 +530,24 @@
 	}
 
 	/*
-	 * If we are a virual interface then we have to unregister for interface
-	 * bouncing.
+	 * If we are a virual interface other than a bridge then we simply
+	 * unregister for interface bouncing and not care about deleting the
+	 * interface.
 	 */
-	if (nq->is_virtual) {
+	if (nq->is_virtual && !nq->is_bridge) {
 		/*
 		 * Unregister for interface bouncing of packets
 	 	 */
 		nssqdisc_info("%s: Unregister for interface bouncing: %p\n",
 				__func__, nq->bounce_context);
-		nss_unregister_shaper_bounce_interface(nq->nss_interface_number);
+		nss_shaper_unregister_shaper_bounce_interface(nq->nss_interface_number);
 	}
 
 	/*
 	 * Finally unregister for shaping
 	 */
 	nssqdisc_info("%s: Unregister for shaping\n", __func__);
-	nss_unregister_shaping(nq->nss_shaping_ctx);
+	nss_shaper_unregister_shaping(nq->nss_shaping_ctx);
 
 	/*
 	 * Now set our final state
@@ -499,45 +560,43 @@
  *	Invoked on the response to a shaper unassign config command issued
  */
 static void nssqdisc_root_cleanup_shaper_unassign_callback(void *app_data,
-					struct nss_shaper_response *response)
+							struct nss_if_msg *nim)
 {
-	struct Qdisc *sch = (struct Qdisc *)app_data;
-	struct nssqdisc_qdisc *nq __attribute__ ((unused)) = qdisc_priv(sch);
-	nssqdisc_info("%s: Root qdisc %p (type %d) shaper unsassign "
-		"response: %d\n", __func__, sch, nq->type, response->type);
-	nssqdisc_root_cleanup_final(sch);
+	struct nssqdisc_qdisc *nq = (struct nssqdisc_qdisc *)app_data;
+	if (nim->cm.response != NSS_CMN_RESPONSE_ACK) {
+		nssqdisc_error("%s: Root qdisc %p (type %d) shaper unsassign FAILED\n", __func__, nq->qdisc, nq->type);
+		BUG();
+	}
+	nssqdisc_root_cleanup_final(nq);
 }
 
 /*
  * nssqdisc_root_cleanup_shaper_unassign()
  *	Issue command to unassign the shaper
  */
-static void nssqdisc_root_cleanup_shaper_unassign(struct Qdisc *sch)
+static void nssqdisc_root_cleanup_shaper_unassign(struct nssqdisc_qdisc *nq)
 {
-	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
-	struct nss_shaper_configure shaper_unassign;
+	struct nss_if_msg nim;
 	nss_tx_status_t rc;
+	int msg_type;
 
 	nssqdisc_info("%s: Root qdisc %p (type %d): shaper unassign: %d\n",
-			__func__, sch, nq->type, nq->shaper_id);
+			__func__, nq->qdisc, nq->type, nq->shaper_id);
 
-	shaper_unassign.interface_num = nq->nss_interface_number;
-	shaper_unassign.i_shaper = (nq->is_bridge)? false : true;
-	shaper_unassign.cb = nssqdisc_root_cleanup_shaper_unassign_callback;
-	shaper_unassign.app_data = sch;
-	shaper_unassign.owner = THIS_MODULE;
-	shaper_unassign.type = NSS_SHAPER_CONFIG_TYPE_UNASSIGN_SHAPER;
-	shaper_unassign.mt.unassign_shaper.shaper_num = nq->shaper_id;
+	msg_type = nssqdisc_get_interface_msg(nq->is_bridge, NSSQDISC_IF_SHAPER_UNASSIGN);
+	nss_cmn_msg_init(&nim.cm, nq->nss_interface_number, msg_type,
+				sizeof(struct nss_if_msg), nssqdisc_root_cleanup_shaper_unassign_callback, nq);
+	nim.msg.shaper_unassign.shaper_id = nq->shaper_id;
+	rc = nss_if_tx_msg(nq->nss_shaping_ctx, &nim);
 
-	rc = nss_shaper_config_send(nq->nss_shaping_ctx, &shaper_unassign);
 	if (rc == NSS_TX_SUCCESS) {
 		return;
 	}
 
 	nssqdisc_error("%s: Root qdisc %p (type %d): unassign command send failed: "
-		"%d, shaper id: %d\n", __func__, sch, nq->type, rc, nq->shaper_id);
+		"%d, shaper id: %d\n", __func__, nq->qdisc, nq->type, rc, nq->shaper_id);
 
-	nssqdisc_root_cleanup_final(sch);
+	nssqdisc_root_cleanup_final(nq);
 }
 
 /*
@@ -545,50 +604,58 @@
  *	Invoked on the response to freeing a shaper node
  */
 static void nssqdisc_root_cleanup_free_node_callback(void *app_data,
-				struct nss_shaper_response *response)
+						struct nss_if_msg *nim)
 {
-	struct Qdisc *sch = (struct Qdisc *)app_data;
-	struct nssqdisc_qdisc *nq __attribute__ ((unused)) = qdisc_priv(sch);
-	nssqdisc_info("%s: Root qdisc %p (type %d) free response "
-		"type: %d\n", __func__, sch, nq->type, response->type);
+	struct nssqdisc_qdisc *nq = (struct nssqdisc_qdisc *)app_data;
+	if (nim->cm.response != NSS_CMN_RESPONSE_ACK) {
+		nssqdisc_error("%s: Root qdisc %p (type %d) free FAILED response "
+				"type: %d\n", __func__, nq->qdisc, nq->type,
+				nim->msg.shaper_configure.config.response_type);
+		BUG();
+	}
 
-	nssqdisc_root_cleanup_shaper_unassign(sch);
+	nssqdisc_info("%s: Root qdisc %p (type %d) free SUCCESS - response "
+			"type: %d\n", __func__, nq->qdisc, nq->type,
+			nim->msg.shaper_configure.config.response_type);
+
+	nssqdisc_root_cleanup_shaper_unassign(nq);
 }
 
 /*
  * nssqdisc_root_cleanup_free_node()
  *	Free the shaper node, issue command to do so.
  */
-static void nssqdisc_root_cleanup_free_node(struct Qdisc *sch)
+static void nssqdisc_root_cleanup_free_node(struct nssqdisc_qdisc *nq)
 {
-	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
-	struct nss_shaper_configure shaper_node_free;
+	struct nss_if_msg nim;
 	nss_tx_status_t rc;
+	int msg_type;
 
 	nssqdisc_info("%s: Root qdisc %p (type %d): freeing shaper node\n",
-			__func__, sch, nq->type);
+			__func__, nq->qdisc, nq->type);
 
-	shaper_node_free.interface_num = nq->nss_interface_number;
-	shaper_node_free.i_shaper = (nq->is_bridge)? false : true;
-	shaper_node_free.cb = nssqdisc_root_cleanup_free_node_callback;
-	shaper_node_free.app_data = sch;
-	shaper_node_free.owner = THIS_MODULE;
-	shaper_node_free.type = NSS_SHAPER_CONFIG_TYPE_FREE_SHAPER_NODE;
-	shaper_node_free.mt.free_shaper_node.qos_tag = nq->qos_tag;
+	/*
+	 * Construct and send the shaper configure message down to the NSS interface
+	 */
+	msg_type = nssqdisc_get_interface_msg(nq->is_bridge, NSSQDISC_IF_SHAPER_CONFIG);
+	nss_cmn_msg_init(&nim.cm, nq->nss_interface_number, msg_type,
+				sizeof(struct nss_if_msg), nssqdisc_root_cleanup_free_node_callback, nq);
+	nim.msg.shaper_configure.config.request_type = NSS_SHAPER_CONFIG_TYPE_FREE_SHAPER_NODE;
+	nim.msg.shaper_configure.config.msg.free_shaper_node.qos_tag = nq->qos_tag;
+	rc = nss_if_tx_msg(nq->nss_shaping_ctx, &nim);
 
-	rc = nss_shaper_config_send(nq->nss_shaping_ctx, &shaper_node_free);
 	if (rc == NSS_TX_SUCCESS) {
 		return;
 	}
 
 	nssqdisc_error("%s: Qdisc %p (type %d): free command send "
-		"failed: %d, qos tag: %x\n", __func__, sch, nq->type,
+		"failed: %d, qos tag: %x\n", __func__, nq->qdisc, nq->type,
 		rc, nq->qos_tag);
 
 	/*
 	 * Move onto unassigning the shaper instead
 	 */
-	nssqdisc_root_cleanup_shaper_unassign(sch);
+	nssqdisc_root_cleanup_shaper_unassign(nq);
 }
 
 /*
@@ -596,36 +663,21 @@
  *	Invoked on the response to assigning shaper node as root
  */
 static void nssqdisc_root_init_root_assign_callback(void *app_data,
-				struct nss_shaper_response *response)
+						struct nss_if_msg *nim)
 {
-	struct Qdisc *sch = (struct Qdisc *)app_data;
-	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
+	struct nssqdisc_qdisc *nq = (struct nssqdisc_qdisc *)app_data;
 
-	nssqdisc_info("%s: Root assign response for qdisc %p (type %d), "
-		"response type: %d\n", __func__, sch, nq->type, response->type);
-
-	if (response->type < 0) {
+	if (nim->cm.response != NSS_CMN_RESPONSE_ACK) {
+		nssqdisc_error("%s: Root assign FAILED for qdisc %p (type %d), "
+			"response type: %d\n", __func__, nq->qdisc, nq->type,
+			nim->msg.shaper_configure.config.response_type);
 		nq->pending_final_state = NSSQDISC_STATE_ROOT_SET_FAIL;
-		nssqdisc_root_cleanup_free_node(sch);
+		nssqdisc_root_cleanup_free_node(nq);
 		return;
 	}
 
-	/*
-	 * If we are not a root upon a bridge then we are ready
-	 */
-	if (!nq->is_bridge) {
-		nssqdisc_info("%s: Qdisc %p (type %d): set as root and "
-			"default, and is READY\n", __func__, sch, nq->type);
-		atomic_set(&nq->state, NSSQDISC_STATE_READY);
-		return;
-	}
-
-	/*
-	 * We need to scan the bridge for ports that must have shapers
-	 * assigned to them
-	 */
-	nssqdisc_info("%s: Qdisc %p (type %d): set as root is done. "
-		"Bridge update..\n", __func__, sch, nq->type);
+	nssqdisc_info("%s: Qdisc %p (type %d): set as root is done. Response - %d"
+			, __func__, nq->qdisc, nq->type, nim->msg.shaper_configure.config.response_type);
 
 	atomic_set(&nq->state, NSSQDISC_STATE_READY);
 }
@@ -635,40 +687,36 @@
  *	Invoked on the response to creating a shaper node as root
  */
 static void nssqdisc_root_init_alloc_node_callback(void *app_data,
-				struct nss_shaper_response *response)
+						struct nss_if_msg *nim)
 {
-	struct Qdisc *sch = (struct Qdisc *)app_data;
-	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
-	struct nss_shaper_configure root_assign;
+	struct nssqdisc_qdisc *nq = (struct nssqdisc_qdisc *)app_data;
 	nss_tx_status_t rc;
+	int msg_type;
 
-	nssqdisc_info("%s: Qdisc %p (type %d) root alloc node "
-		"response type: %d\n", __func__, sch, nq->type,
-		response->type);
+	if (nim->cm.response != NSS_CMN_RESPONSE_ACK) {
+		nssqdisc_info("%s: Qdisc %p (type %d) root alloc node FAILED "
+			"response type: %d\n", __func__, nq->qdisc, nq->type,
+			nim->msg.shaper_configure.config.response_type);
 
-	if (response->type < 0) {
 		nq->pending_final_state = NSSQDISC_STATE_NODE_ALLOC_FAIL;
 
 		/*
 		 * No shaper node created, cleanup from unsassigning the shaper
 		 */
-		nssqdisc_root_cleanup_shaper_unassign(sch);
+		nssqdisc_root_cleanup_shaper_unassign(nq);
 		return;
 	}
 
 	/*
-	 * Shaper node has been allocated. Next step is to assign
-	 * the shaper node as the root node of our shaper.
+	 * Create and send shaper configure message to the NSS interface
 	 */
-	root_assign.interface_num = nq->nss_interface_number;
-	root_assign.i_shaper = (nq->is_bridge)? false : true;
-	root_assign.cb = nssqdisc_root_init_root_assign_callback;
-	root_assign.app_data = sch;
-	root_assign.owner = THIS_MODULE;
-	root_assign.type = NSS_SHAPER_CONFIG_TYPE_SET_ROOT;
-	root_assign.mt.set_root_node.qos_tag = nq->qos_tag;
+	msg_type = nssqdisc_get_interface_msg(nq->is_bridge, NSSQDISC_IF_SHAPER_CONFIG);
+	nss_cmn_msg_init(&nim->cm, nq->nss_interface_number, msg_type,
+				sizeof(struct nss_if_msg), nssqdisc_root_init_root_assign_callback, nq);
+	nim->msg.shaper_configure.config.request_type = NSS_SHAPER_CONFIG_TYPE_SET_ROOT;
+	nim->msg.shaper_configure.config.msg.set_root_node.qos_tag = nq->qos_tag;
+	rc = nss_if_tx_msg(nq->nss_shaping_ctx, nim);
 
-	rc = nss_shaper_config_send(nq->nss_shaping_ctx, &root_assign);
 	if (rc == NSS_TX_SUCCESS) {
 		return;
 	}
@@ -677,7 +725,7 @@
 			__func__, rc);
 
 	nq->pending_final_state = NSSQDISC_STATE_ROOT_SET_SEND_FAIL;
-	nssqdisc_root_cleanup_free_node(sch);
+	nssqdisc_root_cleanup_free_node(nq);
 }
 
 /*
@@ -685,46 +733,55 @@
  *	Invoked on the response to a shaper assign config command issued
  */
 static void nssqdisc_root_init_shaper_assign_callback(void *app_data,
-				struct nss_shaper_response *response)
+						struct nss_if_msg *nim)
 {
-	struct Qdisc *sch = (struct Qdisc *)app_data;
-	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
-	struct nss_shaper_configure shaper_node_create;
+	struct nssqdisc_qdisc *nq = (struct nssqdisc_qdisc *)app_data;
 	nss_tx_status_t rc;
+	int msg_type;
 
-	nssqdisc_info("%s: Qdisc %p (type %d): shaper assign response type: %d\n",
-					__func__, sch, nq->type, response->type);
-
-	if (response->type < 0) {
+	if (nim->cm.response != NSS_CMN_RESPONSE_ACK) {
+		nssqdisc_warning("%s: Qdisc %x (type %d): shaper assign failed - phys_if response type: %d\n",
+			__func__, nq->qos_tag, nq->type, nim->cm.error);
 		/*
 		 * Unable to assign a shaper, perform cleanup from final stage
 		 */
 		nq->pending_final_state = NSSQDISC_STATE_SHAPER_ASSIGN_FAILED;
-		nssqdisc_root_cleanup_final(sch);
+		nssqdisc_root_cleanup_final(nq);
 		return;
 	}
 
+	if (nim->cm.type != NSS_IF_ISHAPER_ASSIGN && nim->cm.type != NSS_IF_BSHAPER_ASSIGN) {
+		nssqdisc_error("%s: Qdisc %x (type %d): shaper assign callback received garbage: %d\n",
+			__func__, nq->qos_tag, nq->type, nim->cm.type);
+		/*
+		 * Unable to assign a shaper, perform cleanup from final stage
+		 */
+		nq->pending_final_state = NSSQDISC_STATE_SHAPER_ASSIGN_FAILED;
+		nssqdisc_root_cleanup_final(nq);
+		return;
+	} else {
+		nssqdisc_error("%s: Qdisc %x (type %d): shaper assign callback received sane message: %d\n",
+			__func__, nq->qos_tag, nq->type, nim->cm.type);
+	}
+
 	/*
 	 * Shaper has been allocated and assigned
 	 */
-	nq->shaper_id = response->rt.shaper_assign_success.shaper_num;
+	nq->shaper_id = nim->msg.shaper_assign.new_shaper_id;
 	nssqdisc_info("%s: Qdisc %p (type %d), shaper assigned: %u\n",
-				__func__, sch, nq->type, nq->shaper_id);
+				__func__, nq->qdisc, nq->type, nq->shaper_id);
 
 	/*
-	 * Next step is to allocate our actual shaper node
-	 * qos_tag will be the handle we have been given
+	 * Create and send the shaper configure message to the NSS interface
 	 */
-	shaper_node_create.interface_num = nq->nss_interface_number;
-	shaper_node_create.i_shaper = (nq->is_bridge)? false : true;
-	shaper_node_create.cb = nssqdisc_root_init_alloc_node_callback;
-	shaper_node_create.app_data = sch;
-	shaper_node_create.owner = THIS_MODULE;
-	shaper_node_create.type = NSS_SHAPER_CONFIG_TYPE_ALLOC_SHAPER_NODE;
-	shaper_node_create.mt.alloc_shaper_node.node_type = nq->type;
-	shaper_node_create.mt.alloc_shaper_node.qos_tag = nq->qos_tag;
+	msg_type = nssqdisc_get_interface_msg(nq->is_bridge, NSSQDISC_IF_SHAPER_CONFIG);
+	nss_cmn_msg_init(&nim->cm, nq->nss_interface_number, msg_type, sizeof(struct nss_if_msg),
+				nssqdisc_root_init_alloc_node_callback, nq);
+	nim->msg.shaper_configure.config.request_type = NSS_SHAPER_CONFIG_TYPE_ALLOC_SHAPER_NODE;
+	nim->msg.shaper_configure.config.msg.alloc_shaper_node.node_type = nq->type;
+	nim->msg.shaper_configure.config.msg.alloc_shaper_node.qos_tag = nq->qos_tag;
+	rc = nss_if_tx_msg(nq->nss_shaping_ctx, nim);
 
-	rc = nss_shaper_config_send(nq->nss_shaping_ctx, &shaper_node_create);
 	if (rc == NSS_TX_SUCCESS) {
 		return;
 	}
@@ -733,10 +790,10 @@
 	 * Unable to send alloc node command, cleanup from unassigning the shaper
 	 */
 	nssqdisc_error("%s: Qdisc %p (type %d) create command failed: %d\n",
-			__func__, sch, nq->type, rc);
+			__func__, nq->qdisc, nq->type, rc);
 
 	nq->pending_final_state = NSSQDISC_STATE_NODE_ALLOC_SEND_FAIL;
-	nssqdisc_root_cleanup_shaper_unassign(sch);
+	nssqdisc_root_cleanup_shaper_unassign(nq);
 }
 
 
@@ -745,18 +802,16 @@
  *	Perform final cleanup of a shaper node after all shaper node
  *	cleanup is complete.
  */
-static void nssqdisc_child_cleanup_final(struct Qdisc *sch)
+static void nssqdisc_child_cleanup_final(struct nssqdisc_qdisc *nq)
 {
-	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
-
 	nssqdisc_info("%s: Final cleanup type %d: %p\n", __func__,
-			nq->type, sch);
+			nq->type, nq->qdisc);
 
 	/*
 	 * Finally unregister for shaping
 	 */
 	nssqdisc_info("%s: Unregister for shaping\n", __func__);
-	nss_unregister_shaping(nq->nss_shaping_ctx);
+	nss_shaper_unregister_shaping(nq->nss_shaping_ctx);
 
 	/*
 	 * Now set our final state
@@ -770,83 +825,78 @@
  *	Invoked on the response to freeing a child shaper node
  */
 static void nssqdisc_child_cleanup_free_node_callback(void *app_data,
-				struct nss_shaper_response *response)
+						struct nss_if_msg *nim)
 {
-	struct Qdisc *sch = (struct Qdisc *)app_data;
-	struct nssqdisc_qdisc *nq __attribute__((unused)) = qdisc_priv(sch);
+	struct nssqdisc_qdisc *nq = (struct nssqdisc_qdisc *)app_data;
 
-	nssqdisc_info("%s: Qdisc %p (type %d): child free response type: %d\n",
-			__func__, sch, nq->type, response->type);
-
-	if (response->type < 0) {
-		nssqdisc_error("%s: Qdisc %p (type %d): free shaper node failed\n",
-				__func__, sch, nq->type);
-	} else {
-		nssqdisc_info("%s: Qdisc %p (type %d): child shaper node "
-				"free complete\n", __func__, sch, nq->type);
+	if (nim->cm.response != NSS_CMN_RESPONSE_ACK) {
+		nssqdisc_info("%s: Qdisc %p (type %d qos_tag %x): child free FAILED response type: %d\n",
+			__func__, nq->qdisc, nq->type, nq->qos_tag, nim->msg.shaper_configure.config.response_type);
+		return;
 	}
 
+	nssqdisc_info("%s: Qdisc %p (type %d): child shaper node "
+			"free complete\n", __func__, nq->qdisc, nq->type);
+
 	/*
 	 * Perform final cleanup
 	 */
-	nssqdisc_child_cleanup_final(sch);
+	nssqdisc_child_cleanup_final(nq);
 }
 
 /*
  * nssqdisc_child_cleanup_free_node()
  *	Free the child shaper node, issue command to do so.
  */
-static void nssqdisc_child_cleanup_free_node(struct Qdisc *sch)
+static void nssqdisc_child_cleanup_free_node(struct nssqdisc_qdisc *nq)
 {
-	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
-	struct nss_shaper_configure shaper_node_free;
+	struct nss_if_msg nim;
 	nss_tx_status_t rc;
+	int msg_type;
 
-	nssqdisc_info("%s: Qdisc %p (type %d): free shaper node command\n",
-			__func__, sch, nq->type);
+	nssqdisc_info("%s: Qdisc %p (type %d qos_tag %x): free shaper node command\n",
+			__func__, nq->qdisc, nq->type, nq->qos_tag);
 
-	shaper_node_free.interface_num = nq->nss_interface_number;
-	shaper_node_free.i_shaper = (nq->is_bridge)? false : true;
-	shaper_node_free.cb = nssqdisc_child_cleanup_free_node_callback;
-	shaper_node_free.app_data = sch;
-	shaper_node_free.owner = THIS_MODULE;
-	shaper_node_free.type = NSS_SHAPER_CONFIG_TYPE_FREE_SHAPER_NODE;
-	shaper_node_free.mt.free_shaper_node.qos_tag = nq->qos_tag;
+	/*
+	 * Create and send the shaper configure message to the NSS interface
+	 */
+	msg_type = nssqdisc_get_interface_msg(nq->is_bridge, NSSQDISC_IF_SHAPER_CONFIG);
+	nss_cmn_msg_init(&nim.cm, nq->nss_interface_number, msg_type, sizeof(struct nss_if_msg),
+				nssqdisc_child_cleanup_free_node_callback, nq);
+	nim.msg.shaper_configure.config.request_type = NSS_SHAPER_CONFIG_TYPE_FREE_SHAPER_NODE;
+	nim.msg.shaper_configure.config.msg.free_shaper_node.qos_tag = nq->qos_tag;
+	rc = nss_if_tx_msg(nq->nss_shaping_ctx, &nim);
 
-	rc = nss_shaper_config_send(nq->nss_shaping_ctx, &shaper_node_free);
 	if (rc == NSS_TX_SUCCESS) {
 		return;
 	}
 
 	nssqdisc_error("%s: Qdisc %p (type %d): child free node command send "
-			"failed: %d, qos tag: %x\n", __func__, sch, nq->type,
+			"failed: %d, qos tag: %x\n", __func__, nq->qdisc, nq->type,
 			rc, nq->qos_tag);
 
 	/*
 	 * Perform final cleanup
 	 */
-	nssqdisc_child_cleanup_final(sch);
+	nssqdisc_child_cleanup_final(nq);
 }
 
 /*
  * nssqdisc_child_init_alloc_node_callback()
  *	Invoked on the response to creating a child shaper node
  */
-static void nssqdisc_child_init_alloc_node_callback(void *app_data,
-				struct nss_shaper_response *response)
+static void nssqdisc_child_init_alloc_node_callback(void *app_data, struct nss_if_msg *nim)
 {
-	struct Qdisc *sch = (struct Qdisc *)app_data;
-	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
+	struct nssqdisc_qdisc *nq = (struct nssqdisc_qdisc *)app_data;
 
-	nssqdisc_info("%s: Qdisc %p (type %d): child alloc node, response "
-		"type: %d\n", __func__, sch, nq->type, response->type);
-
-	if (response->type < 0) {
+	if (nim->cm.response != NSS_CMN_RESPONSE_ACK) {
+		nssqdisc_error("%s: Qdisc %p (type %d): child alloc node FAILED, response "
+			"type: %d\n", __func__, nq->qdisc, nq->type, nim->msg.shaper_configure.config.response_type);
 		/*
 		 * Cleanup from final stage
 		 */
 		nq->pending_final_state = NSSQDISC_STATE_NODE_ALLOC_FAIL_CHILD;
-		nssqdisc_child_cleanup_final(sch);
+		nssqdisc_child_cleanup_final(nq);
 		return;
 	}
 
@@ -854,7 +904,7 @@
 	 * Shaper node has been allocated
 	 */
 	nssqdisc_info("%s: Qdisc %p (type %d): shaper node successfully "
-			"created as a child node\n",__func__, sch, nq->type);
+			"created as a child node\n",__func__, nq->qdisc, nq->type);
 
 	atomic_set(&nq->state, NSSQDISC_STATE_READY);
 }
@@ -907,9 +957,87 @@
 	 * Delete all packets pending in the output queue and reset stats
 	 */
 	qdisc_reset_queue(sch);
+
+	nssqdisc_info("%s: Qdisc %p (type %d) reset complete\n",
+			__func__, sch, nq->type);
 }
 
 /*
+ * nssqdisc_add_to_tail_protected()
+ *	Adds to list while holding the qdisc lock.
+ */
+static inline void nssqdisc_add_to_tail_protected(struct sk_buff *skb, struct Qdisc *sch)
+{
+	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
+
+	/*
+	 * Since packets can come back from the NSS at any time (in case of bounce),
+	 * enqueue's and dequeue's can cause corruption, if not done within locks.
+	 */
+	spin_lock_bh(&nq->bounce_protection_lock);
+
+	/*
+	 * We do not use the qdisc_enqueue_tail() API here in order
+	 * to prevent stats from getting updated by the API.
+	 */
+	__skb_queue_tail(&sch->q, skb);
+
+	spin_unlock_bh(&nq->bounce_protection_lock);
+};
+
+/*
+ * nssqdisc_add_to_tail()
+ *	Adds to list without holding any locks.
+ */
+static inline void nssqdisc_add_to_tail(struct sk_buff *skb, struct Qdisc *sch)
+{
+	/*
+	 * We do not use the qdisc_enqueue_tail() API here in order
+	 * to prevent stats from getting updated by the API.
+	 */
+	__skb_queue_tail(&sch->q, skb);
+};
+
+/*
+ * nssqdisc_remove_from_tail_protected()
+ *	Removes from list while holding the qdisc lock.
+ */
+static inline struct sk_buff *nssqdisc_remove_from_tail_protected(struct Qdisc *sch)
+{
+	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
+	struct sk_buff *skb;
+
+	/*
+	 * Since packets can come back from the NSS at any time (in case of bounce),
+	 * enqueue's and dequeue's can cause corruption, if not done within locks.
+	 */
+	spin_lock_bh(&nq->bounce_protection_lock);
+
+	/*
+	 * We use __skb_dequeue() to ensure that
+	 * stats don't get updated twice.
+	 */
+	skb = __skb_dequeue(&sch->q);
+
+	spin_unlock_bh(&nq->bounce_protection_lock);
+
+	return skb;
+};
+
+/*
+ * nssqdisc_remove_to_tail_protected()
+ *	Removes from list without holding any locks.
+ */
+static inline struct sk_buff *nssqdisc_remove_from_tail(struct Qdisc *sch)
+{
+	/*
+	 * We use __skb_dequeue() to ensure that
+	 * stats don't get updated twice.
+	 */
+	return __skb_dequeue(&sch->q);
+};
+
+/*
  * nssqdisc_enqueue()
  *	Generic enqueue call for enqueuing packets into NSS for shaping
  */
@@ -922,9 +1050,9 @@
 	 * If we are not the root qdisc then we should not be getting packets!!
 	 */
 	if (!nq->is_root) {
-		nssqdisc_warning("%s: Qdisc %p (type %d): unexpected packet "
+		nssqdisc_error("%s: Qdisc %p (type %d): unexpected packet "
 			"for child qdisc - skb: %p\n", __func__, sch, nq->type, skb);
-		__qdisc_enqueue_tail(skb, sch, &sch->q);
+		nssqdisc_add_to_tail(skb, sch);
 		__netif_schedule(sch);
 		return NET_XMIT_SUCCESS;
 	}
@@ -962,12 +1090,12 @@
 	 * shaped we allow it to be dequeued for transmit.
 	 */
 
-	if (!nq->is_bridge && !nq->is_virtual) {
+	if (!nq->is_virtual) {
 		/*
 		 * TX to an NSS physical - the shaping will occur as part of normal
 		 * transmit path.
 		 */
-		__qdisc_enqueue_tail(skb, sch, &sch->q);
+		nssqdisc_add_to_tail(skb, sch);
 		__netif_schedule(sch);
 		return NET_XMIT_SUCCESS;
 	}
@@ -987,7 +1115,11 @@
 				"interface: %d, skb: %p\n", __func__, sch, nq->type,
 				nq->nss_interface_number, skb);
 
-			__qdisc_enqueue_tail(skb, sch, &sch->q);
+			/*
+			 * Protecting the enqueue since this queue is involved in bouncing
+			 * of packets.
+			 */
+			nssqdisc_add_to_tail_protected(skb, sch);
 			__netif_schedule(sch);
 		}
 		return NET_XMIT_SUCCESS;
@@ -1004,7 +1136,11 @@
 		 */
 		nssqdisc_warning("%s: Qdisc %p (type %d): failed to bounce for bridge %d, skb: %p\n",
 					__func__, sch, nq->type, nq->nss_interface_number, skb);
-		__qdisc_enqueue_tail(skb, sch, &sch->q);
+		/*
+		 * Protecting the enqueue since this queue is involved in bouncing
+		 * of packets.
+		 */
+		nssqdisc_add_to_tail_protected(skb, sch);
 		__netif_schedule(sch);
 	}
 	return NET_XMIT_SUCCESS;
@@ -1014,17 +1150,20 @@
  * nssqdisc_dequeue()
  *	Generic dequeue call for dequeuing bounced packets.
  */
-static struct sk_buff *nssqdisc_dequeue(struct Qdisc *sch)
+static inline struct sk_buff *nssqdisc_dequeue(struct Qdisc *sch)
 {
-	struct sk_buff *skb;
+	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
 
 	/*
-	 * We use __skb_dequeue() to ensure that
-	 * stats don't get updated twice.
+	 * We use the protected dequeue API if the interface involves bounce.
+	 * That is, a bridge or a virtual interface. Else, we use the unprotected
+	 * API.
 	 */
-	skb = __skb_dequeue(&sch->q);
-
-	return skb;
+	if (nq->is_virtual) {
+		return nssqdisc_remove_from_tail_protected(sch);
+	} else {
+		return nssqdisc_remove_from_tail(sch);
+	}
 }
 
 /*
@@ -1032,20 +1171,18 @@
  *	The callback function for a shaper node set default
  */
 static void nssqdisc_set_default_callback(void *app_data,
-			struct nss_shaper_response *response)
+					struct nss_if_msg *nim)
 {
-	struct Qdisc *sch = (struct Qdisc *)app_data;
-	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
+	struct nssqdisc_qdisc *nq = (struct nssqdisc_qdisc *)app_data;
 
-	nssqdisc_info("%s: Qdisc %p (type %d): shaper node set default, response type: %d\n",
-			__func__, sch, nq->type, response->type);
-
-	if (response->type < 0) {
+	if (nim->cm.response != NSS_CMN_RESPONSE_ACK) {
+		nssqdisc_error("%s: Qdisc %p (type %d): shaper node set default FAILED, response type: %d\n",
+			__func__, nq->qdisc, nq->type, nim->msg.shaper_configure.config.response_type);
 		atomic_set(&nq->state, NSSQDISC_STATE_FAILED_RESPONSE);
 		return;
 	}
 
-	nssqdisc_info("%s: Qdisc %p (type %d): attach complete\n", __func__, sch, nq->type);
+	nssqdisc_info("%s: Qdisc %p (type %d): attach complete\n", __func__, nq->qdisc, nq->type);
 	atomic_set(&nq->state, NSSQDISC_STATE_READY);
 }
 
@@ -1053,19 +1190,19 @@
  * nssqdisc_node_set_default()
  *	Configuration function that sets shaper node as default for packet enqueue
  */
-static int nssqdisc_set_default(struct Qdisc *sch)
+static int nssqdisc_set_default(struct nssqdisc_qdisc *nq)
 {
-	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
-	struct nss_shaper_configure shaper_node_default;
 	int32_t state, rc;
+	int msg_type;
+	struct nss_if_msg nim;
 
 	nssqdisc_info("%s: Setting qdisc %p (type %d) as default\n", __func__,
-			sch, nq->type);
+			nq->qdisc, nq->type);
 
 	state = atomic_read(&nq->state);
 	if (state != NSSQDISC_STATE_READY) {
-		nssqdisc_error("%s: Qdisc %p (type %d): not ready: %d\n", __func__,
-				sch, nq->type, state);
+		nssqdisc_error("%s: Qdisc %p (type %d): sqdisc_setot ready: %d\n", __func__,
+				nq->qdisc, nq->type, state);
 		BUG();
 	}
 
@@ -1074,18 +1211,20 @@
 	 */
 	atomic_set(&nq->state, NSSQDISC_STATE_IDLE);
 
-	shaper_node_default.interface_num = nq->nss_interface_number;
-	shaper_node_default.i_shaper = (nq->is_bridge)? false : true;
-	shaper_node_default.cb = nssqdisc_set_default_callback;
-	shaper_node_default.app_data = sch;
-	shaper_node_default.owner = THIS_MODULE;
-	shaper_node_default.type = NSS_SHAPER_CONFIG_TYPE_SET_DEFAULT;
-	shaper_node_default.mt.set_default_node.qos_tag = nq->qos_tag;
+	/*
+	 * Create the shaper configure message and send it down to the NSS interface
+	 */
+	msg_type = nssqdisc_get_interface_msg(nq->is_bridge, NSSQDISC_IF_SHAPER_CONFIG);
+	nss_cmn_msg_init(&nim.cm, nq->nss_interface_number, msg_type, sizeof(struct nss_if_msg),
+				nssqdisc_set_default_callback, nq);
+	nim.msg.shaper_configure.config.request_type = NSS_SHAPER_CONFIG_TYPE_SET_DEFAULT;
+	nim.msg.shaper_configure.config.msg.set_default_node.qos_tag = nq->qos_tag;
+	rc = nss_if_tx_msg(nq->nss_shaping_ctx, &nim);
 
-	rc = nss_shaper_config_send(nq->nss_shaping_ctx, &shaper_node_default);
 	if (rc != NSS_TX_SUCCESS) {
 		nssqdisc_warning("%s: Failed to send set default message for "
 					"qdisc type %d\n", __func__, nq->type);
+		atomic_set(&nq->state, NSSQDISC_STATE_READY);
 		return -1;
 	}
 
@@ -1100,12 +1239,13 @@
 
 	if (state == NSSQDISC_STATE_FAILED_RESPONSE) {
 		nssqdisc_error("%s: Qdisc %p (type %d): failed to default "
-			"State: %d\n", __func__, sch, nq->type, state);
+			"State: %d\n", __func__, nq->qdisc, nq->type, state);
+		atomic_set(&nq->state, NSSQDISC_STATE_READY);
 		return -1;
 	}
 
 	nssqdisc_info("%s: Qdisc %p (type %d): shaper node default complete\n",
-			__func__, sch, nq->type);
+			__func__, nq->qdisc, nq->type);
 	return 0;
 }
 
@@ -1114,20 +1254,20 @@
  *	The callback function for a shaper node attach message
  */
 static void nssqdisc_node_attach_callback(void *app_data,
-			struct nss_shaper_response *response)
+					struct nss_if_msg *nim)
 {
-	struct Qdisc *sch = (struct Qdisc *)app_data;
-	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
+	struct nssqdisc_qdisc *nq = (struct nssqdisc_qdisc *)app_data;
 
-	nssqdisc_info("%s: Qdisc %p (type %d) shaper node attach response "
-			"type: %d\n", __func__, sch, nq->type, response->type);
-	if (response->type < 0) {
+	if (nim->cm.response != NSS_CMN_RESPONSE_ACK) {
+		nssqdisc_info("%s: Qdisc %p (type %d) shaper node attach FAILED - response "
+			"type: %d\n", __func__, nq->qdisc, nq->type,
+			nim->msg.shaper_configure.config.response_type);
 		atomic_set(&nq->state, NSSQDISC_STATE_FAILED_RESPONSE);
 		return;
 	}
 
 	nssqdisc_info("%s: qdisc type %d: %p, attach complete\n", __func__,
-			nq->type, sch);
+			nq->type, nq->qdisc);
 
 	atomic_set(&nq->state, NSSQDISC_STATE_READY);
 }
@@ -1136,19 +1276,19 @@
  * nssqdisc_node_attach()
  *	Configuration function that helps attach a child shaper node to a parent.
  */
-static int nssqdisc_node_attach(struct Qdisc *sch,
-	struct nss_shaper_configure *shaper_node_attach, int32_t attach_type)
+static int nssqdisc_node_attach(struct nssqdisc_qdisc *nq,
+			struct nss_if_msg *nim, int32_t attach_type)
 {
-	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
 	int32_t state, rc;
+	int msg_type;
 
 	nssqdisc_info("%s: Qdisc %p (type %d) attaching\n",
-			__func__, sch, nq->type);
+			__func__, nq->qdisc, nq->type);
 
 	state = atomic_read(&nq->state);
 	if (state != NSSQDISC_STATE_READY) {
 		nssqdisc_error("%s: Qdisc %p (type %d): not ready, state: %d\n",
-				__func__, sch, nq->type, state);
+				__func__, nq->qdisc, nq->type, state);
 		BUG();
 	}
 
@@ -1157,17 +1297,28 @@
 	 */
 	atomic_set(&nq->state, NSSQDISC_STATE_IDLE);
 
-	shaper_node_attach->interface_num = nq->nss_interface_number;
-	shaper_node_attach->i_shaper = (nq->is_bridge)? false : true;
-	shaper_node_attach->cb = nssqdisc_node_attach_callback;
-	shaper_node_attach->app_data = sch;
-	shaper_node_attach->owner = THIS_MODULE;
-	shaper_node_attach->type = attach_type;
+	/*
+	 * Create the shaper configure message and send it down to the NSS interface
+	 */
+	msg_type = nssqdisc_get_interface_msg(nq->is_bridge, NSSQDISC_IF_SHAPER_CONFIG);
+	nss_cmn_msg_init(&nim->cm, nq->nss_interface_number, msg_type, sizeof(struct nss_if_msg),
+				nssqdisc_node_attach_callback, nq);
+	nim->msg.shaper_configure.config.request_type = attach_type;
+	rc = nss_if_tx_msg(nq->nss_shaping_ctx, nim);
 
-	rc = nss_shaper_config_send(nq->nss_shaping_ctx, shaper_node_attach);
+	/*
+	 * Send the message to the right type of interface
+	 */
+	if (nq->is_virtual) {
+		nim->cm.len = sizeof(struct nss_virt_if_msg);
+		rc = nss_virt_if_tx_msg((struct nss_virt_if_msg *)nim);
+	} else {
+	}
+
 	if (rc != NSS_TX_SUCCESS) {
 		nssqdisc_warning("%s: Failed to send configure message for "
 					"qdisc type %d\n", __func__, nq->type);
+		atomic_set(&nq->state, NSSQDISC_STATE_READY);
 		return -1;
 	}
 
@@ -1182,12 +1333,13 @@
 
 	if (state == NSSQDISC_STATE_FAILED_RESPONSE) {
 		nssqdisc_error("%s: Qdisc %p (type %d) failed to attach child "
-			"node, State: %d\n", __func__, sch, nq->type, state);
+			"node, State: %d\n", __func__, nq->qdisc, nq->type, state);
+		atomic_set(&nq->state, NSSQDISC_STATE_READY);
 		return -1;
 	}
 
 	nssqdisc_info("%s: Qdisc %p (type %d): shaper node attach complete\n",
-			__func__, sch, nq->type);
+			__func__, nq->qdisc, nq->type);
 	return 0;
 }
 
@@ -1196,42 +1348,40 @@
  *	The callback function for a shaper node detach message
  */
 static void nssqdisc_node_detach_callback(void *app_data,
-			struct nss_shaper_response *response)
+					struct nss_if_msg *nim)
 {
-	struct Qdisc *sch = (struct Qdisc *)app_data;
-	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
+	struct nssqdisc_qdisc *nq = (struct nssqdisc_qdisc *)app_data;
 
-	nssqdisc_info("%s: Qdisc %p (type %d): shaper node detach response "
-			"type: %d\n", __func__, sch, nq->type, response->type);
-
-	if (response->type < 0) {
+	if (nim->cm.response != NSS_CMN_RESPONSE_ACK) {
+		nssqdisc_info("%s: Qdisc %p (type %d): shaper node detach FAILED - response "
+			"type: %d\n", __func__, nq->qdisc, nq->type,
+			nim->msg.shaper_configure.config.response_type);
 		atomic_set(&nq->state, NSSQDISC_STATE_FAILED_RESPONSE);
 		return;
 	}
 
 	nssqdisc_info("%s: Qdisc %p (type %d): detach complete\n",
-			__func__, sch, nq->type);
+			__func__, nq->qdisc, nq->type);
 
 	atomic_set(&nq->state, NSSQDISC_STATE_READY);
 }
 
 /*
- * nssqdisc_detach()
+ * nssqdisc_node_detach()
  *	Configuration function that helps detach a child shaper node to a parent.
  */
-static int nssqdisc_node_detach(struct Qdisc *sch,
-	struct nss_shaper_configure *shaper_node_detach, int32_t detach_type)
+static int nssqdisc_node_detach(struct nssqdisc_qdisc *nq,
+	struct nss_if_msg *nim, int32_t detach_type)
 {
-	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
-	int32_t state, rc;
+	int32_t state, rc, msg_type;
 
 	nssqdisc_info("%s: Qdisc %p (type %d) detaching\n",
-			__func__, sch, nq->type);
+			__func__, nq->qdisc, nq->type);
 
 	state = atomic_read(&nq->state);
 	if (state != NSSQDISC_STATE_READY) {
 		nssqdisc_error("%s: Qdisc %p (type %d): not ready, state: %d\n",
-				__func__, sch, nq->type, state);
+				__func__, nq->qdisc, nq->type, state);
 		BUG();
 	}
 
@@ -1240,17 +1390,19 @@
 	 */
 	atomic_set(&nq->state, NSSQDISC_STATE_IDLE);
 
-	shaper_node_detach->interface_num = nq->nss_interface_number;
-	shaper_node_detach->i_shaper = (nq->is_bridge)? false : true;
-	shaper_node_detach->cb = nssqdisc_node_detach_callback;
-	shaper_node_detach->app_data = sch;
-	shaper_node_detach->owner = THIS_MODULE;
-	shaper_node_detach->type = detach_type;
+	/*
+	 * Create and send the shaper configure message to the NSS interface
+	 */
+	msg_type = nssqdisc_get_interface_msg(nq->is_bridge, NSSQDISC_IF_SHAPER_CONFIG);
+	nss_cmn_msg_init(&nim->cm, nq->nss_interface_number, msg_type, sizeof(struct nss_if_msg),
+				nssqdisc_node_detach_callback, nq);
+	nim->msg.shaper_configure.config.request_type = detach_type;
+	rc = nss_if_tx_msg(nq->nss_shaping_ctx, nim);
 
-	rc = nss_shaper_config_send(nq->nss_shaping_ctx, shaper_node_detach);
 	if (rc != NSS_TX_SUCCESS) {
 		nssqdisc_warning("%s: Qdisc %p (type %d): Failed to send configure "
-					"message.", __func__, sch, nq->type);
+					"message.", __func__, nq->qdisc, nq->type);
+		atomic_set(&nq->state, NSSQDISC_STATE_READY);
 		return -1;
 	}
 
@@ -1264,13 +1416,14 @@
 	}
 
 	if (state == NSSQDISC_STATE_FAILED_RESPONSE) {
-		nssqdisc_error("%s: Qdisc %p (type %d): failed to attach child node, "
-				"State: %d\n", __func__, sch, nq->type, state);
+		nssqdisc_error("%s: Qdisc %p (type %d): failed to detach child node, "
+				"State: %d\n", __func__, nq->qdisc, nq->type, state);
+		atomic_set(&nq->state, NSSQDISC_STATE_READY);
 		return -1;
 	}
 
 	nssqdisc_info("%s: Qdisc %p (type %d): shaper node detach complete\n",
-			__func__, sch, nq->type);
+			__func__, nq->qdisc, nq->type);
 	return 0;
 }
 
@@ -1279,21 +1432,20 @@
  *	The call back function for a shaper node configure message
  */
 static void nssqdisc_configure_callback(void *app_data,
-				struct nss_shaper_response *response)
+				struct nss_if_msg *nim)
 {
-	struct Qdisc *sch = (struct Qdisc *)app_data;
-	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
+	struct nssqdisc_qdisc *nq = (struct nssqdisc_qdisc *)app_data;
 
-	nssqdisc_info("%s: Qdisc %p (type %d): shaper node configure "
-		"response type: %d\n", __func__, sch, nq->type, response->type);
-
-	if (response->type < 0) {
+	if (nim->cm.response != NSS_CMN_RESPONSE_ACK) {
+		nssqdisc_info("%s: Qdisc %p (type %d): shaper node configure FAILED "
+			"response type: %d\n", __func__, nq->qdisc, nq->type,
+			nim->msg.shaper_configure.config.response_type);
 		atomic_set(&nq->state, NSSQDISC_STATE_FAILED_RESPONSE);
 		return;
 	}
 
 	nssqdisc_info("%s: Qdisc %p (type %d): configuration complete\n",
-			__func__, sch, nq->type);
+			__func__, nq->qdisc, nq->type);
 	atomic_set(&nq->state, NSSQDISC_STATE_READY);
 }
 
@@ -1301,18 +1453,18 @@
  * nssqdisc_configure()
  *	Configuration function that aids in tuning of queuing parameters.
  */
-static int nssqdisc_configure(struct Qdisc *sch,
-	struct nss_shaper_configure *shaper_node_configure, int32_t config_type)
+static int nssqdisc_configure(struct nssqdisc_qdisc *nq,
+	struct nss_if_msg *nim, int32_t config_type)
 {
-	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
 	int32_t state, rc;
+	int msg_type;
 
-	nssqdisc_info("%s: Qdisc %p (type %d) configuring\n", __func__, sch, nq->type);
+	nssqdisc_info("%s: Qdisc %p (type %d) configuring\n", __func__, nq->qdisc, nq->type);
 
 	state = atomic_read(&nq->state);
 	if (state != NSSQDISC_STATE_READY) {
 		nssqdisc_error("%s: Qdisc %p (type %d): not ready for configure, "
-			"state : %d\n", __func__, sch, nq->type, state);
+			"state : %d\n", __func__, nq->qdisc, nq->type, state);
 		BUG();
 	}
 
@@ -1321,18 +1473,19 @@
 	 */
 	atomic_set(&nq->state, NSSQDISC_STATE_IDLE);
 
-	shaper_node_configure->interface_num = nq->nss_interface_number;
-	shaper_node_configure->i_shaper = (nq->is_bridge)? false : true;
-	shaper_node_configure->cb = nssqdisc_configure_callback;
-	shaper_node_configure->app_data = sch;
-	shaper_node_configure->owner = THIS_MODULE;
-	shaper_node_configure->type = config_type;
+	/*
+	 * Create and send the shaper configure message to the NSS interface
+	 */
+	msg_type = nssqdisc_get_interface_msg(nq->is_bridge, NSSQDISC_IF_SHAPER_CONFIG);
+	nss_cmn_msg_init(&nim->cm, nq->nss_interface_number, msg_type, sizeof(struct nss_if_msg),
+				nssqdisc_configure_callback, nq);
+	nim->msg.shaper_configure.config.request_type = config_type;
+	rc = nss_if_tx_msg(nq->nss_shaping_ctx, nim);
 
-	nssqdisc_info("Sending config type %d\n", config_type);
-	rc = nss_shaper_config_send(nq->nss_shaping_ctx, shaper_node_configure);
 	if (rc != NSS_TX_SUCCESS) {
 		nssqdisc_warning("%s: Qdisc %p (type %d): Failed to send configure "
-			"message\n", __func__, sch, nq->type);
+			"message\n", __func__, nq->qdisc, nq->type);
+		atomic_set(&nq->state, NSSQDISC_STATE_READY);
 		return -1;
 	}
 
@@ -1347,13 +1500,13 @@
 
 	if (state == NSSQDISC_STATE_FAILED_RESPONSE) {
 		nssqdisc_error("%s: Qdisc %p (type %d): failed to configure shaper "
-			"node: State: %d\n", __func__, sch, nq->type, state);
+			"node: State: %d\n", __func__, nq->qdisc, nq->type, state);
 		atomic_set(&nq->state, NSSQDISC_STATE_READY);
 		return -1;
 	}
 
 	nssqdisc_info("%s: Qdisc %p (type %d): shaper node configure complete\n",
-			__func__, sch, nq->type);
+			__func__, nq->qdisc, nq->type);
 	return 0;
 }
 
@@ -1362,19 +1515,18 @@
  *	Destroys a shaper in NSS, and the sequence is based on the position of
  *	this qdisc (child or root) and the interface to which it is attached to.
  */
-static void nssqdisc_destroy(struct Qdisc *sch)
+static void nssqdisc_destroy(struct nssqdisc_qdisc *nq)
 {
-	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
 	int32_t state;
 
 	nssqdisc_info("%s: Qdisc %p (type %d) destroy\n",
-			__func__, sch, nq->type);
+			__func__, nq->qdisc, nq->type);
 
 
 	state = atomic_read(&nq->state);
 	if (state != NSSQDISC_STATE_READY) {
 		nssqdisc_error("%s: Qdisc %p (type %d): destroy not ready, "
-				"state: %d\n", __func__, sch, nq->type, state);
+				"state: %d\n", __func__, nq->qdisc, nq->type, state);
 		BUG();
 	}
 
@@ -1390,19 +1542,19 @@
 		 */
 		if (nq->is_bridge) {
 			nssqdisc_info("%s: Qdisc %p (type %d): is root on bridge. Need to "
-				"unassign bshapers from its interfaces\n", __func__, sch, nq->type);
-			nssqdisc_refresh_bshaper_assignment(sch, NSSQDISC_UNASSIGN_BSHAPER);
+				"unassign bshapers from its interfaces\n", __func__, nq->qdisc, nq->type);
+			nssqdisc_refresh_bshaper_assignment(nq->qdisc, NSSQDISC_SCAN_AND_UNASSIGN_BSHAPER);
 		}
 
 		/*
 		 * Begin by freeing the root shaper node
 		 */
-		nssqdisc_root_cleanup_free_node(sch);
+		nssqdisc_root_cleanup_free_node(nq);
 	} else {
 		/*
 		 * Begin by freeing the child shaper node
 		 */
-		nssqdisc_child_cleanup_free_node(sch);
+		nssqdisc_child_cleanup_free_node(nq);
 	}
 
 	/*
@@ -1419,7 +1571,7 @@
 	}
 
 	nssqdisc_info("%s: Qdisc %p (type %d): destroy complete\n",
-			__func__, sch, nq->type);
+			__func__, nq->qdisc, nq->type);
 }
 
 
@@ -1428,15 +1580,15 @@
  *	Initializes a shaper in NSS, based on the position of this qdisc (child or root)
  *	and if its a normal interface or a bridge interface.
  */
-static int nssqdisc_init(struct Qdisc *sch, nss_shaper_node_type_t type)
+static int nssqdisc_init(struct Qdisc *sch, struct nssqdisc_qdisc *nq, nss_shaper_node_type_t type, uint32_t classid)
 {
-	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
 	struct Qdisc *root;
 	u32 parent;
 	nss_tx_status_t rc;
 	struct net_device *dev;
 	int32_t state;
-	struct nss_shaper_configure shaper_assign;
+	struct nss_if_msg nim;
+	int msg_type;
 
 	/*
 	 * Record our qdisc and type in the private region for handy use
@@ -1447,7 +1599,7 @@
 	/*
 	 * We dont have to destroy a virtual interface unless
 	 * we are the ones who created it. So set it to false
-	 * as default.
+	 * by default.
 	 */
 	nq->destroy_virtual_interface = false;
 
@@ -1456,7 +1608,30 @@
 	 */
 	atomic_set(&nq->state, NSSQDISC_STATE_IDLE);
 
-	nq->qos_tag = (uint32_t)sch->handle >> 16;
+	/*
+	 * If we are a class, then classid is used as the qos tag.
+	 * Else the qdisc handle will be used as the qos tag.
+	 */
+	if (classid) {
+		nq->qos_tag = classid;
+		nq->is_class = true;
+	} else {
+		nq->qos_tag = (uint32_t)sch->handle;
+		nq->is_class = false;
+	}
+
+	/*
+	 * If our parent is TC_H_ROOT and we are not a class, then we are the root qdisc.
+	 * Note, classes might have its qdisc as root, however we should not set is_root to
+	 * true for classes. This is the reason why we check for classid.
+	 */
+	if ((sch->parent == TC_H_ROOT) && (!nq->is_class)) {
+		nssqdisc_info("%s: Qdisc %p (type %d) is root\n", __func__, nq->qdisc, nq->type);
+		nq->is_root = true;
+	} else {
+		nssqdisc_info("%s: Qdisc %p (type %d) not root\n", __func__, nq->qdisc, nq->type);
+		nq->is_root = false;
+	}
 
 	/*
 	 * The root must be of an nss type (unless we are of course going to be root).
@@ -1464,14 +1639,36 @@
 	 */
 	parent = sch->parent;
 	root = qdisc_root(sch);
-	nssqdisc_info("%s: Qdisc %p (type %d) init root: %p, me: %p, my handle: %x, "
-		"parent: %x rootid: %s owner: %p\n", __func__, sch, nq->type, root,
-		sch, nq->qos_tag, parent, root->ops->id, root->ops->owner);
+
+	/*
+	 * Get the net device as it will tell us if we are on a bridge,
+	 * or on a net device that is represented by a virtual NSS interface (e.g. WIFI)
+	 */
+	dev = qdisc_dev(sch);
+	nssqdisc_info("%s: Qdisc %p (type %d) init dev: %p\n", __func__, nq->qdisc, nq->type, dev);
+
+	/*
+	 * Determine if dev is a bridge or not as this determines if we
+	 * interract with an I or B shaper.
+	 */
+	if (dev->priv_flags == IFF_EBRIDGE) {
+		nssqdisc_info("%s: Qdisc %p (type %d) init qdisc: %p, is bridge\n",
+			__func__, nq->qdisc, nq->type, nq->qdisc);
+		nq->is_bridge = true;
+	} else {
+		nssqdisc_info("%s: Qdisc %p (type %d) init qdisc: %p, not bridge\n",
+			__func__, nq->qdisc, nq->type, nq->qdisc);
+		nq->is_bridge = false;
+	}
+
+	nssqdisc_info("%s: Qdisc %p (type %d) init root: %p, qos tag: %x, "
+		"parent: %x rootid: %s owner: %p\n", __func__, nq->qdisc, nq->type, root,
+		nq->qos_tag, parent, root->ops->id, root->ops->owner);
 
 	if ((parent != TC_H_ROOT) && (root->ops->owner != THIS_MODULE)) {
 		nssqdisc_error("%s: Qdisc %p (type %d) used outside of NSS shaping "
 			"framework. Parent: %x ops: %p Our Module: %p\n", __func__,
-			sch, nq->type, parent, root->ops, THIS_MODULE);
+			nq->qdisc, nq->type, parent, root->ops, THIS_MODULE);
 
 		atomic_set(&nq->state, NSSQDISC_STATE_INIT_FAILED);
 		return -1;
@@ -1480,7 +1677,7 @@
 	/*
 	 * Register for NSS shaping
 	 */
-	nq->nss_shaping_ctx = nss_register_shaping();
+	nq->nss_shaping_ctx = nss_shaper_register_shaping();
 	if (!nq->nss_shaping_ctx) {
 		nssqdisc_error("%s: no shaping context returned for type %d\n",
 				__func__, nq->type);
@@ -1489,45 +1686,12 @@
 	}
 
 	/*
-	 * Are we the root qdisc?
-	 */
-	if (parent == TC_H_ROOT) {
-		nssqdisc_info("%s: Qdisc %p (type %d) is root\n", __func__, sch, nq->type);
-		nq->is_root = true;
-	} else {
-		nssqdisc_info("%s: Qdisc %p (type %d) not root\n", __func__, sch, nq->type);
-		nq->is_root = false;
-	}
-
-	/*
-	 * Get the net device as it will tell us if we are on a bridge,
-	 * or on a net device that is represented by a virtual NSS interface (e.g. WIFI)
-	 */
-	dev = qdisc_dev(sch);
-	nssqdisc_info("%s: Qdisc %p (type %d) init dev: %p\n", __func__, sch, nq->type, dev);
-
-	/*
-	 * Determine if dev is a bridge or not as this determines if we
-	 * interract with an I or B shaper
-	 */
-	if (dev->priv_flags == IFF_EBRIDGE) {
-		nssqdisc_info("%s: Qdisc %p (type %d) init qdisc: %p, is bridge\n",
-			__func__, sch, nq->type, nq->qdisc);
-		nq->is_bridge = true;
-	} else {
-		nssqdisc_info("%s: Qdisc %p (type %d) init qdisc: %p, not bridge\n",
-			__func__, sch, nq->type, nq->qdisc);
-		nq->is_bridge = false;
-	}
-
-	/*
 	 * If we are not the root qdisc then we have a simple enough job to do
 	 */
 	if (!nq->is_root) {
-		struct nss_shaper_configure shaper_node_create;
-
+		struct nss_if_msg nim_alloc;
 		nssqdisc_info("%s: Qdisc %p (type %d) initializing non-root qdisc\n",
-				__func__, sch, nq->type);
+				__func__, nq->qdisc, nq->type);
 
 		/*
 		 * The device we are operational on MUST be recognised as an NSS interface.
@@ -1538,34 +1702,40 @@
 		nq->nss_interface_number = nss_cmn_get_interface_number(nq->nss_shaping_ctx, dev);
 		if (nq->nss_interface_number < 0) {
 			nssqdisc_error("%s: Qdisc %p (type %d) net device unknown to "
-				"nss driver %s\n", __func__, sch, nq->type, dev->name);
-			nss_unregister_shaping(nq->nss_shaping_ctx);
+				"nss driver %s\n", __func__, nq->qdisc, nq->type, dev->name);
+			nss_shaper_unregister_shaping(nq->nss_shaping_ctx);
 			atomic_set(&nq->state, NSSQDISC_STATE_INIT_FAILED);
 			return -1;
 		}
 
 		/*
+		 * Set the virtual flag
+		 */
+		nq->is_virtual = nss_cmn_interface_is_virtual(nq->nss_shaping_ctx, nq->nss_interface_number);
+
+		/*
 		 * Create a shaper node for requested type.
 		 * Essentially all we need to do is create the shaper node.
 		 */
 		nssqdisc_info("%s: Qdisc %p (type %d) non-root (child) create\n",
-				__func__, sch, nq->type);
+				__func__, nq->qdisc, nq->type);
 
-		shaper_node_create.interface_num = nq->nss_interface_number;
-		shaper_node_create.i_shaper = (nq->is_bridge)? false : true;
-		shaper_node_create.cb = nssqdisc_child_init_alloc_node_callback;
-		shaper_node_create.app_data = sch;
-		shaper_node_create.owner = THIS_MODULE;
-		shaper_node_create.type = NSS_SHAPER_CONFIG_TYPE_ALLOC_SHAPER_NODE;
-		shaper_node_create.mt.alloc_shaper_node.node_type = nq->type;
-		shaper_node_create.mt.alloc_shaper_node.qos_tag = nq->qos_tag;
+		/*
+		 * Create and send the shaper configure message to the interface
+		 */
+		msg_type = nssqdisc_get_interface_msg(nq->is_bridge, NSSQDISC_IF_SHAPER_CONFIG);
+		nss_cmn_msg_init(&nim_alloc.cm, nq->nss_interface_number, msg_type, sizeof(struct nss_if_msg),
+					nssqdisc_child_init_alloc_node_callback, nq);
+		nim_alloc.msg.shaper_configure.config.request_type = NSS_SHAPER_CONFIG_TYPE_ALLOC_SHAPER_NODE;
+		nim_alloc.msg.shaper_configure.config.msg.alloc_shaper_node.node_type = nq->type;
+		nim_alloc.msg.shaper_configure.config.msg.alloc_shaper_node.qos_tag = nq->qos_tag;
+		rc = nss_if_tx_msg(nq->nss_shaping_ctx, &nim_alloc);
 
-		rc = nss_shaper_config_send(nq->nss_shaping_ctx, &shaper_node_create);
 		if (rc != NSS_TX_SUCCESS) {
 			nssqdisc_error("%s: Qdisc %p (type %d) create command "
-				"failed: %d\n", __func__, sch, nq->type, rc);
+				"failed: %d\n", __func__, nq->qdisc, nq->type, rc);
 			nq->pending_final_state = NSSQDISC_STATE_CHILD_ALLOC_SEND_FAIL;
-			nssqdisc_child_cleanup_final(sch);
+			nssqdisc_child_cleanup_final(nq);
 			return -1;
 		}
 
@@ -1578,7 +1748,7 @@
 			yield();
 		}
 		nssqdisc_info("%s: Qdisc %p (type %d): initialised with state: %d\n",
-					__func__, sch, nq->type, state);
+					__func__, nq->qdisc, nq->type, state);
 		if (state > 0) {
 			return 0;
 		}
@@ -1592,14 +1762,14 @@
 	 * bridge shaping. Further, when operating on a bridge, we monitor for
 	 * bridge port changes and assign B shapers to the interfaces of the ports.
 	 */
-	nssqdisc_info("%s: init qdisc type %d : %p, ROOT\n", __func__, nq->type, sch);
+	nssqdisc_info("%s: init qdisc type %d : %p, ROOT\n", __func__, nq->type, nq->qdisc);
 
 	/*
 	 * Detect if we are operating on a bridge or interface
 	 */
 	if (nq->is_bridge) {
 		nssqdisc_info("%s: Qdisc %p (type %d): initializing root qdisc on "
-			"bridge\n", __func__, sch, nq->type);
+			"bridge\n", __func__, nq->qdisc, nq->type);
 
 		/*
 		 * As we are a root qdisc on this bridge then we have to create a
@@ -1610,38 +1780,43 @@
 		 * the interface to be released.
 		 */
 		nq->virtual_interface_context = nss_create_virt_if(dev);
-		nq->destroy_virtual_interface = true;
 		if (!nq->virtual_interface_context) {
 			nssqdisc_error("%s: Qdisc %p (type %d): cannot create virtual "
-				"interface\n", __func__, sch, nq->type);
-			nss_unregister_shaping(nq->nss_shaping_ctx);
+				"interface\n", __func__, nq->qdisc, nq->type);
+			nss_shaper_unregister_shaping(nq->nss_shaping_ctx);
 			atomic_set(&nq->state, NSSQDISC_STATE_INIT_FAILED);
 			return -1;
 		}
 		nssqdisc_info("%s: Qdisc %p (type %d): virtual interface registered "
-			"in NSS: %p\n", __func__, sch, nq->type, nq->virtual_interface_context);
+			"in NSS: %p\n", __func__, nq->qdisc, nq->type, nq->virtual_interface_context);
+
+		/*
+		 * Get the virtual interface number, and set the related flags
+		 */
 		nq->nss_interface_number = nss_virt_if_get_interface_num(nq->virtual_interface_context);
+		nq->destroy_virtual_interface = true;
+		nq->is_virtual = true;
 		nssqdisc_info("%s: Qdisc %p (type %d) virtual interface number: %d\n",
-				__func__, sch, nq->type, nq->nss_interface_number);
+				__func__, nq->qdisc, nq->type, nq->nss_interface_number);
 
 		/*
 		 * The root qdisc will get packets enqueued to it, so it must
 		 * register for bridge bouncing as it will be responsible for
 		 * bouncing packets to the NSS for bridge shaping.
 		 */
-		nq->bounce_context = nss_register_shaper_bounce_bridge(nq->nss_interface_number,
-							nssqdisc_bounce_callback, sch, THIS_MODULE);
+		nq->bounce_context = nss_shaper_register_shaper_bounce_bridge(nq->nss_interface_number,
+							nssqdisc_bounce_callback, nq->qdisc, THIS_MODULE);
 		if (!nq->bounce_context) {
 			nssqdisc_error("%s: Qdisc %p (type %d): root but cannot register "
-					"for bridge bouncing\n", __func__, sch, nq->type);
+					"for bridge bouncing\n", __func__, nq->qdisc, nq->type);
 			nss_destroy_virt_if(nq->virtual_interface_context);
-			nss_unregister_shaping(nq->nss_shaping_ctx);
+			nss_shaper_unregister_shaping(nq->nss_shaping_ctx);
 			atomic_set(&nq->state, NSSQDISC_STATE_INIT_FAILED);
 			return -1;
 		}
 
 	} else {
-		nssqdisc_info("%s: Qdisc %p (type %d): is interface\n", __func__, sch, nq->type);
+		nssqdisc_info("%s: Qdisc %p (type %d): is interface\n", __func__, nq->qdisc, nq->type);
 
 		/*
 		 * The device we are operational on MUST be recognised as an NSS interface.
@@ -1652,8 +1827,8 @@
 		nq->nss_interface_number = nss_cmn_get_interface_number(nq->nss_shaping_ctx, dev);
 		if (nq->nss_interface_number < 0) {
 			nssqdisc_error("%s: Qdisc %p (type %d): interface unknown to nss driver %s\n",
-					__func__, sch, nq->type, dev->name);
-			nss_unregister_shaping(nq->nss_shaping_ctx);
+					__func__, nq->qdisc, nq->type, dev->name);
+			nss_shaper_unregister_shaping(nq->nss_shaping_ctx);
 			atomic_set(&nq->state, NSSQDISC_STATE_INIT_FAILED);
 			return -1;
 		}
@@ -1665,20 +1840,20 @@
 		nq->is_virtual = nss_cmn_interface_is_virtual(nq->nss_shaping_ctx, nq->nss_interface_number);
 		if (!nq->is_virtual) {
 			nssqdisc_info("%s: Qdisc %p (type %d): interface %u is physical\n",
-					__func__, sch, nq->type, nq->nss_interface_number);
+					__func__, nq->qdisc, nq->type, nq->nss_interface_number);
 		} else {
 			nssqdisc_info("%s: Qdisc %p (type %d): interface %u is virtual\n",
-					__func__, sch, nq->type, nq->nss_interface_number);
+					__func__, nq->qdisc, nq->type, nq->nss_interface_number);
 
 			/*
 			 * Register for interface bounce shaping.
 			 */
-			nq->bounce_context = nss_register_shaper_bounce_interface(nq->nss_interface_number,
-								nssqdisc_bounce_callback, sch, THIS_MODULE);
+			nq->bounce_context = nss_shaper_register_shaper_bounce_interface(nq->nss_interface_number,
+								nssqdisc_bounce_callback, nq->qdisc, THIS_MODULE);
 			if (!nq->bounce_context) {
 				nssqdisc_error("%s: Qdisc %p (type %d): is root but failed "
-				"to register for interface bouncing\n", __func__, sch, nq->type);
-				nss_unregister_shaping(nq->nss_shaping_ctx);
+				"to register for interface bouncing\n", __func__, nq->qdisc, nq->type);
+				nss_shaper_unregister_shaping(nq->nss_shaping_ctx);
 				atomic_set(&nq->state, NSSQDISC_STATE_INIT_FAILED);
 				return -1;
 			}
@@ -1688,21 +1863,24 @@
 	/*
 	 * We need to issue a command to establish a shaper on the interface.
 	 */
-	shaper_assign.interface_num = nq->nss_interface_number;
-	shaper_assign.i_shaper = (nq->is_bridge)? false : true;
-	shaper_assign.cb = nssqdisc_root_init_shaper_assign_callback;
-	shaper_assign.app_data = sch;
-	shaper_assign.owner = THIS_MODULE;
-	shaper_assign.type = NSS_SHAPER_CONFIG_TYPE_ASSIGN_SHAPER;
-	shaper_assign.mt.assign_shaper.shaper_num = 0;	/* Any free shaper will do */
-	rc = nss_shaper_config_send(nq->nss_shaping_ctx, &shaper_assign);
+
+	/*
+	 * Create and send the shaper assign message to the NSS interface
+	 */
+	msg_type = nssqdisc_get_interface_msg(nq->is_bridge, NSSQDISC_IF_SHAPER_ASSIGN);
+	nss_cmn_msg_init(&nim.cm, nq->nss_interface_number, msg_type, sizeof(struct nss_if_msg),
+				nssqdisc_root_init_shaper_assign_callback, nq);
+	nim.msg.shaper_assign.shaper_id = 0;	/* Any free shaper will do */
+	rc = nss_if_tx_msg(nq->nss_shaping_ctx, &nim);
+
 	if (rc != NSS_TX_SUCCESS) {
 		nssqdisc_error("%s: shaper assign command failed: %d\n", __func__, rc);
 		nq->pending_final_state = NSSQDISC_STATE_ASSIGN_SHAPER_SEND_FAIL;
-		nssqdisc_root_cleanup_final(sch);
-		if (nq->destroy_virtual_interface) {
-			nss_destroy_virt_if(nq->virtual_interface_context);
-		}
+		nssqdisc_root_cleanup_final(nq);
+		/*
+		 * We dont have to clean up the virtual interface, since this is
+		 * taken care of by the nssqdisc_root_cleanup_final() function.
+		 */
 		return -1;
 	}
 
@@ -1712,12 +1890,12 @@
 	 * kernel preemption is required.
 	 */
 	nssqdisc_info("%s: Qdisc %p (type %d): Waiting on response from NSS for "
-			"shaper assign message\n", __func__, sch, nq->type);
+			"shaper assign message\n", __func__, nq->qdisc, nq->type);
 	while (NSSQDISC_STATE_IDLE == (state = atomic_read(&nq->state))) {
 		yield();
 	}
 	nssqdisc_info("%s: Qdisc %p (type %d): is initialised with state: %d\n",
-			__func__, sch, nq->type, state);
+			__func__, nq->qdisc, nq->type, state);
 
 	if (state > 0) {
 
@@ -1734,8 +1912,8 @@
 		 * This is a root qdisc added to a bridge interface. Now we go ahead
 		 * and add this B-shaper to interfaces known to the NSS
 		 */
-		if (nssqdisc_refresh_bshaper_assignment(sch, NSSQDISC_ASSIGN_BSHAPER) < 0) {
-			nssqdisc_destroy(sch);
+		if (nssqdisc_refresh_bshaper_assignment(nq->qdisc, NSSQDISC_SCAN_AND_ASSIGN_BSHAPER) < 0) {
+			nssqdisc_destroy(nq);
 			nssqdisc_error("%s: Bridge linking failed\n", __func__);
 			return -1;
 		}
@@ -1758,15 +1936,18 @@
  *	Invoked after getting basic stats
  */
 static void nssqdisc_basic_stats_callback(void *app_data,
-				struct nss_shaper_response *response)
+				struct nss_if_msg *nim)
 {
-	struct Qdisc *qdisc = (struct Qdisc *)app_data;
-	struct nssqdisc_qdisc *nq = qdisc_priv(qdisc);
+	struct nssqdisc_qdisc *nq = (struct nssqdisc_qdisc *)app_data;
+	struct Qdisc *qdisc = nq->qdisc;
+	struct gnet_stats_basic_packed *bstats;	/* Basic class statistics */
+	struct gnet_stats_queue *qstats;	/* Qstats for use by classes */
+	atomic_t *refcnt;
 
-	if (response->type < 0) {
-		nssqdisc_info("%s: Qdisc %p (type %d): Received stats - "
+	if (nim->cm.response != NSS_CMN_RESPONSE_ACK) {
+		nssqdisc_info("%s: Qdisc %p (type %d): Receive stats FAILED - "
 			"response: type: %d\n", __func__, qdisc, nq->type,
-			response->type);
+			nim->msg.shaper_configure.config.response_type);
 		atomic_sub(1, &nq->pending_stat_requests);
 		return;
 	}
@@ -1774,31 +1955,45 @@
 	/*
 	 * Record latest basic stats
 	 */
-	nq->basic_stats_latest = response->rt.shaper_node_basic_stats_get_success;
+	nq->basic_stats_latest = nim->msg.shaper_configure.config.msg.shaper_node_basic_stats_get;
+
+	/*
+	 * Get the right stats pointers based on whether it is a class
+	 * or a qdisc.
+	 */
+	if (nq->is_class) {
+		bstats = &nq->bstats;
+		qstats = &nq->qstats;
+		refcnt = &nq->refcnt;
+	} else {
+		bstats = &qdisc->bstats;
+		qstats = &qdisc->qstats;
+		refcnt = &qdisc->refcnt;
+		qdisc->q.qlen = nq->basic_stats_latest.qlen_packets;
+	}
 
 	/*
 	 * Update qdisc->bstats
 	 */
-	qdisc->bstats.bytes += (__u64)nq->basic_stats_latest.delta.dequeued_bytes;
-	qdisc->bstats.packets += nq->basic_stats_latest.delta.dequeued_packets;
+	bstats->bytes += (__u64)nq->basic_stats_latest.delta.dequeued_bytes;
+	bstats->packets += nq->basic_stats_latest.delta.dequeued_packets;
 
 	/*
 	 * Update qdisc->qstats
 	 */
-	qdisc->qstats.backlog = nq->basic_stats_latest.qlen_bytes;
-	qdisc->q.qlen = nq->basic_stats_latest.qlen_packets;
+	qstats->backlog = nq->basic_stats_latest.qlen_bytes;
 
-	qdisc->qstats.drops += (nq->basic_stats_latest.delta.enqueued_packets_dropped +
+	qstats->drops += (nq->basic_stats_latest.delta.enqueued_packets_dropped +
 				nq->basic_stats_latest.delta.dequeued_packets_dropped);
 
 	/*
 	 * Update qdisc->qstats
 	 */
-	qdisc->qstats.qlen = qdisc->limit;
-	qdisc->qstats.requeues = 0;
-	qdisc->qstats.overlimits += nq->basic_stats_latest.delta.queue_overrun;
+	qstats->qlen = nq->basic_stats_latest.qlen_packets;
+	qstats->requeues = 0;
+	qstats->overlimits += nq->basic_stats_latest.delta.queue_overrun;
 
-	if (atomic_read(&qdisc->refcnt) == 0) {
+	if (atomic_read(refcnt) == 0) {
 		atomic_sub(1, &nq->pending_stat_requests);
 		return;
 	}
@@ -1808,7 +2003,7 @@
 	 */
 	nq->stats_get_timer.expires += HZ;
 	if (nq->stats_get_timer.expires <= jiffies) {
-		nssqdisc_error("losing time %lu, jiffies = %lu\n",
+		nssqdisc_warning("losing time %lu, jiffies = %lu\n",
 				nq->stats_get_timer.expires, jiffies);
 		nq->stats_get_timer.expires = jiffies + HZ;
 	}
@@ -1821,26 +2016,24 @@
  */
 static void nssqdisc_get_stats_timer_callback(unsigned long int data)
 {
-	struct Qdisc *qdisc = (struct Qdisc *)data;
-	struct nssqdisc_qdisc *nq = qdisc_priv(qdisc);
+	struct nssqdisc_qdisc *nq = (struct nssqdisc_qdisc *)data;
 	nss_tx_status_t rc;
-	struct nss_shaper_configure basic_stats_get;
+	struct nss_if_msg nim;
+	int msg_type;
 
 	/*
-	 * Issue command to get stats
-	 * Stats still in progress?  If not then send a new poll
+	 * Create and send the shaper configure message to the NSS interface
 	 */
-	basic_stats_get.interface_num = nq->nss_interface_number;
-	basic_stats_get.i_shaper = (nq->is_bridge)? false : true;
-	basic_stats_get.cb = nssqdisc_basic_stats_callback;
-	basic_stats_get.app_data = qdisc;
-	basic_stats_get.owner = THIS_MODULE;
-	basic_stats_get.type = NSS_SHAPER_CONFIG_TYPE_SHAPER_NODE_BASIC_STATS_GET;
-	basic_stats_get.mt.shaper_node_basic_stats_get.qos_tag = nq->qos_tag;
-	rc = nss_shaper_config_send(nq->nss_shaping_ctx, &basic_stats_get);
+	msg_type = nssqdisc_get_interface_msg(nq->is_bridge, NSSQDISC_IF_SHAPER_CONFIG);
+	nss_cmn_msg_init(&nim.cm, nq->nss_interface_number, msg_type, sizeof(struct nss_if_msg),
+				nssqdisc_basic_stats_callback, nq);
+	nim.msg.shaper_configure.config.request_type = NSS_SHAPER_CONFIG_TYPE_SHAPER_NODE_BASIC_STATS_GET;
+	nim.msg.shaper_configure.config.msg.shaper_node_basic_stats_get.qos_tag = nq->qos_tag;
+	rc = nss_if_tx_msg(nq->nss_shaping_ctx, &nim);
+
 	if (rc != NSS_TX_SUCCESS) {
 		nssqdisc_error("%s: %p: basic stats get failed to send\n",
-				__func__, qdisc);
+				__func__, nq->qdisc);
 		atomic_sub(1, &nq->pending_stat_requests);
 	}
 }
@@ -1849,13 +2042,11 @@
  * nssqdisc_start_basic_stats_polling()
  *	Call to initiate the stats polling timer
  */
-static void nssqdisc_start_basic_stats_polling(struct Qdisc *sch)
+static void nssqdisc_start_basic_stats_polling(struct nssqdisc_qdisc *nq)
 {
-	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
-
 	init_timer(&nq->stats_get_timer);
 	nq->stats_get_timer.function = nssqdisc_get_stats_timer_callback;
-	nq->stats_get_timer.data = (unsigned long)sch;
+	nq->stats_get_timer.data = (unsigned long)nq;
 	nq->stats_get_timer.expires = jiffies + HZ;
 	atomic_set(&nq->pending_stat_requests, 1);
 	add_timer(&nq->stats_get_timer);
@@ -1865,10 +2056,8 @@
  * nssqdisc_stop_basic_stats_polling()
  *	Call to stop polling of basic stats
  */
-static void nssqdisc_stop_basic_stats_polling(struct Qdisc *sch)
+static void nssqdisc_stop_basic_stats_polling(struct nssqdisc_qdisc *nq)
 {
-	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
-
 	/*
 	 * We wait until we have received the final stats
 	 */
@@ -1976,12 +2165,14 @@
 
 static void nssfifo_destroy(struct Qdisc *sch)
 {
+	struct nssqdisc_qdisc *nq = (struct nssqdisc_qdisc *)qdisc_priv(sch);
+
 	/*
 	 * Stop the polling of basic stats
 	 */
-	nssqdisc_stop_basic_stats_polling(sch);
+	nssqdisc_stop_basic_stats_polling(nq);
 
-	nssqdisc_destroy(sch);
+	nssqdisc_destroy(nq);
 	nssqdisc_info("nssfifo destroyed");
 }
 
@@ -1995,7 +2186,7 @@
 	struct nlattr *na[TCA_NSSFIFO_MAX + 1];
 	struct tc_nssfifo_qopt *qopt;
 	int err;
-	struct nss_shaper_configure shaper_node_change_param;
+	struct nss_if_msg nim;
 
 	q = qdisc_priv(sch);
 
@@ -2027,11 +2218,13 @@
 	q->set_default = qopt->set_default;
 	nssqdisc_info("%s: limit:%u set_default:%u\n", __func__, qopt->limit, qopt->set_default);
 
-	shaper_node_change_param.mt.shaper_node_config.qos_tag = q->nq.qos_tag;
-	shaper_node_change_param.mt.shaper_node_config.snc.fifo_param.limit = q->limit;
-	shaper_node_change_param.mt.shaper_node_config.snc.fifo_param.drop_mode = NSS_SHAPER_FIFO_DROP_MODE_TAIL;
-	if (nssqdisc_configure(sch, &shaper_node_change_param, NSS_SHAPER_CONFIG_TYPE_FIFO_CHANGE_PARAM) < 0)
+	nim.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = q->nq.qos_tag;
+	nim.msg.shaper_configure.config.msg.shaper_node_config.snc.fifo_param.limit = q->limit;
+	nim.msg.shaper_configure.config.msg.shaper_node_config.snc.fifo_param.drop_mode = NSS_SHAPER_FIFO_DROP_MODE_TAIL;
+	if (nssqdisc_configure(&q->nq, &nim, NSS_SHAPER_CONFIG_TYPE_FIFO_CHANGE_PARAM) < 0) {
+		nssqdisc_error("%s: nssfifo %p configuration failed\n", __func__, sch);
 		return -EINVAL;
+	}
 
 	/*
 	 * There is nothing we need to do if the qdisc is not
@@ -2043,8 +2236,10 @@
 	/*
 	 * Set this qdisc to be the default qdisc for enqueuing packets.
 	 */
-	if (nssqdisc_set_default(sch) < 0)
+	if (nssqdisc_set_default(&q->nq) < 0) {
+		nssqdisc_error("%s: nssfifo %p set_default failed\n", __func__, sch);
 		return -EINVAL;
+	}
 
 	nssqdisc_info("%s: nssfifo queue (qos_tag:%u) set as default\n", __func__, q->nq.qos_tag);
 	return 0;
@@ -2052,25 +2247,27 @@
 
 static int nssfifo_init(struct Qdisc *sch, struct nlattr *opt)
 {
+	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
+
 	if (opt == NULL)
 		return -EINVAL;
 
 	nssqdisc_info("Initializing Fifo - type %d\n", NSS_SHAPER_NODE_TYPE_FIFO);
 	nssfifo_reset(sch);
 
-	if (nssqdisc_init(sch, NSS_SHAPER_NODE_TYPE_FIFO) < 0)
+	if (nssqdisc_init(sch, nq, NSS_SHAPER_NODE_TYPE_FIFO, 0) < 0)
 		return -EINVAL;
 
 	nssqdisc_info("NSS fifo initialized - handle %x parent %x\n", sch->handle, sch->parent);
 	if (nssfifo_change(sch, opt) < 0) {
-		nssqdisc_destroy(sch);
+		nssqdisc_destroy(nq);
 		return -EINVAL;
 	}
 
 	/*
 	 * Start the stats polling timer
 	 */
-	nssqdisc_start_basic_stats_polling(sch);
+	nssqdisc_start_basic_stats_polling(nq);
 
 	return 0;
 }
@@ -2099,7 +2296,7 @@
 
 	return nla_nest_end(skb, opts);
 
-nla_put_failure:
+nla_put_failure:		
 	nla_nest_cancel(skb, opts);
 	return -EMSGSIZE;
 }
@@ -2179,11 +2376,12 @@
 
 static void nsscodel_destroy(struct Qdisc *sch)
 {
+	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
 	/*
 	 * Stop the polling of basic stats
 	 */
-	nssqdisc_stop_basic_stats_polling(sch);
-	nssqdisc_destroy(sch);
+	nssqdisc_stop_basic_stats_polling(nq);
+	nssqdisc_destroy(nq);
 	nssqdisc_info("nsscodel destroyed");
 }
 
@@ -2196,7 +2394,7 @@
 	struct nsscodel_sched_data *q;
 	struct nlattr *na[TCA_NSSCODEL_MAX + 1];
 	struct tc_nsscodel_qopt *qopt;
-	struct nss_shaper_configure shaper_node_change_param;
+	struct nss_if_msg nim;
 	int err;
 	struct net_device *dev = qdisc_dev(sch);
 
@@ -2234,18 +2432,19 @@
 		q->target, q->limit, q->interval, qopt->set_default);
 
 
-	shaper_node_change_param.mt.shaper_node_config.qos_tag = q->nq.qos_tag;
+	nim.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = q->nq.qos_tag;
 	/*
 	 * Target and interval time needs to be provided in milliseconds
-	 * (tc provides us the time in mircoseconds and therefore we divide by 100)
+	 * (tc provides us the time in mircoseconds and therefore we divide by 1000)
 	 */
-	shaper_node_change_param.mt.shaper_node_config.snc.codel_param.qlen_max = q->limit;
-	shaper_node_change_param.mt.shaper_node_config.snc.codel_param.cap.interval = q->interval/1000;
-	shaper_node_change_param.mt.shaper_node_config.snc.codel_param.cap.target = q->target/1000;
-	shaper_node_change_param.mt.shaper_node_config.snc.codel_param.cap.mtu = dev->mtu;
-	nssqdisc_info("%s: MTU size of interface %s is %u\n", __func__, dev->name, dev->mtu);
+	nim.msg.shaper_configure.config.msg.shaper_node_config.snc.codel_param.qlen_max = q->limit;
+	nim.msg.shaper_configure.config.msg.shaper_node_config.snc.codel_param.cap.interval = q->interval/1000;
+	nim.msg.shaper_configure.config.msg.shaper_node_config.snc.codel_param.cap.target = q->target/1000;
+	nim.msg.shaper_configure.config.msg.shaper_node_config.snc.codel_param.cap.mtu = psched_mtu(dev);
+	nssqdisc_info("%s: MTU size of interface %s is %u bytes\n", __func__, dev->name,
+			nim.msg.shaper_configure.config.msg.shaper_node_config.snc.codel_param.cap.mtu);
 
-	if (nssqdisc_configure(sch, &shaper_node_change_param,
+	if (nssqdisc_configure(&q->nq, &nim,
 				NSS_SHAPER_CONFIG_TYPE_CODEL_CHANGE_PARAM) < 0) {
 		return -EINVAL;
 	}
@@ -2260,7 +2459,7 @@
 	/*
 	 * Set this qdisc to be the default qdisc for enqueuing packets.
 	 */
-	if (nssqdisc_set_default(sch) < 0)
+	if (nssqdisc_set_default(&q->nq) < 0)
 		return -EINVAL;
 
 	return 0;
@@ -2268,22 +2467,24 @@
 
 static int nsscodel_init(struct Qdisc *sch, struct nlattr *opt)
 {
+	struct nssqdisc_qdisc *nq = qdisc_priv(sch);
+
 	if (opt == NULL)
 		return -EINVAL;
 
 	nsscodel_reset(sch);
-	if (nssqdisc_init(sch, NSS_SHAPER_NODE_TYPE_CODEL) < 0)
+	if (nssqdisc_init(sch, nq, NSS_SHAPER_NODE_TYPE_CODEL, 0) < 0)
 		return -EINVAL;
 
 	if (nsscodel_change(sch, opt) < 0) {
-		nssqdisc_destroy(sch);
+		nssqdisc_destroy(nq);
 		return -EINVAL;
 	}
 
 	/*
 	 * Start the stats polling timer
 	 */
-	nssqdisc_start_basic_stats_polling(sch);
+	nssqdisc_start_basic_stats_polling(nq);
 
 	return 0;
 }
@@ -2360,9 +2561,6 @@
 	u32 peakrate;			/* Maximum rate to control bursts */
 	u32 burst;			/* Maximum allowed burst size */
 	u32 mtu;			/* MTU of the interface attached to */
-	u32 mpu;			/* Minimum size of a packet (when there is
-					 * no data)
-					 */
 	struct Qdisc *qdisc;		/* Qdisc to which it is attached to */
 };
 
@@ -2395,13 +2593,32 @@
 static void nsstbl_destroy(struct Qdisc *sch)
 {
 	struct nsstbl_sched_data *q = qdisc_priv(sch);
+	struct nss_if_msg nim;
+
+	/*
+	 * We must always detach our child node in NSS before destroying it.
+	 * Also, we make sure we dont send down the command for noop qdiscs.
+	 */
+	if (q->qdisc != &noop_qdisc) {
+		nim.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = q->nq.qos_tag;
+		if (nssqdisc_node_detach(&q->nq, &nim,
+				NSS_SHAPER_CONFIG_TYPE_TBL_DETACH) < 0) {
+			nssqdisc_error("%s: Failed to detach child %x from nsstbl %x\n",
+					__func__, q->qdisc->handle, q->nq.qos_tag);
+			return;
+		}
+	}
+
+	/*
+	 * Now we can destroy our child qdisc
+	 */
 	qdisc_destroy(q->qdisc);
 
 	/*
-	 * Stop the polling of basic stats
+	 * Stop the polling of basic stats and destroy qdisc.
 	 */
-	nssqdisc_stop_basic_stats_polling(sch);
-	nssqdisc_destroy(sch);
+	nssqdisc_stop_basic_stats_polling(&q->nq);
+	nssqdisc_destroy(&q->nq);
 }
 
 static const struct nla_policy nsstbl_policy[TCA_NSSTBL_MAX + 1] = {
@@ -2410,13 +2627,12 @@
 
 static int nsstbl_change(struct Qdisc *sch, struct nlattr *opt)
 {
-	struct nsstbl_sched_data *q;
+	struct nsstbl_sched_data *q = qdisc_priv(sch);
 	struct nlattr *na[TCA_NSSTBL_MAX + 1];
 	struct tc_nsstbl_qopt *qopt;
-	struct nss_shaper_configure shaper_node_change_param;
+	struct nss_if_msg nim;
 	int err;
-
-	q = qdisc_priv(sch);
+	struct net_device *dev = qdisc_dev(sch);
 
 	if (opt == NULL)
 		return -EINVAL;
@@ -2431,6 +2647,14 @@
 	qopt = nla_data(na[TCA_NSSTBL_PARMS]);
 
 	/*
+	 * Set MTU if it wasn't specified explicitely
+	 */
+	if (!qopt->mtu) {
+		qopt->mtu = psched_mtu(dev);
+		nssqdisc_info("MTU not provided for nsstbl. Setting it to %s's default %u bytes\n", dev->name, qopt->mtu);
+	}
+
+	/*
 	 * Burst size cannot be less than MTU
 	 */
 	if (qopt->burst < qopt->mtu) {
@@ -2439,15 +2663,6 @@
 	}
 
 	/*
-	 * For peak rate to work, MTU must be specified.
-	 */
-	if (qopt->peakrate > 0 && qopt->mtu == 0) {
-		nssqdisc_error("MTU cannot be zero if peakrate is specified\n");
-		return -EINVAL;
-	}
-
-
-	/*
 	 * Rate can be zero. Therefore we dont do a check on it.
 	 */
 	q->rate = qopt->rate;
@@ -2459,28 +2674,30 @@
 	q->peakrate = qopt->peakrate;
 	nssqdisc_info("Peak Rate = %u", qopt->peakrate);
 
-	shaper_node_change_param.mt.shaper_node_config.qos_tag = q->nq.qos_tag;
-	shaper_node_change_param.mt.shaper_node_config.snc.tbl_param.lap_cir.rate = q->rate;
-	shaper_node_change_param.mt.shaper_node_config.snc.tbl_param.lap_cir.burst = q->burst;
-	shaper_node_change_param.mt.shaper_node_config.snc.tbl_param.lap_cir.max_size = q->mtu;
-	shaper_node_change_param.mt.shaper_node_config.snc.tbl_param.lap_cir.short_circuit = false;
-	shaper_node_change_param.mt.shaper_node_config.snc.tbl_param.lap_pir.rate = q->peakrate;
+	nim.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = q->nq.qos_tag;
+	nim.msg.shaper_configure.config.msg.shaper_node_config.snc.tbl_param.lap_cir.rate = q->rate;
+	nim.msg.shaper_configure.config.msg.shaper_node_config.snc.tbl_param.lap_cir.burst = q->burst;
+	nim.msg.shaper_configure.config.msg.shaper_node_config.snc.tbl_param.lap_cir.max_size = q->mtu;
+	nim.msg.shaper_configure.config.msg.shaper_node_config.snc.tbl_param.lap_cir.short_circuit = false;
+	nim.msg.shaper_configure.config.msg.shaper_node_config.snc.tbl_param.lap_pir.rate = q->peakrate;
 
 	/*
 	 * It is important to set these two parameters to be the same as MTU.
 	 * This ensures bursts from CIR dont go above the specified peakrate.
 	 */
-	shaper_node_change_param.mt.shaper_node_config.snc.tbl_param.lap_pir.burst = q->mtu;
-	shaper_node_change_param.mt.shaper_node_config.snc.tbl_param.lap_pir.max_size = q->mtu;
+	nim.msg.shaper_configure.config.msg.shaper_node_config.snc.tbl_param.lap_pir.burst = q->mtu;
+	nim.msg.shaper_configure.config.msg.shaper_node_config.snc.tbl_param.lap_pir.max_size = q->mtu;
 
+	/*
+	 * We can short circuit peakrate limiter if it is not being configured.
+	 */
 	if (q->peakrate) {
-		shaper_node_change_param.mt.shaper_node_config.snc.tbl_param.lap_pir.short_circuit = false;
+		nim.msg.shaper_configure.config.msg.shaper_node_config.snc.tbl_param.lap_pir.short_circuit = false;
 	} else {
-		shaper_node_change_param.mt.shaper_node_config.snc.tbl_param.lap_pir.short_circuit = true;
+		nim.msg.shaper_configure.config.msg.shaper_node_config.snc.tbl_param.lap_pir.short_circuit = true;
 	}
 
-	if (nssqdisc_configure(sch, &shaper_node_change_param,
-			NSS_SHAPER_CONFIG_TYPE_TBL_CHANGE_PARAM) < 0) {
+	if (nssqdisc_configure(&q->nq, &nim, NSS_SHAPER_CONFIG_TYPE_TBL_CHANGE_PARAM) < 0) {
 		return -EINVAL;
 	}
 
@@ -2496,19 +2713,19 @@
 
 	q->qdisc = &noop_qdisc;
 
-	if (nssqdisc_init(sch, NSS_SHAPER_NODE_TYPE_TBL) < 0)
+	if (nssqdisc_init(sch, &q->nq, NSS_SHAPER_NODE_TYPE_TBL, 0) < 0)
 		return -EINVAL;
 
 	if (nsstbl_change(sch, opt) < 0) {
 		nssqdisc_info("Failed to configure tbl\n");
-		nssqdisc_destroy(sch);
+		nssqdisc_destroy(&q->nq);
 		return -EINVAL;
 	}
 
 	/*
 	 * Start the stats polling timer
 	 */
-	nssqdisc_start_basic_stats_polling(sch);
+	nssqdisc_start_basic_stats_polling(&q->nq);
 
 	return 0;
 }
@@ -2533,7 +2750,7 @@
 
 nla_put_failure:
 	nla_nest_cancel(skb, opts);
-	return -EMSGSIZE;
+	return -EMSGSIZE;	
 }
 
 static int nsstbl_dump_class(struct Qdisc *sch, unsigned long cl,
@@ -2553,7 +2770,8 @@
 {
 	struct nsstbl_sched_data *q = qdisc_priv(sch);
 	struct nssqdisc_qdisc *nq_new = (struct nssqdisc_qdisc *)qdisc_priv(new);
-	struct nss_shaper_configure shaper_node_attach, shaper_node_detach;
+	struct nss_if_msg nim_attach;
+	struct nss_if_msg nim_detach;
 
 	if (new == NULL)
 		new = &noop_qdisc;
@@ -2568,8 +2786,8 @@
 	nssqdisc_info("%s:Grafting old: %p with new: %p\n", __func__, *old, new);
 	if (*old != &noop_qdisc) {
 		nssqdisc_info("%s: Detaching old: %p\n", __func__, *old);
-		shaper_node_detach.mt.shaper_node_config.qos_tag = q->nq.qos_tag;
-		if (nssqdisc_node_detach(sch, &shaper_node_detach,
+		nim_detach.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = q->nq.qos_tag;
+		if (nssqdisc_node_detach(&q->nq, &nim_detach,
 				NSS_SHAPER_CONFIG_TYPE_TBL_DETACH) < 0) {
 			return -EINVAL;
 		}
@@ -2577,9 +2795,9 @@
 
 	if (new != &noop_qdisc) {
 		nssqdisc_info("%s: Attaching new: %p\n", __func__, new);
-		shaper_node_attach.mt.shaper_node_config.qos_tag = q->nq.qos_tag;
-		shaper_node_attach.mt.shaper_node_config.snc.tbl_attach.child_qos_tag = nq_new->qos_tag;
-		if (nssqdisc_node_attach(sch, &shaper_node_attach,
+		nim_attach.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = q->nq.qos_tag;
+		nim_attach.msg.shaper_configure.config.msg.shaper_node_config.snc.tbl_attach.child_qos_tag = nq_new->qos_tag;
+		if (nssqdisc_node_attach(&q->nq, &nim_attach,
 				NSS_SHAPER_CONFIG_TYPE_TBL_ATTACH) < 0) {
 			return -EINVAL;
 		}
@@ -2682,6 +2900,7 @@
 static void nssprio_destroy(struct Qdisc *sch)
 {
 	struct nssprio_sched_data *q = qdisc_priv(sch);
+	struct nss_if_msg nim;
 	int i;
 
 	nssqdisc_info("Destroying prio");
@@ -2689,15 +2908,39 @@
 	/*
 	 * Destroy all attached child nodes before destroying prio
 	 */
-	for (i = 0; i < q->bands; i++)
+	for (i = 0; i < q->bands; i++) {
+
+		/*
+		 * We always detach the shaper in NSS before destroying it.
+		 * It is very important to check for noop qdisc since those dont
+		 * exist in the NSS.
+		 */
+		if (q->queues[i] != &noop_qdisc) {
+			nim.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = q->nq.qos_tag;
+			nim.msg.shaper_configure.config.msg.shaper_node_config.snc.prio_detach.priority = i;
+			if (nssqdisc_node_detach(&q->nq, &nim,
+					NSS_SHAPER_CONFIG_TYPE_PRIO_DETACH) < 0) {
+				nssqdisc_error("%s: Failed to detach child in band %d from prio %x\n",
+							__func__, i, q->nq.qos_tag);
+				return;
+			}
+		}
+
+		/*
+		 * We can now destroy it
+		 */
 		qdisc_destroy(q->queues[i]);
+	}
 
 	/*
 	 * Stop the polling of basic stats
 	 */
-	nssqdisc_stop_basic_stats_polling(sch);
+	nssqdisc_stop_basic_stats_polling(&q->nq);
 
-	nssqdisc_destroy(sch);
+	/*
+	 * Destroy the qdisc in NSS
+	 */
+	nssqdisc_destroy(&q->nq);
 }
 
 static const struct nla_policy nssprio_policy[TCA_NSSTBL_MAX + 1] = {
@@ -2750,20 +2993,21 @@
 		q->queues[i] = &noop_qdisc;
 
 	q->bands = 0;
-	if (nssqdisc_init(sch, NSS_SHAPER_NODE_TYPE_PRIO) < 0)
+	if (nssqdisc_init(sch, &q->nq, NSS_SHAPER_NODE_TYPE_PRIO, 0) < 0)
 		return -EINVAL;
 
 	nssqdisc_info("Nssprio initialized - handle %x parent %x\n",
 			sch->handle, sch->parent);
+
 	if (nssprio_change(sch, opt) < 0) {
-		nssqdisc_destroy(sch);
+		nssqdisc_destroy(&q->nq);
 		return -EINVAL;
 	}
 
 	/*
 	 * Start the stats polling timer
 	 */
-	nssqdisc_start_basic_stats_polling(sch);
+	nssqdisc_start_basic_stats_polling(&q->nq);
 	return 0;
 }
 
@@ -2771,7 +3015,7 @@
 {
 	struct nssprio_sched_data *q = qdisc_priv(sch);
 	struct nlattr *opts = NULL;
-	struct tc_nssprio_qopt qopt;
+	struct tc_nssprio_qopt qopt; 
 
 	nssqdisc_info("Nssprio dumping");
 	qopt.bands = q->bands;
@@ -2784,7 +3028,7 @@
 
 nla_put_failure:
 	nla_nest_cancel(skb, opts);
-	return -EMSGSIZE;
+	return -EMSGSIZE;	
 }
 
 static int nssprio_graft(struct Qdisc *sch, unsigned long arg,
@@ -2793,7 +3037,8 @@
 	struct nssprio_sched_data *q = qdisc_priv(sch);
 	struct nssqdisc_qdisc *nq_new = (struct nssqdisc_qdisc *)qdisc_priv(new);
 	uint32_t band = (uint32_t)(arg - 1);
-	struct nss_shaper_configure shaper_node_attach, shaper_node_detach;
+	struct nss_if_msg nim_attach;
+	struct nss_if_msg nim_detach;
 
 	nssqdisc_info("Grafting band %u, available bands %u\n", band, q->bands);
 
@@ -2812,9 +3057,9 @@
 	nssqdisc_info("%s:Grafting old: %p with new: %p\n", __func__, *old, new);
 	if (*old != &noop_qdisc) {
 		nssqdisc_info("%s:Detaching old: %p\n", __func__, *old);
-		shaper_node_detach.mt.shaper_node_config.qos_tag = q->nq.qos_tag;
-		shaper_node_detach.mt.shaper_node_config.snc.prio_detach.priority = band;
-		if (nssqdisc_node_detach(sch, &shaper_node_detach,
+		nim_detach.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = q->nq.qos_tag;
+		nim_detach.msg.shaper_configure.config.msg.shaper_node_config.snc.prio_detach.priority = band;
+		if (nssqdisc_node_detach(&q->nq, &nim_detach,
 				NSS_SHAPER_CONFIG_TYPE_PRIO_DETACH) < 0) {
 			return -EINVAL;
 		}
@@ -2823,10 +3068,10 @@
 	if (new != &noop_qdisc) {
 		nssqdisc_info("%s:Attaching new child with qos tag: %x, priority: %u to "
 				"qos_tag: %x\n", __func__, nq_new->qos_tag, band, q->nq.qos_tag);
-		shaper_node_attach.mt.shaper_node_config.qos_tag = q->nq.qos_tag;
-		shaper_node_attach.mt.shaper_node_config.snc.prio_attach.child_qos_tag = nq_new->qos_tag;
-		shaper_node_attach.mt.shaper_node_config.snc.prio_attach.priority = band;
-		if (nssqdisc_node_attach(sch, &shaper_node_attach,
+		nim_attach.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = q->nq.qos_tag;
+		nim_attach.msg.shaper_configure.config.msg.shaper_node_config.snc.prio_attach.child_qos_tag = nq_new->qos_tag;
+		nim_attach.msg.shaper_configure.config.msg.shaper_node_config.snc.prio_attach.priority = band;
+		if (nssqdisc_node_attach(&q->nq, &nim_attach,
 				NSS_SHAPER_CONFIG_TYPE_PRIO_ATTACH) < 0) {
 			return -EINVAL;
 		}
@@ -2841,7 +3086,7 @@
 	struct nssprio_sched_data *q = qdisc_priv(sch);
 	uint32_t band = (uint32_t)(arg - 1);
 
-	nssqdisc_info("Nssprio returns leaf");
+	nssqdisc_info("Nssprio returns leaf\n");
 
 	if (band > q->bands)
 		return NULL;
@@ -2854,7 +3099,7 @@
 	struct nssprio_sched_data *q = qdisc_priv(sch);
 	unsigned long band = TC_H_MIN(classid);
 
-	nssqdisc_info("Inside get. Handle - %x Classid - %x Band %lu Available band %u", sch->handle, classid, band, q->bands);
+	nssqdisc_info("Inside get. Handle - %x Classid - %x Band %lu Available band %u\n", sch->handle, classid, band, q->bands);
 
 	if (band > q->bands)
 		return 0;
@@ -2886,7 +3131,7 @@
 		}
 		arg->count++;
 	}
-	nssqdisc_info("Nssprio walk called");
+	nssqdisc_info("Nssprio walk called\n");
 }
 
 static int nssprio_dump_class(struct Qdisc *sch, unsigned long cl,
@@ -2897,7 +3142,7 @@
 	tcm->tcm_handle |= TC_H_MIN(cl);
 	tcm->tcm_info = q->queues[cl - 1]->handle;
 
-	nssqdisc_info("Nssprio dumping class");
+	nssqdisc_info("Nssprio dumping class\n");
 	return 0;
 }
 
@@ -2913,7 +3158,7 @@
 	    gnet_stats_copy_queue(d, &cl_q->qstats) < 0)
 		return -1;
 
-	nssqdisc_info("Nssprio dumping class stats");
+	nssqdisc_info("Nssprio dumping class stats\n");
 	return 0;
 }
 
@@ -2944,13 +3189,1376 @@
 	.owner		=	THIS_MODULE,
 };
 
+/* ========================= NSSBF ===================== */
+
+struct nssbf_class_data {
+	struct nssqdisc_qdisc nq;		/* Base class used by nssqdisc */
+	struct Qdisc_class_common cl_common;	/* Common class structure */
+	u32 rate;				/* Allowed bandwidth for this class */
+	u32 burst;				/* Allowed burst for this class */
+	u32 mtu;				/* MTU size of the interface */
+	u32 quantum;				/* Quantum allocation for DRR */
+	struct Qdisc *qdisc;			/* Pointer to child qdisc */
+};
+
+struct nssbf_sched_data {
+	struct nssqdisc_qdisc nq;		/* Base class used by nssqdisc */
+	u16 defcls;				/* default class id */
+	struct nssbf_class_data root;		/* root class */
+	struct Qdisc_class_hash clhash;		/* class hash */
+};
+
+static inline struct nssbf_class_data *nssbf_find_class(u32 classid,
+							struct Qdisc *sch)
+{
+	struct nssbf_sched_data *q = qdisc_priv(sch);
+	struct Qdisc_class_common *clc;
+	clc = qdisc_class_find(&q->clhash, classid);
+	if (clc == NULL) {
+		nssqdisc_warning("%s: Cannot find class with classid %u in qdisc %p hash table %p\n", __func__, classid, sch, &q->clhash);
+		return NULL;
+	}
+	return container_of(clc, struct nssbf_class_data, cl_common);
+}
+
+static const struct nla_policy nssbf_policy[TCA_NSSBF_MAX + 1] = {
+	[TCA_NSSBF_CLASS_PARMS] = { .len = sizeof(struct tc_nssbf_class_qopt) },
+};
+
+static int nssbf_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
+		  struct nlattr **tca, unsigned long *arg)
+{
+	struct nssbf_sched_data *q = qdisc_priv(sch);
+	struct nssbf_class_data *cl = (struct nssbf_class_data *)*arg;
+	struct nlattr *opt = tca[TCA_OPTIONS];
+	struct nlattr *na[TCA_NSSBF_MAX + 1];
+	struct tc_nssbf_class_qopt *qopt;
+	int err;
+	struct nss_if_msg nim_config;
+	struct net_device *dev = qdisc_dev(sch);
+
+	nssqdisc_info("%s: Changing bf class %u\n", __func__, classid);
+        if (opt == NULL)
+                return -EINVAL;
+
+        err = nla_parse_nested(na, TCA_NSSBF_MAX, opt, nssbf_policy);
+        if (err < 0)
+                return err;
+
+        if (na[TCA_NSSBF_CLASS_PARMS] == NULL)
+                return -EINVAL;
+
+	/*
+	 * If class with a given classid is not found, we allocate a new one
+	 */
+	if (!cl) {
+		struct nss_if_msg nim_attach;
+		nssqdisc_info("%s: Bf class %u not found. Allocating a new class.\n", __func__, classid);
+		cl = kzalloc(sizeof(struct nssbf_class_data), GFP_KERNEL);
+
+		if (!cl) {
+			nssqdisc_error("%s: Class allocation failed for classid %u\n", __func__, classid);
+			return -EINVAL;
+		}
+
+		nssqdisc_info("%s: Bf class %u allocated %p\n", __func__, classid, cl);
+		cl->cl_common.classid = classid;
+
+		/*
+		 * We make the child qdisc a noop qdisc, and
+		 * set reference count to 1. This is important,
+		 * reference count should not be 0.
+		 */
+		cl->qdisc = &noop_qdisc;
+		atomic_set(&cl->nq.refcnt, 1);
+		*arg = (unsigned long)cl;
+
+		nssqdisc_info("%s: Adding classid %u to qdisc %p hash queue %p\n", __func__, classid, sch, &q->clhash);
+
+		/*
+		 * This is where a class gets initialized. Classes do not have a init function
+		 * that is registered to Linux. Therefore we initialize the NSSBF_GROUP shaper
+		 * here.
+		 */
+		if (nssqdisc_init(sch, &cl->nq, NSS_SHAPER_NODE_TYPE_BF_GROUP, classid) < 0) {
+			nssqdisc_error("%s: Nss init for class %u failed\n", __func__, classid);
+			return -EINVAL;
+		}
+
+		/*
+		 * Set qos_tag of parent to which the class needs to e attached to.
+		 */
+		nim_attach.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = q->nq.qos_tag;
+
+		/*
+		 * Set the child to be this class.
+		 */
+		nim_attach.msg.shaper_configure.config.msg.shaper_node_config.snc.bf_attach.child_qos_tag = cl->nq.qos_tag;
+
+		/*
+		 * Send node_attach command down to the NSS
+		 */
+		if (nssqdisc_node_attach(&q->nq, &nim_attach,
+				NSS_SHAPER_CONFIG_TYPE_BF_ATTACH) < 0) {
+			nssqdisc_error("%s: Nss attach for class %u failed\n", __func__, classid);
+			return -EINVAL;
+		}
+
+		/*
+		 * Add class to hash tree once it is attached in the NSS
+		 */
+		sch_tree_lock(sch);
+		qdisc_class_hash_insert(&q->clhash, &cl->cl_common);
+		sch_tree_unlock(sch);
+
+		/*
+		 * Hash grow should not come within the tree lock
+		 */
+		qdisc_class_hash_grow(sch, &q->clhash);
+
+		/*
+		 * Start the stats polling timer
+		 */
+		nssqdisc_start_basic_stats_polling(&cl->nq);
+
+		nssqdisc_info("%s: Class %u successfully allocated\n", __func__, classid);
+	}
+
+	qopt = nla_data(na[TCA_NSSBF_CLASS_PARMS]);
+
+	sch_tree_lock(sch);
+	cl->rate = qopt->rate;
+	cl->burst = qopt->burst;
+
+	/*
+	 * If MTU and quantum values are not provided, set them to
+	 * the interface's MTU value.
+	 */
+	if (!qopt->mtu) {
+		cl->mtu = psched_mtu(dev);
+		nssqdisc_info("MTU not provided for bf class on interface %s. "
+				"Setting MTU to %u bytes\n", dev->name, cl->mtu);
+	} else {
+		cl->mtu = qopt->mtu;
+	}
+
+	if (!qopt->quantum) {
+		cl->quantum = psched_mtu(dev);
+		nssqdisc_info("Quantum value not provided for bf class on interface %s. "
+				"Setting quantum to %u\n", dev->name, cl->quantum);
+	} else {
+		cl->mtu = qopt->quantum;
+	}
+
+	sch_tree_unlock(sch);
+
+	/*
+	 * Fill information that needs to be sent down to the NSS for configuring the
+	 * bf class.
+	 */
+	nim_config.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = cl->nq.qos_tag;
+	nim_config.msg.shaper_configure.config.msg.shaper_node_config.snc.bf_group_param.quantum = cl->quantum;
+	nim_config.msg.shaper_configure.config.msg.shaper_node_config.snc.bf_group_param.lap.rate = cl->rate;
+	nim_config.msg.shaper_configure.config.msg.shaper_node_config.snc.bf_group_param.lap.burst = cl->burst;
+	nim_config.msg.shaper_configure.config.msg.shaper_node_config.snc.bf_group_param.lap.max_size = cl->mtu;
+	nim_config.msg.shaper_configure.config.msg.shaper_node_config.snc.bf_group_param.lap.short_circuit = false;
+
+	nssqdisc_info("Rate = %u Burst = %u MTU = %u Quantum = %u\n", cl->rate, cl->burst, cl->mtu, cl->quantum);
+
+	/*
+	 * Send configure command to the NSS
+	 */
+	if (nssqdisc_configure(&cl->nq, &nim_config,
+			NSS_SHAPER_CONFIG_TYPE_BF_GROUP_CHANGE_PARAM) < 0) {
+		nssqdisc_error("%s: Failed to configure class %u\n", __func__, classid);
+		return -EINVAL;
+	}
+
+	nssqdisc_info("%s: Class %u changed successfully\n", __func__, classid);
+	return 0;
+}
+
+static void nssbf_destroy_class(struct Qdisc *sch, struct nssbf_class_data *cl)
+{
+	struct nssbf_sched_data *q = qdisc_priv(sch);
+	struct nss_if_msg nim;
+
+	nssqdisc_info("Destroying bf class %p from qdisc %p\n", cl, sch);
+
+	/*
+	 * Note, this function gets called even for NSSBF and not just for NSSBF_GROUP.
+	 * If this is BF qdisc then we should not call nssqdisc_destroy or stop polling
+	 * for stats. These two actions will happen inside nssbf_destroy(), which is called
+	 * only for the root qdisc.
+	 */
+	if (cl == &q->root) {
+		nssqdisc_info("%s: We do not destroy bf class %p here since this is "
+				"the qdisc %p\n", __func__, cl, sch);
+		return;
+	}
+
+	/*
+	 * We always have to detach our child qdisc in NSS, before destroying it.
+	 */
+	if (cl->qdisc != &noop_qdisc) {
+		nim.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = cl->nq.qos_tag;
+		if (nssqdisc_node_detach(&cl->nq, &nim,
+				NSS_SHAPER_CONFIG_TYPE_BF_GROUP_DETACH) < 0) {
+			nssqdisc_error("%s: Failed to detach child %x from class %x\n",
+					__func__, cl->qdisc->handle, q->nq.qos_tag);
+			return;
+		}
+	}
+
+	/*
+	 * And now we destroy the child.
+	 */
+	qdisc_destroy(cl->qdisc);
+
+	/*
+	 * Stop the stats polling timer and free class
+	 */
+	nssqdisc_stop_basic_stats_polling(&cl->nq);
+
+	/*
+	 * Destroy the shaper in NSS
+	 */
+	nssqdisc_destroy(&cl->nq);
+
+	/*
+	 * Free class
+	 */
+	kfree(cl);
+}
+
+static int nssbf_delete_class(struct Qdisc *sch, unsigned long arg)
+{
+	struct nssbf_sched_data *q = qdisc_priv(sch);
+	struct nssbf_class_data *cl = (struct nssbf_class_data *)arg;
+	struct nss_if_msg nim;
+	int refcnt;
+
+	/*
+	 * Since all classes are leaf nodes in our case, we dont have to make
+	 * that check.
+	 */
+	if (cl == &q->root)
+		return -EBUSY;
+
+	/*
+	 * The message to NSS should be sent to the parent of this class
+	 */
+	nssqdisc_info("%s: Detaching bf class: %p\n", __func__, cl);
+	nim.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = q->nq.qos_tag;
+	nim.msg.shaper_configure.config.msg.shaper_node_config.snc.bf_detach.child_qos_tag = cl->nq.qos_tag;
+	if (nssqdisc_node_detach(&q->nq, &nim,
+			NSS_SHAPER_CONFIG_TYPE_BF_DETACH) < 0) {
+		return -EINVAL;
+	}
+
+	sch_tree_lock(sch);
+	qdisc_reset(cl->qdisc);
+	qdisc_class_hash_remove(&q->clhash, &cl->cl_common);
+	refcnt = atomic_sub_return(1, &cl->nq.refcnt);
+	sch_tree_unlock(sch);
+	if (!refcnt) {
+		nssqdisc_error("%s: Reference count should not be zero for class %p\n", __func__, cl);
+	}
+
+	return 0;
+}
+
+static int nssbf_graft_class(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
+								 struct Qdisc **old)
+{
+	struct nssbf_class_data *cl = (struct nssbf_class_data *)arg;
+	struct nss_if_msg nim_detach;
+	struct nss_if_msg nim_attach;
+	struct nssqdisc_qdisc *nq_new = qdisc_priv(new);
+
+	nssqdisc_info("Grafting class %p\n", sch);
+	if (new == NULL)
+		new = &noop_qdisc;
+
+	sch_tree_lock(sch);
+	*old = cl->qdisc;
+	sch_tree_unlock(sch);
+
+	/*
+	 * Since we initially attached a noop qdisc as child (in Linux),
+	 * we do not perform a detach in the NSS if its a noop qdisc.
+	 */
+	nssqdisc_info("%s:Grafting old: %p with new: %p\n", __func__, *old, new);
+	if (*old != &noop_qdisc) {
+		nssqdisc_info("%s: Detaching old: %p\n", __func__, *old);
+		nim_detach.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = cl->nq.qos_tag;
+		if (nssqdisc_node_detach(&cl->nq, &nim_detach,
+				NSS_SHAPER_CONFIG_TYPE_BF_GROUP_DETACH) < 0) {
+			return -EINVAL;
+		}
+	}
+
+	/*
+	 * If the new qdisc is a noop qdisc, we do not send down an attach command
+	 * to the NSS.
+	 */
+	if (new != &noop_qdisc) {
+		nssqdisc_info("%s: Attaching new: %p\n", __func__, new);
+		nim_attach.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = cl->nq.qos_tag;
+		nim_attach.msg.shaper_configure.config.msg.shaper_node_config.snc.bf_group_attach.child_qos_tag = nq_new->qos_tag;
+		if (nssqdisc_node_attach(&cl->nq, &nim_attach,
+				NSS_SHAPER_CONFIG_TYPE_BF_GROUP_ATTACH) < 0) {
+			return -EINVAL;
+		}
+	}
+
+	/*
+	 * Attach qdisc once it is done in the NSS
+	 */
+	sch_tree_lock(sch);
+	cl->qdisc = new;
+	sch_tree_unlock(sch);
+
+	nssqdisc_info("Nssbf grafted");
+
+	return 0;
+}
+
+static struct Qdisc *nssbf_leaf_class(struct Qdisc *sch, unsigned long arg)
+{
+	struct nssbf_class_data *cl = (struct nssbf_class_data *)arg;
+	nssqdisc_info("bf class leaf %p\n", cl);
+
+	/*
+	 * Since all nssbf groups are leaf nodes, we can always
+	 * return the attached qdisc.
+	 */
+	return cl->qdisc;
+}
+
+static void nssbf_qlen_notify(struct Qdisc *sch, unsigned long arg)
+{
+	nssqdisc_info("bf qlen notify %p\n", sch);
+	/*
+	 * Gets called when qlen of child changes (Useful for deactivating)
+	 * Not useful for us here.
+	 */
+}
+
+static unsigned long nssbf_get_class(struct Qdisc *sch, u32 classid)
+{
+	struct nssbf_class_data *cl = nssbf_find_class(classid, sch);
+
+	nssqdisc_info("Get bf class %p - class match = %p\n", sch, cl);
+
+	if (cl != NULL)
+		atomic_add(1, &cl->nq.refcnt);
+
+	return (unsigned long)cl;
+}
+
+static void nssbf_put_class(struct Qdisc *sch, unsigned long arg)
+{
+	struct nssbf_class_data *cl = (struct nssbf_class_data *)arg;
+	nssqdisc_info("bf put class for %p\n", cl);
+
+	/*
+	 * We are safe to destroy the qdisc if the reference count
+	 * goes down to 0.
+	 */
+	if (atomic_sub_return(1, &cl->nq.refcnt) == 0) {
+		nssbf_destroy_class(sch, cl);
+	}
+}
+
+static int nssbf_dump_class(struct Qdisc *sch, unsigned long arg, struct sk_buff *skb,
+		struct tcmsg *tcm)
+{
+	struct nssbf_class_data *cl = (struct nssbf_class_data *)arg;
+	struct nlattr *opts;
+	struct tc_nssbf_class_qopt qopt;
+
+	nssqdisc_info("Dumping class %p of Qdisc %p\n", cl, sch);
+
+	qopt.burst = cl->burst;
+	qopt.rate = cl->rate;
+	qopt.mtu = cl->mtu;
+	qopt.quantum = cl->quantum;
+
+	/*
+	 * All bf group nodes are root nodes. i.e. they dont
+	 * have any mode bf groups attached beneath them.
+	 */
+	tcm->tcm_parent = TC_H_ROOT;
+	tcm->tcm_handle = cl->cl_common.classid;
+	tcm->tcm_info = cl->qdisc->handle;
+
+	opts = nla_nest_start(skb, TCA_OPTIONS);
+	if (opts == NULL)
+		goto nla_put_failure;
+	NLA_PUT(skb, TCA_NSSBF_CLASS_PARMS, sizeof(qopt), &qopt);
+	return nla_nest_end(skb, opts);
+
+nla_put_failure:
+	nla_nest_cancel(skb, opts);
+	return -EMSGSIZE;
+}
+
+static int nssbf_dump_class_stats(struct Qdisc *sch, unsigned long arg, struct gnet_dump *d)
+{
+	struct nssqdisc_qdisc *nq = (struct nssqdisc_qdisc *)arg;
+
+	if (gnet_stats_copy_basic(d, &nq->bstats) < 0 ||
+		gnet_stats_copy_queue(d, &nq->qstats) < 0) {
+		return -1;
+	}
+
+	return 0;
+}
+
+static void nssbf_walk(struct Qdisc *sch, struct qdisc_walker *arg)
+{
+	struct nssbf_sched_data *q = qdisc_priv(sch);
+	struct hlist_node *n;
+	struct nssbf_class_data *cl;
+	unsigned int i;
+
+	nssqdisc_info("In bf walk %p\n", sch);
+	if (arg->stop)
+		return;
+
+	for (i = 0; i < q->clhash.hashsize; i++) {
+		hlist_for_each_entry(cl, n, &q->clhash.hash[i],
+				cl_common.hnode) {
+			if (arg->count < arg->skip) {
+				arg->count++;
+				continue;
+			}
+			if (arg->fn(sch, (unsigned long)cl, arg) < 0) {
+				arg->stop = 1;
+				return;
+			}
+			arg->count++;
+		}
+	}
+}
+
+static int nssbf_init_qdisc(struct Qdisc *sch, struct nlattr *opt)
+{
+	struct nssbf_sched_data *q = qdisc_priv(sch);
+	struct tc_nssbf_qopt *qopt;
+	int err;
+
+	nssqdisc_info("Init bf qdisc %p\n", sch);
+	if (opt == NULL || nla_len(opt) < sizeof(*qopt))
+		return -EINVAL;
+	qopt = nla_data(opt);
+
+	q->defcls = qopt->defcls;
+	err = qdisc_class_hash_init(&q->clhash);
+	if (err < 0)
+		return err;
+
+	q->root.cl_common.classid = sch->handle;
+	q->root.qdisc = &noop_qdisc;
+
+	qdisc_class_hash_insert(&q->clhash, &q->root.cl_common);
+	qdisc_class_hash_grow(sch, &q->clhash);
+
+	/*
+	 * Initialize the NSSBF shaper in NSS
+	 */
+	if (nssqdisc_init(sch, &q->nq, NSS_SHAPER_NODE_TYPE_BF, 0) < 0)
+		return -EINVAL;
+
+	nssqdisc_info("Nssbf initialized - handle %x parent %x\n", sch->handle, sch->parent);
+
+	/*
+	 * Start the stats polling timer
+	 */
+	nssqdisc_start_basic_stats_polling(&q->nq);
+
+	return 0;
+}
+
+static int nssbf_change_qdisc(struct Qdisc *sch, struct nlattr *opt)
+{
+	struct nssbf_sched_data *q = qdisc_priv(sch);
+	struct tc_nssbf_qopt *qopt;
+
+	/*
+	 * NSSBF does not care about the defcls, so we dont send down any
+	 * configuration parameter.
+	 */
+	nssqdisc_info("Changing bf qdisc %p\n", sch);
+	if (opt == NULL || nla_len(opt) < sizeof(*qopt))
+		return -EINVAL;
+	qopt = nla_data(opt);
+
+	sch_tree_lock(sch);
+	q->defcls = qopt->defcls;
+	sch_tree_unlock(sch);
+
+	return 0;
+}
+
+static void nssbf_reset_class(struct nssbf_class_data *cl)
+{
+	nssqdisc_reset(cl->qdisc);
+	nssqdisc_info("Nssbf class resetted %p\n", cl->qdisc);
+}
+
+static void nssbf_reset_qdisc(struct Qdisc *sch)
+{
+	struct nssbf_sched_data *q = qdisc_priv(sch);
+	struct nssbf_class_data *cl;
+	struct hlist_node *n;
+	unsigned int i;
+
+	for (i = 0; i < q->clhash.hashsize; i++) {
+		hlist_for_each_entry(cl, n, &q->clhash.hash[i], cl_common.hnode)
+			nssbf_reset_class(cl);
+	}
+
+	nssqdisc_reset(sch);
+	nssqdisc_info("Nssbf qdisc resetted %p\n", sch);
+}
+
+static void nssbf_destroy_qdisc(struct Qdisc *sch)
+{
+	struct nssbf_sched_data *q = qdisc_priv(sch);
+	struct hlist_node *n, *next;
+	struct nssbf_class_data *cl;
+	struct nss_if_msg nim;
+	unsigned int i;
+
+	/*
+	 * Destroy all the classes before the root qdisc is destroyed.
+	 */
+	for (i = 0; i < q->clhash.hashsize; i++) {
+		hlist_for_each_entry_safe(cl, n, next, &q->clhash.hash[i], cl_common.hnode) {
+
+			/*
+			 * If this is the root class, we dont have to destroy it. This will be taken
+			 * care of by the nssbf_destroy() function.
+			 */
+			if (cl == &q->root) {
+				nssqdisc_info("%s: We do not detach or destroy bf class %p here since this is "
+						"the qdisc %p\n", __func__, cl, sch);
+				continue;
+			}
+
+			/*
+			 * Reduce refcnt by 1 before destroying. This is to
+			 * ensure that polling of stat stops properly.
+			 */
+			atomic_sub(1, &cl->nq.refcnt);
+
+			/*
+			 * Detach class before destroying it. We dont check for noop qdisc here
+			 * since we do not attach anu such at init.
+			 */
+			nim.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = q->nq.qos_tag;
+			nim.msg.shaper_configure.config.msg.shaper_node_config.snc.bf_detach.child_qos_tag = cl->nq.qos_tag;
+			if (nssqdisc_node_detach(&q->nq, &nim,
+					NSS_SHAPER_CONFIG_TYPE_BF_DETACH) < 0) {
+				nssqdisc_error("%s: Node detach failed for qdisc %x class %x\n",
+							__func__, cl->nq.qos_tag, q->nq.qos_tag);
+				return;
+			}
+
+			/*
+			 * Now we can destroy the class.
+			 */
+			nssbf_destroy_class(sch, cl);
+		}
+	}
+	qdisc_class_hash_destroy(&q->clhash);
+
+	/*
+	 * Stop the polling of basic stats
+	 */
+	nssqdisc_stop_basic_stats_polling(&q->nq);
+
+	/*
+	 * Now we can go ahead and destroy the qdisc.
+	 * Note: We dont have to detach ourself from our parent because this
+	 *	 will be taken care of by the graft call.
+	 */
+	nssqdisc_destroy(&q->nq);
+	nssqdisc_info("Nssbf destroyed %p\n", sch);
+}
+
+static int nssbf_dump_qdisc(struct Qdisc *sch, struct sk_buff *skb)
+{
+	struct nssbf_sched_data *q = qdisc_priv(sch);
+	unsigned char *b = skb_tail_pointer(skb);
+	struct tc_nssbf_qopt qopt;
+	struct nlattr *nest;
+
+	nssqdisc_info("In bf dump qdisc\n");
+
+	nest = nla_nest_start(skb, TCA_OPTIONS);
+	if (nest == NULL) {
+		goto nla_put_failure;
+	}
+
+	qopt.defcls = q->defcls;
+	NLA_PUT(skb, TCA_NSSBF_QDISC_PARMS, sizeof(qopt), &qopt);
+	nla_nest_end(skb, nest);
+
+	return skb->len;
+
+ nla_put_failure:
+	nlmsg_trim(skb, b);
+	return -1;
+}
+
+static int nssbf_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+{
+	return nssqdisc_enqueue(skb, sch);
+}
+
+static struct sk_buff *nssbf_dequeue(struct Qdisc *sch)
+{
+	return nssqdisc_dequeue(sch);
+}
+
+static unsigned int nssbf_drop(struct Qdisc *sch)
+{
+	printk("In bf drop\n");
+	return nssqdisc_drop(sch);
+}
+
+static const struct Qdisc_class_ops nssbf_class_ops = {
+	.change		= nssbf_change_class,
+	.delete		= nssbf_delete_class,
+	.graft		= nssbf_graft_class,
+	.leaf		= nssbf_leaf_class,
+	.qlen_notify	= nssbf_qlen_notify,
+	.get		= nssbf_get_class,
+	.put		= nssbf_put_class,
+	.dump		= nssbf_dump_class,
+	.dump_stats	= nssbf_dump_class_stats,
+	.walk		= nssbf_walk
+};
+
+static struct Qdisc_ops nssbf_qdisc_ops __read_mostly = {
+	.id		= "nssbf",
+	.init		= nssbf_init_qdisc,
+	.change		= nssbf_change_qdisc,
+	.reset		= nssbf_reset_qdisc,
+	.destroy	= nssbf_destroy_qdisc,
+	.dump		= nssbf_dump_qdisc,
+	.enqueue	= nssbf_enqueue,
+	.dequeue	= nssbf_dequeue,
+	.peek		= qdisc_peek_dequeued,
+	.drop		= nssbf_drop,
+	.cl_ops		= &nssbf_class_ops,
+	.priv_size	= sizeof(struct nssbf_sched_data),
+	.owner		= THIS_MODULE
+};
+
+/* ========================= NSSWRR ===================== */
+
+struct nsswrr_class_data {
+	struct nssqdisc_qdisc nq;		/* Base class used by nssqdisc */
+	struct Qdisc_class_common cl_common;	/* Common class structure */
+	u32 quantum;				/* Quantum allocation for DRR */
+	struct Qdisc *qdisc;			/* Pointer to child qdisc */
+};
+
+struct nsswrr_sched_data {
+	struct nssqdisc_qdisc nq;		/* Base class used by nssqdisc */
+	struct nsswrr_class_data root;		/* root class */
+	struct Qdisc_class_hash clhash;		/* class hash */
+};
+
+static inline struct nsswrr_class_data *nsswrr_find_class(u32 classid,
+							struct Qdisc *sch)
+{
+	struct nsswrr_sched_data *q = qdisc_priv(sch);
+	struct Qdisc_class_common *clc;
+	clc = qdisc_class_find(&q->clhash, classid);
+	if (clc == NULL) {
+		nssqdisc_warning("%s: Cannot find class with classid %u in qdisc %p hash table %p\n", __func__, classid, sch, &q->clhash);
+		return NULL;
+	}
+	return container_of(clc, struct nsswrr_class_data, cl_common);
+}
+
+static const struct nla_policy nsswrr_policy[TCA_NSSWRR_MAX + 1] = {
+	[TCA_NSSWRR_CLASS_PARMS] = { .len = sizeof(struct tc_nsswrr_class_qopt) },
+};
+
+static void nsswrr_destroy_class(struct Qdisc *sch, struct nsswrr_class_data *cl)
+{
+	struct nsswrr_sched_data *q = qdisc_priv(sch);
+	struct nss_if_msg nim;
+
+	nssqdisc_info("Destroying nsswrr class %p from qdisc %p\n", cl, sch);
+
+	/*
+	 * Note, this function gets called even for NSSWRR and not just for NSSWRR_GROUP.
+	 * If this is wrr qdisc then we should not call nssqdisc_destroy or stop polling
+	 * for stats. These two actions will happen inside nsswrr_destroy(), which is called
+	 * only for the root qdisc.
+	 */
+	if (cl == &q->root) {
+		nssqdisc_info("%s: We do not destroy nsswrr class %p here since this is "
+				"the qdisc %p\n", __func__, cl, sch);
+		return;
+	}
+
+	/*
+	 * We always have to detach our child qdisc in NSS, before destroying it.
+	 */
+	if (cl->qdisc != &noop_qdisc) {
+		nim.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = cl->nq.qos_tag;
+		if (nssqdisc_node_detach(&cl->nq, &nim,
+				NSS_SHAPER_CONFIG_TYPE_WRR_GROUP_DETACH) < 0) {
+			nssqdisc_error("%s: Failed to detach child %x from class %x\n",
+					__func__, cl->qdisc->handle, q->nq.qos_tag);
+			return;
+		}
+	}
+
+	/*
+	 * And now we destroy the child.
+	 */
+	qdisc_destroy(cl->qdisc);
+
+	/*
+	 * Stop the stats polling timer and free class
+	 */
+	nssqdisc_stop_basic_stats_polling(&cl->nq);
+
+	/*
+	 * Destroy the shaper in NSS
+	 */
+	nssqdisc_destroy(&cl->nq);
+
+	/*
+	 * Free class
+	 */
+	kfree(cl);
+}
+
+static int nsswrr_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
+		  struct nlattr **tca, unsigned long *arg)
+{
+	struct nsswrr_sched_data *q = qdisc_priv(sch);
+	struct nsswrr_class_data *cl = (struct nsswrr_class_data *)*arg;
+	struct nlattr *opt = tca[TCA_OPTIONS];
+	struct nlattr *na[TCA_NSSWRR_MAX + 1];
+	struct tc_nsswrr_class_qopt *qopt;
+	struct nss_if_msg nim_config;
+	struct net_device *dev = qdisc_dev(sch);
+	bool new_init = false;
+	int err;
+
+	nssqdisc_info("%s: Changing nsswrr class %u\n", __func__, classid);
+        if (opt == NULL)
+                return -EINVAL;
+
+        err = nla_parse_nested(na, TCA_NSSWRR_MAX, opt, nsswrr_policy);
+        if (err < 0)
+                return err;
+
+        if (na[TCA_NSSWRR_CLASS_PARMS] == NULL)
+                return -EINVAL;
+
+	/*
+	 * If class with a given classid is not found, we allocate a new one
+	 */
+	if (!cl) {
+
+		struct nss_if_msg nim_attach;
+
+		/*
+		 * The class does not already exist, we are newly initializing it.
+		 */
+		new_init = true;
+
+		nssqdisc_info("%s: nsswrr class %u not found. Allocating a new class.\n", __func__, classid);
+		cl = kzalloc(sizeof(struct nsswrr_class_data), GFP_KERNEL);
+
+		if (!cl) {
+			nssqdisc_error("%s: Class allocation failed for classid %u\n", __func__, classid);
+			return -EINVAL;
+		}
+
+		nssqdisc_info("%s: Bf class %u allocated %p\n", __func__, classid, cl);
+		cl->cl_common.classid = classid;
+
+		/*
+		 * We make the child qdisc a noop qdisc, and
+		 * set reference count to 1. This is important,
+		 * reference count should not be 0.
+		 */
+		cl->qdisc = &noop_qdisc;
+		atomic_set(&cl->nq.refcnt, 1);
+		*arg = (unsigned long)cl;
+
+		nssqdisc_info("%s: Adding classid %u to qdisc %p hash queue %p\n", __func__, classid, sch, &q->clhash);
+
+		/*
+		 * This is where a class gets initialized. Classes do not have a init function
+		 * that is registered to Linux. Therefore we initialize the NSSWRR_GROUP shaper
+		 * here.
+		 */
+		if (nssqdisc_init(sch, &cl->nq, NSS_SHAPER_NODE_TYPE_WRR_GROUP, classid) < 0) {
+			nssqdisc_error("%s: Nss init for class %u failed\n", __func__, classid);
+			return -EINVAL;
+		}
+
+		/*
+		 * Set qos_tag of parent to which the class needs to e attached to.
+		 */
+		nim_attach.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = q->nq.qos_tag;
+
+		/*
+		 * Set the child to be this class.
+		 */
+		nim_attach.msg.shaper_configure.config.msg.shaper_node_config.snc.wrr_attach.child_qos_tag = cl->nq.qos_tag;
+
+		/*
+		 * Send node_attach command down to the NSS
+		 */
+		if (nssqdisc_node_attach(&q->nq, &nim_attach,
+				NSS_SHAPER_CONFIG_TYPE_WRR_ATTACH) < 0) {
+			nssqdisc_error("%s: Nss attach for class %u failed\n", __func__, classid);
+			nssqdisc_destroy(&cl->nq);
+			return -EINVAL;
+		}
+
+		/*
+		 * Add class to hash tree once it is attached in the NSS
+		 */
+		sch_tree_lock(sch);
+		qdisc_class_hash_insert(&q->clhash, &cl->cl_common);
+		sch_tree_unlock(sch);
+
+		/*
+		 * Hash grow should not come within the tree lock
+		 */
+		qdisc_class_hash_grow(sch, &q->clhash);
+
+		/*
+		 * Start the stats polling timer
+		 */
+		nssqdisc_start_basic_stats_polling(&cl->nq);
+
+		nssqdisc_info("%s: Class %u successfully allocated\n", __func__, classid);
+	}
+
+	qopt = nla_data(na[TCA_NSSWRR_CLASS_PARMS]);
+
+	sch_tree_lock(sch);
+
+	/*
+	 * If the value of quantum is not provided default it based on the type
+	 * of operation (i.e. wrr or wfq)
+	 */
+	cl->quantum = qopt->quantum;
+	if (!cl->quantum) {
+		if (strncmp(sch->ops->id, "nsswrr", 6) == 0) {
+			cl->quantum = 1;
+			nssqdisc_info("Quantum value not provided for nsswrr class on interface %s. "
+					"Setting quantum to %up\n", dev->name, cl->quantum);
+		} else if (strncmp(sch->ops->id, "nsswfq", 6) == 0) {
+			cl->quantum = psched_mtu(dev);
+			nssqdisc_info("Quantum value not provided for nsswrr class on interface %s. "
+					"Setting quantum to %ubytes\n", dev->name, cl->quantum);
+		} else {
+			nssqdisc_error("%s: Unsupported parent type", __func__);
+			return -EINVAL;
+		}
+	}
+
+	sch_tree_unlock(sch);
+
+	/*
+	 * Fill information that needs to be sent down to the NSS for configuring the
+	 * bf class.
+	 */
+	nim_config.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = cl->nq.qos_tag;
+	nim_config.msg.shaper_configure.config.msg.shaper_node_config.snc.wrr_group_param.quantum = cl->quantum;
+
+	nssqdisc_info("Quantum = %u\n", cl->quantum);
+
+	/*
+	 * Send configure command to the NSS
+	 */
+	if (nssqdisc_configure(&cl->nq, &nim_config,
+			NSS_SHAPER_CONFIG_TYPE_WRR_GROUP_CHANGE_PARAM) < 0) {
+		nssqdisc_error("%s: Failed to configure class %x\n", __func__, classid);
+
+		/*
+		 * We dont have to destroy the class if this was just a
+		 * change command.
+		 */
+		if (!new_init) {
+			return -EINVAL;
+		}
+
+		/*
+		 * Else, we have failed in the NSS and we will have to
+		 * destroy the class
+		 */
+		nsswrr_destroy_class(sch, cl);
+		return -EINVAL;
+	}
+
+	nssqdisc_info("%s: Class %x changed successfully\n", __func__, classid);
+	return 0;
+}
+
+static int nsswrr_delete_class(struct Qdisc *sch, unsigned long arg)
+{
+	struct nsswrr_sched_data *q = qdisc_priv(sch);
+	struct nsswrr_class_data *cl = (struct nsswrr_class_data *)arg;
+	struct nss_if_msg nim;
+	int refcnt;
+
+	/*
+	 * Since all classes are leaf nodes in our case, we dont have to make
+	 * that check.
+	 */
+	if (cl == &q->root)
+		return -EBUSY;
+
+	/*
+	 * The message to NSS should be sent to the parent of this class
+	 */
+	nssqdisc_info("%s: Detaching nsswrr class: %p\n", __func__, cl);
+	nim.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = q->nq.qos_tag;
+	nim.msg.shaper_configure.config.msg.shaper_node_config.snc.wrr_detach.child_qos_tag = cl->nq.qos_tag;
+	if (nssqdisc_node_detach(&q->nq, &nim,
+			NSS_SHAPER_CONFIG_TYPE_WRR_DETACH) < 0) {
+		return -EINVAL;
+	}
+
+	sch_tree_lock(sch);
+	qdisc_reset(cl->qdisc);
+	qdisc_class_hash_remove(&q->clhash, &cl->cl_common);
+	refcnt = atomic_sub_return(1, &cl->nq.refcnt);
+	sch_tree_unlock(sch);
+	if (!refcnt) {
+		nssqdisc_error("%s: Reference count should not be zero for class %p\n", __func__, cl);
+	}
+
+	return 0;
+}
+
+static int nsswrr_graft_class(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
+								 struct Qdisc **old)
+{
+	struct nsswrr_class_data *cl = (struct nsswrr_class_data *)arg;
+	struct nss_if_msg nim_detach;
+	struct nss_if_msg nim_attach;
+	struct nssqdisc_qdisc *nq_new = qdisc_priv(new);
+
+	nssqdisc_info("Grafting class %p\n", sch);
+	if (new == NULL)
+		new = &noop_qdisc;
+
+	sch_tree_lock(sch);
+	*old = cl->qdisc;
+	sch_tree_unlock(sch);
+
+	/*
+	 * Since we initially attached a noop qdisc as child (in Linux),
+	 * we do not perform a detach in the NSS if its a noop qdisc.
+	 */
+	nssqdisc_info("%s:Grafting old: %p with new: %p\n", __func__, *old, new);
+	if (*old != &noop_qdisc) {
+		nssqdisc_info("%s: Detaching old: %p\n", __func__, *old);
+		nim_detach.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = cl->nq.qos_tag;
+		if (nssqdisc_node_detach(&cl->nq, &nim_detach,
+				NSS_SHAPER_CONFIG_TYPE_WRR_GROUP_DETACH) < 0) {
+			return -EINVAL;
+		}
+	}
+
+	/*
+	 * If the new qdisc is a noop qdisc, we do not send down an attach command
+	 * to the NSS.
+	 */
+	if (new != &noop_qdisc) {
+		nssqdisc_info("%s: Attaching new: %p\n", __func__, new);
+		nim_attach.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = cl->nq.qos_tag;
+		nim_attach.msg.shaper_configure.config.msg.shaper_node_config.snc.wrr_group_attach.child_qos_tag = nq_new->qos_tag;
+		if (nssqdisc_node_attach(&cl->nq, &nim_attach,
+				NSS_SHAPER_CONFIG_TYPE_WRR_GROUP_ATTACH) < 0) {
+			return -EINVAL;
+		}
+	}
+
+	/*
+	 * Attach qdisc once it is done in the NSS
+	 */
+	sch_tree_lock(sch);
+	cl->qdisc = new;
+	sch_tree_unlock(sch);
+
+	nssqdisc_info("Nsswrr grafted");
+
+	return 0;
+}
+
+static struct Qdisc *nsswrr_leaf_class(struct Qdisc *sch, unsigned long arg)
+{
+	struct nsswrr_class_data *cl = (struct nsswrr_class_data *)arg;
+	nssqdisc_info("nsswrr class leaf %p\n", cl);
+
+	/*
+	 * Since all nsswrr groups are leaf nodes, we can always
+	 * return the attached qdisc.
+	 */
+	return cl->qdisc;
+}
+
+static void nsswrr_qlen_notify(struct Qdisc *sch, unsigned long arg)
+{
+	nssqdisc_info("nsswrr qlen notify %p\n", sch);
+	/*
+	 * Gets called when qlen of child changes (Useful for deactivating)
+	 * Not useful for us here.
+	 */
+}
+
+static unsigned long nsswrr_get_class(struct Qdisc *sch, u32 classid)
+{
+	struct nsswrr_class_data *cl = nsswrr_find_class(classid, sch);
+
+	nssqdisc_info("Get nsswrr class %p - class match = %p\n", sch, cl);
+
+	if (cl != NULL)
+		atomic_add(1, &cl->nq.refcnt);
+
+	return (unsigned long)cl;
+}
+
+static void nsswrr_put_class(struct Qdisc *sch, unsigned long arg)
+{
+	struct nsswrr_class_data *cl = (struct nsswrr_class_data *)arg;
+	nssqdisc_info("nsswrr put class for %p\n", cl);
+
+	/*
+	 * We are safe to destroy the qdisc if the reference count
+	 * goes down to 0.
+	 */
+	if (atomic_sub_return(1, &cl->nq.refcnt) == 0) {
+		nsswrr_destroy_class(sch, cl);
+	}
+}
+
+static int nsswrr_dump_class(struct Qdisc *sch, unsigned long arg, struct sk_buff *skb,
+		struct tcmsg *tcm)
+{
+	struct nsswrr_class_data *cl = (struct nsswrr_class_data *)arg;
+	struct nlattr *opts;
+	struct tc_nsswrr_class_qopt qopt;
+
+	nssqdisc_info("Dumping class %p of Qdisc %x\n", cl, sch->handle);
+
+	qopt.quantum = cl->quantum;
+
+	/*
+	 * All bf group nodes are root nodes. i.e. they dont
+	 * have any mode bf groups attached beneath them.
+	 */
+	tcm->tcm_parent = TC_H_ROOT;
+	tcm->tcm_handle = cl->cl_common.classid;
+	tcm->tcm_info = cl->qdisc->handle;
+
+	opts = nla_nest_start(skb, TCA_OPTIONS);
+	if (opts == NULL)
+		goto nla_put_failure;
+	NLA_PUT(skb, TCA_NSSWRR_CLASS_PARMS, sizeof(qopt), &qopt);
+	return nla_nest_end(skb, opts);
+
+nla_put_failure:
+	nla_nest_cancel(skb, opts);
+	return -EMSGSIZE;
+}
+
+static int nsswrr_dump_class_stats(struct Qdisc *sch, unsigned long arg, struct gnet_dump *d)
+{
+	struct nssqdisc_qdisc *nq = (struct nssqdisc_qdisc *)arg;
+
+	if (gnet_stats_copy_basic(d, &nq->bstats) < 0 ||
+		gnet_stats_copy_queue(d, &nq->qstats) < 0) {
+		return -1;
+	}
+
+	return 0;
+}
+
+static void nsswrr_walk(struct Qdisc *sch, struct qdisc_walker *arg)
+{
+	struct nsswrr_sched_data *q = qdisc_priv(sch);
+	struct hlist_node *n;
+	struct nsswrr_class_data *cl;
+	unsigned int i;
+
+	nssqdisc_info("In nsswrr walk %p\n", sch);
+	if (arg->stop)
+		return;
+
+	for (i = 0; i < q->clhash.hashsize; i++) {
+		hlist_for_each_entry(cl, n, &q->clhash.hash[i],
+				cl_common.hnode) {
+			if (arg->count < arg->skip) {
+				arg->count++;
+				continue;
+			}
+			if (arg->fn(sch, (unsigned long)cl, arg) < 0) {
+				arg->stop = 1;
+				return;
+			}
+			arg->count++;
+		}
+	}
+}
+
+static int nsswrr_init_qdisc(struct Qdisc *sch, struct nlattr *opt)
+{
+	struct nsswrr_sched_data *q = qdisc_priv(sch);
+	int err;
+	struct nss_if_msg nim;
+
+	nssqdisc_info("Init nsswrr qdisc %p\n", sch);
+
+	err = qdisc_class_hash_init(&q->clhash);
+	if (err < 0)
+		return err;
+
+	q->root.cl_common.classid = sch->handle;
+	q->root.qdisc = &noop_qdisc;
+
+	qdisc_class_hash_insert(&q->clhash, &q->root.cl_common);
+	qdisc_class_hash_grow(sch, &q->clhash);
+
+	/*
+	 * Initialize the NSSWRR shaper in NSS
+	 */
+	if (nssqdisc_init(sch, &q->nq, NSS_SHAPER_NODE_TYPE_WRR, 0) < 0)
+		return -EINVAL;
+
+	/*
+	 * Configure nsswrr in NSS to operate in round robin mode (not fair queue)
+	 */
+	nim.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = q->nq.qos_tag;
+	if (strncmp(sch->ops->id, "nsswrr", 6) == 0) {
+		nim.msg.shaper_configure.config.msg.shaper_node_config.snc.wrr_param.operation_mode = NSS_SHAPER_WRR_MODE_ROUND_ROBIN;
+	} else if (strncmp(sch->ops->id, "nsswfq", 6) == 0) {
+		nim.msg.shaper_configure.config.msg.shaper_node_config.snc.wrr_param.operation_mode = NSS_SHAPER_WRR_MODE_FAIR_QUEUEING;
+	} else {
+		nssqdisc_error("%s: Unknow qdisc association", __func__);
+		nssqdisc_destroy(&q->nq);
+		return -EINVAL;
+	}
+
+	/*
+	 * Send configure command to the NSS
+	 */
+	if (nssqdisc_configure(&q->nq, &nim, NSS_SHAPER_CONFIG_TYPE_WRR_CHANGE_PARAM) < 0) {
+		nssqdisc_error("%s: Failed to configure nsswrr qdisc %x\n", __func__, q->nq.qos_tag);
+		nssqdisc_destroy(&q->nq);
+		return -EINVAL;
+	}
+
+	nssqdisc_info("Nsswrr initialized - handle %x parent %x\n", sch->handle, sch->parent);
+
+	/*
+	 * Start the stats polling timer
+	 */
+	nssqdisc_start_basic_stats_polling(&q->nq);
+
+	return 0;
+}
+
+static int nsswrr_change_qdisc(struct Qdisc *sch, struct nlattr *opt)
+{
+	return 0;
+}
+
+static void nsswrr_reset_class(struct nsswrr_class_data *cl)
+{
+	nssqdisc_reset(cl->qdisc);
+	nssqdisc_info("Nsswrr class resetted %p\n", cl->qdisc);
+}
+
+static void nsswrr_reset_qdisc(struct Qdisc *sch)
+{
+	struct nsswrr_sched_data *q = qdisc_priv(sch);
+	struct nsswrr_class_data *cl;
+	struct hlist_node *n;
+	unsigned int i;
+
+	for (i = 0; i < q->clhash.hashsize; i++) {
+		hlist_for_each_entry(cl, n, &q->clhash.hash[i], cl_common.hnode)
+			nsswrr_reset_class(cl);
+	}
+
+	nssqdisc_reset(sch);
+	nssqdisc_info("Nsswrr qdisc resetted %p\n", sch);
+}
+
+static void nsswrr_destroy_qdisc(struct Qdisc *sch)
+{
+	struct nsswrr_sched_data *q = qdisc_priv(sch);
+	struct hlist_node *n, *next;
+	struct nsswrr_class_data *cl;
+	struct nss_if_msg nim;
+	unsigned int i;
+
+	/*
+	 * Destroy all the classes before the root qdisc is destroyed.
+	 */
+	for (i = 0; i < q->clhash.hashsize; i++) {
+		hlist_for_each_entry_safe(cl, n, next, &q->clhash.hash[i], cl_common.hnode) {
+
+			/*
+			 * If this is the root class, we dont have to destroy it. This will be taken
+			 * care of by the nsswrr_destroy() function.
+			 */
+			if (cl == &q->root) {
+				nssqdisc_info("%s: We do not detach or destroy nsswrr class %p here since this is "
+						"the qdisc %p\n", __func__, cl, sch);
+				continue;
+			}
+
+			/*
+			 * Reduce refcnt by 1 before destroying. This is to
+			 * ensure that polling of stat stops properly.
+			 */
+			atomic_sub(1, &cl->nq.refcnt);
+
+			/*
+			 * Detach class before destroying it. We dont check for noop qdisc here
+			 * since we do not attach anu such at init.
+			 */
+			nim.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = q->nq.qos_tag;
+			nim.msg.shaper_configure.config.msg.shaper_node_config.snc.wrr_detach.child_qos_tag = cl->nq.qos_tag;
+			if (nssqdisc_node_detach(&q->nq, &nim, NSS_SHAPER_CONFIG_TYPE_WRR_DETACH) < 0) {
+				nssqdisc_error("%s: Node detach failed for qdisc %x class %x\n",
+							__func__, cl->nq.qos_tag, q->nq.qos_tag);
+				return;
+			}
+
+			/*
+			 * Now we can destroy the class.
+			 */
+			nsswrr_destroy_class(sch, cl);
+		}
+	}
+	qdisc_class_hash_destroy(&q->clhash);
+
+	/*
+	 * Stop the polling of basic stats
+	 */
+	nssqdisc_stop_basic_stats_polling(&q->nq);
+
+	/*
+	 * Now we can go ahead and destroy the qdisc.
+	 * Note: We dont have to detach ourself from our parent because this
+	 *	 will be taken care of by the graft call.
+	 */
+	nssqdisc_destroy(&q->nq);
+	nssqdisc_info("Nsswrr destroyed %p\n", sch);
+}
+
+static int nsswrr_dump_qdisc(struct Qdisc *sch, struct sk_buff *skb)
+{
+	nssqdisc_info("Nsswrr dumping qdisc\n");
+	return skb->len;
+}
+
+static int nsswrr_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+{
+	return nssqdisc_enqueue(skb, sch);
+}
+
+static struct sk_buff *nsswrr_dequeue(struct Qdisc *sch)
+{
+	return nssqdisc_dequeue(sch);
+}
+
+static unsigned int nsswrr_drop(struct Qdisc *sch)
+{
+	printk("In nsswrr drop\n");
+	return nssqdisc_drop(sch);
+}
+
+static const struct Qdisc_class_ops nsswrr_class_ops = {
+	.change		= nsswrr_change_class,
+	.delete		= nsswrr_delete_class,
+	.graft		= nsswrr_graft_class,
+	.leaf		= nsswrr_leaf_class,
+	.qlen_notify	= nsswrr_qlen_notify,
+	.get		= nsswrr_get_class,
+	.put		= nsswrr_put_class,
+	.dump		= nsswrr_dump_class,
+	.dump_stats	= nsswrr_dump_class_stats,
+	.walk		= nsswrr_walk
+};
+
+static struct Qdisc_ops nsswrr_qdisc_ops __read_mostly = {
+	.id		= "nsswrr",
+	.init		= nsswrr_init_qdisc,
+	.change		= nsswrr_change_qdisc,
+	.reset		= nsswrr_reset_qdisc,
+	.destroy	= nsswrr_destroy_qdisc,
+	.dump		= nsswrr_dump_qdisc,
+	.enqueue	= nsswrr_enqueue,
+	.dequeue	= nsswrr_dequeue,
+	.peek		= qdisc_peek_dequeued,
+	.drop		= nsswrr_drop,
+	.cl_ops		= &nsswrr_class_ops,
+	.priv_size	= sizeof(struct nsswrr_sched_data),
+	.owner		= THIS_MODULE
+};
+
+static const struct Qdisc_class_ops nsswfq_class_ops = {
+	.change		= nsswrr_change_class,
+	.delete		= nsswrr_delete_class,
+	.graft		= nsswrr_graft_class,
+	.leaf		= nsswrr_leaf_class,
+	.qlen_notify	= nsswrr_qlen_notify,
+	.get		= nsswrr_get_class,
+	.put		= nsswrr_put_class,
+	.dump		= nsswrr_dump_class,
+	.dump_stats	= nsswrr_dump_class_stats,
+	.walk		= nsswrr_walk
+};
+
+static struct Qdisc_ops nsswfq_qdisc_ops __read_mostly = {
+	.id		= "nsswfq",
+	.init		= nsswrr_init_qdisc,
+	.change		= nsswrr_change_qdisc,
+	.reset		= nsswrr_reset_qdisc,
+	.destroy	= nsswrr_destroy_qdisc,
+	.dump		= nsswrr_dump_qdisc,
+	.enqueue	= nsswrr_enqueue,
+	.dequeue	= nsswrr_dequeue,
+	.peek		= qdisc_peek_dequeued,
+	.drop		= nsswrr_drop,
+	.cl_ops		= &nsswrr_class_ops,
+	.priv_size	= sizeof(struct nsswrr_sched_data),
+	.owner		= THIS_MODULE
+};
+
+
 /* ================== Module registration ================= */
 
 static int __init nssqdisc_module_init(void)
 {
 	int ret;
 	nssqdisc_info("Module initializing");
-	nssqdisc_ctx = nss_register_shaping();
+	nssqdisc_ctx = nss_shaper_register_shaping();
 
 	ret = register_qdisc(&nsspfifo_qdisc_ops);
 	if (ret != 0)
@@ -2977,10 +4585,25 @@
 		return ret;
 	nssqdisc_info("NSSPRIO registered");
 
+	ret = register_qdisc(&nssbf_qdisc_ops);
+	if (ret != 0)
+		return ret;
+	nssqdisc_info("NSSBF registered");
+
+	ret = register_qdisc(&nsswrr_qdisc_ops);
+	if (ret != 0)
+		return ret;
+	nssqdisc_info("NSSWRR registered");
+
+	ret = register_qdisc(&nsswfq_qdisc_ops);
+	if (ret != 0)
+		return ret;
+	nssqdisc_info("NSSWFQ registered");
+
 	ret = register_netdevice_notifier(&nssqdisc_device_notifier);
 	if (ret != 0)
 		return ret;
- 	nssqdisc_info("NSS qdisc device notifiers registered");
+	nssqdisc_info("NSS qdisc device notifiers registered");
 
 	return 0;
 }
@@ -2989,14 +4612,28 @@
 {
 	unregister_qdisc(&nsspfifo_qdisc_ops);
 	nssqdisc_info("NSSPFIFO Unregistered");
+
 	unregister_qdisc(&nssbfifo_qdisc_ops);
 	nssqdisc_info("NSSBFIFO Unregistered");
+
 	unregister_qdisc(&nsscodel_qdisc_ops);
 	nssqdisc_info("NSSCODEL Unregistered");
+
 	unregister_qdisc(&nsstbl_qdisc_ops);
 	nssqdisc_info("NSSTBL Unregistered");
+
 	unregister_qdisc(&nssprio_qdisc_ops);
 	nssqdisc_info("NSSPRIO Unregistered");
+
+	unregister_qdisc(&nssbf_qdisc_ops);
+	nssqdisc_info("NSSBF Unregistered\n");
+
+	unregister_qdisc(&nsswrr_qdisc_ops);
+	nssqdisc_info("NSSWRR Unregistered\n");
+
+	unregister_qdisc(&nsswfq_qdisc_ops);
+	nssqdisc_info("NSSWFQ Unregistered\n");
+
 	unregister_netdevice_notifier(&nssqdisc_device_notifier);
 }