Merge "[qca-nss-drv] add supporting multi-tun6rd interface"
diff --git a/exports/nss_api_if.h b/exports/nss_api_if.h
index f6698e9..9d34dbb 100644
--- a/exports/nss_api_if.h
+++ b/exports/nss_api_if.h
@@ -75,7 +75,7 @@
 #define NSS_MAX_VIRTUAL_INTERFACES 16
 #define NSS_MAX_TUNNEL_INTERFACES 4
 #define NSS_MAX_SPECIAL_INTERFACES 24
-#define NSS_MAX_DYNAMIC_INTERFACES 3
+#define NSS_MAX_DYNAMIC_INTERFACES 8
 
 /**
  * Start of individual interface groups
diff --git a/exports/nss_dynamic_interface.h b/exports/nss_dynamic_interface.h
index c82a3b3..79d8582 100644
--- a/exports/nss_dynamic_interface.h
+++ b/exports/nss_dynamic_interface.h
@@ -29,6 +29,7 @@
 	NSS_DYNAMIC_INTERFACE_TYPE_NONE = 0,
 	NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR = 1,	/* GRE_REDIR Interface type */
 	NSS_DYNAMIC_INTERFACE_TYPE_CAPVAPV1 = 2,	/* CAPVAPV1 Interface type */
+	NSS_DYNAMIC_INTERFACE_TYPE_TUN6RD = 3,		/* TUN6RD Interface type */
 	NSS_DYNAMIC_INTERFACE_TYPE_MAX
 };
 
@@ -51,4 +52,13 @@
  */
 extern nss_tx_status_t nss_dynamic_interface_dealloc_node(int if_num, enum nss_dynamic_interface_type type);
 
+/**
+ * @brief The inferface number belong to the dynamic interface
+ *
+ * @param if_num interface number of dynamic interface
+ *
+ * @return bool true or false
+ */
+bool nss_is_dynamic_interface(int if_num);
+
 #endif /* __NSS_DYNAMIC_INTERFACE_H*/
diff --git a/exports/nss_tun6rd.h b/exports/nss_tun6rd.h
index cf58fa1..98b9bea 100644
--- a/exports/nss_tun6rd.h
+++ b/exports/nss_tun6rd.h
@@ -30,50 +30,51 @@
  * 6rd tunnel request/response types
  */
 enum nss_tun6rd_metadata_types {
-	NSS_TUN6RD_TX_IF_CREATE,
-	NSS_TUN6RD_TX_IF_DESTROY,
+	NSS_TUN6RD_ATTACH_PNODE,
 	NSS_TUN6RD_RX_STATS_SYNC,
+	NSS_TUN6RD_ADD_UPDATE_PEER,
 	NSS_TUN6RD_MAX,
 };
 
 /**
  * 6rd tunnel configuration message structure
  */
