[qca-nss-drv] Add GRE Tunnel Support

Provide general apis that allow users to send
messages, packets, and configures to the firmware.

Gives the ability to create dynamic interfaces

Ability to receive GRE Tunnel specific messages
and stats

Change-Id: I24c3b689316f0541de352f1401679d9cd18d5f42
Signed-off-by: Thomas Wu <wthomas@codeaurora.org>
diff --git a/nss_stats.c b/nss_stats.c
index 72775cd..c772e87 100644
--- a/nss_stats.c
+++ b/nss_stats.c
@@ -22,6 +22,7 @@
 
 #include "nss_core.h"
 #include "nss_dtls_stats.h"
+#include "nss_gre_tunnel_stats.h"
 
 /*
  * Maximum string length:
@@ -564,6 +565,35 @@
 };
 
 /*
+ * nss_stats_str_gre_tunnel_session_stats
+ *	GRE Tunnel statistics strings for nss session stats
+ */
+static int8_t *nss_stats_str_gre_tunnel_session_debug_stats[NSS_STATS_GRE_TUNNEL_SESSION_MAX] = {
+	"RX_PKTS",
+	"TX_PKTS",
+	"RX_DROPPED",
+	"RX_MALFORMED",
+	"RX_INVALID_PROT",
+	"DECAP_QUEUE_FULL",
+	"RX_SINGLE_REC_DGRAM",
+	"RX_INVALID_REC_DGRAM",
+	"BUFFER_ALLOC_FAIL",
+	"BUFFER_COPY_FAIL",
+	"OUTFLOW_QUEUE_FULL",
+	"TX_DROPPED_HROOM",
+	"RX_CBUFFER_ALLOC_FAIL",
+	"RX_CENQUEUE_FAIL",
+	"RX_DECRYPT_DONE",
+	"RX_FORWARD_ENQUEUE_FAIL",
+	"TX_CBUFFER_ALLOC_FAIL",
+	"TX_CENQUEUE_FAIL",
+	"TX_DROPPED_TROOM",
+	"TX_FORWARD_ENQUEUE_FAIL",
+	"TX_CIPHER_DONE",
+	"CRYPTO_NOSUPP",
+};
+
+/*
  * nss_stats_str_l2tpv2_session_stats
  *	l2tpv2 statistics strings for nss session stats
  */
