As the common.h is only meant to be used by the network shell files, rename it to be more descriptive in order to avoid possible conflicts with any other common.h file. Signed-off-by: Jukka Rissanen <jukka.rissanen@nordicsemi.no>
660 lines
18 KiB
C
660 lines
18 KiB
C
/*
|
|
* Copyright (c) 2016 Intel Corporation
|
|
* Copyright (c) 2023 Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/logging/log.h>
|
|
LOG_MODULE_DECLARE(net_shell);
|
|
|
|
#include <zephyr/net/net_stats.h>
|
|
|
|
#include "net_shell_private.h"
|
|
|
|
#include "../ip/net_stats.h"
|
|
|
|
#if defined(CONFIG_NET_STATISTICS)
|
|
|
|
#if NET_TC_COUNT > 1
|
|
static const char *priority2str(enum net_priority priority)
|
|
{
|
|
switch (priority) {
|
|
case NET_PRIORITY_BK:
|
|
return "BK"; /* Background */
|
|
case NET_PRIORITY_BE:
|
|
return "BE"; /* Best effort */
|
|
case NET_PRIORITY_EE:
|
|
return "EE"; /* Excellent effort */
|
|
case NET_PRIORITY_CA:
|
|
return "CA"; /* Critical applications */
|
|
case NET_PRIORITY_VI:
|
|
return "VI"; /* Video, < 100 ms latency and jitter */
|
|
case NET_PRIORITY_VO:
|
|
return "VO"; /* Voice, < 10 ms latency and jitter */
|
|
case NET_PRIORITY_IC:
|
|
return "IC"; /* Internetwork control */
|
|
case NET_PRIORITY_NC:
|
|
return "NC"; /* Network control */
|
|
}
|
|
|
|
return "??";
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_ETHERNET) && \
|
|
defined(CONFIG_NET_STATISTICS_USER_API)
|
|
static void print_eth_stats(struct net_if *iface, struct net_stats_eth *data,
|
|
const struct shell *sh)
|
|
{
|
|
PR("Statistics for Ethernet interface %p [%d]\n", iface,
|
|
net_if_get_by_iface(iface));
|
|
|
|
PR("Bytes received : %u\n", data->bytes.received);
|
|
PR("Bytes sent : %u\n", data->bytes.sent);
|
|
PR("Packets received : %u\n", data->pkts.rx);
|
|
PR("Packets sent : %u\n", data->pkts.tx);
|
|
PR("Bcast received : %u\n", data->broadcast.rx);
|
|
PR("Bcast sent : %u\n", data->broadcast.tx);
|
|
PR("Mcast received : %u\n", data->multicast.rx);
|
|
PR("Mcast sent : %u\n", data->multicast.tx);
|
|
|
|
PR("Send errors : %u\n", data->errors.tx);
|
|
PR("Receive errors : %u\n", data->errors.rx);
|
|
PR("Collisions : %u\n", data->collisions);
|
|
PR("Send Drops : %u\n", data->tx_dropped);
|
|
PR("Send timeouts : %u\n", data->tx_timeout_count);
|
|
PR("Send restarts : %u\n", data->tx_restart_queue);
|
|
PR("Unknown protocol : %u\n", data->unknown_protocol);
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_ETHERNET_VENDOR)
|
|
if (data->vendor) {
|
|
PR("Vendor specific statistics for Ethernet "
|
|
"interface %p [%d]:\n",
|
|
iface, net_if_get_by_iface(iface));
|
|
size_t i = 0;
|
|
|
|
do {
|
|
PR("%s : %u\n", data->vendor[i].key,
|
|
data->vendor[i].value);
|
|
i++;
|
|
} while (data->vendor[i].key);
|
|
}
|
|
#endif /* CONFIG_NET_STATISTICS_ETHERNET_VENDOR */
|
|
}
|
|
#endif /* CONFIG_NET_STATISTICS_ETHERNET && CONFIG_NET_STATISTICS_USER_API */
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_PPP) && \
|
|
defined(CONFIG_NET_STATISTICS_USER_API)
|
|
static void print_ppp_stats(struct net_if *iface, struct net_stats_ppp *data,
|
|
const struct shell *sh)
|
|
{
|
|
PR("Frames recv %u\n", data->pkts.rx);
|
|
PR("Frames sent %u\n", data->pkts.tx);
|
|
PR("Frames dropped %u\n", data->drop);
|
|
PR("Bad FCS %u\n", data->chkerr);
|
|
}
|
|
#endif /* CONFIG_NET_STATISTICS_PPP && CONFIG_NET_STATISTICS_USER_API */
|
|
|
|
#if !defined(CONFIG_NET_NATIVE)
|
|
#define GET_STAT(a, b) 0
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_PKT_TXTIME_STATS_DETAIL) || \
|
|
defined(CONFIG_NET_PKT_RXTIME_STATS_DETAIL)
|
|
#if (NET_TC_TX_COUNT > 1) || (NET_TC_RX_COUNT > 1)
|
|
static char *get_net_pkt_tc_stats_detail(struct net_if *iface, int i,
|
|
bool is_tx)
|
|
{
|
|
static char extra_stats[sizeof("\t[0=xxxx us]") +
|
|
sizeof("->xxxx") *
|
|
NET_PKT_DETAIL_STATS_COUNT];
|
|
int j, total = 0, pos = 0;
|
|
|
|
pos += snprintk(extra_stats, sizeof(extra_stats), "\t[0");
|
|
|
|
for (j = 0; j < NET_PKT_DETAIL_STATS_COUNT; j++) {
|
|
net_stats_t count = 0;
|
|
uint32_t avg;
|
|
|
|
if (is_tx) {
|
|
#if defined(CONFIG_NET_PKT_TXTIME_STATS_DETAIL) && (NET_TC_TX_COUNT > 1)
|
|
count = GET_STAT(iface,
|
|
tc.sent[i].tx_time_detail[j].count);
|
|
#endif
|
|
} else {
|
|
#if defined(CONFIG_NET_PKT_RXTIME_STATS_DETAIL) && (NET_TC_RX_COUNT > 1)
|
|
count = GET_STAT(iface,
|
|
tc.recv[i].rx_time_detail[j].count);
|
|
#endif
|
|
}
|
|
|
|
if (count == 0) {
|
|
break;
|
|
}
|
|
|
|
if (is_tx) {
|
|
#if defined(CONFIG_NET_PKT_TXTIME_STATS_DETAIL) && (NET_TC_TX_COUNT > 1)
|
|
avg = (uint32_t)(GET_STAT(iface,
|
|
tc.sent[i].tx_time_detail[j].sum) /
|
|
(uint64_t)count);
|
|
#endif
|
|
} else {
|
|
#if defined(CONFIG_NET_PKT_RXTIME_STATS_DETAIL) && (NET_TC_RX_COUNT > 1)
|
|
avg = (uint32_t)(GET_STAT(iface,
|
|
tc.recv[i].rx_time_detail[j].sum) /
|
|
(uint64_t)count);
|
|
#endif
|
|
}
|
|
|
|
if (avg == 0) {
|
|
continue;
|
|
}
|
|
|
|
total += avg;
|
|
|
|
pos += snprintk(extra_stats + pos, sizeof(extra_stats) - pos,
|
|
"->%u", avg);
|
|
}
|
|
|
|
if (total == 0U) {
|
|
return "\0";
|
|
}
|
|
|
|
pos += snprintk(extra_stats + pos, sizeof(extra_stats) - pos,
|
|
"=%u us]", total);
|
|
|
|
return extra_stats;
|
|
}
|
|
#endif /* (NET_TC_TX_COUNT > 1) || (NET_TC_RX_COUNT > 1) */
|
|
|
|
#if (NET_TC_TX_COUNT <= 1) || (NET_TC_RX_COUNT <= 1)
|
|
static char *get_net_pkt_stats_detail(struct net_if *iface, bool is_tx)
|
|
{
|
|
static char extra_stats[sizeof("\t[0=xxxx us]") + sizeof("->xxxx") *
|
|
NET_PKT_DETAIL_STATS_COUNT];
|
|
int j, total = 0, pos = 0;
|
|
|
|
pos += snprintk(extra_stats, sizeof(extra_stats), "\t[0");
|
|
|
|
for (j = 0; j < NET_PKT_DETAIL_STATS_COUNT; j++) {
|
|
net_stats_t count;
|
|
uint32_t avg;
|
|
|
|
if (is_tx) {
|
|
#if defined(CONFIG_NET_PKT_TXTIME_STATS_DETAIL)
|
|
count = GET_STAT(iface, tx_time_detail[j].count);
|
|
#endif
|
|
} else {
|
|
#if defined(CONFIG_NET_PKT_RXTIME_STATS_DETAIL)
|
|
count = GET_STAT(iface, rx_time_detail[j].count);
|
|
#endif
|
|
}
|
|
|
|
if (count == 0) {
|
|
break;
|
|
}
|
|
|
|
if (is_tx) {
|
|
#if defined(CONFIG_NET_PKT_TXTIME_STATS_DETAIL)
|
|
avg = (uint32_t)(GET_STAT(iface,
|
|
tx_time_detail[j].sum) /
|
|
(uint64_t)count);
|
|
#endif
|
|
} else {
|
|
#if defined(CONFIG_NET_PKT_RXTIME_STATS_DETAIL)
|
|
avg = (uint32_t)(GET_STAT(iface,
|
|
rx_time_detail[j].sum) /
|
|
(uint64_t)count);
|
|
#endif
|
|
}
|
|
|
|
if (avg == 0) {
|
|
continue;
|
|
}
|
|
|
|
total += avg;
|
|
|
|
pos += snprintk(extra_stats + pos,
|
|
sizeof(extra_stats) - pos,
|
|
"->%u", avg);
|
|
}
|
|
|
|
if (total == 0U) {
|
|
return "\0";
|
|
}
|
|
|
|
pos += snprintk(extra_stats + pos, sizeof(extra_stats) - pos,
|
|
"=%u us]", total);
|
|
|
|
return extra_stats;
|
|
}
|
|
#endif /* (NET_TC_TX_COUNT == 1) || (NET_TC_RX_COUNT == 1) */
|
|
|
|
#else /* CONFIG_NET_PKT_TXTIME_STATS_DETAIL || CONFIG_NET_PKT_RXTIME_STATS_DETAIL */
|
|
|
|
#if defined(CONFIG_NET_PKT_TXTIME_STATS) || \
|
|
defined(CONFIG_NET_PKT_RXTIME_STATS)
|
|
|
|
#if (NET_TC_TX_COUNT > 1) || (NET_TC_RX_COUNT > 1)
|
|
static char *get_net_pkt_tc_stats_detail(struct net_if *iface, int i,
|
|
bool is_tx)
|
|
{
|
|
ARG_UNUSED(iface);
|
|
ARG_UNUSED(i);
|
|
ARG_UNUSED(is_tx);
|
|
|
|
return "\0";
|
|
}
|
|
#endif
|
|
|
|
#if (NET_TC_TX_COUNT == 1) || (NET_TC_RX_COUNT == 1)
|
|
static char *get_net_pkt_stats_detail(struct net_if *iface, bool is_tx)
|
|
{
|
|
ARG_UNUSED(iface);
|
|
ARG_UNUSED(is_tx);
|
|
|
|
return "\0";
|
|
}
|
|
#endif
|
|
#endif /* CONFIG_NET_PKT_TXTIME_STATS) || CONFIG_NET_PKT_RXTIME_STATS */
|
|
#endif /* CONFIG_NET_PKT_TXTIME_STATS_DETAIL || CONFIG_NET_PKT_RXTIME_STATS_DETAIL */
|
|
|
|
static void print_tc_tx_stats(const struct shell *sh, struct net_if *iface)
|
|
{
|
|
#if NET_TC_TX_COUNT > 1
|
|
int i;
|
|
|
|
PR("TX traffic class statistics:\n");
|
|
|
|
#if defined(CONFIG_NET_PKT_TXTIME_STATS)
|
|
PR("TC Priority\tSent pkts\tbytes\ttime\n");
|
|
|
|
for (i = 0; i < NET_TC_TX_COUNT; i++) {
|
|
net_stats_t count = GET_STAT(iface,
|
|
tc.sent[i].tx_time.count);
|
|
if (count == 0) {
|
|
PR("[%d] %s (%d)\t%d\t\t%d\t-\n", i,
|
|
priority2str(GET_STAT(iface, tc.sent[i].priority)),
|
|
GET_STAT(iface, tc.sent[i].priority),
|
|
GET_STAT(iface, tc.sent[i].pkts),
|
|
GET_STAT(iface, tc.sent[i].bytes));
|
|
} else {
|
|
PR("[%d] %s (%d)\t%d\t\t%d\t%u us%s\n", i,
|
|
priority2str(GET_STAT(iface, tc.sent[i].priority)),
|
|
GET_STAT(iface, tc.sent[i].priority),
|
|
GET_STAT(iface, tc.sent[i].pkts),
|
|
GET_STAT(iface, tc.sent[i].bytes),
|
|
(uint32_t)(GET_STAT(iface,
|
|
tc.sent[i].tx_time.sum) /
|
|
(uint64_t)count),
|
|
get_net_pkt_tc_stats_detail(iface, i, true));
|
|
}
|
|
}
|
|
#else
|
|
PR("TC Priority\tSent pkts\tbytes\n");
|
|
|
|
for (i = 0; i < NET_TC_TX_COUNT; i++) {
|
|
PR("[%d] %s (%d)\t%d\t\t%d\n", i,
|
|
priority2str(GET_STAT(iface, tc.sent[i].priority)),
|
|
GET_STAT(iface, tc.sent[i].priority),
|
|
GET_STAT(iface, tc.sent[i].pkts),
|
|
GET_STAT(iface, tc.sent[i].bytes));
|
|
}
|
|
#endif /* CONFIG_NET_PKT_TXTIME_STATS */
|
|
#else
|
|
ARG_UNUSED(sh);
|
|
|
|
#if defined(CONFIG_NET_PKT_TXTIME_STATS)
|
|
net_stats_t count = GET_STAT(iface, tx_time.count);
|
|
|
|
if (count != 0) {
|
|
PR("Avg %s net_pkt (%u) time %" PRIu32 " us%s\n", "TX", count,
|
|
(uint32_t)(GET_STAT(iface, tx_time.sum) / (uint64_t)count),
|
|
get_net_pkt_stats_detail(iface, true));
|
|
}
|
|
#else
|
|
ARG_UNUSED(iface);
|
|
#endif /* CONFIG_NET_PKT_TXTIME_STATS */
|
|
#endif /* NET_TC_TX_COUNT > 1 */
|
|
}
|
|
|
|
static void print_tc_rx_stats(const struct shell *sh, struct net_if *iface)
|
|
{
|
|
#if NET_TC_RX_COUNT > 1
|
|
int i;
|
|
|
|
PR("RX traffic class statistics:\n");
|
|
|
|
#if defined(CONFIG_NET_PKT_RXTIME_STATS)
|
|
PR("TC Priority\tRecv pkts\tbytes\ttime\n");
|
|
|
|
for (i = 0; i < NET_TC_RX_COUNT; i++) {
|
|
net_stats_t count = GET_STAT(iface,
|
|
tc.recv[i].rx_time.count);
|
|
if (count == 0) {
|
|
PR("[%d] %s (%d)\t%d\t\t%d\t-\n", i,
|
|
priority2str(GET_STAT(iface, tc.recv[i].priority)),
|
|
GET_STAT(iface, tc.recv[i].priority),
|
|
GET_STAT(iface, tc.recv[i].pkts),
|
|
GET_STAT(iface, tc.recv[i].bytes));
|
|
} else {
|
|
PR("[%d] %s (%d)\t%d\t\t%d\t%u us%s\n", i,
|
|
priority2str(GET_STAT(iface, tc.recv[i].priority)),
|
|
GET_STAT(iface, tc.recv[i].priority),
|
|
GET_STAT(iface, tc.recv[i].pkts),
|
|
GET_STAT(iface, tc.recv[i].bytes),
|
|
(uint32_t)(GET_STAT(iface,
|
|
tc.recv[i].rx_time.sum) /
|
|
(uint64_t)count),
|
|
get_net_pkt_tc_stats_detail(iface, i, false));
|
|
}
|
|
}
|
|
#else
|
|
PR("TC Priority\tRecv pkts\tbytes\n");
|
|
|
|
for (i = 0; i < NET_TC_RX_COUNT; i++) {
|
|
PR("[%d] %s (%d)\t%d\t\t%d\n", i,
|
|
priority2str(GET_STAT(iface, tc.recv[i].priority)),
|
|
GET_STAT(iface, tc.recv[i].priority),
|
|
GET_STAT(iface, tc.recv[i].pkts),
|
|
GET_STAT(iface, tc.recv[i].bytes));
|
|
}
|
|
#endif /* CONFIG_NET_PKT_RXTIME_STATS */
|
|
#else
|
|
ARG_UNUSED(sh);
|
|
|
|
#if defined(CONFIG_NET_PKT_RXTIME_STATS)
|
|
net_stats_t count = GET_STAT(iface, rx_time.count);
|
|
|
|
if (count != 0) {
|
|
PR("Avg %s net_pkt (%u) time %" PRIu32 " us%s\n", "RX", count,
|
|
(uint32_t)(GET_STAT(iface, rx_time.sum) / (uint64_t)count),
|
|
get_net_pkt_stats_detail(iface, false));
|
|
}
|
|
#else
|
|
ARG_UNUSED(iface);
|
|
#endif /* CONFIG_NET_PKT_RXTIME_STATS */
|
|
|
|
#endif /* NET_TC_RX_COUNT > 1 */
|
|
}
|
|
|
|
static void print_net_pm_stats(const struct shell *sh, struct net_if *iface)
|
|
{
|
|
#if defined(CONFIG_NET_STATISTICS_POWER_MANAGEMENT)
|
|
PR("PM suspend stats:\n");
|
|
PR("\tLast time : %u ms\n",
|
|
GET_STAT(iface, pm.last_suspend_time));
|
|
PR("\tAverage time : %u ms\n",
|
|
(uint32_t)(GET_STAT(iface, pm.overall_suspend_time) /
|
|
GET_STAT(iface, pm.suspend_count)));
|
|
PR("\tTotal time : %" PRIu64 " ms\n",
|
|
GET_STAT(iface, pm.overall_suspend_time));
|
|
PR("\tHow many times: %u\n",
|
|
GET_STAT(iface, pm.suspend_count));
|
|
#else
|
|
ARG_UNUSED(sh);
|
|
ARG_UNUSED(iface);
|
|
#endif
|
|
}
|
|
|
|
static void net_shell_print_statistics(struct net_if *iface, void *user_data)
|
|
{
|
|
struct net_shell_user_data *data = user_data;
|
|
const struct shell *sh = data->sh;
|
|
|
|
if (iface) {
|
|
const char *extra;
|
|
|
|
PR("\nInterface %p (%s) [%d]\n", iface,
|
|
iface2str(iface, &extra), net_if_get_by_iface(iface));
|
|
PR("===========================%s\n", extra);
|
|
} else {
|
|
PR("\nGlobal statistics\n");
|
|
PR("=================\n");
|
|
}
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_IPV6) && defined(CONFIG_NET_NATIVE_IPV6)
|
|
PR("IPv6 recv %d\tsent\t%d\tdrop\t%d\tforwarded\t%d\n",
|
|
GET_STAT(iface, ipv6.recv),
|
|
GET_STAT(iface, ipv6.sent),
|
|
GET_STAT(iface, ipv6.drop),
|
|
GET_STAT(iface, ipv6.forwarded));
|
|
#if defined(CONFIG_NET_STATISTICS_IPV6_ND)
|
|
PR("IPv6 ND recv %d\tsent\t%d\tdrop\t%d\n",
|
|
GET_STAT(iface, ipv6_nd.recv),
|
|
GET_STAT(iface, ipv6_nd.sent),
|
|
GET_STAT(iface, ipv6_nd.drop));
|
|
#endif /* CONFIG_NET_STATISTICS_IPV6_ND */
|
|
#if defined(CONFIG_NET_STATISTICS_MLD)
|
|
PR("IPv6 MLD recv %d\tsent\t%d\tdrop\t%d\n",
|
|
GET_STAT(iface, ipv6_mld.recv),
|
|
GET_STAT(iface, ipv6_mld.sent),
|
|
GET_STAT(iface, ipv6_mld.drop));
|
|
#endif /* CONFIG_NET_STATISTICS_MLD */
|
|
#endif /* CONFIG_NET_STATISTICS_IPV6 */
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_IPV4) && defined(CONFIG_NET_NATIVE_IPV4)
|
|
PR("IPv4 recv %d\tsent\t%d\tdrop\t%d\tforwarded\t%d\n",
|
|
GET_STAT(iface, ipv4.recv),
|
|
GET_STAT(iface, ipv4.sent),
|
|
GET_STAT(iface, ipv4.drop),
|
|
GET_STAT(iface, ipv4.forwarded));
|
|
#endif /* CONFIG_NET_STATISTICS_IPV4 */
|
|
|
|
PR("IP vhlerr %d\thblener\t%d\tlblener\t%d\n",
|
|
GET_STAT(iface, ip_errors.vhlerr),
|
|
GET_STAT(iface, ip_errors.hblenerr),
|
|
GET_STAT(iface, ip_errors.lblenerr));
|
|
PR("IP fragerr %d\tchkerr\t%d\tprotoer\t%d\n",
|
|
GET_STAT(iface, ip_errors.fragerr),
|
|
GET_STAT(iface, ip_errors.chkerr),
|
|
GET_STAT(iface, ip_errors.protoerr));
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_ICMP) && defined(CONFIG_NET_NATIVE_IPV4)
|
|
PR("ICMP recv %d\tsent\t%d\tdrop\t%d\n",
|
|
GET_STAT(iface, icmp.recv),
|
|
GET_STAT(iface, icmp.sent),
|
|
GET_STAT(iface, icmp.drop));
|
|
PR("ICMP typeer %d\tchkerr\t%d\n",
|
|
GET_STAT(iface, icmp.typeerr),
|
|
GET_STAT(iface, icmp.chkerr));
|
|
#endif
|
|
#if defined(CONFIG_NET_STATISTICS_IGMP)
|
|
PR("IGMP recv %d\tsent\t%d\tdrop\t%d\n",
|
|
GET_STAT(iface, ipv4_igmp.recv),
|
|
GET_STAT(iface, ipv4_igmp.sent),
|
|
GET_STAT(iface, ipv4_igmp.drop));
|
|
#endif /* CONFIG_NET_STATISTICS_IGMP */
|
|
#if defined(CONFIG_NET_STATISTICS_UDP) && defined(CONFIG_NET_NATIVE_UDP)
|
|
PR("UDP recv %d\tsent\t%d\tdrop\t%d\n",
|
|
GET_STAT(iface, udp.recv),
|
|
GET_STAT(iface, udp.sent),
|
|
GET_STAT(iface, udp.drop));
|
|
PR("UDP chkerr %d\n",
|
|
GET_STAT(iface, udp.chkerr));
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_TCP) && defined(CONFIG_NET_NATIVE_TCP)
|
|
PR("TCP bytes recv %u\tsent\t%d\tresent\t%d\n",
|
|
GET_STAT(iface, tcp.bytes.received),
|
|
GET_STAT(iface, tcp.bytes.sent),
|
|
GET_STAT(iface, tcp.resent));
|
|
PR("TCP seg recv %d\tsent\t%d\tdrop\t%d\n",
|
|
GET_STAT(iface, tcp.recv),
|
|
GET_STAT(iface, tcp.sent),
|
|
GET_STAT(iface, tcp.seg_drop));
|
|
PR("TCP seg resent %d\tchkerr\t%d\tackerr\t%d\n",
|
|
GET_STAT(iface, tcp.rexmit),
|
|
GET_STAT(iface, tcp.chkerr),
|
|
GET_STAT(iface, tcp.ackerr));
|
|
PR("TCP seg rsterr %d\trst\t%d\n",
|
|
GET_STAT(iface, tcp.rsterr),
|
|
GET_STAT(iface, tcp.rst));
|
|
PR("TCP conn drop %d\tconnrst\t%d\n",
|
|
GET_STAT(iface, tcp.conndrop),
|
|
GET_STAT(iface, tcp.connrst));
|
|
PR("TCP pkt drop %d\n", GET_STAT(iface, tcp.drop));
|
|
#endif
|
|
|
|
PR("Bytes received %u\n", GET_STAT(iface, bytes.received));
|
|
PR("Bytes sent %u\n", GET_STAT(iface, bytes.sent));
|
|
PR("Processing err %d\n", GET_STAT(iface, processing_error));
|
|
|
|
print_tc_tx_stats(sh, iface);
|
|
print_tc_rx_stats(sh, iface);
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_ETHERNET) && \
|
|
defined(CONFIG_NET_STATISTICS_USER_API)
|
|
if (iface && net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) {
|
|
struct net_stats_eth eth_data;
|
|
int ret;
|
|
|
|
ret = net_mgmt(NET_REQUEST_STATS_GET_ETHERNET, iface,
|
|
ð_data, sizeof(eth_data));
|
|
if (!ret) {
|
|
print_eth_stats(iface, ð_data, sh);
|
|
}
|
|
}
|
|
#endif /* CONFIG_NET_STATISTICS_ETHERNET && CONFIG_NET_STATISTICS_USER_API */
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_PPP) && \
|
|
defined(CONFIG_NET_STATISTICS_USER_API)
|
|
if (iface && net_if_l2(iface) == &NET_L2_GET_NAME(PPP)) {
|
|
struct net_stats_ppp ppp_data;
|
|
int ret;
|
|
|
|
ret = net_mgmt(NET_REQUEST_STATS_GET_PPP, iface,
|
|
&ppp_data, sizeof(ppp_data));
|
|
if (!ret) {
|
|
print_ppp_stats(iface, &ppp_data, sh);
|
|
}
|
|
}
|
|
#endif /* CONFIG_NET_STATISTICS_PPP && CONFIG_NET_STATISTICS_USER_API */
|
|
|
|
print_net_pm_stats(sh, iface);
|
|
}
|
|
#endif /* CONFIG_NET_STATISTICS */
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_PER_INTERFACE)
|
|
static void net_shell_print_statistics_all(struct net_shell_user_data *data)
|
|
{
|
|
net_if_foreach(net_shell_print_statistics, data);
|
|
}
|
|
#endif
|
|
|
|
int cmd_net_stats_all(const struct shell *sh, size_t argc, char *argv[])
|
|
{
|
|
#if defined(CONFIG_NET_STATISTICS)
|
|
struct net_shell_user_data user_data;
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_STATISTICS)
|
|
user_data.sh = sh;
|
|
|
|
/* Print global network statistics */
|
|
net_shell_print_statistics_all(&user_data);
|
|
#else
|
|
ARG_UNUSED(argc);
|
|
ARG_UNUSED(argv);
|
|
|
|
PR_INFO("Set %s to enable %s support.\n", "CONFIG_NET_STATISTICS",
|
|
"statistics");
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
int cmd_net_stats_iface(const struct shell *sh, size_t argc, char *argv[])
|
|
{
|
|
#if defined(CONFIG_NET_STATISTICS)
|
|
#if defined(CONFIG_NET_STATISTICS_PER_INTERFACE)
|
|
struct net_shell_user_data data;
|
|
struct net_if *iface;
|
|
char *endptr;
|
|
int idx;
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_STATISTICS)
|
|
#if defined(CONFIG_NET_STATISTICS_PER_INTERFACE)
|
|
if (argv[1] == NULL) {
|
|
PR_WARNING("Network interface index missing!\n");
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
idx = strtol(argv[1], &endptr, 10);
|
|
if (*endptr != '\0') {
|
|
PR_WARNING("Invalid index %s\n", argv[1]);
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
iface = net_if_get_by_index(idx);
|
|
if (!iface) {
|
|
PR_WARNING("No such interface in index %d\n", idx);
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
data.sh = sh;
|
|
|
|
net_shell_print_statistics(iface, &data);
|
|
#else
|
|
PR_INFO("Per network interface statistics not collected.\n");
|
|
PR_INFO("Please enable CONFIG_NET_STATISTICS_PER_INTERFACE\n");
|
|
#endif /* CONFIG_NET_STATISTICS_PER_INTERFACE */
|
|
#else
|
|
ARG_UNUSED(argc);
|
|
ARG_UNUSED(argv);
|
|
|
|
PR_INFO("Set %s to enable %s support.\n", "CONFIG_NET_STATISTICS",
|
|
"statistics");
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_net_stats(const struct shell *sh, size_t argc, char *argv[])
|
|
{
|
|
#if defined(CONFIG_NET_STATISTICS)
|
|
if (!argv[1]) {
|
|
cmd_net_stats_all(sh, argc, argv);
|
|
return 0;
|
|
}
|
|
|
|
if (strcmp(argv[1], "reset") == 0) {
|
|
net_stats_reset(NULL);
|
|
} else {
|
|
cmd_net_stats_iface(sh, argc, argv);
|
|
}
|
|
#else
|
|
ARG_UNUSED(argc);
|
|
ARG_UNUSED(argv);
|
|
|
|
PR_INFO("Set %s to enable %s support.\n", "CONFIG_NET_STATISTICS",
|
|
"statistics");
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if defined(CONFIG_NET_SHELL_DYN_CMD_COMPLETION)
|
|
|
|
#include "iface_dynamic.h"
|
|
|
|
#endif /* CONFIG_NET_SHELL_DYN_CMD_COMPLETION */
|
|
|
|
SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_stats,
|
|
SHELL_CMD(all, NULL,
|
|
"Show network statistics for all network interfaces.",
|
|
cmd_net_stats_all),
|
|
SHELL_CMD(iface, IFACE_DYN_CMD,
|
|
"'net stats <index>' shows network statistics for "
|
|
"one specific network interface.",
|
|
cmd_net_stats_iface),
|
|
SHELL_SUBCMD_SET_END
|
|
);
|
|
|
|
SHELL_SUBCMD_ADD((net), stats, &net_cmd_stats,
|
|
"Show network statistics.",
|
|
cmd_net_stats, 1, 1);
|