-struct nss_tun6rd_create_msg {
-	uint32_t prefix[4];	/* 6rd prefix */
-	uint32_t relay_prefix;	/* Relay prefix */
-	uint16_t prefixlen;	/* 6rd prefix len */
-	uint16_t relay_prefixlen;/* Relay prefix length*/
+struct nss_tun6rd_attach_tunnel_msg {
+	uint32_t prefix[4];		/* 6rd prefix */
+	uint32_t relay_prefix;		/* Relay prefix */
+	uint16_t prefixlen;		/* 6rd prefix len */
+	uint16_t relay_prefixlen;	/* Relay prefix length*/
 	uint32_t saddr;		/* Tunnel source address */
 	uint32_t daddr;		/* Tunnel destination addresss */
-	uint8_t  tos;		/* Tunnel tos field */
-	uint8_t  ttl;		/* Tunnel ttl field */
-	uint16_t reserved;	/* Reserved field */
-};
-
-/**
- * 6rd tunnel interface down message structure
- */
-struct nss_tun6rd_destroy_msg {
-	uint32_t prefix[4];	/* Place holder */
+	uint8_t  tos;			/* Tunnel tos field */
+	uint8_t  ttl;			/* Tunnel ttl field */
+	uint16_t reserved;		/* Reserved field */
 };
 
 /**
  * 6rd tunnel statistics sync message structure.
  */
-struct nss_tun6rd_stats_sync_msg {
-	struct nss_cmn_node_stats node_stats;
+struct nss_tun6rd_sync_stats_msg {
+	struct nss_cmn_node_stats node_stats;	/* Node statstics*/
+};
+
+/**
+ * 6rd tunnel peer addr.
+ */
+struct nss_tun6rd_set_peer_msg {
+	uint32_t ipv6_address[4];	/* The peer's ipv6 addr*/
+	uint32_t dest;			/* The peer's ipv4 addr*/
 };
 
 /**
  * Message structure to send/receive 6rd tunnel messages
  */
 struct nss_tun6rd_msg {
-	struct nss_cmn_msg cm;		/* Message Header */
+	struct nss_cmn_msg cm;					/* Message Header */
 	union {
-		struct nss_tun6rd_create_msg tun6rd_create;	/* Message: Create 6rd tunnel */
-		struct nss_tun6rd_destroy_msg tun6rd_destroy;	/* Message: Destroy 6rd tunnel */
-		struct nss_tun6rd_stats_sync_msg stats_sync;	/* Message: interface stats sync */
+		struct nss_tun6rd_attach_tunnel_msg tunnel;	/* Message: Attach 6rd tunnel */
+		struct nss_tun6rd_sync_stats_msg stats;	/* Message: interface stats sync */
+		struct nss_tun6rd_set_peer_msg peer;		/* Message: add/update peer */
 	} msg;
 };
 
@@ -98,10 +99,17 @@
 extern nss_tx_status_t nss_tun6rd_tx(struct nss_ctx_instance *nss_ctx, struct nss_tun6rd_msg *msg);
 
 /**
+ * @brief Get the tun6rd context used in the nss_tun6rd_tx
+ *
+ * @return struct nss_ctx_instance *NSS context
+ */
+extern struct nss_ctx_instance *nss_tun6rd_get_context(void);
+
+/**
  * @brief Callback to receive 6rd tunnel data
  *
  * @param app_data Application context of the message
- * @param os_buf  Pointer to data buffer
+ * @param os_buf Pointer to data buffer
  *
  * @return void
  */
@@ -118,7 +126,7 @@
  * @return nss_ctx_instance* NSS context
  */
 extern struct nss_ctx_instance *nss_register_tun6rd_if(uint32_t if_num, nss_tun6rd_callback_t tun6rd_callback,
-							nss_tun6rd_msg_callback_t msg_callback, struct net_device *netdev);
+					nss_tun6rd_msg_callback_t msg_callback, struct net_device *netdev);
 
 /**
  * @brief Unregister 6rd tunnel interface with NSS
diff --git a/nss_connmgr_tun6rd.c b/nss_connmgr_tun6rd.c
index 2a52087..801dc43 100644
--- a/nss_connmgr_tun6rd.c
+++ b/nss_connmgr_tun6rd.c
@@ -31,6 +31,7 @@
 #include <net/ipip.h>
 #include <linux/if_arp.h>
 #include <nss_api_if.h>
+#include <nss_dynamic_interface.h>
 
 /*
  * NSS tun6rd debug macros
@@ -38,46 +39,40 @@
 #if (NSS_TUN6RD_DEBUG_LEVEL < 1)
 #define nss_tun6rd_assert(fmt, args...)
 #else
-#define nss_tun6d_assert(c) if (!(c)) { BUG_ON(!(c)); }
+#define nss_tun6rd_assert(c) if (!(c)) { BUG_ON(!(c)); }
 #endif
 
-#if (NSS_TUN6RD_DEBUG_LEVEL < 2)
-#define nss_tun6rd_error(fmt, args...)
+#if defined(CONFIG_DYNAMIC_DEBUG)
+/*
+ * Compile messages for dynamic enable/disable
+ */
+#define nss_tun6rd_warning(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
+#define nss_tun6rd_info(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
+#define nss_tun6rd_trace(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
 #else
-#define nss_tun6rd_error(fmt, args...) printk(KERN_WARNING "nss tun6rd:"fmt, ##args)
+
+/*
+ * Statically compile messages at different levels
+ */
+#if (NSS_TUN6RD_DEBUG_LEVEL < 2)
+#define nss_tun6rd_warning(s, ...)
+#else
+#define nss_tun6rd_warning(s, ...) pr_warn("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
 #endif
 
 #if (NSS_TUN6RD_DEBUG_LEVEL < 3)
-#define nss_tun6rd_warning(fmt, args...)
+#define nss_tun6rd_info(s, ...)
 #else
-#define nss_tun6rd_warning(fmt, args...) printk(KERN_WARNING "nss tun6rd:"fmt, ##args)
+#define nss_tun6rd_info(s, ...)   pr_notice("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
 #endif
 
 #if (NSS_TUN6RD_DEBUG_LEVEL < 4)
-#define nss_tun6rd_info(fmt, args...)
+#define nss_tun6rd_trace(s, ...)
 #else
-#define nss_tun6rd_info(fmt, args...) printk(KERN_INFO "nss tun6rd :"fmt, ##args)
+#define nss_tun6rd_trace(s, ...)  pr_info("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
 #endif
-
-#if (NSS_TUN6RD_DEBUG_LEVEL < 5)
-#define nss_tun6rd_trace(fmt, args...)
-#else
-#define nss_tun6rd_trace(fmt, args...) printk(KERN_DEBUG "nss tun6rd :"fmt, ##args)
 #endif
 
-void nss_tun6rd_exception(void *ctx, void *buf, __attribute__((unused)) struct napi_struct *napi);
-void nss_tun6rd_event_receive(void *ctx, struct nss_tun6rd_msg *msg);
-
-/*
- * 6rd tunnel host instance
- */
-struct nss_tun6rd_tunnel{
-	struct nss_ctx_instance *nss_ctx;
-	uint32_t if_num;
-	struct net_device *netdev;
-	uint32_t device_up;
-};
-
 /*
  * 6rd tunnel stats
  */
@@ -88,45 +83,106 @@
 	uint32_t tx_bytes;	/* Number of transmitted bytes */
 };
 
