Merge "[qca-nss-drv] New commands for NSS EXTAP."
diff --git a/Makefile b/Makefile
index 41b9ebf..30f9c5b 100644
--- a/Makefile
+++ b/Makefile
@@ -62,6 +62,7 @@
 			nss_pptp.o \
 			nss_pptp_stats.o \
 			nss_rps.o \
+			nss_qrfs.o \
 			nss_shaper.o \
 			nss_sjack.o \
 			nss_sjack_stats.o \
diff --git a/exports/arch/nss_fsm9010.h b/exports/arch/nss_fsm9010.h
index dcddc63..f5cadbf 100644
--- a/exports/arch/nss_fsm9010.h
+++ b/exports/arch/nss_fsm9010.h
@@ -22,12 +22,12 @@
 #define __NSS_FSM9010_H
 
 /**
- * @addtogroup nss_fsm9010_subsystem
+ * @addtogroup nss_arch_macros
  * @{
  */
 
-#define NSS_MAX_NUM_PRI 1		/**< Maximum number of priority queues in NSS. */
-#define NSS_HOST_CORES 4		/**< Number of host cores. */
+#define NSS_MAX_NUM_PRI 1		/**< Maximum number of priority queues in NSS for the FSM9010 chipset. */
+#define NSS_HOST_CORES 4		/**< Number of host cores for the FSM9010 chipset. */
 
 /**
  * @}
diff --git a/exports/arch/nss_ipq40xx.h b/exports/arch/nss_ipq40xx.h
index e96f15a..dc84984 100644
--- a/exports/arch/nss_ipq40xx.h
+++ b/exports/arch/nss_ipq40xx.h
@@ -22,12 +22,12 @@
 #define __NSS_IPQ40XX_H
 
 /**
- * @addtogroup nss_ipq40xx_subsystem
+ * @addtogroup nss_arch_macros
  * @{
  */
 
-#define NSS_MAX_NUM_PRI 1		/**< Maximum number of priority queues in NSS. */
-#define NSS_HOST_CORES 4		/**< Number of host cores. */
+#define NSS_MAX_NUM_PRI 1		/**< Maximum number of priority queues in NSS for the IPQ40xx chipsets. */
+#define NSS_HOST_CORES 4		/**< Number of host cores for the IPQ40xx chipsets. */
 
 /**
  * @}
diff --git a/exports/arch/nss_ipq806x.h b/exports/arch/nss_ipq806x.h
index ffcd4da..b8f4d05 100644
--- a/exports/arch/nss_ipq806x.h
+++ b/exports/arch/nss_ipq806x.h
@@ -22,12 +22,12 @@
 #define __NSS_IPQ806X_H
 
 /**
- * @addtogroup nss_ipq806x_subsystem
+ * @addtogroup nss_arch_macros
  * @{
  */
 
-#define NSS_MAX_NUM_PRI 1		/**< Maximum number of priority queues in NSS. */
-#define NSS_HOST_CORES 2		/**< Number of host cores. */
+#define NSS_MAX_NUM_PRI 1		/**< Maximum number of priority queues in NSS for the IPQ806x chipsets. */
+#define NSS_HOST_CORES 2		/**< Number of host cores for the IPQ806x chipsets. */
 
 /**
  * @}
diff --git a/exports/arch/nss_ipq807x.h b/exports/arch/nss_ipq807x.h
index e910658..05122bc 100644
--- a/exports/arch/nss_ipq807x.h
+++ b/exports/arch/nss_ipq807x.h
@@ -22,12 +22,12 @@
 #define __NSS_IPQ807X_H
 
 /**
- * @addtogroup nss_ipq807x_subsystem
+ * @addtogroup nss_arch_macros
  * @{
  */
 
-#define NSS_MAX_NUM_PRI 4		/**< Maximum number of priority queues in NSS. */
-#define NSS_HOST_CORES 4		/**< Number of host cores. */
+#define NSS_MAX_NUM_PRI 4		/**< Maximum number of priority queues in NSS for the IPQ807x chipsets. */
+#define NSS_HOST_CORES 4		/**< Number of host cores for the IPQ807x chipsets. */
 
 /**
  * @}
diff --git a/exports/arch/nss_ipq807x_64.h b/exports/arch/nss_ipq807x_64.h
index f75f2fe..ca6d07f 100644
--- a/exports/arch/nss_ipq807x_64.h
+++ b/exports/arch/nss_ipq807x_64.h
@@ -22,12 +22,12 @@
 #define __NSS_IPQ807x_64_H
 
 /**
- * @addtogroup nss_ipq807x_subsystem
+ * @addtogroup nss_arch_macros
  * @{
  */
 
-#define NSS_MAX_NUM_PRI 4		/**< Maximum number of priority queues in NSS. */
-#define NSS_HOST_CORES 4		/**< Number of host cores. */
+#define NSS_MAX_NUM_PRI 4		/**< Maximum number of priority queues in NSS for the IPQ807x 64-bit chipsets. */
+#define NSS_HOST_CORES 4		/**< Number of host cores for the IPQ807x 64-bit chipsets. */
 
 /**
  * @}
diff --git a/exports/nss_api_if.h b/exports/nss_api_if.h
index ec97f4b..554f55c 100644
--- a/exports/nss_api_if.h
+++ b/exports/nss_api_if.h
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
  * above copyright notice and this permission notice appear in all copies.
@@ -68,6 +68,7 @@
 #include "nss_vlan.h"
 #include "nss_wifili_if.h"
 #include "nss_project.h"
+#include "nss_qrfs.h"
 #endif
 
 /**
@@ -86,7 +87,7 @@
 #define NSS_MAX_PHYSICAL_INTERFACES 8	/**< Maximum number of physical interfaces. */
 #define NSS_MAX_VIRTUAL_INTERFACES 16	/**< Maximum number of virtual interfaces. */
 #define NSS_MAX_TUNNEL_INTERFACES 4	/**< Maximum number of tunnel interfaces. */
-#define NSS_MAX_SPECIAL_INTERFACES 50	/**< Maximum number of special interfaces. */
+#define NSS_MAX_SPECIAL_INTERFACES 52	/**< Maximum number of special interfaces. */
 #define NSS_MAX_WIFI_RADIO_INTERFACES 3	/**< Maximum number of radio interfaces. */
 
 /*
@@ -201,11 +202,15 @@
 #define NSS_GRE_INTERFACE (NSS_SPECIAL_IF_START + 46)
 		/**< Special interface number for GRE. */
 #define NSS_WIFILI_INTERFACE (NSS_SPECIAL_IF_START + 47)
-		/**< Special interface number for  WIFILI. */
+		/**< Special interface number for wifili. */
 #define NSS_PROJECT_INTERFACE (NSS_SPECIAL_IF_START + 48)
 		/**< Special interface number for project node. */
 #define NSS_PBUF_MGR_FREE_INTERFACE (NSS_SPECIAL_IF_START + 49)
 		/**< Special interface number for PBUF_MGR_FREE node. */
+#define NSS_REDIR_RX_INTERFACE (NSS_SPECIAL_IF_START + 50)
+		/**< Special interface number for 802.3 redirect node. */
+#define NSS_QRFS_INTERFACE (NSS_SPECIAL_IF_START + 51)
+		/**<Special interface number for QRFS. */
 
 /**
  * Wireless Multimedia Extention Access Category to TID. @hideinitializer
diff --git a/exports/nss_dtls_cmn.h b/exports/nss_dtls_cmn.h
index 640f487..7571bb9 100644
--- a/exports/nss_dtls_cmn.h
+++ b/exports/nss_dtls_cmn.h
@@ -285,12 +285,13 @@
  * nss_dtls_cmn_data_callback_t \n
  * nss_dtls_cmn_msg_callback_t
  *
- * @param[in] if_num        NSS interface number.
- * @param[in] data_cb       Callback function for the message.
- * @param[in] msg_cb        Callback for DTLS tunnel message.
- * @param[in] netdev        Pointer to the associated network device.
- * @param[in] features      Data socket buffer types supported by this interface.
- * @param[in] app_ctx       Pointer to the application context.
+ * @param[in] if_num    NSS interface number.
+ * @param[in] data_cb   Callback function for the message.
+ * @param[in] msg_cb    Callback for DTLS tunnel message.
+ * @param[in] netdev    Pointer to the associated network device.
+ * @param[in] features  Data socket buffer types supported by this interface.
+ * @param[in] type      Type of message.
+ * @param[in] app_ctx   Pointer to the application context.
  *
  * @return
  * Pointer to the NSS core context.
@@ -321,9 +322,9 @@
  * nss_dtls_cmn_notify_register
  *	Register an event callback to handle notification from DTLS firmware package.
  *
- * @param[in] if_num     NSS interface number.
- * @param[in] ev_cb      Callback for DTLS tunnel message.
- * @param[in] app_data   Pointer to the application context.
+ * @param[in] ifnum     NSS interface number.
+ * @param[in] ev_cb     Callback for DTLS tunnel message.
+ * @param[in] app_data  Pointer to the application context.
  *
  * @return
  * Pointer to NSS core context.
@@ -335,7 +336,7 @@
  * nss_dtls_cmn_notify_unregister
  *	Unregister an event callback.
  *
- * @param[in] if_num      NSS interface number.
+ * @param[in] ifnum  NSS interface number.
  *
  * @return
  * None.
diff --git a/exports/nss_dynamic_interface.h b/exports/nss_dynamic_interface.h
index 0c037d4..97fafa8 100644
--- a/exports/nss_dynamic_interface.h
+++ b/exports/nss_dynamic_interface.h
@@ -38,7 +38,7 @@
 	NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR,
 	NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP,
 	NSS_DYNAMIC_INTERFACE_TYPE_TUN6RD,
-	NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR,
+	NSS_DYNAMIC_INTERFACE_TYPE_RESERVED_0,
 	NSS_DYNAMIC_INTERFACE_TYPE_WIFI,
 	NSS_DYNAMIC_INTERFACE_TYPE_VAP,
 	NSS_DYNAMIC_INTERFACE_TYPE_TUNIPIP6,
@@ -66,6 +66,8 @@
 	NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_OUTER,
 	NSS_DYNAMIC_INTERFACE_TYPE_GRE_TUNNEL_INLINE_INNER,
 	NSS_DYNAMIC_INTERFACE_TYPE_GRE_TUNNEL_INLINE_OUTER,
+	NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR_N2H,
+	NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR_H2N,
 	NSS_DYNAMIC_INTERFACE_TYPE_MAX
 };
 
diff --git a/exports/nss_ipv4.h b/exports/nss_ipv4.h
index e779ff2..c1de678 100644
--- a/exports/nss_ipv4.h
+++ b/exports/nss_ipv4.h
@@ -89,6 +89,9 @@
 #define NSS_IPV4_RULE_CREATE_FLAG_EXCEPTION 0x200
 		/**< Rule to except packets. */
 
