blob: 1d438780847875e44649377580b0a4ecd9e682a4 [file] [log] [blame]
/*
**************************************************************************
* Copyright (c) 2017-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 "nss_drv_stats.h"
#include "nss_core.h"
#include "nss_capwap.h"
#include "nss_capwap_stats.h"
#include "nss_capwap_strings.h"
/*
* Declare atomic notifier data structure for statistics.
*/
ATOMIC_NOTIFIER_HEAD(nss_capwap_stats_notifier);
/*
* nss_capwap_stats_encap()
* Make a row for CAPWAP encap stats.
*/
static ssize_t nss_capwap_stats_encap(char *line, int len, int i, struct nss_capwap_tunnel_stats *s)
{
uint64_t tcnt = 0;
switch (i) {
case 0:
tcnt = s->pnode_stats.tx_packets;
break;
case 1:
tcnt = s->pnode_stats.tx_bytes;
break;
case 2:
tcnt = s->tx_segments;
break;
case 3:
tcnt = s->tx_dropped_sg_ref;
break;
case 4:
tcnt = s->tx_dropped_ver_mis;
break;
case 5:
tcnt = s->tx_dropped_inner;
break;
case 6:
tcnt = s->tx_dropped_hroom;
break;
case 7:
tcnt = s->tx_dropped_dtls;
break;
case 8:
tcnt = s->tx_dropped_nwireless;
break;
case 9:
tcnt = s->tx_queue_full_drops;
break;
case 10:
tcnt = s->tx_mem_failure_drops;
break;
case 11:
tcnt = s->fast_mem;
break;
default:
return 0;
}
return snprintf(line, len, "%s = %llu\n", nss_capwap_strings_encap_stats[i].stats_name, tcnt);
}
/*
* nss_capwap_stats_decap()
* Make a row for CAPWAP decap stats.
*/
static ssize_t nss_capwap_stats_decap(char *line, int len, int i, struct nss_capwap_tunnel_stats *s)
{
uint64_t tcnt = 0;
switch (i) {
case 0:
tcnt = s->pnode_stats.rx_packets;
break;
case 1:
tcnt = s->pnode_stats.rx_bytes;
break;
case 2:
tcnt = s->dtls_pkts;
break;
case 3:
tcnt = s->rx_segments;
break;
case 4:
tcnt = s->pnode_stats.rx_dropped;
break;
case 5:
tcnt = s->rx_oversize_drops;
break;
case 6:
tcnt = s->rx_frag_timeout_drops;
break;
case 7:
tcnt = s->rx_dup_frag;
break;
case 8:
tcnt = s->rx_frag_gap_drops;
break;
case 9:
tcnt = s->rx_n2h_drops;
return snprintf(line, len, "%s = %llu (n2h = %llu)\n", nss_capwap_strings_decap_stats[i].stats_name, tcnt, s->rx_n2h_queue_full_drops);
case 10:
tcnt = s->rx_n2h_queue_full_drops;
break;
case 11:
tcnt = s->rx_mem_failure_drops;
break;
case 12:
tcnt = s->rx_csum_drops;
break;
case 13:
tcnt = s->rx_malformed;
break;
case 14:
tcnt = s->fast_mem;
break;
default:
return 0;
}
return snprintf(line, len, "%s = %llu\n", nss_capwap_strings_decap_stats[i].stats_name, tcnt);
}
/*
* nss_capwap_stats_read()
* Read CAPWAP stats
*/
static ssize_t nss_capwap_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos, uint16_t type)
{
struct nss_stats_data *data = fp->private_data;
ssize_t bytes_read = 0;
struct nss_capwap_tunnel_stats stats;
size_t bytes;
char line[80];
int start;
uint32_t if_num = NSS_DYNAMIC_IF_START;
uint32_t max_if_num = NSS_DYNAMIC_IF_START + NSS_MAX_DYNAMIC_INTERFACES;
if (data) {
if_num = data->if_num;
}
/*
* If we are done accomodating all the CAPWAP tunnels.
*/
if (if_num > max_if_num) {
return 0;
}
for (; if_num <= max_if_num; if_num++) {
bool isthere;
enum nss_dynamic_interface_type dtype;
if (nss_is_dynamic_interface(if_num) == false) {
continue;
}
dtype = nss_dynamic_interface_get_type(nss_capwap_get_ctx(), if_num);
/*
* Read encap stats from inner node and decap stats from outer node.
*/
if ((type == 1) && (dtype != NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP_HOST_INNER)) {
continue;
}
if ((type == 0) && (dtype != NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP_OUTER)) {
continue;
}
/*
* If CAPWAP tunnel does not exists, then isthere will be false.
*/
isthere = nss_capwap_get_stats(if_num, &stats);
if (!isthere) {
continue;
}
bytes = snprintf(line, sizeof(line), "----if_num : %2d----\n", 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;
while (bytes_read < sz) {
if (type == 1) {
bytes = nss_capwap_stats_encap(line, sizeof(line), start, &stats);
} else {
bytes = nss_capwap_stats_decap(line, sizeof(line), start, &stats);
}
/*
* If we don't have any more lines in decap/encap.
*/
if (bytes == 0) {
break;
}
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->if_num = if_num;
}
fail:
return bytes_read;
}
/*
* nss_capwap_decap_stats_read()
* Read CAPWAP decap stats
*/
static ssize_t nss_capwap_decap_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
{
return nss_capwap_stats_read(fp, ubuf, sz, ppos, 0);
}
/*
* nss_capwap_encap_stats_read()
* Read CAPWAP encap stats
*/
static ssize_t nss_capwap_encap_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
{
return nss_capwap_stats_read(fp, ubuf, sz, ppos, 1);
}
/*
* nss_capwap_stats_ops
*/
NSS_STATS_DECLARE_FILE_OPERATIONS(capwap_encap);
NSS_STATS_DECLARE_FILE_OPERATIONS(capwap_decap);
/*
* nss_capwap_stats_dentry_create()
* Create CAPWAP statistics debug entry
*/
void nss_capwap_stats_dentry_create(void)
{
nss_stats_create_dentry("capwap_encap", &nss_capwap_encap_stats_ops);
nss_stats_create_dentry("capwap_decap", &nss_capwap_decap_stats_ops);
}
/*
* nss_capwap_stats_notify()
* Sends notifications to the registered modules.
*
* Leverage NSS-FW statistics timing to update Netlink.
*/
void nss_capwap_stats_notify(uint32_t if_num, uint32_t core_id)
{
struct nss_capwap_stats_notification capwap_stats;
capwap_stats.core_id = core_id;
capwap_stats.if_num = if_num;
nss_capwap_get_stats(if_num, &capwap_stats.stats);
atomic_notifier_call_chain(&nss_capwap_stats_notifier, NSS_STATS_EVENT_NOTIFY, (void *)&capwap_stats);
}
/*
* nss_capwap_stats_register_notifier()
* Registers statistics notifier.
*/
int nss_capwap_stats_register_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_register(&nss_capwap_stats_notifier, nb);
}
EXPORT_SYMBOL(nss_capwap_stats_register_notifier);
/*
* nss_capwap_stats_unregister_notifier()
* Deregisters statistics notifier.
*/
int nss_capwap_stats_unregister_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_unregister(&nss_capwap_stats_notifier, nb);
}
EXPORT_SYMBOL(nss_capwap_stats_unregister_notifier);