+/*
+ * nss_tun6rd_update_dev_stats
+ *	Update the Dev stats received from NetAp
+ */
+static void nss_tun6rd_update_dev_stats(struct net_device *dev,
+					struct nss_tun6rd_sync_stats_msg *sync_stats)
+{
+	struct nss_tun6rd_stats stats;
 
-struct nss_tun6rd_tunnel g_tun6rd;
+	stats.rx_packets = sync_stats->node_stats.rx_packets;
+	stats.rx_bytes = sync_stats->node_stats.rx_bytes;
+	stats.tx_packets = sync_stats->node_stats.tx_packets;
+	stats.tx_bytes = sync_stats->node_stats.tx_bytes;
+
+	ipip6_update_offload_stats(dev, (void *)&stats);
+}
 
 /*
- * Internal function
+ * nss_tun6rd_event_receive()
+ *	Event Callback to receive events from NSS
  */
-static int
-nss_tun6rd_dev_event(struct notifier_block  *nb,
-			unsigned long event,
-			void  *dev);
+static void nss_tun6rd_event_receive(void *if_ctx, struct nss_tun6rd_msg *tnlmsg)
+{
+	struct net_device *netdev = if_ctx;
+
+	switch (tnlmsg->cm.type) {
+	case NSS_TUN6RD_RX_STATS_SYNC:
+		nss_tun6rd_update_dev_stats(netdev, (struct nss_tun6rd_sync_stats_msg *)&tnlmsg->msg.stats);
+		break;
+
+	default:
+		nss_tun6rd_info("Unknown Event from NSS\n");
+		break;
+	}
+}
 
 /*
- * Linux Net device Notifier
+ * nss_tun6rd_exception()
+ *	Exception handler registered to NSS driver
  */
-struct notifier_block nss_tun6rd_notifier = {
-	.notifier_call = nss_tun6rd_dev_event,
-};
+static void nss_tun6rd_exception(void *ctx, void *buf, __attribute__((unused)) struct napi_struct *napi)
+{
+	struct net_device *dev = (struct net_device *)ctx;
+	struct sk_buff *skb = (struct sk_buff *)buf;
+	const struct iphdr *iph;
+
+	skb->dev = dev;
+	nss_tun6rd_info("received - %d bytes name %s ver %x\n",
+			skb->len,dev->name,skb->data[0]);
+
+	iph = (const struct iphdr *)skb->data;
+
+	/*
+	 * Packet after Decap/Encap Did not find the Rule.
+	 */
+	if (iph->version != 4) {
+		skb->protocol = htons(ETH_P_IPV6);
+	} else {
+		if (iph->protocol == IPPROTO_IPV6) {
+			skb_pull(skb, sizeof(struct iphdr));
+			skb->protocol = htons(ETH_P_IPV6);
+			skb_reset_network_header(skb);
+			skb->pkt_type = PACKET_HOST;
+			skb->ip_summed = CHECKSUM_NONE;
+			dev_queue_xmit(skb);
+			return;
+		}
+		skb->protocol = htons(ETH_P_IP);
+	}
+
+	skb_reset_network_header(skb);
+	skb->pkt_type = PACKET_HOST;
+	skb->skb_iif = dev->ifindex;
+	skb->ip_summed = CHECKSUM_NONE;
+	netif_receive_skb(skb);
+}
 
 /*
  * nss_tun6rd_dev_up()
  *	6RD Tunnel device i/f up handler
  */