+#define NSS_IPV4_RULE_CREATE_FLAG_SRC_INTERFACE_CHECK 0x400
+		/**< Check the source interface for the rule. */
+
 /*
  * Validity flags for rule creation.
  */
@@ -642,7 +645,7 @@
 	NSS_IPV4_EXCEPTION_EVENT_6RD_NEEDS_FRAGMENTATION,
 	NSS_IPV4_EXCEPTION_EVENT_DSCP_MARKING_MISMATCH,
 	NSS_IPV4_EXCEPTION_EVENT_VLAN_MARKING_MISMATCH,
-	NSS_IPV4_EXCEPTION_EVENT_DEPRECATED,
+	NSS_IPV4_EXCEPTION_EVENT_INTERFACE_MISMATCH,
 	NSS_IPV4_EXCEPTION_EVENT_GRE_HEADER_INCOMPLETE,
 	NSS_IPV4_EXCEPTION_EVENT_GRE_NO_ICME,
 	NSS_IPV4_EXCEPTION_EVENT_GRE_IP_OPTION,
diff --git a/exports/nss_ipv6.h b/exports/nss_ipv6.h
index ad531ee..2d1d6bd 100644
--- a/exports/nss_ipv6.h
+++ b/exports/nss_ipv6.h
@@ -87,6 +87,9 @@
 #define NSS_IPV6_RULE_CREATE_FLAG_EXCEPTION 0x200
 		/**< Rule to except packets. */
 
+#define NSS_IPV6_RULE_CREATE_FLAG_SRC_INTERFACE_CHECK 0x400
+		/**< Check the source interface for the rule. */
+
 /*
  * IPv6 rule creation validity flags.
  */
@@ -188,7 +191,7 @@
 	NSS_IPV6_EXCEPTION_EVENT_IVID_MISSING,
 	NSS_IPV6_EXCEPTION_EVENT_DSCP_MARKING_MISMATCH,
 	NSS_IPV6_EXCEPTION_EVENT_VLAN_MARKING_MISMATCH,
-	NSS_IPV6_EXCEPTION_EVENT_DEPRECATED,
+	NSS_IPV6_EXCEPTION_EVENT_INTERFACE_MISMATCH,
 	NSS_IPV6_EXCEPTION_EVENT_GRE_NO_ICME,
 	NSS_IPV6_EXCEPTION_EVENT_GRE_NEEDS_FRAGMENTATION,
 	NSS_IPV6_EXCEPTION_EVENT_GRE_SMALL_HOP_LIMIT,
