blob: c8f3a2b0c2d667581a1e3021ee4deff2ac54fca2 [file] [log] [blame]
/*
**************************************************************************
* Copyright (c) 2020, 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 <linux/types.h>
#include <nss_api_if.h>
#include <linux/debugfs.h>
#include "nss_match_db.h"
#include "nss_match_priv.h"
/*
* nss_match_stats_str
* MATCH statistics strings for nss MATCH stats
*/
static int8_t *nss_match_stats_str[NSS_MATCH_STATS_INSTANCE_MAX] = {
"rx_packets",
"rx_bytes",
"tx_packets",
"tx_bytes",
"rx_queue_0_drop",
"rx_queue_1_drop",
"rx_queue_2_drop",
"rx_queue_3_drop",
};
/*
* nss_match_stats_read()
* Read MATCH statistics
*/
static ssize_t nss_match_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
{
int instance_count = nss_match_table_count_get();
uint32_t max_output_lines = 2 /* header & footer for instance stats */
+ instance_count * (NSS_MATCH_STATS_INSTANCE_MAX + 2) /*instance stats */
+ 2;
size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
size_t size_wr = 0;
int id, i;
ssize_t bytes_read = 0;
struct nss_match_stats match_stats = {0};
char *lbuf = kzalloc(size_al, GFP_KERNEL);
if (unlikely(lbuf == NULL)) {
nss_match_warn("Could not allocate memory for local statistics buffer\n");
return 0;
}
/*
* Session stats
*/
size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nmatch instance stats start:\n\n");
for (id = 1; id <= NSS_MATCH_INSTANCE_MAX; id++) {
if (!nss_match_db_table_validate(id)) {
continue;
}
if (!nss_match_db_stats_get(id, &match_stats)) {
nss_match_warn("Could not read stats for table_id = %d\n", id);
continue;
}
size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "Table_id= %d\n\n", id);
size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "if_num of match instance = %d\n\n", nss_match_get_ifnum_by_table_id(id));
size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "%s = %llu\n", nss_match_stats_str[NSS_MATCH_STATS_RX_PACKETS],
match_stats.pstats.rx_packets);
size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "%s = %llu\n", nss_match_stats_str[NSS_MATCH_STATS_RX_BYTES],
match_stats.pstats.rx_bytes);
size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "%s = %llu\n", nss_match_stats_str[NSS_MATCH_STATS_TX_PACKETS],
match_stats.pstats.tx_packets);
size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "%s = %llu\n", nss_match_stats_str[NSS_MATCH_STATS_TX_BYTES],
match_stats.pstats.tx_bytes);
for (i = 0; i < NSS_MAX_NUM_PRI ; ++i) {
size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "%s = %llu\n",
nss_match_stats_str[i + NSS_MATCH_STATS_RX_QUEUE_0_DROP],
match_stats.pstats.rx_dropped[i]);
}
for (i = 0; i < NSS_MATCH_INSTANCE_RULE_MAX; ++i) {
if (match_stats.hit_count[i] <= 0) {
continue;
}
size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
"Hit count of rule ID %d = %llu\n", i+1,
match_stats.hit_count[i]);
}
size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n");
}
size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nMatch instance stats end\n");
bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, size_wr);
kfree(lbuf);
return bytes_read;
}
/*
* nss_match_stats_table_read()
* Read match table entry
*/
static ssize_t nss_match_stats_table_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
{
/*
* TODO: Optimize buffer size needed for table information.
*/
uint32_t max_output_lines = 2 + NSS_MATCH_INSTANCE_MAX * 2 /* for 2 maskset */
+ NSS_MATCH_INSTANCE_MAX * NSS_MATCH_INSTANCE_RULE_MAX *(9) /* for: 4 rule fields + 1 rule_id + 3 action fields + 1 hit count*/
+ 2;
int i;
int if_num;
size_t size_wr = 0, buflen = 0;
size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
ssize_t bytes_read = 0;
char *lbuf = kzalloc(size_al, GFP_KERNEL);
char *bufp;
if (unlikely(lbuf == NULL)) {
nss_match_warn("%px: Could not allocate memory for local statistics buffer", fp);
return 0;
}
for (i = 1; i <= NSS_MATCH_INSTANCE_MAX; ++i) {
if_num = nss_match_get_ifnum_by_table_id(i);
if (if_num < 0) {
continue;
}
size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nTable_id =%d\n", i);
size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "Match if_num = %d\n\n", if_num);
bufp = lbuf + size_wr;
buflen = size_al - size_wr;
size_wr += nss_match_db_table_read(i, buflen, bufp);
}
bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, size_wr);
kfree(lbuf);
return bytes_read;
}
/*
* nss_match_stats_show_table_ops
*/
static const struct file_operations nss_match_stats_show_table_ops = {
.read = nss_match_stats_table_read,
};
/*
* nss_match_stats_ops
*/
static const struct file_operations nss_match_stats_ops = {
.read = nss_match_stats_read,
};
/*
* nss_match_stats_debugfs_create()
* Create MATCH node statistics debug entry.
*/
bool nss_match_stats_debugfs_create(struct dentry *match_config)
{
if (!debugfs_create_file("showtable", 0400, match_config, NULL, &nss_match_stats_show_table_ops)) {
nss_match_warn("Cannot create match display dentry file");
debugfs_remove_recursive(match_config);
return false;
}
if (!debugfs_create_file("stats", 0400, match_config, NULL, &nss_match_stats_ops)) {
nss_match_warn("Cannot create MATCH dentry file");
return false;
}
return true;
}