Merge "[qca-nss-drv] Remove deprecated connection manager"
diff --git a/Makefile b/Makefile
index 90019c6..650fcd2 100644
--- a/Makefile
+++ b/Makefile
@@ -31,6 +31,7 @@
 			nss_init.o \
 			nss_ipsec.o \
 			nss_ipv4.o \
+			nss_ipv4_reasm.o \
 			nss_ipv6.o \
 			nss_lag.o \
 			nss_phys_if.o \
diff --git a/exports/nss_api_if.h b/exports/nss_api_if.h
index 9723c1d..afae832 100644
--- a/exports/nss_api_if.h
+++ b/exports/nss_api_if.h
@@ -76,7 +76,7 @@
 #define NSS_MAX_PHYSICAL_INTERFACES 4
 #define NSS_MAX_VIRTUAL_INTERFACES 16
 #define NSS_MAX_TUNNEL_INTERFACES 4
-#define NSS_MAX_SPECIAL_INTERFACES 24
+#define NSS_MAX_SPECIAL_INTERFACES 25
 #define NSS_MAX_DYNAMIC_INTERFACES 32
 
 /**
@@ -113,6 +113,7 @@
 #define NSS_DYNAMIC_INTERFACE (NSS_SPECIAL_IF_START + 20) /* Special Interface Number for Dynamic Interfaces */
 #define NSS_GRE_REDIR_INTERFACE (NSS_SPECIAL_IF_START + 21) /* Interface Number for GRE REDIR base interface */
 #define NSS_SJACK_INTERFACE (NSS_SPECIAL_IF_START + 23) /* Interface Number for GRE REDIR base interface */
+#define NSS_IPV4_REASM_INTERFACE (NSS_SPECIAL_IF_START + 24) /* Special IF number for IPv4 */
 
 /**
  * This macro converts format for IPv6 address (from Linux to NSS)
diff --git a/nss_core.h b/nss_core.h
index 626b21d..b7473d8 100755
--- a/nss_core.h
+++ b/nss_core.h
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014, 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.
@@ -217,6 +217,22 @@
 };
 
 /*
+ * IPV4 reasm node statistics
+ *
+ * WARNING: There is a 1:1 mapping between values below and corresponding
+ *	stats string array in nss_stats.c
+ */
+enum nss_stats_ipv4_reasm {
+	NSS_STATS_IPV4_REASM_EVICTIONS = 0,
+					/* Number of evicted fragment queues due to set memory threshold */
+	NSS_STATS_IPV4_REASM_ALLOC_FAILS,
+					/* Number of fragment queue allocation failures */
+	NSS_STATS_IPV4_REASM_TIMEOUTS,
+					/* Number of expired fragment queues */
+	NSS_STATS_IPV4_REASM_MAX,
+};
+
+/*
  * IPV6 node statistics
  *
  * WARNING: There is a 1:1 mapping between values below and corresponding
@@ -489,6 +505,8 @@
 	struct dentry *top_dentry;	/* Top dentry for nss */
 	struct dentry *stats_dentry;	/* Top dentry for nss stats */
 	struct dentry *ipv4_dentry;	/* IPv4 stats dentry */
+	struct dentry *ipv4_reasm_dentry;
+					/* IPv4 stats dentry */
 	struct dentry *ipv6_dentry;	/* IPv6 stats dentry */
 	struct dentry *eth_rx_dentry;	/* ETH_RX stats dentry */
 	struct dentry *n2h_dentry;	/* N2H stats dentry */
@@ -508,6 +526,7 @@
 	uint8_t gre_redir_handler_id;
 	uint8_t shaping_handler_id;
 	uint8_t ipv4_handler_id;
+	uint8_t ipv4_reasm_handler_id;
 	uint8_t ipv6_handler_id;
 	uint8_t crypto_handler_id;
 	uint8_t ipsec_handler_id;
@@ -576,6 +595,8 @@
 	 */
 	uint64_t stats_ipv4[NSS_STATS_IPV4_MAX];
 					/* IPv4 statistics */
+	uint64_t stats_ipv4_reasm[NSS_STATS_IPV4_REASM_MAX];
+					/* IPv4 reasm statistics */
 	uint64_t stats_ipv6[NSS_STATS_IPV6_MAX];
 					/* IPv6 statistics */
 	uint64_t stats_drv[NSS_STATS_DRV_MAX];