diff --git a/exports/nss_qrfs.h b/exports/nss_qrfs.h
new file mode 100644
index 0000000..cf1ed0a
--- /dev/null
+++ b/exports/nss_qrfs.h
@@ -0,0 +1,183 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all copies.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ **************************************************************************
+ */
+
+/*
+ * @file nss_qrfs.h
+ *	NSS QRFS interface definitions.
+ */
+
+#ifndef __NSS_QRFS_H
+#define __NSS_QRFS_H
+
+/**
+ * @addtogroup nss_qrfs_subsystem
+ * @{
+ */
+
+/**
+ * nss_qrfs_msg_types
+ *	Message types for the NSS QRFS.
+ */
+enum nss_qrfs_msg_types {
+	NSS_QRFS_MSG_FLOW_ADD,
+	NSS_QRFS_MSG_FLOW_DELETE,
+	NSS_QRFS_MSG_MAC_ADD,
+	NSS_QRFS_MSG_MAC_DELETE,
+	NSS_QRFS_MSG_MAX,
+};
+
+/**
+ * nss_qrfs_error_types
+ *	Error types for the NSS QRFS.
+ */
+enum nss_qrfs_error_types {
+	NSS_QRFS_ERROR_INVALID_MSG_TYPE,
+	NSS_QRFS_ERROR_INVALID_MSG_SIZE,
+	NSS_QRFS_ERROR_INVALID_IP_VERSION,
+	NSS_QRFS_ERROR_V4_FLOW_TABLE_FULL,
+	NSS_QRFS_ERROR_V6_FLOW_TABLE_FULL,
+	NSS_QRFS_ERROR_MAC_TABLE_FULL,
+	NSS_QRFS_ERROR_MAX,
+};
+
+/**
+ * nss_qrfs_flow_rule_msg
+ *	Information for the NSS QRFS flow rule message.
+ */
+struct nss_qrfs_flow_rule_msg {
+	uint16_t src_port;		/**< Source port. */
+	uint16_t dst_port;		/**< Destination port. */
+	uint32_t ip_version;		/**< IPv4:4 IPv6:6. */
+	uint32_t src_addr[4];		/**< Source IP address. */
+	uint32_t dst_addr[4];		/**< Destination IP address. */
+	uint16_t protocol;		/**< IP protocol. */
+	uint16_t cpu;			/**< CPU core ID. */
+	uint32_t if_num;		/**< Physical interface number. */
+};
+
+/**
+ * nss_qrfs_mac_rule_msg
+ *	Information for the NSS QRFS MAC rule message.
+ */
+struct nss_qrfs_mac_rule_msg {
+	uint8_t mac[ETH_ALEN];	/**< Ethernet address. */
+	uint16_t cpu;		/**< CPU core ID. */
+	uint32_t if_num;	/**< Physical interface number. */
+};
+
+/**
+ * nss_qrfs_msg
+ *	Data for sending and receiving NSS QRFS rule messages.
+ */
+struct nss_qrfs_msg {
+	struct nss_cmn_msg cm;	/**< Common message header. */
+
+	/**
+	 * Payload of a NSS QRFS rule message.
+	 */
+	union {
+		struct nss_qrfs_flow_rule_msg flow_add; 	/**< Add flow rule. */
+		struct nss_qrfs_flow_rule_msg flow_delete; 	/**< Delete flow rule. */
+		struct nss_qrfs_mac_rule_msg mac_add;		/**< Add MAC rule. */
+		struct nss_qrfs_mac_rule_msg mac_delete;	/**< Delete MAC rule. */
+	} msg;			/**< Message payload. */
+};
+
+/**
+ * Callback function for receiving QRFS messages.
+ *
+ * @datatypes
+ * nss_qrfs_msg
+ *
+ * @param[in] app_data Pointer to the application context of the message.
+ * @param[in] msg      Pointer to the message data.
+ */
+typedef void (*nss_qrfs_msg_callback_t)(void *app_data, struct nss_qrfs_msg *msg);
+
+/**
+ * nss_qrfs_register_handler
+ *	Registers the QRFS interface with the NSS for sending and receiving
+ *	messages.
+ *
+ * @datatypes
+ * nss_ctx_instance
+ *
+ * @return
+ * None.
+ */
+void nss_qrfs_register_handler(struct nss_ctx_instance *nss_ctx);
+
+/**
+ * nss_qrfs_notify_register
+ *	Registers a notifier callback for QRFS messages with the NSS.
+ *
+ * @datatypes
+ * nss_qrfs_msg_callback_t
+ *
+ * @param[in] core      NSS core number index to the notifier callback table.
+ * @param[in] cb        Callback function for the message.
+ * @param[in] app_data  Pointer to the application context of the message.
+ *
+ * @return
+ * Pointer to the NSS core context.
+ */
+struct nss_ctx_instance *nss_qrfs_notify_register(int core, nss_qrfs_msg_callback_t cb, void *app_data);
+
+/**
+ * nss_qrfs_notify_unregister
+ *	Deregisters a QRFS message notifier callback from the NSS.
+ *
+ * @param[in] core  NSS core number index to the notifier callback table.
+ *
+ * @return
+ * None.
+ */
+void nss_qrfs_notify_unregister(int core);
+
+/**
+ * nss_qrfs_set_flow_rule
+ *	Sends a QRFS message to the NSS core to set the flow rule.
+ *
+ * @datatypes
+ * net_device \n
+ * flow_keys
+ *
+ * @param[in] netdev  Pointer to the network device.
+ * @param[in] if_num  Physical interface number.
+ * @param[in] skb     Pointer to the SKB buffer.
+ * @param[in] cpu     CPU number to set in the flow table.
+ * @param[in] action  Action to perform on the flow table.
+ *
+ * @return
+ * Status of the Tx operation.
+ */
+nss_tx_status_t nss_qrfs_set_flow_rule(struct net_device *netdev, uint32_t if_num,
+					struct sk_buff *skb, uint32_t cpu, uint32_t action);
+
+/**
+ * nss_qrfs_init
+ *	Initializes the QRFS.
+ *
+ * @return
+ * None.
+ */
+void nss_qrfs_init(void);
+
+/**
+ * @}
+ */
+
+#endif /* __NSS_QRFS_H */
diff --git a/exports/nss_tunipip6.h b/exports/nss_tunipip6.h
index 6755055..3c19c4b 100644
--- a/exports/nss_tunipip6.h
+++ b/exports/nss_tunipip6.h
@@ -27,7 +27,7 @@
  * @{
  */
 
-#define NSS_TUNIPIP6_MAX_FMR_NUMBER 4
+#define NSS_TUNIPIP6_MAX_FMR_NUMBER 4	/**< Maximum number of forward mapping rule (FMR). */
 
 /**
  * nss_tunipip6_fmr
diff --git a/exports/nss_virt_if.h b/exports/nss_virt_if.h
index b3f8c2d..f83e527 100644
--- a/exports/nss_virt_if.h
+++ b/exports/nss_virt_if.h
@@ -48,8 +48,7 @@
 	NSS_VIRT_IF_BSHAPER_CONFIG = NSS_IF_BSHAPER_CONFIG,
 	NSS_VIRT_IF_VSI_ASSIGN = NSS_IF_VSI_ASSIGN,
 	NSS_VIRT_IF_VSI_UNASSIGN = NSS_IF_VSI_UNASSIGN,
-	NSS_VIRT_IF_TX_CREATE_MSG = NSS_IF_MAX_MSG_TYPES + 1,
-	NSS_VIRT_IF_TX_DESTROY_MSG,
+	NSS_VIRT_IF_TX_CONFIG_MSG = NSS_IF_MAX_MSG_TYPES + 1,
 	NSS_VIRT_IF_STATS_SYNC_MSG,
 	NSS_VIRT_IF_MAX_MSG_TYPES,
 };
@@ -79,23 +78,17 @@
 };
 
 /**
- * nss_virt_if_create_msg
- *	Configuration information for the virtual interface.
+ * nss_virt_if_config_msg
+ *	Message information for configuring the virtual interface.
  */
-struct nss_virt_if_create_msg {
+struct nss_virt_if_config_msg {
 	uint32_t flags;			/**< Interface flags. */
+	uint32_t sibling;		/**< Sibling interface number. */
+	uint32_t nexthop;		/**< Next hop interface number. */
 	uint8_t mac_addr[ETH_ALEN];	/**< MAC address. */
 };
 
 /**
- * nss_virt_if_destroy_msg
- *	Deletion information for the virtual interface.
- */
-struct nss_virt_if_destroy_msg {
-	int32_t reserved;		/**< Reserved for future use. */
-};
-
-/**
  * nss_virt_if_msg
  *	Data for sending and receiving virtual interface messages.
  */
@@ -108,10 +101,8 @@
 	union {
 		union nss_if_msgs if_msgs;
 				/**< NSS interface base message. */
-		struct nss_virt_if_create_msg if_create;
+		struct nss_virt_if_config_msg if_config;
 				/**< Rule for creating a virtual interface. */
-		struct nss_virt_if_destroy_msg if_destroy;
-				/**< Rule for destroying a virtual interface. */
 		struct nss_virt_if_stats stats;
 				/**< Virtual interface statistics. */
 	} msg;			/**< Message payload. */
@@ -161,7 +152,8 @@
  */
 struct nss_virt_if_handle {
 	struct nss_ctx_instance *nss_ctx;	/**< NSS context. */
-	int32_t if_num;				/**< Interface number. */
+	int32_t if_num_n2h;			/**< Redirect interface number on NSS-to-host path. */
+	int32_t if_num_h2n;			/**< Redirect interface number on host-to-NSS path. */
 	struct net_device *ndev;		/**< Associated network device. */
 	struct nss_virt_if_pvt *pvt;		/**< Private data structure. */
 	struct nss_virt_if_stats stats;		/**< Virtual interface statistics. */
@@ -171,6 +163,15 @@
 };
 
 /**
+ * nss_virt_if_dp_type
+ *	Virtual interface datapath types. Redirect interface on NSS-to-host path will be seen by ECM for rules.
+ */
+enum nss_virt_if_dp_type {
+	NSS_VIRT_IF_DP_REDIR_N2H,		/**< Redirect interface on NSS-to-host path has zero value. */
+	NSS_VIRT_IF_DP_REDIR_H2N,		/**< Redirect interface on host-to-NSS path has non-zero value. */
+};
+
+/**
  * nss_virt_if_create
  *	Creates a virtual interface asynchronously.
  *
@@ -327,6 +328,17 @@
 extern int32_t nss_virt_if_get_interface_num(struct nss_virt_if_handle *handle);
 
 /**
+ * nss_virt_if_verify_if_num
+ *	Verifies if the interface is 802.3 redirect type.
+ *
+ * @param[in] if_num  Interface number to be verified.
+ *
+ * @return
+ * True if if_num is 802.3 redirect type.
+ */
+bool nss_virt_if_verify_if_num(uint32_t if_num);
+
+/**
  * @}
  */
 
diff --git a/nss_cmn.c b/nss_cmn.c
index 3f4a9fd..50c3834 100644
--- a/nss_cmn.c
+++ b/nss_cmn.c
@@ -173,9 +173,12 @@
  */
 bool nss_cmn_interface_is_redirect(struct nss_ctx_instance *nss_ctx, int32_t interface_num)
 {
-	return (nss_dynamic_interface_get_type(nss_ctx, interface_num) == NSS_DYNAMIC_INTERFACE_TYPE_WIFI)
-		|| (nss_dynamic_interface_get_type(nss_ctx, interface_num) == NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR)
-		|| (nss_dynamic_interface_get_type(nss_ctx, interface_num) == NSS_DYNAMIC_INTERFACE_TYPE_VIRTIF_DEPRECATED);
+	enum nss_dynamic_interface_type type = nss_dynamic_interface_get_type(nss_ctx, interface_num);
+
+	return type == NSS_DYNAMIC_INTERFACE_TYPE_WIFI
+		|| type == NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR_N2H
+		|| type == NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR_H2N
+		|| type == NSS_DYNAMIC_INTERFACE_TYPE_VIRTIF_DEPRECATED;
 }
 EXPORT_SYMBOL(nss_cmn_interface_is_redirect);
 
diff --git a/nss_core.c b/nss_core.c
index f74aa5f..adfb6e6 100644
--- a/nss_core.c
+++ b/nss_core.c
@@ -255,6 +255,7 @@
 	reg->app_data = NULL;
 	reg->ndev = NULL;
 	reg->features = 0;
+	reg->type = 0;
 }
 
 /*
@@ -832,8 +833,18 @@
 		return;
 	}
 
+	/*
+	 * Check if core_id value is valid.
+	 */
+	if (core_id > NSS_MAX_CORES) {
+		nss_warning("%p: Invalid core id: %d", nss_ctx, core_id);
+		return;
+	}
+
+	/*
+	 * Check if need to convert to local core value.
+	 */
 	if (core_id) {
-		nss_assert(core_id < NSS_MAX_CORES);
 		nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[core_id - 1];
 	}
 
diff --git a/nss_core.h b/nss_core.h
index c860df2..77dbda3 100644
--- a/nss_core.h
+++ b/nss_core.h
@@ -528,7 +528,7 @@
 	 * Network processing handler core ids (CORE0/CORE1) for various interfaces
 	 */
 	uint8_t phys_if_handler_id[NSS_MAX_PHYSICAL_INTERFACES];
-	uint8_t virt_if_handler_id[NSS_MAX_VIRTUAL_INTERFACES];
+	uint8_t virt_if_handler_id;
 	uint8_t gre_redir_handler_id;
 	uint8_t gre_tunnel_handler_id;
 	uint8_t shaping_handler_id;
diff --git a/nss_data_plane/nss_data_plane_edma.c b/nss_data_plane/nss_data_plane_edma.c
index 9f90f75..29fd81c 100644
--- a/nss_data_plane/nss_data_plane_edma.c
+++ b/nss_data_plane/nss_data_plane_edma.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
  * above copyright notice and this permission notice appear in all copies.
@@ -154,6 +154,24 @@
 }
 
 /*
+ * __nss_data_plane_rx_flow_steer()
+ *	Called by nss-dp to set flow rule of a data plane
+ */
+static int __nss_data_plane_rx_flow_steer(struct nss_dp_data_plane_ctx *dpc, struct sk_buff *skb,
+						uint32_t cpu, bool is_add)
+{
+	struct nss_data_plane_edma_param *dp = (struct nss_data_plane_edma_param *)dpc;
+
+	if (is_add) {
+		return nss_qrfs_set_flow_rule(dpc->dev, dp->if_num, skb, cpu,
+						NSS_QRFS_MSG_FLOW_ADD);
+	}
+
+	return nss_qrfs_set_flow_rule(dpc->dev, dp->if_num, skb, cpu,
+						NSS_QRFS_MSG_FLOW_DELETE);
+}
+
+/*
  * __nss_data_plane_buf()
  *	Called by nss-dp to pass a sk_buff for xmit
  */
@@ -220,6 +238,7 @@
 	.pause_on_off	= __nss_data_plane_pause_on_off,
 	.vsi_assign	= __nss_data_plane_vsi_assign,
 	.vsi_unassign	= __nss_data_plane_vsi_unassign,
