diff --git a/.known-issues/doc/networking.conf b/.known-issues/doc/networking.conf index 6b95c9a69d13..33d1779dd303 100644 --- a/.known-issues/doc/networking.conf +++ b/.known-issues/doc/networking.conf @@ -58,3 +58,9 @@ ^(?P[-._/\w]+/doc/api/networking.rst):(?P[0-9]+): WARNING: Invalid definition: Expected end of definition. \[error at [0-9]+] ^.*net_context.options ^[- \t]*\^ +# +# include/net/net_stats.h +# +^(?P[-._/\w]+/doc/api/networking.rst):(?P[0-9]+): WARNING: Invalid definition: Expected end of definition. \[error at [0-9]+] +^.*net_stats_tc.[a-z]+ +^[- \t]*\^ diff --git a/include/net/net_pkt.h b/include/net/net_pkt.h index 62fbdf34806d..dbeb56aa7caa 100644 --- a/include/net/net_pkt.h +++ b/include/net/net_pkt.h @@ -80,6 +80,13 @@ struct net_pkt { struct net_linkaddr lladdr_src; struct net_linkaddr lladdr_dst; +#if defined(CONFIG_NET_STATISTICS) + /* If statistics is enabled, then speed up length calculation by + * doing it only once. This value is updated in net_if_queue_tx() + * when packet is about to be sent. + */ + u16_t total_pkt_len; +#endif u16_t data_len; /* amount of payload data that can be added */ u16_t appdatalen; diff --git a/include/net/net_stats.h b/include/net/net_stats.h index 6c6be5a95ecb..341be1e32986 100644 --- a/include/net/net_stats.h +++ b/include/net/net_stats.h @@ -15,6 +15,7 @@ #define __NET_STATS_H #include +#include #ifdef __cplusplus extern "C" { @@ -228,6 +229,23 @@ struct net_stats_ipv6_mld { net_stats_t drop; }; +struct net_stats_tc { + /** Traffic class sent statistics */ + struct { + net_stats_t pkts; + net_stats_t bytes; + u8_t priority; + } sent[NET_TC_TX_COUNT]; + + /** Traffic class receive statistics */ + struct { + net_stats_t pkts; + net_stats_t bytes; + u8_t priority; + } recv[NET_TC_RX_COUNT]; +}; + + struct net_stats { net_stats_t processing_error; @@ -270,6 +288,10 @@ struct net_stats { #if defined(CONFIG_NET_IPV6_MLD) struct net_stats_ipv6_mld ipv6_mld; #endif + +#if NET_TC_COUNT > 1 + struct net_stats_tc tc; +#endif }; #if defined(CONFIG_NET_STATISTICS_USER_API) diff --git a/subsys/net/ip/net_core.c b/subsys/net/ip/net_core.c index ec9fad3e2bd9..e05e8b5682e4 100644 --- a/subsys/net/ip/net_core.c +++ b/subsys/net/ip/net_core.c @@ -284,7 +284,12 @@ int net_send_data(struct net_pkt *pkt) static void net_rx(struct net_if *iface, struct net_pkt *pkt) { #if defined(CONFIG_NET_STATISTICS) || defined(CONFIG_NET_DEBUG_CORE) - size_t pkt_len = net_pkt_get_len(pkt); + size_t pkt_len; +#if defined(CONFIG_NET_STATISTICS) + pkt_len = pkt->total_pkt_len; +#else + pkt_len = net_pkt_get_len(pkt); +#endif #endif NET_DBG("Received pkt %p len %zu", pkt, pkt_len); @@ -313,6 +318,14 @@ static void net_queue_rx(struct net_if *iface, struct net_pkt *pkt) k_work_init(net_pkt_work(pkt), process_rx_packet); +#if defined(CONFIG_NET_STATISTICS) + pkt->total_pkt_len = net_pkt_get_len(pkt); + + net_stats_update_tc_recv_pkt(tc); + net_stats_update_tc_recv_bytes(tc, pkt->total_pkt_len); + net_stats_update_tc_recv_priority(tc, prio); +#endif + #if NET_TC_RX_COUNT > 1 NET_DBG("TC %d with prio %d pkt %p", tc, prio, pkt); #endif diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index 1c14c3f77114..6a3d88bafb04 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -70,17 +70,25 @@ static sys_slist_t mcast_monitor_callbacks; #endif #if defined(CONFIG_NET_DEBUG_IF) +#if defined(CONFIG_NET_STATISTICS) #define debug_check_packet(pkt) \ - { \ - size_t len = net_pkt_get_len(pkt); \ - \ - NET_DBG("Processing (pkt %p, data len %zu, " \ + do { \ + NET_DBG("Processing (pkt %p, data len %d, " \ "prio %d) network packet", \ - pkt, len, \ + pkt, pkt->total_pkt_len, \ net_pkt_priority(pkt)); \ \ - NET_ASSERT(pkt->frags && len); \ + NET_ASSERT(pkt->frags && pkt->total_pkt_len); \ } while (0) +#else /* CONFIG_NET_STATISTICS */ +#define debug_check_packet(pkt) \ + do { \ + NET_DBG("Processing (pkt %p, prio %d) network packet", \ + pkt, net_pkt_priority(pkt)); \ + \ + NET_ASSERT(pkt->frags); \ + } while (0) +#endif /* CONFIG_NET_STATISTICS */ #else #define debug_check_packet(...) #endif /* CONFIG_NET_DEBUG_IF */ @@ -117,9 +125,6 @@ static bool net_if_tx(struct net_if *iface, struct net_pkt *pkt) struct net_context *context; void *context_token; int status; -#if defined(CONFIG_NET_STATISTICS) - size_t pkt_len; -#endif if (!pkt) { return false; @@ -132,10 +137,6 @@ static bool net_if_tx(struct net_if *iface, struct net_pkt *pkt) context_token = net_pkt_token(pkt); if (atomic_test_bit(iface->if_dev->flags, NET_IF_UP)) { -#if defined(CONFIG_NET_STATISTICS) - pkt_len = net_pkt_get_len(pkt); -#endif - if (IS_ENABLED(CONFIG_NET_TCP)) { net_pkt_set_sent(pkt, true); net_pkt_set_queued(pkt, false); @@ -155,7 +156,7 @@ static bool net_if_tx(struct net_if *iface, struct net_pkt *pkt) net_pkt_unref(pkt); } else { - net_stats_update_bytes_sent(pkt_len); + net_stats_update_bytes_sent(pkt->total_pkt_len); } if (context) { @@ -188,6 +189,14 @@ void net_if_queue_tx(struct net_if *iface, struct net_pkt *pkt) k_work_init(net_pkt_work(pkt), process_tx_packet); +#if defined(CONFIG_NET_STATISTICS) + pkt->total_pkt_len = net_pkt_get_len(pkt); + + net_stats_update_tc_sent_pkt(tc); + net_stats_update_tc_sent_bytes(tc, pkt->total_pkt_len); + net_stats_update_tc_sent_priority(tc, prio); +#endif + #if NET_TC_TX_COUNT > 1 NET_DBG("TC %d with prio %d pkt %p", tc, prio, pkt); #endif diff --git a/subsys/net/ip/net_shell.c b/subsys/net/ip/net_shell.c index d50152e6a16d..a19d5ca96c4f 100644 --- a/subsys/net/ip/net_shell.c +++ b/subsys/net/ip/net_shell.c @@ -446,6 +446,32 @@ static void iface_per_mcast_route_cb(struct net_if *iface, void *user_data) #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 + static inline void net_shell_print_statistics(void) { #if defined(CONFIG_NET_IPV6) @@ -560,6 +586,38 @@ static inline void net_shell_print_statistics(void) printk("Bytes received %u\n", GET_STAT(bytes.received)); printk("Bytes sent %u\n", GET_STAT(bytes.sent)); printk("Processing err %d\n", GET_STAT(processing_error)); + +#if NET_TC_COUNT > 1 + { + int i; + +#if NET_TC_TX_COUNT > 1 + printk("TX traffic class statistics:\n"); + printk("TC Priority\tSent pkts\tbytes\n"); + + for (i = 0; i < NET_TC_TX_COUNT; i++) { + printk("[%d] %s (%d)\t%d\t\t%d\n", i, + priority2str(GET_STAT(tc.sent[i].priority)), + GET_STAT(tc.sent[i].priority), + GET_STAT(tc.sent[i].pkts), + GET_STAT(tc.sent[i].bytes)); + } +#endif + +#if NET_TC_RX_COUNT > 1 + printk("RX traffic class statistics:\n"); + printk("TC Priority\tRecv pkts\tbytes\n"); + + for (i = 0; i < NET_TC_RX_COUNT; i++) { + printk("[%d] %s (%d)\t%d\t\t%d\n", i, + priority2str(GET_STAT(tc.recv[i].priority)), + GET_STAT(tc.recv[i].priority), + GET_STAT(tc.recv[i].pkts), + GET_STAT(tc.recv[i].bytes)); + } + } +#endif +#endif /* NET_TC_COUNT > 1 */ } #endif /* CONFIG_NET_STATISTICS */ diff --git a/subsys/net/ip/net_stats.h b/subsys/net/ip/net_stats.h index 92da615a7cff..7808b64273b9 100644 --- a/subsys/net/ip/net_stats.h +++ b/subsys/net/ip/net_stats.h @@ -390,6 +390,45 @@ static inline void net_stats_update_ipv6_mld_drop(void) #define net_stats_update_ipv6_mld_drop() #endif /* CONFIG_NET_STATISTICS_MLD */ +#if (NET_TC_COUNT > 1) && defined(CONFIG_NET_STATISTICS) +static inline void net_stats_update_tc_sent_pkt(u8_t tc) +{ + net_stats.tc.sent[tc].pkts++; +} + +static inline void net_stats_update_tc_sent_bytes(u8_t tc, size_t bytes) +{ + net_stats.tc.sent[tc].bytes += bytes; +} + +static inline void net_stats_update_tc_sent_priority(u8_t tc, u8_t priority) +{ + net_stats.tc.sent[tc].priority = priority; +} + +static inline void net_stats_update_tc_recv_pkt(u8_t tc) +{ + net_stats.tc.recv[tc].pkts++; +} + +static inline void net_stats_update_tc_recv_bytes(u8_t tc, size_t bytes) +{ + net_stats.tc.recv[tc].bytes += bytes; +} + +static inline void net_stats_update_tc_recv_priority(u8_t tc, u8_t priority) +{ + net_stats.tc.recv[tc].priority = priority; +} +#else +#define net_stats_update_tc_sent_pkt(tc) +#define net_stats_update_tc_sent_bytes(tc, bytes) +#define net_stats_update_tc_sent_priority(tc, priority) +#define net_stats_update_tc_recv_pkt(tc) +#define net_stats_update_tc_recv_bytes(tc, bytes) +#define net_stats_update_tc_recv_priority(tc, priority) +#endif /* NET_TC_COUNT > 1 */ + #if defined(CONFIG_NET_STATISTICS_PERIODIC_OUTPUT) /* A simple periodic statistic printer, used only in net core */ void net_print_statistics(void); diff --git a/subsys/net/ip/net_tc.c b/subsys/net/ip/net_tc.c index 6afdb9378abb..0aa3d945af69 100644 --- a/subsys/net/ip/net_tc.c +++ b/subsys/net/ip/net_tc.c @@ -266,6 +266,29 @@ static int rx_tc2thread(int tc) #define RX_STACK(idx) NET_STACK_GET_NAME(RX, rx_stack, 0)[idx] #endif +#if defined(CONFIG_NET_STATISTICS) +/* Fixup the traffic class statistics so that "net stats" shell command will + * print output correctly. + */ +static void tc_tx_stats_priority_setup(void) +{ + int i; + + for (i = 0; i < 8; i++) { + net_stats_update_tc_sent_priority(net_tx_priority2tc(i), i); + } +} + +static void tc_rx_stats_priority_setup(void) +{ + int i; + + for (i = 0; i < 8; i++) { + net_stats_update_tc_recv_priority(net_rx_priority2tc(i), i); + } +} +#endif + /* Create workqueue for each traffic class we are using. All the network * traffic goes through these classes. There needs to be at least one traffic * class in the system. @@ -276,6 +299,10 @@ void net_tc_tx_init(void) BUILD_ASSERT(NET_TC_TX_COUNT > 0); +#if defined(CONFIG_NET_STATISTICS) + tc_tx_stats_priority_setup(); +#endif + for (i = 0; i < NET_TC_TX_COUNT; i++) { u8_t thread_priority; @@ -312,6 +339,10 @@ void net_tc_rx_init(void) BUILD_ASSERT(NET_TC_RX_COUNT > 0); +#if defined(CONFIG_NET_STATISTICS) + tc_rx_stats_priority_setup(); +#endif + for (i = 0; i < NET_TC_RX_COUNT; i++) { u8_t thread_priority;