[qca-nss-drv]: Adding gre_redir stats to debugfs
Adding gre_redir tunnel stats to debugfs.
CRs-Fixed: 754011
Change-Id: I5d49dc57bae1a096f9e4a158669ff5ee46904904
Signed-off-by: Ankit Dhanuka <adhanuka@codeaurora.org>
diff --git a/exports/nss_gre_redir.h b/exports/nss_gre_redir.h
index 8c386a2..6b41522 100644
--- a/exports/nss_gre_redir.h
+++ b/exports/nss_gre_redir.h
@@ -22,6 +22,7 @@
#ifndef __NSS_GRE_REDIR_H
#define __NSS_GRE_REDIR_H
+#define NSS_GRE_REDIR_MAX_INTERFACES 3
#define NSS_GRE_REDIR_IP_DF_OVERRIDE_FLAG 0x80
#define NSS_GRE_REDIR_PER_PACKET_METADATA_OFFSET 4
#define NSS_GRE_REDIR_IP_HDR_TYPE_IPV4 1
@@ -83,7 +84,7 @@
};
/**
- * #brief: GRE tunnel statistics sync message structure.
+ * @brief: GRE tunnel statistics sync message structure.
*/
struct nss_gre_redir_stats_sync_msg {
struct nss_cmn_node_stats node_stats; /**< Tunnel stats sync */
@@ -91,6 +92,16 @@
};
/**
+ * @brief: GRE tunnel statistics as seen by HLOS.
+ */
+struct nss_gre_redir_tunnel_stats {
+ int if_num; /**< Tunnel Interface num */
+ bool valid; /**< Tunnel validity flag */
+ struct nss_cmn_node_stats node_stats; /**< Tunnel stats sync */
+ uint32_t tx_dropped; /**< Tunnel Tx drops */
+};
+
+/**
* @brief Message structure to send/receive GRE tunnel message.
*/
struct nss_gre_redir_msg {
@@ -193,4 +204,14 @@
extern nss_tx_status_t nss_gre_redir_tx_buf(struct nss_ctx_instance *nss_ctx, struct sk_buff *os_buf,
uint32_t if_num);
+/**
+ * @brief Get gre_redir tunnel statistics
+ *
+ * @param index index in tunnel stats array.
+ * @param stats tunnel stats structure.
+ *
+ * @return true or false.
+ */
+extern bool nss_gre_redir_get_stats(int index, struct nss_gre_redir_tunnel_stats *stats);
+
#endif /* __NSS_GRE_REDIR_H */
diff --git a/nss_core.h b/nss_core.h
index ad994c5..3e97c4b 100755
--- a/nss_core.h
+++ b/nss_core.h
@@ -532,6 +532,7 @@
struct dentry *gmac_dentry; /* GMAC ethnode stats dentry */
struct dentry *capwap_decap_dentry; /* CAPWAP decap ethnode stats dentry */
struct dentry *capwap_encap_dentry; /* CAPWAP encap ethnode stats dentry */
+ struct dentry *gre_redir_dentry; /* gre_redir ethnode stats dentry */
struct nss_ctx_instance nss[NSS_MAX_CORES];
/* NSS contexts */
diff --git a/nss_gre_redir.c b/nss_gre_redir.c
index 3b1d496..78c65b5 100644
--- a/nss_gre_redir.c
+++ b/nss_gre_redir.c
@@ -17,11 +17,48 @@
#include "nss_tx_rx_common.h"
/*
+ * Spinlock to update tunnel stats
+ */
+DEFINE_SPINLOCK(nss_gre_redir_stats_lock);
+
+/*
+ * Array to hold tunnel stats along with if_num
+ */
+static struct nss_gre_redir_tunnel_stats tun_stats[NSS_GRE_REDIR_MAX_INTERFACES];
+
+/*
+ * nss_gre_redir_tunnel_update_stats()
+ * Update gre_redir tunnel stats.
+ */
+static void nss_gre_redir_tunnel_update_stats(struct nss_ctx_instance *nss_ctx, int if_num, struct nss_gre_redir_stats_sync_msg *ngss)
+{
+ int i;
+
+ spin_lock_bh(&nss_gre_redir_stats_lock);
+ for (i = 0; i < NSS_GRE_REDIR_MAX_INTERFACES; i++) {
+ if ((tun_stats[i].if_num == if_num) && (tun_stats[i].valid)) {
+
+ tun_stats[i].node_stats.rx_packets += ngss->node_stats.rx_packets;
+ tun_stats[i].node_stats.rx_bytes += ngss->node_stats.rx_bytes;
+ tun_stats[i].node_stats.tx_packets += ngss->node_stats.tx_packets;
+ tun_stats[i].node_stats.tx_bytes += ngss->node_stats.tx_bytes;
+ tun_stats[i].node_stats.rx_dropped += ngss->node_stats.rx_dropped;
+ tun_stats[i].tx_dropped += ngss->tx_dropped;
+
+ break;
+ }
+ }
+ spin_unlock_bh(&nss_gre_redir_stats_lock);
+}
+
+
+/*
* nss_gre_redir_handler()
* Handle NSS -> HLOS messages for gre tunnel
*/
static void nss_gre_redir_msg_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, __attribute__((unused))void *app_data)
{
+ struct nss_gre_redir_msg *ngrm = (struct nss_gre_redir_msg *)ncm;
void *ctx;
nss_gre_redir_msg_callback_t cb;
@@ -58,6 +95,20 @@
*/
nss_core_log_msg_failures(nss_ctx, ncm);
+ switch (ncm->type) {
+ case NSS_GRE_REDIR_RX_STATS_SYNC_MSG:
+ /*
+ * Update Tunnel statistics.
+ */
+ if (!(nss_is_dynamic_interface(ncm->interface))) {
+ nss_warning("%p: stats received for wrong interface %d\n", nss_ctx, ncm->interface);
+ break;
+ }
+
+ nss_gre_redir_tunnel_update_stats(nss_ctx, ncm->interface, &ngrm->msg.stats_sync);
+ break;
+ }
+
/*
* Do we have a call back
*/
@@ -74,14 +125,31 @@
/*
* call gre tunnel callback
*/
- if (!ctx) {
- nss_warning("%p: Event received for gre tunnel interface %d before registration", nss_ctx, ncm->interface);
- return;
- }
-
cb(ctx, ncm);
}
+/*
+ * nss_gre_redir_get_stats()
+ * get gre_redir tunnel stats.
+ */
+bool nss_gre_redir_get_stats(int index, struct nss_gre_redir_tunnel_stats *stats)
+{
+ spin_lock_bh(&nss_gre_redir_stats_lock);
+ if (!tun_stats[index].valid) {
+ spin_unlock_bh(&nss_gre_redir_stats_lock);
+ return false;
+ }
+
+ if (nss_is_dynamic_interface(tun_stats[index].if_num) == false) {
+ spin_unlock_bh(&nss_gre_redir_stats_lock);
+ return false;
+ }
+
+ memcpy(stats, &tun_stats[index], sizeof(struct nss_gre_redir_tunnel_stats));
+ spin_unlock_bh(&nss_gre_redir_stats_lock);
+
+ return true;
+}
/*
* nss_gre_redir_tx_msg()
@@ -202,6 +270,7 @@
nss_gre_redir_msg_callback_t cb_func_msg)
{
uint32_t status;
+ int i;
nss_assert((if_num >= NSS_DYNAMIC_IF_START) && (if_num < (NSS_DYNAMIC_IF_START + NSS_MAX_DYNAMIC_INTERFACES)));
@@ -218,6 +287,16 @@
nss_top_main.if_rx_callback[if_num] = cb_func_data;
nss_top_main.if_rx_msg_callback[if_num] = cb_func_msg;
+ spin_lock_bh(&nss_gre_redir_stats_lock);
+ for (i = 0; i < NSS_GRE_REDIR_MAX_INTERFACES; i++) {
+ if (!(tun_stats[i].valid)) {
+ tun_stats[i].valid = true;
+ tun_stats[i].if_num = if_num;
+ break;
+ }
+ }
+ spin_unlock_bh(&nss_gre_redir_stats_lock);
+
return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.gre_redir_handler_id];
}
@@ -227,6 +306,7 @@
void nss_gre_redir_unregister_if(uint32_t if_num)
{
uint32_t status;
+ int i;
nss_assert((if_num >= NSS_DYNAMIC_IF_START) && (if_num < (NSS_DYNAMIC_IF_START + NSS_MAX_DYNAMIC_INTERFACES)));
@@ -236,9 +316,19 @@
return;
}
- nss_top_main.if_rx_callback[if_num] = NULL;
- nss_top_main.if_ctx[if_num] = NULL;
- nss_top_main.if_rx_msg_callback[if_num] = NULL;
+ nss_top_main.if_rx_callback[if_num] = NULL;
+ nss_top_main.if_ctx[if_num] = NULL;
+ nss_top_main.if_rx_msg_callback[if_num] = NULL;
+
+ spin_lock_bh(&nss_gre_redir_stats_lock);
+ for (i = 0; i < NSS_GRE_REDIR_MAX_INTERFACES; i++) {
+ if ((tun_stats[i].if_num == if_num) && (tun_stats[i].valid)) {
+ tun_stats[i].valid = false;
+ tun_stats[i].if_num = -1;
+ break;
+ }
+ }
+ spin_unlock_bh(&nss_gre_redir_stats_lock);
}
/*
@@ -258,3 +348,4 @@
EXPORT_SYMBOL(nss_gre_redir_tx_buf);
EXPORT_SYMBOL(nss_gre_redir_register_if);
EXPORT_SYMBOL(nss_gre_redir_unregister_if);
+EXPORT_SYMBOL(nss_gre_redir_get_stats);
diff --git a/nss_stats.c b/nss_stats.c
index 4874690..5d2e9cd 100644
--- a/nss_stats.c
+++ b/nss_stats.c
@@ -41,6 +41,7 @@
*/
struct nss_stats_data {
uint32_t if_num; /**< Interface number for CAPWAP stats */
+ uint32_t index; /**< Index for GRE_REDIR stats */
};
/*
@@ -1205,6 +1206,118 @@
}
/*
+ * nss_stats_gre_redir()
+ * 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)
+{
+ char *header[] = { "TX Packets", "TX Bytes", "TX Drops", "RX Packets", "RX Bytes", "Rx Drops" };
+ uint64_t tcnt = 0;
+
+ switch (i) {
+ case 0:
+ tcnt = s->node_stats.tx_packets;
+ break;
+ case 1:
+ tcnt = s->node_stats.tx_bytes;
+ break;
+ case 2:
+ tcnt = s->tx_dropped;
+ break;
+ case 3:
+ tcnt = s->node_stats.rx_packets;
+ break;
+ case 4:
+ tcnt = s->node_stats.rx_bytes;
+ break;
+ case 5:
+ tcnt = s->node_stats.rx_dropped;
+ break;
+ default:
+ i = 6;
+ break;
+ }
+
+ return (snprintf(line, len, "%s = %llu\n", header[i], tcnt));
+}
+
+/*
+ * nss_stats_gre_redir_read()
+ * 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)
+{
+ struct nss_stats_data *data = fp->private_data;
+ ssize_t bytes_read = 0;
+ struct nss_gre_redir_tunnel_stats stats;
+ size_t bytes;
+ char line[80];
+ int start, end;
+ int index = 0;
+
+ if (data) {
+ index = data->index;
+ }
+
+ /*
+ * If we are done accomodating all the GRE_REDIR tunnels.
+ */
+ if (index >= NSS_GRE_REDIR_MAX_INTERFACES) {
+ return 0;
+ }
+
+ for (; index < NSS_GRE_REDIR_MAX_INTERFACES; index++) {
+ bool isthere;
+
+ /*
+ * If gre_redir tunnel does not exists, then isthere will be false.
+ */
+ isthere = nss_gre_redir_get_stats(index, &stats);
+ if (!isthere) {
+ continue;
+ }
+
+ bytes = snprintf(line, sizeof(line), "\nTunnel if_num: %2d\n", stats.if_num);
+ if ((bytes_read + bytes) > sz) {
+ break;
+ }
+
+ if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) {
+ bytes_read = -EFAULT;
+ goto fail;
+ }
+ bytes_read += bytes;
+ start = 0;
+ end = 6;
+ while (bytes_read < sz && start < end) {
+ bytes = nss_stats_gre_redir(line, sizeof(line), start, &stats);
+
+ if ((bytes_read + bytes) > sz)
+ break;
+
+ if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) {
+ bytes_read = -EFAULT;
+ goto fail;
+ }
+
+ bytes_read += bytes;
+ start++;
+ }
+ }
+
+ if (bytes_read > 0) {
+ *ppos = bytes_read;
+ }
+
+ if (data) {
+ data->index = index;
+ }
+
+fail:
+ return bytes_read;
+}
+
+/*
* nss_stats_open()
*/
static int nss_stats_open(struct inode *inode, struct file *filp)
@@ -1217,6 +1330,7 @@
}
memset(data, 0, sizeof (struct nss_stats_data));
data->if_num = NSS_DYNAMIC_IF_START;
+ data->index = 0;
filp->private_data = data;
return 0;
@@ -1296,6 +1410,11 @@
NSS_STATS_DECLARE_FILE_OPERATIONS(eth_rx)
/*
+ * gre_redir_ops
+ */
+NSS_STATS_DECLARE_FILE_OPERATIONS(gre_redir)
+
+/*
* nss_stats_init()
* Enable NSS statistics
*/
@@ -1436,6 +1555,16 @@
nss_warning("Failed to create qca-nss-drv/stats/capwap_decap file in debugfs");
return;
}
+
+ /*
+ * GRE_REDIR stats
+ */
+ nss_top_main.gre_redir_dentry = debugfs_create_file("gre_redir", 0400,
+ nss_top_main.stats_dentry, &nss_top_main, &nss_stats_gre_redir_ops);
+ if (unlikely(nss_top_main.gre_redir_dentry == NULL)) {
+ nss_warning("Failed to create qca-nss-drv/stats/gre_redir file in debugfs");
+ return;
+ }
}