+	.rx_flow_steer	= __nss_data_plane_rx_flow_steer,
 };
 
 /*
diff --git a/nss_hal/nss_hal.c b/nss_hal/nss_hal.c
index d3e31e5..38ffd50 100644
--- a/nss_hal/nss_hal.c
+++ b/nss_hal/nss_hal.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
  * above copyright notice and this permission notice appear in all copies.
@@ -332,6 +332,7 @@
 	nss_dynamic_interface_register_handler(nss_ctx);
 	nss_n2h_register_handler(nss_ctx);
 	nss_project_register_handler(nss_ctx);
+	nss_qrfs_register_handler(nss_ctx);
 
 	/*
 	 * Check functionalities are supported by this NSS core
@@ -355,11 +356,10 @@
 		nss_top->trustsec_tx_handler_id = nss_dev->id;
 		nss_trustsec_tx_register_handler();
 
-		for (i = 0; i < NSS_MAX_VIRTUAL_INTERFACES; i++) {
-			nss_top->virt_if_handler_id[i] = nss_dev->id;
-		}
+		nss_top->virt_if_handler_id = nss_dev->id;
 
-		nss_top->dynamic_interface_table[NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR] = nss_dev->id;
+		nss_top->dynamic_interface_table[NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR_N2H] = nss_dev->id;
+		nss_top->dynamic_interface_table[NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR_H2N] = nss_dev->id;
 	}
 
 	if (npd->capwap_enabled == NSS_FEATURE_ENABLED) {
diff --git a/nss_init.c b/nss_init.c
index 870990d..738c9eb 100644
--- a/nss_init.c
+++ b/nss_init.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
  * above copyright notice and this permission notice appear in all copies.
@@ -702,6 +702,11 @@
 	nss_capwap_init();
 
 	/*
+	 * Init QRFS
+	 */
+	nss_qrfs_init();
+
+	/*
 	 * INIT ppe on supported platform
 	 */
 	if (of_machine_is_compatible("qcom,ipq807x")) {
diff --git a/nss_ipv4_stats.c b/nss_ipv4_stats.c
index 7317f6a..81ef46a 100644
--- a/nss_ipv4_stats.c
+++ b/nss_ipv4_stats.c
@@ -74,7 +74,7 @@
 	"IPV4_6RD_NEEDS_FRAGMENTATION",
 	"IPV4_DSCP_MARKING_MISMATCH",
 	"IPV4_VLAN_MARKING_MISMATCH",
-	"IPV4_DEPRECATED",
+	"IPV4_INTERFACE_MISMATCH",
 	"IPV4_GRE_HEADER_INCOMPLETE",
 	"IPV4_GRE_NO_ICME",
 	"IPV4_GRE_IP_OPTION",
diff --git a/nss_ipv6_stats.c b/nss_ipv6_stats.c
index 24b1e77..c4b2fab 100644
--- a/nss_ipv6_stats.c
+++ b/nss_ipv6_stats.c
@@ -55,7 +55,7 @@
 	"IPV6_INGRESS_VID_MISSING",
 	"IPV6_DSCP_MARKING_MISMATCH",
 	"IPV6_VLAN_MARKING_MISMATCH",
-	"IPV6_DEPRECATED",
+	"IPV6_INTERFACE_MISMATCH",
 	"IPV6_GRE_NO_ICME",
 	"IPV6_GRE_NEEDS_FRAGMENTATION",
 	"IPV6_GRE_SMALL_HOP_LIMIT",
diff --git a/nss_qrfs.c b/nss_qrfs.c
new file mode 100644
index 0000000..d1125ed
--- /dev/null
+++ b/nss_qrfs.c
@@ -0,0 +1,482 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all copies.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ **************************************************************************
+ */
+
+#include "nss_tx_rx_common.h"
+
+/*
+ * Notify data structure
+ */
+struct nss_qrfs_notify_data {
+	nss_qrfs_msg_callback_t qrfs_callback;
+	void *app_data;
+};
+
+static struct nss_qrfs_notify_data nss_qrfs_notify[NSS_CORE_MAX];
+
+/*
+ * nss_qrfs_verify_if_num()
+ *	Verify if_num passed to us.
+ */
+static bool nss_qrfs_verify_if_num(uint32_t if_num)
+{
+	return if_num == NSS_QRFS_INTERFACE;
+}
+
+/*
+ * nss_qrfs_msg_handler()
+ *	Handle NSS -> HLOS messages for QRFS
+ */
+static void nss_qrfs_msg_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, void *app_data)
+{
+	struct nss_qrfs_msg *nqm = (struct nss_qrfs_msg *)ncm;
+	nss_qrfs_msg_callback_t cb;
+
+	if (!nss_qrfs_verify_if_num(ncm->interface)) {
+		nss_warning("%p: invalid interface %d for QRFS\n", nss_ctx, ncm->interface);
+		return;
+	}
+
+	/*
+	 * Is this a valid request/response?
+	 */
+	if (ncm->type >= NSS_QRFS_MSG_MAX) {
+		nss_warning("%p: invalid message %d for QRFS\n", nss_ctx, ncm->type);
+		return;
+	}
+
+	if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_qrfs_msg)) {
+		nss_warning("%p: message length is greater than required: %d\n", nss_ctx, nss_cmn_get_msg_len(ncm));
+		return;
+	}
+
+	/*
+	 * Log failures
+	 */
+	nss_core_log_msg_failures(nss_ctx, ncm);
+
+	/*
+	 * Update the callback and app_data for NOTIFY messages
+	 */
+	if (ncm->response == NSS_CMM_RESPONSE_NOTIFY) {
+		ncm->cb = (nss_ptr_t)nss_qrfs_notify[nss_ctx->id].qrfs_callback;
+		ncm->app_data = (nss_ptr_t)nss_qrfs_notify[nss_ctx->id].app_data;
+	}
+
+	/*
+	 * Do we have a callback?
+	 */
+	if (!ncm->cb) {
+		return;
+	}
+
+	/*
+	 * callback
+	 */
+	cb = (nss_qrfs_msg_callback_t)ncm->cb;
+	cb((void *)ncm->app_data, nqm);
+}
+
+/*
+ * nss_qrfs_get_ctx()
+ */
+static struct nss_ctx_instance *nss_qrfs_get_ctx(int core_id)
+{
+	return &nss_top_main.nss[core_id];
+}
+
+/*
+ * nss_qrfs_get_flow_keys()
+ *	Get 5 tuple information from flow keys and set in flow rule message.
+ */
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 18, 21))
+static bool nss_qrfs_get_flow_keys(struct nss_ctx_instance *nss_ctx, struct sk_buff *skb,
+					struct nss_qrfs_flow_rule_msg *nqfrm)
+{
+	struct flow_keys keys;
+	uint16_t protocol = skb->protocol;
+	bool res;
+	struct ipv6hdr *ip6hdr;
+
+	res = skb_flow_dissect(skb, &keys);
+	if (!res) {
+		nss_warning("%p: failed to get flow keys\n", nss_ctx);
+		return res;
+	}
+
+	nqfrm->protocol = keys.ip_proto;
+	nqfrm->src_port = keys.port16[0];
+	nqfrm->dst_port = keys.port16[1];
+
+	if (protocol == htons(ETH_P_IP)) {
+		nqfrm->ip_version = 4;
+		nqfrm->src_addr[0] = keys.src;
+		nqfrm->dst_addr[0] = keys.dst;
+		return true;
+	}
+
+	nqfrm->ip_version = 6;
+	ip6hdr = (struct ipv6hdr *)skb_network_header(skb);
+	if (!ip6hdr) {
+		nss_warning("%p: failed to get IPv6 address\n", nss_ctx);
+		return false;
+	}
+
+	memcpy(nqfrm->src_addr, &ip6hdr->saddr, sizeof(struct in6_addr));
+	memcpy(nqfrm->dst_addr, &ip6hdr->daddr, sizeof(struct in6_addr));
+
+	return true;
+}
+#else
+static bool nss_qrfs_get_flow_keys(struct nss_ctx_instance *nss_ctx, struct sk_buff *skb,
+					struct nss_qrfs_flow_rule_msg *nqfrm)
+{
+	struct flow_keys keys;
+	bool res;
+
+	res = skb_flow_dissect_flow_keys(skb, &keys, 0);
+	if (!res) {
+		nss_warning("%p: failed to get flow keys\n", nss_ctx);
+		return res;
+	}
+
+	nqfrm->protocol = (uint16_t)keys.basic.ip_proto;
+	nqfrm->src_port = keys.ports.src;
+	nqfrm->dst_port = keys.ports.dst;
+
+	if (keys.basic.n_proto == htons(ETH_P_IP)) {
+		nqfrm->ip_version = 4;
+		nqfrm->src_addr[0] = keys.addrs.v4addrs.src;
+		nqfrm->dst_addr[0] = keys.addrs.v4addrs.dst;
+		return true;
+	}
+
+	nqfrm->ip_version = 6;
+	memcpy(nqfrm->src_addr, &keys.addrs.v6addrs.src, sizeof(struct in6_addr));
+	memcpy(nqfrm->dst_addr, &keys.addrs.v6addrs.dst, sizeof(struct in6_addr));
+
+	return true;
+}
+#endif
+
+/*
+ * nss_qrfs_flow_add_msg_callback()
+ *	Callback function for receiving flow add response messages.
+ */
+static void nss_qrfs_flow_add_msg_callback(void *app_data, struct nss_qrfs_msg *nqm)
+{
+	struct nss_ctx_instance *nss_ctx __maybe_unused = (struct nss_ctx_instance *)app_data;
+	struct nss_qrfs_flow_rule_msg *nqfrm;
+
+	if (nqm->cm.type != NSS_QRFS_MSG_FLOW_ADD) {
+		nss_warning("%p: invalid flow response message %d\n", nss_ctx, nqm->cm.type);
+		return;
+	}
+
+	nqfrm = &nqm->msg.flow_add;
+
+	if ((nqfrm->ip_version != 4) && (nqfrm->ip_version != 6)) {
+		nss_warning("%p: invalid IP version %d\n", nss_ctx, nqfrm->ip_version);
+		return;
+	}
+
+	if (nqm->cm.response != NSS_CMN_RESPONSE_ACK) {
+		nss_warning("%p: flow add configuration error: %d for NSS core %d\n",
+				nss_ctx, nqm->cm.error, nss_ctx->id);
+	}
+}
+
+/*
+ * nss_qrfs_flow_delete_msg_callback()
+ *	Callback function for receiving flow delete response messages.
+ */
+static void nss_qrfs_flow_delete_msg_callback(void *app_data, struct nss_qrfs_msg *nqm)
+{
+	struct nss_ctx_instance *nss_ctx __maybe_unused = (struct nss_ctx_instance *)app_data;
+	struct nss_qrfs_flow_rule_msg *nqfrm;
+
+	if (nqm->cm.type != NSS_QRFS_MSG_FLOW_DELETE) {
+		nss_warning("%p: invalid flow response message %d\n", nss_ctx, nqm->cm.type);
+		return;
+	}
+
+	nqfrm = &nqm->msg.flow_delete;
+
+	if ((nqfrm->ip_version != 4) && (nqfrm->ip_version != 6)) {
+		nss_warning("%p: invalid IP version %d\n", nss_ctx, nqfrm->ip_version);
+		return;
+	}
+
+	if (nqm->cm.response != NSS_CMN_RESPONSE_ACK) {
+		nss_warning("%p: flow delete configuration error: %d for NSS core %d\n",
+				nss_ctx, nqm->cm.error, nss_ctx->id);
+	}
+}
+
+/*
+ * nss_qrfs_msg_init()
+ *	Initialize the common header of QRFS message
+ */
+static void nss_qrfs_msg_init(struct nss_qrfs_msg *nqm, uint16_t if_num, uint32_t type, uint32_t len, void *cb, void *app_data)
+{
+	nss_cmn_msg_init(&nqm->cm, if_num, type, len, cb, app_data);
+}
+
+/*
+ * nss_qrfs_tx_msg()
+ *	Transmit a QRFS message to NSS firmware
+ */
+static nss_tx_status_t nss_qrfs_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_qrfs_msg *msg)
+{
+	struct nss_qrfs_msg *nqm;
+	struct nss_cmn_msg *ncm = &msg->cm;
+	struct sk_buff *nbuf;
+	int32_t status;
+
+	if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
+		nss_warning("%p: message dropped as core not ready\n", nss_ctx);
+		return NSS_TX_FAILURE_NOT_READY;
+	}
+
+	/*
+	 * Sanity check the message
+	 */
+	if (!nss_qrfs_verify_if_num(ncm->interface)) {
+		nss_warning("%p: interface is not QRFS interface: %d\n", nss_ctx, ncm->interface);
+		return NSS_TX_FAILURE;
+	}
+
+	if (ncm->type >= NSS_QRFS_MSG_MAX) {
+		nss_warning("%p: message type is out of range: %d\n", nss_ctx, ncm->type);
+		return NSS_TX_FAILURE;
+	}
+
+	if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_qrfs_msg)) {
+		nss_warning("%p: message length is invalid: %d\n", nss_ctx, nss_cmn_get_msg_len(ncm));
+		return NSS_TX_FAILURE;
+	}
+
+	nbuf = dev_alloc_skb(NSS_NBUF_PAYLOAD_SIZE);
+	if (unlikely(!nbuf)) {
+		NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS]);
+		nss_warning("%p: message allocation failed\n", nss_ctx);
+		return NSS_TX_FAILURE;
+	}
+
+	/*
+	 * Copy the message to our skb
+	 */
+	nqm = (struct nss_qrfs_msg *)skb_put(nbuf, sizeof(struct nss_qrfs_msg));
+	memcpy(nqm, msg, sizeof(struct nss_qrfs_msg));
+
+	status = nss_core_send_buffer(nss_ctx, 0, nbuf, NSS_IF_CMD_QUEUE, H2N_BUFFER_CTRL, 0);
+	if (status != NSS_CORE_STATUS_SUCCESS) {
+		dev_kfree_skb_any(nbuf);
+		nss_warning("%p: unable to enqueue QRFS message\n", nss_ctx);
+		return NSS_TX_FAILURE;
+	}
+
+	nss_hal_send_interrupt(nss_ctx, NSS_H2N_INTR_DATA_COMMAND_QUEUE);
+
+	NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_CMD_REQ]);
+
+	return NSS_TX_SUCCESS;
+}
+
+/*
+ * nss_qrfs_add_flow_rule()
+ *	Set a QRFS flow rule add message and transmit the message to NSS core.
+ */
+static nss_tx_status_t nss_qrfs_add_flow_rule(struct nss_ctx_instance *nss_ctx, uint32_t if_num,
+					struct sk_buff *skb, uint32_t cpu, bool need_cb)
+{
+	struct nss_qrfs_msg nqm;
+	struct nss_qrfs_flow_rule_msg *nqfrm;
+	nss_tx_status_t status;
+	nss_qrfs_msg_callback_t cb = NULL;
+	void *app_data = NULL;
+	bool res;
+
+	memset(&nqm, 0, sizeof(struct nss_qrfs_msg));
+
+	if (need_cb) {
+		cb = nss_qrfs_flow_add_msg_callback;
+		app_data = (void *)nss_ctx;
+	}
+
+	/*
+	 * Initialize common header of QRFS flow rule add message.
+	 */
+	nss_qrfs_msg_init(&nqm, NSS_QRFS_INTERFACE, NSS_QRFS_MSG_FLOW_ADD,
+				sizeof(struct nss_qrfs_flow_rule_msg), cb, app_data);
+
+	/*
+	 * Set flow rule of QRFS flow rule add message
+	 */
+	nqfrm = &nqm.msg.flow_add;
+	res = nss_qrfs_get_flow_keys(nss_ctx, skb, nqfrm);
+	if (!res) {
+		return NSS_TX_FAILURE;
+	}
+
+	nqfrm->cpu = (uint16_t)cpu;
+	nqfrm->if_num = if_num;
+
+	/*
+	 * Send QRFS flow rule add message to NSS core
+	 */
+	status = nss_qrfs_tx_msg(nss_ctx, &nqm);
+	if (status == NSS_TX_SUCCESS) {
+		return status;
+	}
+
+	return NSS_TX_FAILURE;
+}
+
+/*
+ * nss_qrfs_delete_flow_rule()
+ *	Set a QRFS delete flow rule message and transmit the message to all NSS core.
+ */
+static nss_tx_status_t nss_qrfs_delete_flow_rule(struct nss_ctx_instance *nss_ctx, uint32_t if_num,
+						struct sk_buff *skb, uint32_t cpu, bool need_cb)
+{
+	struct nss_qrfs_msg nqm;
+	struct nss_qrfs_flow_rule_msg *nqfrm;
+	nss_tx_status_t status;
+	nss_qrfs_msg_callback_t cb = NULL;
+	void *app_data = NULL;
+	bool res;
+
+	memset(&nqm, 0, sizeof(struct nss_qrfs_msg));
+
+	if (need_cb) {
+		cb = nss_qrfs_flow_delete_msg_callback;
+		app_data = (void *)nss_ctx;
+	}
+
+	/*
+	 * Initialize common header of QRFS flow rule delete message.
+	 */
+	nss_qrfs_msg_init(&nqm, NSS_QRFS_INTERFACE, NSS_QRFS_MSG_FLOW_DELETE,
+				sizeof(struct nss_qrfs_flow_rule_msg), cb, app_data);
+
+	/*
+	 * Set flow rule of QRFS flow rule delete message
+	 */
+	nqfrm = &nqm.msg.flow_delete;
+	res = nss_qrfs_get_flow_keys(nss_ctx, skb, nqfrm);
+	if (!res) {
+		return NSS_TX_FAILURE;
+	}
+
+	nqfrm->cpu = (uint16_t)cpu;
+	nqfrm->if_num = if_num;
+
+	/*
+	 * Send QRFS flow rule delete message to NSS core
+	 */
+	status = nss_qrfs_tx_msg(nss_ctx, &nqm);
+	if (status == NSS_TX_SUCCESS) {
+		return status;
+	}
+
+	return NSS_TX_FAILURE;
+}
+
+/*
+ * nss_qrfs_set_flow_rule()
+ *	Set a QRFS flow rule message and transmit the message to all NSS cores.
+ */
+nss_tx_status_t nss_qrfs_set_flow_rule(struct net_device *netdev, uint32_t if_num,
+					struct sk_buff *skb, uint32_t cpu, uint32_t action)
+{
+	struct nss_ctx_instance *nss_ctx;
+	nss_tx_status_t status;
+	int i;
+
+	for (i = 0; i < NSS_CORE_MAX; i++) {
+		nss_ctx = nss_qrfs_get_ctx(i);
+
+		/*
+		 * Set QRFS flow rule message and transmit the message to NSS core.
+		 */
+		if (action == NSS_QRFS_MSG_FLOW_ADD) {
+			status = nss_qrfs_add_flow_rule(nss_ctx, if_num, skb, cpu, true);
+		} else {
+			status = nss_qrfs_delete_flow_rule(nss_ctx, if_num, skb, cpu, true);
+		}
+
+		if (status != NSS_TX_SUCCESS) {
+			nss_warning("%p: failed to send flow rule to NSS core %d\n", nss_ctx, i);
+			return NSS_TX_FAILURE;
+		}
+	}
+
+	return NSS_TX_SUCCESS;
+}
+EXPORT_SYMBOL(nss_qrfs_set_flow_rule);
+
+/*
+ * nss_qrfs_register_handler()
+ */
+void nss_qrfs_register_handler(struct nss_ctx_instance *nss_ctx)
+{
+	nss_core_register_handler(nss_ctx, NSS_QRFS_INTERFACE, nss_qrfs_msg_handler, NULL);
+}
+EXPORT_SYMBOL(nss_qrfs_register_handler);
+
+/*
+ * nss_qrfs_notify_register()
+ *	Register to receive QRFS notify messages.
+ */
+struct nss_ctx_instance *nss_qrfs_notify_register(int core, nss_qrfs_msg_callback_t cb, void *app_data)
+{
+	if (core >= NSS_CORE_MAX) {
+		nss_warning("Input core number %d is wrong\n", core);
+		return NULL;
+	}
+
+	nss_qrfs_notify[core].qrfs_callback = cb;
+	nss_qrfs_notify[core].app_data = app_data;
+
+	return (struct nss_ctx_instance *)&nss_top_main.nss[core];
+}
+
+/*
+ * nss_qrfs_notify_unregister()
+ *	Unregister to receive QRFS notify messages.
+ */
+void nss_qrfs_notify_unregister(int core)
+{
+	if (core >= NSS_CORE_MAX) {
+		nss_warning("Input core number %d is wrong\n", core);
+		return;
+	}
+
+	nss_qrfs_notify[core].qrfs_callback = NULL;
+	nss_qrfs_notify[core].app_data = NULL;
+}
+
+/*
+ * nss_qrfs_init()
+ */
+void nss_qrfs_init(void)
+{
+	int core;
+
+	for (core = 0; core < NSS_CORE_MAX; core++) {
+		nss_qrfs_notify_register(core, NULL, NULL);
+	}
+}
diff --git a/nss_virt_if.c b/nss_virt_if.c
index ec3b48d..4c4fa8b 100644
--- a/nss_virt_if.c
+++ b/nss_virt_if.c
@@ -39,6 +39,27 @@
 DEFINE_SPINLOCK(nss_virt_if_lock);
 
 /*
+ * nss_virt_if_get_context()
+ */
+struct nss_ctx_instance *nss_virt_if_get_context(void)
+{
+	return &nss_top_main.nss[nss_top_main.virt_if_handler_id];
+}
+
+/*
+ * nss_virt_if_verify_if_num()
+ *	Verify if_num passed to us.
+ */
+bool nss_virt_if_verify_if_num(uint32_t if_num)
+{
+	enum nss_dynamic_interface_type type = nss_dynamic_interface_get_type(nss_virt_if_get_context(), if_num);
+
+	return type == NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR_N2H
+		|| type == NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR_H2N;
+}
+EXPORT_SYMBOL(nss_virt_if_verify_if_num);
+
+/*
  * nss_virt_if_msg_handler()
  *	Handle msg responses from the FW on virtual interfaces
  */
