| /* |
| * 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); |
| |
| PR("Checksum offload : RX good %u errors %u\n", |
| data->csum.rx_csum_offload_good, |
| data->csum.rx_csum_offload_errors); |
| PR("Flow control : RX xon %u xoff %u TX xon %u xoff %u\n", |
| data->flow_control.rx_flow_control_xon, |
| data->flow_control.rx_flow_control_xoff, |
| data->flow_control.tx_flow_control_xon, |
| data->flow_control.tx_flow_control_xoff); |
| PR("ECC errors : uncorrected %u corrected %u\n", |
| data->error_details.uncorr_ecc_errors, |
| data->error_details.corr_ecc_errors); |
| PR("HW timestamp : RX cleared %u TX timeout %u skipped %u\n", |
| data->hw_timestamp.rx_hwtstamp_cleared, |
| data->hw_timestamp.tx_hwtstamp_timeouts, |
| data->hw_timestamp.tx_hwtstamp_skipped); |
| |
| PR("RX errors : %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s\n", |
| "Len", "Over", "CRC", "Frame", "NoBuf", "Miss", "Long", "Short", |
| "Align", "DMA", "Alloc"); |
| PR(" %5u %5u %5u %5u %5u %5u %5u %5u %5u %5u %5u\n", |
| data->error_details.rx_length_errors, |
| data->error_details.rx_over_errors, |
| data->error_details.rx_crc_errors, |
| data->error_details.rx_frame_errors, |
| data->error_details.rx_no_buffer_count, |
| data->error_details.rx_missed_errors, |
| data->error_details.rx_long_length_errors, |
| data->error_details.rx_short_length_errors, |
| data->error_details.rx_align_errors, |
| data->error_details.rx_dma_failed, |
| data->error_details.rx_buf_alloc_failed); |
| PR("TX errors : %5s %8s %5s %10s %7s %5s\n", |
| "Abort", "Carrier", "Fifo", "Heartbeat", "Window", "DMA"); |
| PR(" %5u %8u %5u %10u %7u %5u\n", |
| data->error_details.tx_aborted_errors, |
| data->error_details.tx_carrier_errors, |
| data->error_details.tx_fifo_errors, |
| data->error_details.tx_heartbeat_errors, |
| data->error_details.tx_window_errors, |
| data->error_details.tx_dma_failed); |
| |
| #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); |