diff --git a/nss_hlos_if.h b/nss_hlos_if.h
index 71325ce..0a0b9ed 100755
--- a/nss_hlos_if.h
+++ b/nss_hlos_if.h
@@ -193,6 +193,34 @@
 };
 
 /*
+ * IPv4 reasm node stats
+ */
+struct nss_ipv4_reasm_stats_sync {
+	struct nss_cmn_node_stats node_stats;
+					/* Common node stats for N2H */
+	uint32_t ipv4_reasm_evictions;
+	uint32_t ipv4_reasm_alloc_fails;
+	uint32_t ipv4_reasm_timeouts;
+};
+
+/*
+ * IPv4 reasm message types
+ */
+enum nss_ipv4_reasm_message_types {
+	NSS_IPV4_REASM_STATS_SYNC_MSG,
+};
+
+/*
+ * IPv4 reassembly message structure
+ */
+struct nss_ipv4_reasm_msg {
+	struct nss_cmn_msg cm;
+	union {
+		struct nss_ipv4_reasm_stats_sync stats_sync;
+	} msg;
+};
+
+/*
  * Generic interface messages
  */
 enum nss_generic_metadata_types {
diff --git a/nss_init.c b/nss_init.c
index 3c8c991..c08cdae 100755
--- a/nss_init.c
+++ b/nss_init.c
@@ -355,6 +355,11 @@
 		nss_top->dynamic_interface_table[NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR] = nss_dev->id;
 	}
 
+	if (npd->ipv4_reasm_enabled == NSS_FEATURE_ENABLED) {
+		nss_top->ipv4_reasm_handler_id = nss_dev->id;
+		nss_ipv4_reasm_register_handler();
+	}
+
 	if (npd->ipv6_enabled == NSS_FEATURE_ENABLED) {
 		nss_top->ipv6_handler_id = nss_dev->id;
 		nss_ipv6_register_handler();
diff --git a/nss_ipv4_reasm.c b/nss_ipv4_reasm.c
new file mode 100644
index 0000000..9a681ac
--- /dev/null
+++ b/nss_ipv4_reasm.c
@@ -0,0 +1,86 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2014, 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.
+ **************************************************************************
+ */
+
+/*
+ * nss_ipv4_reasm.c
+ *	NSS IPv4 Reassembly APIs
+ */
+#include "nss_tx_rx_common.h"
+
+/*
+ * nss_ipv4_reasm_stats_sync()
+ *	Update driver specific information from the messsage.
+ */
+static void nss_ipv4_reasm_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_ipv4_reasm_stats_sync *nirs)
+{
+	struct nss_top_instance *nss_top = nss_ctx->nss_top;
+
+	spin_lock_bh(&nss_top->stats_lock);
+
+	/*
+	 * Common node stats
+	 */
+	nss_top->stats_node[NSS_IPV4_REASM_INTERFACE][NSS_STATS_NODE_RX_PKTS] += nirs->node_stats.rx_packets;
+	nss_top->stats_node[NSS_IPV4_REASM_INTERFACE][NSS_STATS_NODE_RX_BYTES] += nirs->node_stats.rx_bytes;
+	nss_top->stats_node[NSS_IPV4_REASM_INTERFACE][NSS_STATS_NODE_RX_DROPPED] += nirs->node_stats.rx_dropped;
+	nss_top->stats_node[NSS_IPV4_REASM_INTERFACE][NSS_STATS_NODE_TX_PKTS] += nirs->node_stats.tx_packets;
+	nss_top->stats_node[NSS_IPV4_REASM_INTERFACE][NSS_STATS_NODE_TX_BYTES] += nirs->node_stats.tx_bytes;
+
+	/*
+	 * IPv4 reasm node stats
+	 */
+	nss_top->stats_ipv4_reasm[NSS_STATS_IPV4_REASM_EVICTIONS] += nirs->ipv4_reasm_evictions;
+	nss_top->stats_ipv4_reasm[NSS_STATS_IPV4_REASM_ALLOC_FAILS] += nirs->ipv4_reasm_alloc_fails;
+	nss_top->stats_ipv4_reasm[NSS_STATS_IPV4_REASM_TIMEOUTS] += nirs->ipv4_reasm_timeouts;
+
+	spin_unlock_bh(&nss_top->stats_lock);
+}
+
+/*
+ * nss_ipv4_reasm_msg_handler()
+ *	Handle NSS -> HLOS messages for IPv4 reasm
+ */
+static void nss_ipv4_reasm_msg_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, __attribute__((unused))void *app_data)
+{
+	struct nss_ipv4_reasm_msg *nim = (struct nss_ipv4_reasm_msg *)ncm;
+
+	BUG_ON(ncm->interface != NSS_IPV4_REASM_INTERFACE);
+
+	/*
+	 * Handle deprecated messages.  Eventually these messages should be removed.
+	 */
+	switch (nim->cm.type) {
+	case NSS_IPV4_REASM_STATS_SYNC_MSG:
+		/*
+		* Update driver statistics on node sync.
+		*/
+		nss_ipv4_reasm_stats_sync(nss_ctx, &nim->msg.stats_sync);
+		break;
+	default:
+		nss_warning("IPv4 reasm received an unknown message type");
+	}
+}
+
+/*
+ * nss_ipv4_reasm_register_handler()
+ *	Register our handler to receive messages for this interface
+ */
+void nss_ipv4_reasm_register_handler(void)
+{
+	if (nss_core_register_handler(NSS_IPV4_REASM_INTERFACE, nss_ipv4_reasm_msg_handler, NULL) != NSS_CORE_STATUS_SUCCESS) {
+		nss_warning("IPv4 reasm handler failed to register");
+	}
+}
diff --git a/nss_stats.c b/nss_stats.c
index 726ac87..3875c63 100644
--- a/nss_stats.c
+++ b/nss_stats.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014, 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,16 @@
 };
 
 /*
+ * nss_stats_str_ipv4_reasm
+ *	IPv4 reassembly stats strings
+ */
+static int8_t *nss_stats_str_ipv4_reasm[NSS_STATS_IPV4_REASM_MAX] = {
+	"evictions",
+	"alloc_fails",
+	"timeouts",
+};
+
+/*
  * nss_stats_str_ipv6
  *	IPv6 stats strings
  */