@@ -67,7 +88,7 @@
 		return nss_if_msg_handler(nss_ctx, ncm, app_data);
 	}
 
-	if (!NSS_IS_IF_TYPE(DYNAMIC, ncm->interface)) {
+	if (!nss_virt_if_verify_if_num(ncm->interface)) {
 		nss_warning("%p: response for another interface: %d", nss_ctx, ncm->interface);
 		return;
 	}
@@ -187,114 +208,40 @@
 }
 
 /*
- * nss_virt_if_get_context()
- */
-struct nss_ctx_instance *nss_virt_if_get_context(int i)
-{
-	return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.virt_if_handler_id[i]];
-}
-
-/*
- * nss_virt_if_register_handler()
- * 	register msg handler for virtual interface.
- */
-static uint32_t nss_virt_if_register_handler(struct nss_ctx_instance *nss_ctx, struct nss_virt_if_handle *handle)
-{
-	uint32_t ret;
-	int32_t if_num = handle->if_num;
-
-	ret = nss_core_register_handler(nss_ctx, if_num, nss_virt_if_msg_handler, NULL);
-	if (ret != NSS_CORE_STATUS_SUCCESS) {
-		nss_warning("%d: Message handler failed to be registered for interface\n", if_num);
-		return NSS_VIRT_IF_CORE_FAILURE;
-	}
-
-	return NSS_VIRT_IF_SUCCESS;
-}
-
-/*
- * nss_virt_if_handle_destroy_cb()
- *	Callback to handle the response of destroy message.
- */
-static void nss_virt_if_handle_destroy_cb(void *app_data, struct nss_dynamic_interface_msg *ndim)
-{
-	nss_virt_if_msg_callback_t cb;
-	void *data;
-	uint32_t index;
-	struct nss_virt_if_handle *handle = (struct nss_virt_if_handle *)app_data;
-
-	cb = handle->cb;
-	data = handle->app_data;
-
-	if (ndim->cm.response != NSS_CMN_RESPONSE_ACK) {
-		nss_warning("%p: Received NACK from DI\n", handle->nss_ctx);
-		goto callback;
-	}
-
-	index = NSS_VIRT_IF_GET_INDEX(handle->if_num);
-	spin_lock_bh(&nss_virt_if_lock);
-	nss_virt_if_handle_t[index] = NULL;
-	spin_unlock_bh(&nss_virt_if_lock);
-
-	kfree(handle);
-callback:
-	if (!cb) {
-		nss_warning("callback is NULL\n");
-		return;
-	}
-
-	cb(data, &ndim->cm);
-}
-
-/*
- * nss_virt_if_handle_destroy()
- *	Destroy the virt handle either due to request from WLAN or due to error.
- */
-static int nss_virt_if_handle_destroy(struct nss_virt_if_handle *handle)
-{
-	nss_tx_status_t status;
-	int32_t if_num = handle->if_num;
-	struct nss_ctx_instance *nss_ctx = handle->nss_ctx;
-	struct nss_dynamic_interface_msg ndim;
-	struct nss_dynamic_interface_dealloc_node_msg *ndid;
-
-	nss_dynamic_interface_msg_init(&ndim, NSS_DYNAMIC_INTERFACE, NSS_DYNAMIC_INTERFACE_DEALLOC_NODE,
-				sizeof(struct nss_dynamic_interface_dealloc_node_msg), nss_virt_if_handle_destroy_cb, (void *)handle);
-
-	ndid = &ndim.msg.dealloc_node;
-	ndid->type = NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR;
-	ndid->if_num = if_num;
-
-	/*
-	 * Send an asynchronous message to the firmware.
-	 */
-	status = nss_dynamic_interface_tx(nss_ctx, &ndim);
-	if (status != NSS_TX_SUCCESS) {
-		nss_warning("%p: Dynamic interface destroy failed status %d\n", nss_ctx, status);
-		return status;
-	}
-
-	return status;
-}
-
-/*
  * nss_virt_if_handle_destroy_sync()
  *	Destroy the virt handle either due to request from user or due to error, synchronously.
  */
 static int nss_virt_if_handle_destroy_sync(struct nss_virt_if_handle *handle)
 {
 	nss_tx_status_t status;
-	int32_t if_num = handle->if_num;
-	int32_t index = NSS_VIRT_IF_GET_INDEX(if_num);
+	int32_t if_num_n2h = handle->if_num_n2h;
+	int32_t if_num_h2n = handle->if_num_h2n;
+	int32_t index_n2h;
+	int32_t index_h2n;
 
-	status = nss_dynamic_interface_dealloc_node(if_num, NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR);
+	if (!nss_virt_if_verify_if_num(if_num_n2h) || !nss_virt_if_verify_if_num(if_num_h2n)) {
+		nss_warning("%p: bad interface numbers %d %d\n", handle->nss_ctx, if_num_n2h, if_num_h2n);
+		return NSS_TX_FAILURE_BAD_PARAM;
+	}
+
+	index_n2h = NSS_VIRT_IF_GET_INDEX(if_num_n2h);
+	index_h2n = NSS_VIRT_IF_GET_INDEX(if_num_h2n);
+
+	status = nss_dynamic_interface_dealloc_node(if_num_n2h, NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR_N2H);
+	if (status != NSS_TX_SUCCESS) {
+		nss_warning("%p: Dynamic interface destroy failed status %d\n", handle->nss_ctx, status);
+		return status;
+	}
+
+	status = nss_dynamic_interface_dealloc_node(if_num_h2n, NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR_H2N);
 	if (status != NSS_TX_SUCCESS) {
 		nss_warning("%p: Dynamic interface destroy failed status %d\n", handle->nss_ctx, status);
 		return status;
 	}
 
 	spin_lock_bh(&nss_virt_if_lock);
-	nss_virt_if_handle_t[index] = NULL;
+	nss_virt_if_handle_t[index_n2h] = NULL;
+	nss_virt_if_handle_t[index_h2n] = NULL;
 	spin_unlock_bh(&nss_virt_if_lock);
 
 	kfree(handle->pvt);
@@ -304,131 +251,22 @@
 }
 
 /*
- * nss_virt_if_handle_create_cb()
- *	Callback to handle the response from dynamic interface for an alloc node msg.
- */
-static void nss_virt_if_handle_create_cb(void *app_data, struct nss_dynamic_interface_msg *ndim)
-{
-	struct nss_virt_if_handle *handle = (struct nss_virt_if_handle *)app_data;
-	struct nss_ctx_instance *nss_ctx = handle->nss_ctx;
-	nss_virt_if_msg_callback_t cb;
-	struct nss_virt_if_msg nvim;
-	struct nss_virt_if_create_msg *nvcm;
-	void *data;
-	int32_t if_num;
-	uint32_t index;
-	int ret;
-
-	cb = handle->cb;
-	data = handle->app_data;
-
-	if (ndim->cm.response != NSS_CMN_RESPONSE_ACK) {
-		nss_warning("%p: received NACK from NSS %d\n", handle->nss_ctx, ndim->cm.response);
-		kfree(handle);
-		goto fail;
-	}
-
-	if_num = ndim->msg.alloc_node.if_num;
-
-	spin_lock_bh(&nss_virt_if_lock);
-	handle->if_num = if_num;
-	index = NSS_VIRT_IF_GET_INDEX(if_num);
-	nss_virt_if_handle_t[index] = handle;
-	spin_unlock_bh(&nss_virt_if_lock);
-
-	/* Register the msg handler for if_num */
-	ret = nss_virt_if_register_handler(nss_ctx, handle);
-	if (ret != NSS_VIRT_IF_SUCCESS) {
-		nss_warning("%p: Registration handler failed reason: %d\n", handle->nss_ctx, ret);
-		nss_virt_if_handle_destroy(handle);
-		goto fail;
-	}
-
-	/*
-	 * Send virt_if message to the Firmware to copy the netdev's macaddr
-	 */
-	nss_virt_if_msg_init(&nvim, handle->if_num, NSS_VIRT_IF_TX_CREATE_MSG,
-				sizeof(struct nss_virt_if_create_msg), NULL, NULL);
-
-	nvcm = &nvim.msg.if_create;
-	nvcm->flags = 0;
-	memcpy(nvcm->mac_addr, handle->ndev->dev_addr, ETH_ALEN);
-
-	ret = nss_virt_if_tx_msg(handle->nss_ctx, &nvim);
-	if (ret != NSS_TX_SUCCESS) {
-		nss_warning("%p: nss_virt_if_tx_msg failed %u\n", handle->nss_ctx, ret);
-		nss_virt_if_handle_destroy(handle);
-		goto fail;
-	}
-
-	nss_core_register_subsys_dp(nss_ctx, handle->if_num, NULL, NULL, NULL, handle->ndev, 0);
-
-	/*
-	 * Hold a reference to the net_device
-	 */
-	dev_hold(handle->ndev);
-
-	/*
-	 * The context returned is the handle which contains all the info related to
-	 * the interface if_num.
-	 */
-
-fail:
-	if (!cb) {
-		nss_warning("cb is NULL\n");
-		return;
-	}
-
-	cb(data, &ndim->cm);
-}
-
-/*
- * nss_virt_if_handle_create()
- *	Create and initialize virt_if handle.
- */
-static struct nss_virt_if_handle *nss_virt_if_handle_create(struct nss_ctx_instance *nss_ctx,
-							struct net_device *ndev,
-							nss_virt_if_msg_callback_t cb,
-							void *app_data,
-							int *cmd_rsp)
-{
-	struct nss_virt_if_handle *handle;
-
-	handle = (struct nss_virt_if_handle *)kzalloc(sizeof(struct nss_virt_if_handle),
-									GFP_ATOMIC);
-	if (!handle) {
-		nss_warning("%p: handle memory alloc failed\n", nss_ctx);
-		*cmd_rsp = NSS_VIRT_IF_ALLOC_FAILURE;
-		goto error;
-	}
-
-	/*
-	 * Save the callback & appdata of the user. The callback will be invoked from
-	 * nss_virt_if_handle_create_cb.
-	 */
-	handle->nss_ctx = nss_ctx;
-	handle->ndev = ndev;
-	handle->cb = cb;
-	handle->app_data = app_data;
-
-	*cmd_rsp = NSS_VIRT_IF_SUCCESS;
-
-	return handle;
-
-error:
-	return NULL;
-}
-
-/*
  * nss_virt_if_handle_create_sync()
  *	Initialize virt handle which holds the if_num and stats per interface.
  */