-void nss_tun6rd_dev_up( struct net_device * netdev)
+static int nss_tun6rd_dev_up(struct net_device *netdev)
 {
 	struct ip_tunnel *tunnel;
 	struct ip_tunnel_6rd_parm *ip6rd;
 	const struct iphdr  *tiph;
 	struct nss_tun6rd_msg tun6rdmsg;
-	struct nss_tun6rd_create_msg *tun6rdcfg;
+	struct nss_tun6rd_attach_tunnel_msg *tun6rdcfg;
+	uint32_t if_number;
 	nss_tx_status_t status;
+	struct nss_ctx_instance *nss_ctx;
 
 	/*
 	 * Validate netdev for ipv6-in-ipv4  Tunnel
 	 */
-	if (netdev->type != ARPHRD_SIT ) {
-		return;
+	if (netdev->type != ARPHRD_SIT) {
+		return NOTIFY_BAD;
 	}
 
-	tunnel = (struct ip_tunnel*)netdev_priv(netdev);
+	tunnel = (struct ip_tunnel *)netdev_priv(netdev);
 	ip6rd =  &tunnel->ip6rd;
 
 	/*
@@ -139,16 +195,14 @@
 	if ((ip6rd->prefixlen == 0 )
 			|| (ip6rd->relay_prefixlen > 32)
 			|| (ip6rd->prefixlen
-				+ (32 - ip6rd->relay_prefixlen) > 64)){
+				+ (32 - ip6rd->relay_prefixlen) > 64)) {
 
-		nss_tun6rd_error("Invalid 6rd argument prefix len %d     \
-				relayprefix len %d \n",
+		nss_tun6rd_warning("Invalid 6rd argument prefix len %d relayprefix len %d \n",
 				ip6rd->prefixlen,ip6rd->relay_prefixlen);
-		return;
+		return NOTIFY_BAD;
 	}
 
-	nss_tun6rd_info(" Valid 6rd Tunnel Prefix %x %x %x %x  \n        \
-			prefix len %d  relay_prefix %d relay_prefixlen %d \n",
+	nss_tun6rd_info("Valid 6rd Tunnel Prefix %x %x %x %x\n Prefix len %d relay_prefix %d relay_prefixlen %d \n",
 			ip6rd->prefix.s6_addr32[0],ip6rd->prefix.s6_addr32[1],
 			ip6rd->prefix.s6_addr32[2],ip6rd->prefix.s6_addr32[3],
 			ip6rd->prefixlen, ip6rd->relay_prefix,
@@ -158,41 +212,42 @@
 	 * Find the Tunnel device IP header info
 	 */
 	tiph = &tunnel->parms.iph ;
-	nss_tun6rd_trace(" Tunnel Param srcaddr %x daddr %x ttl %d tos %x\n",
+	nss_tun6rd_trace("Tunnel Param srcaddr %x daddr %x ttl %d tos %x\n",
 			tiph->saddr, tiph->daddr,tiph->ttl,tiph->tos);
 
-	if(tiph->saddr == 0) {
-		nss_tun6rd_error("Tunnel src address not configured  %x\n",
+	if (tiph->saddr == 0) {
+		nss_tun6rd_warning("Tunnel src address not configured %x\n",
 				tiph->saddr);
-		return;
+		return NOTIFY_BAD;
 	}
 
-	if (tiph->daddr == 0) {
-		nss_tun6rd_error("Tunnel dest address not configured  %x\n",
-				tiph->daddr);
-		return;
+	if_number = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_TUN6RD);
+	if (-1 == if_number) {
+		nss_tun6rd_warning("Request interface number failed\n");
+		return NOTIFY_BAD;
 	}
 
 	/*
 	 * Register 6rd tunnel with NSS
 	 */
-	g_tun6rd.nss_ctx = nss_register_tun6rd_if(g_tun6rd.if_num,
+	nss_ctx = nss_register_tun6rd_if(if_number,
 				nss_tun6rd_exception,
 				nss_tun6rd_event_receive,
 				netdev);
-	if (g_tun6rd.nss_ctx == NULL) {
-		nss_tun6rd_trace("nss_register_tun6rd_if Failed \n");
-		return;
+	if (!nss_ctx) {
+		status = nss_dynamic_interface_dealloc_node(if_number, NSS_DYNAMIC_INTERFACE_TYPE_TUN6RD);
+		if (status != NSS_TX_SUCCESS) {
+			nss_tun6rd_warning("Unable to dealloc the node[%d] in the NSS fw!\n", if_number);
+		}
+		nss_tun6rd_trace("nss_register_tun6rd_if failed \n");
+		return NOTIFY_BAD;
 	}
 
-	nss_tun6rd_trace("nss_register_tun6rd_if Success \n");
-
 	/*
 	 * Prepare The Tunnel configuration parameter to send to nss
 	 */
 	memset(&tun6rdmsg, 0, sizeof(struct nss_tun6rd_msg));
-	tun6rdcfg = &tun6rdmsg.msg.tun6rd_create;
-
+	tun6rdcfg = &tun6rdmsg.msg.tunnel;
 	tun6rdcfg->prefixlen = ip6rd->prefixlen;
 	tun6rdcfg->relay_prefix = ip6rd->relay_prefix;
 	tun6rdcfg->relay_prefixlen = ip6rd->relay_prefixlen;
@@ -205,61 +260,68 @@
 	tun6rdcfg->ttl = tiph->ttl;
 	tun6rdcfg->tos = tiph->tos;
 
-	nss_tun6rd_trace(" 6rd Tunnel info \n");
-	nss_tun6rd_trace(" saddr %x daddr %d ttl %x  tos %x \n",
+	nss_tun6rd_trace(" 6rd Tunnel info\n");
+	nss_tun6rd_trace(" saddr %x daddr %d ttl %x  tos %x\n",
 			tiph->saddr, tiph->daddr, tiph->ttl, tiph->tos);
-	nss_tun6rd_trace(" Prefix %x:%x:%x:%x  Prefix len %d \n",
+	nss_tun6rd_trace(" Prefix %x:%x:%x:%x  Prefix len %d\n",
 			ip6rd->prefix.s6_addr32[0], ip6rd->prefix.s6_addr32[1],
 			ip6rd->prefix.s6_addr32[2], ip6rd->prefix.s6_addr32[3],
 			ip6rd->prefixlen);
 	nss_tun6rd_trace("Relay Prefix %x Len %d\n",
 			ip6rd->relay_prefix, ip6rd->relay_prefixlen);
 
-	nss_tun6rd_trace("Sending 6rd tunnel i/f up command to NSS  %x \n",
-			(int)g_tun6rd.nss_ctx);
+	nss_tun6rd_trace("Sending 6rd tunnel i/f up command to NSS %x\n",
+			(int)nss_ctx);
 
 	/*
 	 * Send 6rd Tunnel UP command to NSS
 	 */
-	nss_cmn_msg_init(&tun6rdmsg.cm, NSS_TUN6RD_INTERFACE, NSS_TUN6RD_TX_IF_CREATE,
-			sizeof(struct nss_tun6rd_create_msg), NULL, NULL);
+	nss_cmn_msg_init(&tun6rdmsg.cm, if_number, NSS_TUN6RD_ATTACH_PNODE,
+			sizeof(struct nss_tun6rd_attach_tunnel_msg), NULL, NULL);
 
-	status = nss_tun6rd_tx(g_tun6rd.nss_ctx, &tun6rdmsg);
+	status = nss_tun6rd_tx(nss_ctx, &tun6rdmsg);
 	if (status != NSS_TX_SUCCESS) {
-		nss_tun6rd_error("Tunnel up command error %d \n", status);
-		return;
+		nss_unregister_tun6rd_if(if_number);
+		status = nss_dynamic_interface_dealloc_node(if_number, NSS_DYNAMIC_INTERFACE_TYPE_TUN6RD);
+		if (status != NSS_TX_SUCCESS) {
+			nss_tun6rd_warning("Unable to dealloc the node[%d] in the NSS fw!\n", if_number);
+		}
+		nss_tun6rd_warning("Tunnel up command error %d\n", status);
+		return NOTIFY_BAD;
 	}
 
-	g_tun6rd.device_up = 1;
+	return NOTIFY_DONE;
 }
 
 /*
  * nss_tun6rd_dev_down()
  *	6RD Tunnel device i/f down handler
  */
-void nss_tun6rd_dev_down(struct net_device *netdev)
+static int nss_tun6rd_dev_down(struct net_device *netdev)
 {
 	struct ip_tunnel *tunnel;
 	struct ip_tunnel_6rd_parm *ip6rd;
-	struct nss_tun6rd_msg tun6rdmsg;
-	struct nss_tun6rd_destroy_msg *tun6rdcfg;
+	int32_t if_number;
 	nss_tx_status_t status;
 
 	/*
-	 * Check if tunnel 6rd is registered ?
-	 */
-	if (g_tun6rd.nss_ctx == NULL) {
-		return;
-	}
-
-	/*
 	 * Validate netdev for ipv6-in-ipv4  Tunnel
 	 */
-	if (netdev->type != ARPHRD_SIT ) {
-		return;
+	if (netdev->type != ARPHRD_SIT) {
+		return NOTIFY_BAD;
 	}
 
-	tunnel = (struct ip_tunnel*)netdev_priv(netdev);
+	/*
+	 * Check if tunnel 6rd is registered ?
+	 */
+	if_number = nss_cmn_get_interface_number_by_dev(netdev);
+	if (if_number < 0) {
+		nss_tun6rd_warning("Net device:%p is not registered \n",netdev);
+		return NOTIFY_BAD;
+	}
+
+
+	tunnel = (struct ip_tunnel *)netdev_priv(netdev);
 	ip6rd =  &tunnel->ip6rd;
 
 	/*
@@ -268,53 +330,27 @@
 	if ((ip6rd->prefixlen == 0 )
 			|| (ip6rd->relay_prefixlen > 32 )
 			|| (ip6rd->prefixlen
-				+ (32 - ip6rd->relay_prefixlen) > 64)){
+				+ (32 - ip6rd->relay_prefixlen) > 64)) {
 
-		nss_tun6rd_error("Invalid 6rd argument prefix len %d  \
-				relayprefix len %d \n",
+		nss_tun6rd_warning("Invalid 6rd argument prefix len %d relayprefix len %d \n",
 				ip6rd->prefixlen,ip6rd->relay_prefixlen);
-		return;
-	}
-
-	/*
-	 * Prepare The Tunnel configuration parameter to send to nss
-	 */
-	memset(&tun6rdmsg, 0, sizeof(struct nss_tun6rd_msg));
-	tun6rdcfg = &tun6rdmsg.msg.tun6rd_destroy;
-
-	tun6rdcfg->prefix[0] = ntohl(ip6rd->prefix.s6_addr32[0]);
-	tun6rdcfg->prefix[1] = ntohl(ip6rd->prefix.s6_addr32[1]);
-	tun6rdcfg->prefix[2] = ntohl(ip6rd->prefix.s6_addr32[2]);
-	tun6rdcfg->prefix[3] = ntohl(ip6rd->prefix.s6_addr32[3]);
-
-	nss_tun6rd_trace(" Prefix %x:%x:%x:%x  Prefix len %d \n",
-			ip6rd->prefix.s6_addr32[0], ip6rd->prefix.s6_addr32[1],
-			ip6rd->prefix.s6_addr32[2], ip6rd->prefix.s6_addr32[3],
-			ip6rd->prefixlen);
-
-	nss_tun6rd_trace("Sending Tunnle 6rd Down command %x \n",g_tun6rd.if_num);
-
-	/*
-	 * Send 6rd Tunnel DESTROY command to NSS
-	 */
-	nss_cmn_msg_init(&tun6rdmsg.cm, NSS_TUN6RD_INTERFACE, NSS_TUN6RD_TX_IF_DESTROY,
-			sizeof(struct nss_tun6rd_destroy_msg), NULL, NULL);
-
-	status = nss_tun6rd_tx(g_tun6rd.nss_ctx, &tun6rdmsg);
-	if (status != NSS_TX_SUCCESS) {
-		nss_tun6rd_error("Tunnel down command error %d \n", status);
-		return;
+		return NOTIFY_BAD;
 	}
 
 	/*
 	 * Un-Register 6rd tunnel with NSS
 	 */
-	nss_unregister_tun6rd_if(g_tun6rd.if_num);
-	g_tun6rd.nss_ctx = NULL;
-	g_tun6rd.device_up = 0;
-	return;
+	nss_unregister_tun6rd_if(if_number);
+	status = nss_dynamic_interface_dealloc_node(if_number, NSS_DYNAMIC_INTERFACE_TYPE_TUN6RD);
+	if (status != NSS_TX_SUCCESS) {
+		nss_tun6rd_warning("Dealloc node failure\n");
+		return NOTIFY_BAD;
+	}
+
+	return NOTIFY_DONE;
 }
 
+
 /*
  * nss_tun6rd_dev_event()
  *	Net device notifier for 6rd module
@@ -324,23 +360,17 @@
 {
 	struct net_device *netdev = (struct net_device *)dev;
 
-	nss_tun6rd_trace("%s\n",__FUNCTION__);
 	switch (event) {
 	case NETDEV_UP:
-		nss_tun6rd_trace(" NETDEV_UP :event %lu name %s \n",
-				event,netdev->name);
-		nss_tun6rd_dev_up(netdev);
-		break;
+		nss_tun6rd_trace("NETDEV_UP: event %lu name %s\n", event, netdev->name);
+		return nss_tun6rd_dev_up(netdev);
 
 	case NETDEV_DOWN:
-		nss_tun6rd_trace(" NETDEV_DOWN :event %lu name %s \n",
-				event,netdev->name);
-		nss_tun6rd_dev_down(netdev);
-		break;
+		nss_tun6rd_trace("NETDEV_DOWN: event %lu name %s\n", event, netdev->name);
+		return nss_tun6rd_dev_down(netdev);
 
 	default:
-		nss_tun6rd_trace("Unhandled notifier dev %s  event %x  \n",
-				netdev->name,(int)event);
+		nss_tun6rd_trace("Unhandled notifier event %lu name %s\n",event, netdev->name);
 		break;
 	}
 
@@ -348,87 +378,12 @@
 }
 
 /*
- * nss_tun6rd_exception()
- *	Exception handler registered to NSS driver
+ * Linux Net device Notifier
  */
-void nss_tun6rd_exception(void *ctx, void *buf, __attribute__((unused)) struct napi_struct *napi)
-{
-	struct net_device *dev = (struct net_device *)ctx;
-	struct sk_buff *skb = (struct sk_buff *)buf;
-	const struct iphdr *iph;
+struct notifier_block nss_tun6rd_notifier = {
+	.notifier_call = nss_tun6rd_dev_event,
+};
 
-	skb->dev = dev;
-	nss_tun6rd_info("received - %d bytes name %s ver %x \n",
-			skb->len,dev->name,skb->data[0]);
-
-	iph = (const struct iphdr *)skb->data;
-
-	/*
-	 * Packet after Decap/Encap Did not find the Rule.
-	 */
-	if (iph->version == 4) {
-		if(iph->protocol == IPPROTO_IPV6){
-			skb_pull(skb, sizeof(struct iphdr));
-			skb->protocol = htons(ETH_P_IPV6);
-			skb_reset_network_header(skb);
-			skb->pkt_type = PACKET_HOST;
-			skb->ip_summed = CHECKSUM_NONE;
-			dev_queue_xmit(skb);
-			return;
-		}
-		skb->protocol = htons(ETH_P_IP);
-	} else {
-		skb->protocol = htons(ETH_P_IPV6);
-	}
-
-	skb_reset_network_header(skb);
-	skb->pkt_type = PACKET_HOST;
-	skb->skb_iif = dev->ifindex;
-	skb->ip_summed = CHECKSUM_NONE;
-	netif_receive_skb(skb);
-}
-
-/*
- *  nss_tun6rd_update_dev_stats
- *	Update the Dev stats received from NetAp
- */
-static void nss_tun6rd_update_dev_stats(struct net_device *dev,
-					struct nss_tun6rd_stats_sync_msg *sync_stats)
-{
-	struct nss_tun6rd_stats stats;
-	void *ptr;
-
-	stats.rx_packets = sync_stats->node_stats.rx_packets;
-	stats.rx_bytes = sync_stats->node_stats.rx_bytes;
-	stats.tx_packets = sync_stats->node_stats.tx_packets;
-	stats.tx_bytes = sync_stats->node_stats.tx_bytes;
-
-	ptr = (void *)&stats;
-	ipip6_update_offload_stats(dev, ptr);
-}
-
-/**
- * @brief Event Callback to receive events from NSS
- * @param[in] pointer to net device context
- * @param[in] pointer to buffer
- * @return Returns void
- */
-void nss_tun6rd_event_receive(void *if_ctx, struct nss_tun6rd_msg *tnlmsg)
-{
-	struct net_device *netdev = NULL;
-	netdev = (struct net_device *)if_ctx;
-
-	switch (tnlmsg->cm.type) {
-	case NSS_TUN6RD_RX_STATS_SYNC:
-		nss_tun6rd_update_dev_stats(netdev, (struct nss_tun6rd_stats_sync_msg *)&tnlmsg->msg.stats_sync);
-		break;
-
-	default:
-		nss_tun6rd_info("%s: Unknown Event from NSS",
-			      __FUNCTION__);
-		break;
-	}
-}
 
 /*
  * nss_tun6rd_init_module()
@@ -442,11 +397,6 @@
 	register_netdevice_notifier(&nss_tun6rd_notifier);
 	nss_tun6rd_trace("Netdev Notifier registerd \n");
 
-	g_tun6rd.if_num = NSS_TUN6RD_INTERFACE;
-	g_tun6rd.netdev = NULL;
-	g_tun6rd.device_up = 0;
-	g_tun6rd.nss_ctx = NULL;
-
 	return 0;
 }
 
@@ -456,7 +406,6 @@
  */
 void __exit nss_tun6rd_exit_module(void)
 {
-
 	unregister_netdevice_notifier(&nss_tun6rd_notifier);
 	nss_tun6rd_info("module unloaded\n");
 }
diff --git a/nss_dynamic_interface.c b/nss_dynamic_interface.c
index 6b35852..ced3dea 100644
--- a/nss_dynamic_interface.c
+++ b/nss_dynamic_interface.c
@@ -336,5 +336,15 @@
 	di.current_if_num = -1;
 }
 
+/*
+ * nss_is_dynamic_interface()
+ *	Judge it is a valid dynamic interface
+ */
+bool nss_is_dynamic_interface(int if_num)
+{
+	return (if_num >= NSS_DYNAMIC_IF_START && if_num < NSS_SPECIAL_IF_START);
+}
+
 EXPORT_SYMBOL(nss_dynamic_interface_alloc_node);
 EXPORT_SYMBOL(nss_dynamic_interface_dealloc_node);
+EXPORT_SYMBOL(nss_is_dynamic_interface);
diff --git a/nss_init.c b/nss_init.c
index 646ab0d..1a6e56b 100755
--- a/nss_init.c
+++ b/nss_init.c
@@ -370,7 +370,6 @@
 
 	if (npd->tun6rd_enabled == NSS_FEATURE_ENABLED) {
 		nss_top->tun6rd_handler_id = nss_dev->id;
-		nss_tun6rd_register_handler();
 	}
 
 	if (npd->tunipip6_enabled == NSS_FEATURE_ENABLED) {
diff --git a/nss_tun6rd.c b/nss_tun6rd.c
index b4d83d0..705f041 100644
--- a/nss_tun6rd.c
+++ b/nss_tun6rd.c
@@ -24,9 +24,11 @@
 {
 	struct nss_tun6rd_msg *ntm = (struct nss_tun6rd_msg *)ncm;
 	void *ctx;
+
 	nss_tun6rd_msg_callback_t cb;
 
-	BUG_ON(ncm->interface != NSS_TUN6RD_INTERFACE);
+	BUG_ON(!nss_is_dynamic_interface(ncm->interface));
+
 	/*
 	 * Is this a valid request/response packet?
 	 */
@@ -77,7 +79,6 @@
 	cb(ctx, ntm);
 }
 
-
 /*
  * nss_tun6rd_tx()
  * 	Transmit a tun6rd message to NSSFW
@@ -98,7 +99,7 @@
 	/*
 	 * Sanity check the message
 	 */
-	if (ncm->interface != NSS_TUN6RD_INTERFACE) {
+	if (!nss_is_dynamic_interface(ncm->interface)) {
 		nss_warning("%p: tx request for another interface: %d", nss_ctx, ncm->interface);
 		return NSS_TX_FAILURE;
 	}
@@ -151,17 +152,26 @@
 /*
  * nss_register_tun6rd_if()
  */
-struct nss_ctx_instance *nss_register_tun6rd_if(uint32_t if_num,
-                                nss_tun6rd_callback_t tun6rd_callback,
-                                nss_tun6rd_msg_callback_t event_callback, struct net_device *netdev)
+struct nss_ctx_instance *nss_register_tun6rd_if(uint32_t if_num, nss_tun6rd_callback_t tun6rd_callback,
+			nss_tun6rd_msg_callback_t event_callback, struct net_device *netdev)
 {
-        nss_assert((if_num >= NSS_MAX_VIRTUAL_INTERFACES) && (if_num < NSS_MAX_NET_INTERFACES));
+	nss_assert((if_num >=  NSS_DYNAMIC_IF_START) && (if_num < NSS_SPECIAL_IF_START));
 
-        nss_top_main.if_ctx[if_num] = netdev;
-        nss_top_main.if_rx_callback[if_num] = tun6rd_callback;
-        nss_top_main.tun6rd_msg_callback = event_callback;
+	nss_top_main.if_ctx[if_num] = netdev;
+	nss_top_main.if_rx_callback[if_num] = tun6rd_callback;
+	nss_top_main.tun6rd_msg_callback = event_callback;
 
-        return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.tun6rd_handler_id];
+	nss_core_register_handler(if_num, nss_tun6rd_handler, NULL);
+
+	return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.tun6rd_handler_id];
+}
+
+/*
+ * nss_get_tun6rd_context()
+ */
+struct nss_ctx_instance * nss_tun6rd_get_context()
+{
+	return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.tun6rd_handler_id];
 }
 
 /*
@@ -169,22 +179,16 @@
  */
 void nss_unregister_tun6rd_if(uint32_t if_num)
 {
-        nss_assert((if_num >= NSS_MAX_VIRTUAL_INTERFACES) && (if_num < NSS_MAX_NET_INTERFACES));
+	nss_assert(nss_is_dynamic_interface(ncm->interface));
 
-        nss_top_main.if_rx_callback[if_num] = NULL;
-        nss_top_main.if_ctx[if_num] = NULL;
-        nss_top_main.tun6rd_msg_callback = NULL;
+	nss_top_main.if_rx_callback[if_num] = NULL;
+	nss_top_main.if_ctx[if_num] = NULL;
+	nss_top_main.tun6rd_msg_callback = NULL;
+
+	nss_core_unregister_handler(if_num);
 }
 
-/*
- * nss_tun6rd_register_handler()
- */
-void nss_tun6rd_register_handler()
-{
-	nss_core_register_handler(NSS_TUN6RD_INTERFACE, nss_tun6rd_handler, NULL);
-}
-
-
+EXPORT_SYMBOL(nss_tun6rd_get_context);
 EXPORT_SYMBOL(nss_tun6rd_tx);
 EXPORT_SYMBOL(nss_register_tun6rd_if);
 EXPORT_SYMBOL(nss_unregister_tun6rd_if);
diff --git a/nss_tx_rx_common.h b/nss_tx_rx_common.h
index 9d155bd..9e29a30 100644
--- a/nss_tx_rx_common.h
+++ b/nss_tx_rx_common.h
@@ -69,7 +69,6 @@
 extern void nss_ipv4_register_handler(void);
 extern void nss_ipv6_register_handler(void);
 extern void nss_n2h_register_handler(void);
-extern void nss_tun6rd_register_handler(void);
 extern void nss_tunipip6_register_handler(void);
 extern void nss_pppoe_register_handler(void);
 extern void nss_core_freq_register_handler(void);