@@ -385,6 +395,77 @@
 }
 
 /*
+ * nss_stats_ipv4_reasm_read()
+ *	Read IPV4 reassembly stats
+ */
+static ssize_t nss_stats_ipv4_reasm_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
+{
+	int32_t i;
+	/*
+	 * max output lines = #stats + start tag line + end tag line + three blank lines
+	 */
+	uint32_t max_output_lines = (NSS_STATS_NODE_MAX + 2) + (NSS_STATS_IPV4_REASM_MAX + 3) + 5;
+	size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
+	size_t size_wr = 0;
+	ssize_t bytes_read = 0;
+	uint64_t *stats_shadow;
+
+	char *lbuf = kzalloc(size_al, GFP_KERNEL);
+	if (unlikely(lbuf == NULL)) {
+		nss_warning("Could not allocate memory for local statistics buffer");
+		return 0;
+	}
+
+	stats_shadow = kzalloc(NSS_STATS_IPV4_REASM_MAX * 8, GFP_KERNEL);
+	if (unlikely(stats_shadow == NULL)) {
+		nss_warning("Could not allocate memory for local shadow buffer");
+		return 0;
+	}
+
+	size_wr = scnprintf(lbuf, size_al, "ipv4 reasm stats start:\n\n");
+
+	/*
+	 * Common node stats
+	 */
+	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "common node stats:\n\n");
+	spin_lock_bh(&nss_top_main.stats_lock);
+	for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
+		stats_shadow[i] = nss_top_main.stats_node[NSS_IPV4_REASM_INTERFACE][i];
+	}
+
+	spin_unlock_bh(&nss_top_main.stats_lock);
+
+	for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
+		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
+					"%s = %llu\n", nss_stats_str_node[i], stats_shadow[i]);
+	}
+
+	/*
+	 * IPv4 reasm node stats
+	 */
+	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nipv4 reasm node stats:\n\n");
+
+	spin_lock_bh(&nss_top_main.stats_lock);
+	for (i = 0; (i < NSS_STATS_IPV4_REASM_MAX); i++) {
+		stats_shadow[i] = nss_top_main.stats_ipv4_reasm[i];
+	}
+
+	spin_unlock_bh(&nss_top_main.stats_lock);
+
+	for (i = 0; (i < NSS_STATS_IPV4_REASM_MAX); i++) {
+		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
+					"%s = %llu\n", nss_stats_str_ipv4_reasm[i], stats_shadow[i]);
+	}
+
+	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nipv4 reasm stats end\n\n");
+	bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
+	kfree(lbuf);
+	kfree(stats_shadow);
+
+	return bytes_read;
+}
+
+/*
  * nss_stats_ipv6_read()
  *	Read IPV6 stats
  */
@@ -1084,6 +1165,11 @@
 NSS_STATS_DECLARE_FILE_OPERATIONS(ipv4)
 
 /*
+ * ipv4_reasm_stats_ops
+ */
+NSS_STATS_DECLARE_FILE_OPERATIONS(ipv4_reasm)
+
+/*
  * ipv6_stats_ops
  */
 NSS_STATS_DECLARE_FILE_OPERATIONS(ipv6)
@@ -1164,6 +1250,16 @@
 	}
 
 	/*
+	 * ipv4_reasm_stats
+	 */
+	nss_top_main.ipv4_reasm_dentry = debugfs_create_file("ipv4_reasm", 0400,
+						nss_top_main.stats_dentry, &nss_top_main, &nss_stats_ipv4_reasm_ops);
+	if (unlikely(nss_top_main.ipv4_reasm_dentry == NULL)) {
+		nss_warning("Failed to create qca-nss-drv/stats/ipv4_reasm file in debugfs");
+		return;
+	}
+
+	/*
 	 * ipv6_stats
 	 */
 	nss_top_main.ipv6_dentry = debugfs_create_file("ipv6", 0400,
diff --git a/nss_tx_rx_common.h b/nss_tx_rx_common.h
index bb3597f..399890c 100644
--- a/nss_tx_rx_common.h
+++ b/nss_tx_rx_common.h
@@ -67,6 +67,7 @@
 extern void nss_crypto_register_handler(void);
 extern void nss_ipsec_register_handler(void);
 extern void nss_ipv4_register_handler(void);
+extern void nss_ipv4_reasm_register_handler(void);
 extern void nss_ipv6_register_handler(void);
 extern void nss_n2h_register_handler(void);
 extern void nss_tunipip6_register_handler(void);