-static struct nss_virt_if_handle *nss_virt_if_handle_create_sync(struct nss_ctx_instance *nss_ctx, int32_t if_num, int32_t *cmd_rsp)
+static struct nss_virt_if_handle *nss_virt_if_handle_create_sync(struct nss_ctx_instance *nss_ctx, int32_t if_num_n2h, int32_t if_num_h2n, int32_t *cmd_rsp)
 {
-	int32_t index;
+	int32_t index_n2h;
+	int32_t index_h2n;
 	struct nss_virt_if_handle *handle;
 
-	index = NSS_VIRT_IF_GET_INDEX(if_num);
+	if (!nss_virt_if_verify_if_num(if_num_n2h) || !nss_virt_if_verify_if_num(if_num_h2n)) {
+		nss_warning("%p: bad interface numbers %d %d\n", nss_ctx, if_num_n2h, if_num_h2n);
+		return NULL;
+	}
+
+	index_n2h = NSS_VIRT_IF_GET_INDEX(if_num_n2h);
+	index_h2n = NSS_VIRT_IF_GET_INDEX(if_num_h2n);
 
 	handle = (struct nss_virt_if_handle *)kzalloc(sizeof(struct nss_virt_if_handle),
 									GFP_KERNEL);
@@ -439,7 +277,8 @@
 	}
 
 	handle->nss_ctx = nss_ctx;