@@ -1800,7 +1830,7 @@
 
 /*
  * nss_stats_wifi_read()
- * 	Read wifi statistics
+ *	Read wifi statistics
  */
 static ssize_t nss_stats_wifi_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
 {
@@ -1856,7 +1886,7 @@
 
 /*
  * nss_stats_dtls_read()
- * 	Read DTLS session statistics
+ *	Read DTLS session statistics
  */
 static ssize_t nss_stats_dtls_read(struct file *fp, char __user *ubuf,
 				   size_t sz, loff_t *ppos)
@@ -1932,6 +1962,83 @@
 }
 
 /*
+ * nss_stats_gre_tunnel_read()
+ *	Read GRE Tunnel session statistics
+ */
+static ssize_t nss_stats_gre_tunnel_read(struct file *fp, char __user *ubuf,
+				   size_t sz, loff_t *ppos)
+{
+	uint32_t max_output_lines = 2 + (NSS_MAX_GRE_TUNNEL_SESSIONS
+					* (NSS_STATS_GRE_TUNNEL_SESSION_MAX + 2)) + 2;
+	size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
+	size_t size_wr = 0;
+	ssize_t bytes_read = 0;
+	struct net_device *dev;
+	int id, i;
+	struct nss_stats_gre_tunnel_session_debug *gre_tunnel_session_stats = NULL;
+
+	char *lbuf = kzalloc(size_al, GFP_KERNEL);
+	if (unlikely(lbuf == NULL)) {
+		nss_warning("Could not allocate memory for local statistics buffer");
+		return 0;
+	}
+
+	gre_tunnel_session_stats = kzalloc((sizeof(struct nss_stats_gre_tunnel_session_debug)
+				     * NSS_MAX_GRE_TUNNEL_SESSIONS), GFP_KERNEL);
+	if (unlikely(gre_tunnel_session_stats == NULL)) {
+		nss_warning("Could not allocate memory for populating GRE Tunnel stats");
+		kfree(lbuf);
+		return 0;
+	}
+
+	/*
+	 * Get all stats
+	 */
+	nss_gre_tunnel_session_debug_stats_get(gre_tunnel_session_stats);
+
+	/*
+	 * Session stats
+	 */
+	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
+			     "\nGRE Tunnel session stats start:\n\n");
+
+	for (id = 0; id < NSS_MAX_GRE_TUNNEL_SESSIONS; id++) {
+		if (!gre_tunnel_session_stats[id].valid)
+			break;
+
+		dev = dev_get_by_index(&init_net, gre_tunnel_session_stats[id].if_index);
+		if (likely(dev)) {
+			size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
+					     "%d. nss interface id=%d, netdevice=%s\n",
+					     id, gre_tunnel_session_stats[id].if_num,
+					     dev->name);
+			dev_put(dev);
+		} else {
+			size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
+					     "%d. nss interface id=%d\n", id,
+					     gre_tunnel_session_stats[id].if_num);
+		}
+
+		for (i = 0; i < NSS_STATS_GRE_TUNNEL_SESSION_MAX; i++) {
+			size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
+					     "\t%s = %llu\n",
+					     nss_stats_str_gre_tunnel_session_debug_stats[i],
+					     gre_tunnel_session_stats[id].stats[i]);
+		}
+
+		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n");
+	}
+
+	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
+			     "\nGRE Tunnel session stats end\n");
+	bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, size_wr);
+
+	kfree(gre_tunnel_session_stats);
+	kfree(lbuf);
+	return bytes_read;
+}
+
+/*
  * nss_stats_l2tpv2_read()
  *	Read l2tpv2 statistics
  */
@@ -2259,7 +2366,8 @@
 }
 
 /*
- * Make a row for CAPWAP encap stats.
+ * nss_stats_capwap_encap()
+ *	Make a row for CAPWAP encap stats.
  */
 static ssize_t nss_stats_capwap_encap(char *line, int len, int i, struct nss_capwap_tunnel_stats *s)
 {
@@ -2309,7 +2417,8 @@
 }
 
 /*
- * Make a row for CAPWAP decap stats.
+ * nss_stats_capwap_decap()
+ *	Make a row for CAPWAP decap stats.
  */
 static ssize_t nss_stats_capwap_decap(char *line, int len, int i, struct nss_capwap_tunnel_stats *s)
 {
@@ -2479,7 +2588,7 @@
 
 /*
  * nss_stats_gre_redir()
- * 	Make a row for GRE_REDIR stats.
+ *	Make a row for GRE_REDIR stats.
  */
 static ssize_t nss_stats_gre_redir(char *line, int len, int i, struct nss_gre_redir_tunnel_stats *s)
 {
@@ -2514,7 +2623,7 @@
 
 /*
  * nss_stats_gre_redir_read()
- * 	READ gre_redir tunnel stats.
+ *	READ gre_redir tunnel stats.
  */
 static ssize_t nss_stats_gre_redir_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
 {
@@ -3010,6 +3119,11 @@
 NSS_STATS_DECLARE_FILE_OPERATIONS(dtls)
 
 /*
+ * gre_tunnel_stats_ops
+ */
+NSS_STATS_DECLARE_FILE_OPERATIONS(gre_tunnel)
+
+/*
  * nss_stats_init()
  * 	Enable NSS statistics
  */
@@ -3426,6 +3540,18 @@
 		return;
 	}
 
+	/*
+	 *  GRE Tunnel Stats
+	 */
+	nss_top_main.gre_tunnel_dentry = debugfs_create_file("gre_tunnel", 0400,
+							nss_top_main.stats_dentry,
+							&nss_top_main,
+							&nss_stats_gre_tunnel_ops);
+	if (unlikely(nss_top_main.gre_tunnel_dentry == NULL)) {
+		nss_warning("Failed to create qca-nss-drv/stats/gre_tunnel file in debugfs");
+		return;
+	}
+
 	nss_log_init();
 }