-	handle->if_num = if_num;
+	handle->if_num_n2h = if_num_n2h;
+	handle->if_num_h2n = if_num_h2n;
 	handle->pvt = (struct nss_virt_if_pvt *)kzalloc(sizeof(struct nss_virt_if_pvt),
 								GFP_KERNEL);
 	if (!handle->pvt) {
@@ -452,7 +291,8 @@
 	handle->app_data = NULL;
 
 	spin_lock_bh(&nss_virt_if_lock);
-	nss_virt_if_handle_t[index] = handle;
+	nss_virt_if_handle_t[index_n2h] = handle;
+	nss_virt_if_handle_t[index_h2n] = handle;
 	spin_unlock_bh(&nss_virt_if_lock);
 
 	*cmd_rsp = NSS_VIRT_IF_SUCCESS;
@@ -473,11 +313,19 @@
 {
 	uint32_t ret;
 	struct nss_virt_if_pvt *nvip = NULL;
-	int32_t if_num = handle->if_num;
+	int32_t if_num_n2h = handle->if_num_n2h;
+	int32_t if_num_h2n = handle->if_num_h2n;
 
-	ret = nss_core_register_handler(nss_ctx, if_num, nss_virt_if_msg_handler, NULL);
+	ret = nss_core_register_handler(nss_ctx, if_num_n2h, nss_virt_if_msg_handler, NULL);
 	if (ret != NSS_CORE_STATUS_SUCCESS) {
-		nss_warning("%d: Message handler failed to be registered for interface\n", if_num);
+		nss_warning("%p: Failed to register message handler for redir_n2h interface %d\n", nss_ctx, if_num_n2h);
+		return NSS_VIRT_IF_CORE_FAILURE;
+	}
+
+	ret = nss_core_register_handler(nss_ctx, if_num_h2n, nss_virt_if_msg_handler, NULL);
+	if (ret != NSS_CORE_STATUS_SUCCESS) {
+		nss_core_unregister_handler(nss_ctx, if_num_n2h);
+		nss_warning("%p: Failed to register message handler for redir_h2n interface %d\n", nss_ctx, if_num_h2n);
 		return NSS_VIRT_IF_CORE_FAILURE;
 	}
 
@@ -493,104 +341,83 @@
 }
 
 /*
- * nss_virt_if_create()
- *	Create a virtual interface and associate it with the netdev, asynchronously.
- */
-int nss_virt_if_create(struct net_device *netdev, nss_virt_if_msg_callback_t cb, void *app_data)
-{
-	struct nss_ctx_instance *nss_ctx = &nss_top_main.nss[nss_top_main.wlan_handler_id];
-	struct nss_dynamic_interface_msg ndim;
-	struct nss_dynamic_interface_alloc_node_msg *ndia;
-	int ret;
-	struct nss_virt_if_handle *handle = NULL;
-
-	if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
-		nss_warning("%p: Interface could not be created as core not ready\n", nss_ctx);
-		return NSS_VIRT_IF_CORE_FAILURE;
-	}
-
-	/*
-	 * Create the virt_if handle and associate the cb and app_data with it.
-	 */
-	handle = nss_virt_if_handle_create(nss_ctx, netdev, cb, app_data, &ret);
-	if (!handle) {
-		nss_warning("%p:virt_if handle create failed ret %d\n", nss_ctx, ret);
-		return ret;
-	}
-
-	ndia = &ndim.msg.alloc_node;
-	ndia->type = NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR;
-
-	/*
-	 * Construct a dynamic interface message and send it to the firmware.
-	 */
-	nss_dynamic_interface_msg_init(&ndim, NSS_DYNAMIC_INTERFACE, NSS_DYNAMIC_INTERFACE_ALLOC_NODE,
-				sizeof(struct nss_dynamic_interface_alloc_node_msg), nss_virt_if_handle_create_cb, (void *)handle);
-
-	ret = nss_dynamic_interface_tx(nss_ctx, &ndim);
-	if (ret != NSS_TX_SUCCESS) {
-		nss_warning("%p: failure allocating virt if\n", nss_ctx);
-		ret = NSS_VIRT_IF_DYNAMIC_IF_FAILURE;
-		kfree(handle);
-		return ret;
-	}
-
-	return ret;
-}
-EXPORT_SYMBOL(nss_virt_if_create);
-
-/*
  * nss_virt_if_create_sync()
- *	Create a virt interface, synchronously and associate it with the netdev
+ *	Create redir_n2h and redir_h2n interfaces, synchronously and associate it with same netdev
  */
 struct nss_virt_if_handle *nss_virt_if_create_sync(struct net_device *netdev)
 {
-	struct nss_ctx_instance *nss_ctx = &nss_top_main.nss[nss_top_main.wlan_handler_id];
+	struct nss_ctx_instance *nss_ctx = nss_virt_if_get_context();
 	struct nss_virt_if_msg nvim;
-	struct nss_virt_if_create_msg *nvcm;
+	struct nss_virt_if_config_msg *nvcm;
 	uint32_t ret;
 	struct nss_virt_if_handle *handle = NULL;
-	int32_t if_num;
+	int32_t if_num_n2h, if_num_h2n;
 
 	if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
 		nss_warning("%p: Interface could not be created as core not ready\n", nss_ctx);
 		return NULL;
 	}
 
-	if_num = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR);
-	if (if_num < 0) {
-		nss_warning("%p: failure allocating virt if\n", nss_ctx);
+	if_num_n2h = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR_N2H);
+	if (if_num_n2h < 0) {
+		nss_warning("%p: failure allocating redir_n2h\n", nss_ctx);
 		return NULL;
 	}
 
-	handle = nss_virt_if_handle_create_sync(nss_ctx, if_num, &ret);
+	if_num_h2n = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR_H2N);
+	if (if_num_h2n < 0) {
+		nss_warning("%p: failure allocating redir_h2n\n", nss_ctx);
+		nss_dynamic_interface_dealloc_node(if_num_n2h, NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR_N2H);
+		return NULL;
+	}
+
+	handle = nss_virt_if_handle_create_sync(nss_ctx, if_num_n2h, if_num_h2n, &ret);
 	if (!handle) {
-		nss_warning("%p:virt_if handle creation failed ret %d\n", nss_ctx, ret);
-		nss_dynamic_interface_dealloc_node(if_num, NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR);
+		nss_warning("%p: virt_if handle creation failed ret %d\n", nss_ctx, ret);
+		nss_dynamic_interface_dealloc_node(if_num_n2h, NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR_N2H);
+		nss_dynamic_interface_dealloc_node(if_num_h2n, NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR_H2N);
 		return NULL;
 	}
 
-	/* Initializes the semaphore and also sets the msg handler for if_num */
+	/*
+	 * Initializes the semaphore and also sets the msg handler for if_num.
+	 */
 	ret = nss_virt_if_register_handler_sync(nss_ctx, handle);
 	if (ret != NSS_VIRT_IF_SUCCESS) {
 		nss_warning("%p: Registration handler failed reason: %d\n", nss_ctx, ret);
-		goto error;
+		goto error1;
 	}
 
-	nss_virt_if_msg_init(&nvim, handle->if_num, NSS_VIRT_IF_TX_CREATE_MSG,
-				sizeof(struct nss_virt_if_create_msg), nss_virt_if_callback, handle);
+	nss_virt_if_msg_init(&nvim, handle->if_num_n2h, NSS_VIRT_IF_TX_CONFIG_MSG,
+				sizeof(struct nss_virt_if_config_msg), nss_virt_if_callback, handle);
 
-	nvcm = &nvim.msg.if_create;
+	nvcm = &nvim.msg.if_config;
 	nvcm->flags = 0;
+	nvcm->sibling = if_num_h2n;
+	nvcm->nexthop = NSS_N2H_INTERFACE;
 	memcpy(nvcm->mac_addr, netdev->dev_addr, ETH_ALEN);
 
 	ret = nss_virt_if_tx_msg_sync(handle, &nvim);
 	if (ret != NSS_TX_SUCCESS) {
 		nss_warning("%p: nss_virt_if_tx_msg_sync failed %u\n", nss_ctx, ret);
-		goto error;
+		goto error2;
 	}
 
-	nss_core_register_subsys_dp(nss_ctx, handle->if_num, NULL, NULL, NULL, netdev, 0);
+	nvim.cm.interface = if_num_h2n;
+	nvcm->sibling = if_num_n2h;
+	nvcm->nexthop = NSS_ETH_RX_INTERFACE;
+
+	ret = nss_virt_if_tx_msg_sync(handle, &nvim);
+	if (ret != NSS_TX_SUCCESS) {
+		nss_warning("%p: nss_virt_if_tx_msg_sync failed %u\n", nss_ctx, ret);
+		goto error2;
+	}
+
+	nss_core_register_subsys_dp(nss_ctx, handle->if_num_n2h, NULL, NULL, NULL, netdev, 0);
+	nss_core_register_subsys_dp(nss_ctx, handle->if_num_h2n, NULL, NULL, NULL, netdev, 0);
+
+	nss_core_set_subsys_dp_type(nss_ctx, netdev, if_num_n2h, NSS_VIRT_IF_DP_REDIR_N2H);
+	nss_core_set_subsys_dp_type(nss_ctx, netdev, if_num_h2n, NSS_VIRT_IF_DP_REDIR_H2N);
 
 	/*
 	 * Hold a reference to the net_device
@@ -604,69 +431,17 @@
 
 	return handle;
 
-error:
+error2:
+	nss_core_unregister_handler(nss_ctx, if_num_n2h);
+	nss_core_unregister_handler(nss_ctx, if_num_h2n);
+
+error1:
 	nss_virt_if_handle_destroy_sync(handle);
 	return NULL;
 }
 EXPORT_SYMBOL(nss_virt_if_create_sync);
 
 /*
- * nss_virt_if_destroy()
- *	Destroy the virt interface associated with the interface number, by sending
- * sending an asynchronous message to dynamic interface.
- */
-nss_tx_status_t nss_virt_if_destroy(struct nss_virt_if_handle *handle, nss_virt_if_msg_callback_t cb, void *app_data)
-{
-	nss_tx_status_t status;
-	struct net_device *dev;
-	int32_t if_num;
-	struct nss_ctx_instance *nss_ctx;
-	uint32_t ret;
-
-	if (!handle) {
-		nss_warning("handle is NULL\n");
-		return NSS_TX_FAILURE_BAD_PARAM;
-	}
-
-	if_num = handle->if_num;
-	nss_ctx = handle->nss_ctx;
-	handle->cb = cb;
-	handle->app_data = app_data;
-
-	if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
-		nss_warning("%p: Interface could not be destroyed as core not ready\n", nss_ctx);
-		return NSS_TX_FAILURE_NOT_READY;
-	}
-
-	spin_lock_bh(&nss_top_main.lock);
-	if (!nss_ctx->subsys_dp_register[if_num].ndev) {
-		spin_unlock_bh(&nss_top_main.lock);
-		nss_warning("%p: Unregister virt interface %d: no context\n", nss_ctx, if_num);
-		return NSS_TX_FAILURE_BAD_PARAM;
-	}
-
-	dev = nss_ctx->subsys_dp_register[if_num].ndev;
-	nss_core_unregister_subsys_dp(nss_ctx, if_num);
-	spin_unlock_bh(&nss_top_main.lock);
-	dev_put(dev);
-
-	status = nss_virt_if_handle_destroy(handle);
-	if (status != NSS_TX_SUCCESS) {
-		nss_warning("%p: handle destroy tx failed %d\n", nss_ctx, status);
-		return NSS_TX_FAILURE;
-	}
-
-	ret = nss_core_unregister_handler(nss_ctx, if_num);
-	if (ret != NSS_CORE_STATUS_SUCCESS) {
-		nss_warning("Not able to unregister handler for virt_if interface %d with NSS core\n", if_num);
-		return NSS_TX_FAILURE_BAD_PARAM;
-	}
-
-	return status;
-}
-EXPORT_SYMBOL(nss_virt_if_destroy);
-
-/*
  * nss_virt_if_destroy_sync()
  *	Destroy the virt interface associated with the interface number, synchronously.
  */
@@ -674,7 +449,8 @@
 {
 	nss_tx_status_t status;
 	struct net_device *dev;
-	int32_t if_num;
+	int32_t if_num_n2h;
+	int32_t if_num_h2n;
 	struct nss_ctx_instance *nss_ctx;
 	uint32_t ret;
 
@@ -683,7 +459,8 @@
 		return NSS_TX_FAILURE_BAD_PARAM;
 	}
 
-	if_num = handle->if_num;
+	if_num_n2h = handle->if_num_n2h;
+	if_num_h2n = handle->if_num_h2n;
 	nss_ctx = handle->nss_ctx;
 
 	if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
@@ -692,26 +469,34 @@
 	}
 
 	spin_lock_bh(&nss_top_main.lock);
-	if (!nss_ctx->subsys_dp_register[if_num].ndev) {
+	if (!nss_ctx->subsys_dp_register[if_num_n2h].ndev || !nss_ctx->subsys_dp_register[if_num_h2n].ndev) {
 		spin_unlock_bh(&nss_top_main.lock);
-		nss_warning("%p: Unregister virt interface %d: no context\n", nss_ctx, if_num);
+		nss_warning("%p: Unregister virt interface %d %d: no context\n", nss_ctx, if_num_n2h, if_num_h2n);
 		return NSS_TX_FAILURE_BAD_PARAM;
 	}
 
-	dev = nss_ctx->subsys_dp_register[if_num].ndev;
-	nss_core_unregister_subsys_dp(nss_ctx, if_num);
+	dev = nss_ctx->subsys_dp_register[if_num_n2h].ndev;
+	nss_assert(dev == nss_ctx->subsys_dp_register[if_num_h2n].ndev);
+	nss_core_unregister_subsys_dp(nss_ctx, if_num_n2h);
+	nss_core_unregister_subsys_dp(nss_ctx, if_num_h2n);
 	spin_unlock_bh(&nss_top_main.lock);
 	dev_put(dev);
 
 	status = nss_virt_if_handle_destroy_sync(handle);
 	if (status != NSS_TX_SUCCESS) {
-		nss_warning("%p: handle destroy failed for if_num %d\n", nss_ctx, if_num);
+		nss_warning("%p: handle destroy failed for if_num_n2h %d and if_num_h2n %d\n", nss_ctx, if_num_n2h, if_num_h2n);
 		return NSS_TX_FAILURE;
 	}
 
-	ret = nss_core_unregister_handler(nss_ctx, if_num);
+	ret = nss_core_unregister_handler(nss_ctx, if_num_n2h);
 	if (ret != NSS_CORE_STATUS_SUCCESS) {
-		nss_warning("%p: Not able to unregister handler for virt_if interface %d with NSS core\n", nss_ctx, if_num);
+		nss_warning("%p: Not able to unregister handler for redir_n2h interface %d with NSS core\n", nss_ctx, if_num_n2h);
+		return NSS_TX_FAILURE_BAD_PARAM;
+	}
+
+	ret = nss_core_unregister_handler(nss_ctx, if_num_h2n);
+	if (ret != NSS_CORE_STATUS_SUCCESS) {
+		nss_warning("%p: Not able to unregister handler for redir_h2n interface %d with NSS core\n", nss_ctx, if_num_h2n);
 		return NSS_TX_FAILURE_BAD_PARAM;
 	}
 
@@ -727,7 +512,7 @@
 						struct sk_buff *skb)
 {
 	int32_t status;
-	int32_t if_num = handle->if_num;
+	int32_t if_num = handle->if_num_h2n;
 	struct nss_ctx_instance *nss_ctx = handle->nss_ctx;
 
 	if (unlikely(nss_ctl_redirect == 0)) {
@@ -738,7 +523,11 @@
 		return NSS_TX_FAILURE_NOT_SUPPORTED;
 	}
 
-	nss_assert(NSS_IS_IF_TYPE(DYNAMIC, if_num));
+	if (!nss_virt_if_verify_if_num(if_num)) {
+		nss_warning("%p: bad interface number %d\n", nss_ctx, if_num);
+		return NSS_TX_FAILURE_BAD_PARAM;
+	}
+
 	nss_trace("%p: Virtual Rx packet, if_num:%d, skb:%p", nss_ctx, if_num, skb);
 
 	/*
@@ -804,7 +593,7 @@
 	/*
 	 * Sanity check the message
 	 */
-	if (!NSS_IS_IF_TYPE(DYNAMIC, ncm->interface)) {
+	if (!nss_virt_if_verify_if_num(ncm->interface)) {
 		nss_warning("%p: tx request for another interface: %d", nss_ctx, ncm->interface);
 		return NSS_TX_FAILURE;
 	}
@@ -863,7 +652,13 @@
 	}
 
 	nss_ctx = handle->nss_ctx;
-	if_num = handle->if_num;
+
+	if (!nss_virt_if_verify_if_num(handle->if_num_h2n)) {
+		nss_warning("if_num is invalid\n");
+		return;
+	}
+
+	if_num = handle->if_num_h2n;
 
 	nss_core_register_subsys_dp(nss_ctx, if_num, data_callback, NULL, NULL, netdev, (uint32_t)netdev->features);
 	nss_top_main.if_rx_msg_callback[if_num] = NULL;
@@ -884,7 +679,13 @@
 	}
 
 	nss_ctx = handle->nss_ctx;
-	if_num = handle->if_num;
+
+	if (!nss_virt_if_verify_if_num(handle->if_num_h2n)) {
+		nss_warning("if_num is invalid\n");
+		return;
+	}
+
+	if_num = handle->if_num_h2n;
 
 	nss_core_unregister_subsys_dp(nss_ctx, if_num);
 
@@ -894,7 +695,7 @@
 
 /*
  * nss_virt_if_get_interface_num()
- * Get interface number for a virtual interface
+ *	Get interface number for a virtual interface
  */
 int32_t nss_virt_if_get_interface_num(struct nss_virt_if_handle *handle)
 {
@@ -903,6 +704,9 @@
 		return -1;
 	}
 
-	return handle->if_num;
+	/*
+	 * Return if_num_n2h whose datapath type is 0.
+	 */
+	return handle->if_num_n2h;
 }
 EXPORT_SYMBOL(nss_virt_if_get_interface_num);
diff --git a/nss_virt_if_stats.c b/nss_virt_if_stats.c
index 28ed8fb..7b2f7ba 100644
--- a/nss_virt_if_stats.c
+++ b/nss_virt_if_stats.c
@@ -39,7 +39,7 @@
 	uint32_t len = 80;
 	struct nss_virt_if_handle *handle = NULL;
 
-	if (if_num < 0) {
+	if (!nss_virt_if_verify_if_num(if_num)) {
 		nss_warning("invalid if_num\n");
 		return 0;
 	}
@@ -123,7 +123,10 @@
 	}
 
 	for (; if_num < max_if_num; if_num++) {
-		if (nss_dynamic_interface_get_type(nss_ctx, if_num) != NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR)
+		/*
+		 * redir_h2n will collect stats from redir_n2h and redir_h2n in nss.
+		 */
+		if (nss_dynamic_interface_get_type(nss_ctx, if_num) != NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR_H2N)
 			continue;
 
 		bytes = scnprintf(line, sizeof(line), "if_num %d stats start:\n\n", if_num);