1 /*
2  * Copyright (c) 2016 Intel Corporation
3  * Copyright (c) 2023 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/logging/log.h>
9 LOG_MODULE_DECLARE(net_shell);
10 
11 #include <zephyr/net/net_stats.h>
12 
13 #include "net_shell_private.h"
14 
15 #include "../ip/net_stats.h"
16 
17 #if defined(CONFIG_NET_STATISTICS)
18 
19 #if NET_TC_COUNT > 1
priority2str(enum net_priority priority)20 static const char *priority2str(enum net_priority priority)
21 {
22 	switch (priority) {
23 	case NET_PRIORITY_BK:
24 		return "BK"; /* Background */
25 	case NET_PRIORITY_BE:
26 		return "BE"; /* Best effort */
27 	case NET_PRIORITY_EE:
28 		return "EE"; /* Excellent effort */
29 	case NET_PRIORITY_CA:
30 		return "CA"; /* Critical applications */
31 	case NET_PRIORITY_VI:
32 		return "VI"; /* Video, < 100 ms latency and jitter */
33 	case NET_PRIORITY_VO:
34 		return "VO"; /* Voice, < 10 ms latency and jitter  */
35 	case NET_PRIORITY_IC:
36 		return "IC"; /* Internetwork control */
37 	case NET_PRIORITY_NC:
38 		return "NC"; /* Network control */
39 	}
40 
41 	return "??";
42 }
43 #endif
44 
45 #if defined(CONFIG_NET_STATISTICS_ETHERNET) && \
46 					defined(CONFIG_NET_STATISTICS_USER_API)
print_eth_stats(struct net_if * iface,struct net_stats_eth * data,const struct shell * sh)47 static void print_eth_stats(struct net_if *iface, struct net_stats_eth *data,
48 			    const struct shell *sh)
49 {
50 	PR("Statistics for Ethernet interface %p [%d]\n", iface,
51 	       net_if_get_by_iface(iface));
52 
53 	PR("Bytes received   : %u\n", data->bytes.received);
54 	PR("Bytes sent       : %u\n", data->bytes.sent);
55 	PR("Packets received : %u\n", data->pkts.rx);
56 	PR("Packets sent     : %u\n", data->pkts.tx);
57 	PR("Bcast received   : %u\n", data->broadcast.rx);
58 	PR("Bcast sent       : %u\n", data->broadcast.tx);
59 	PR("Mcast received   : %u\n", data->multicast.rx);
60 	PR("Mcast sent       : %u\n", data->multicast.tx);
61 
62 	PR("Send errors      : %u\n", data->errors.tx);
63 	PR("Receive errors   : %u\n", data->errors.rx);
64 	PR("Collisions       : %u\n", data->collisions);
65 	PR("Send Drops       : %u\n", data->tx_dropped);
66 	PR("Send timeouts    : %u\n", data->tx_timeout_count);
67 	PR("Send restarts    : %u\n", data->tx_restart_queue);
68 	PR("Unknown protocol : %u\n", data->unknown_protocol);
69 
70 	PR("Checksum offload : RX good %u errors %u\n",
71 	   data->csum.rx_csum_offload_good,
72 	   data->csum.rx_csum_offload_errors);
73 	PR("Flow control     : RX xon %u xoff %u TX xon %u xoff %u\n",
74 	   data->flow_control.rx_flow_control_xon,
75 	   data->flow_control.rx_flow_control_xoff,
76 	   data->flow_control.tx_flow_control_xon,
77 	   data->flow_control.tx_flow_control_xoff);
78 	PR("ECC errors       : uncorrected %u corrected %u\n",
79 	   data->error_details.uncorr_ecc_errors,
80 	   data->error_details.corr_ecc_errors);
81 	PR("HW timestamp     : RX cleared %u TX timeout %u skipped %u\n",
82 	   data->hw_timestamp.rx_hwtstamp_cleared,
83 	   data->hw_timestamp.tx_hwtstamp_timeouts,
84 	   data->hw_timestamp.tx_hwtstamp_skipped);
85 
86 	PR("RX errors : %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s\n",
87 	   "Len", "Over", "CRC", "Frame", "NoBuf", "Miss", "Long", "Short",
88 	   "Align", "DMA", "Alloc");
89 	PR("            %5u %5u %5u %5u %5u %5u %5u %5u %5u %5u %5u\n",
90 	   data->error_details.rx_length_errors,
91 	   data->error_details.rx_over_errors,
92 	   data->error_details.rx_crc_errors,
93 	   data->error_details.rx_frame_errors,
94 	   data->error_details.rx_no_buffer_count,
95 	   data->error_details.rx_missed_errors,
96 	   data->error_details.rx_long_length_errors,
97 	   data->error_details.rx_short_length_errors,
98 	   data->error_details.rx_align_errors,
99 	   data->error_details.rx_dma_failed,
100 	   data->error_details.rx_buf_alloc_failed);
101 	PR("TX errors : %5s %8s %5s %10s %7s %5s\n",
102 	   "Abort", "Carrier", "Fifo", "Heartbeat", "Window", "DMA");
103 	PR("            %5u %8u %5u %10u %7u %5u\n",
104 	   data->error_details.tx_aborted_errors,
105 	   data->error_details.tx_carrier_errors,
106 	   data->error_details.tx_fifo_errors,
107 	   data->error_details.tx_heartbeat_errors,
108 	   data->error_details.tx_window_errors,
109 	   data->error_details.tx_dma_failed);
110 
111 #if defined(CONFIG_NET_STATISTICS_ETHERNET_VENDOR)
112 	if (data->vendor) {
113 		PR("Vendor specific statistics for Ethernet "
114 		   "interface %p [%d]:\n",
115 			iface, net_if_get_by_iface(iface));
116 		size_t i = 0;
117 
118 		do {
119 			PR("%s : %u\n", data->vendor[i].key,
120 			   data->vendor[i].value);
121 			i++;
122 		} while (data->vendor[i].key);
123 	}
124 #endif /* CONFIG_NET_STATISTICS_ETHERNET_VENDOR */
125 }
126 #endif /* CONFIG_NET_STATISTICS_ETHERNET && CONFIG_NET_STATISTICS_USER_API */
127 
128 #if defined(CONFIG_NET_STATISTICS_PPP) && \
129 					defined(CONFIG_NET_STATISTICS_USER_API)
print_ppp_stats(struct net_if * iface,struct net_stats_ppp * data,const struct shell * sh)130 static void print_ppp_stats(struct net_if *iface, struct net_stats_ppp *data,
131 			    const struct shell *sh)
132 {
133 	PR("Frames recv    %u\n", data->pkts.rx);
134 	PR("Frames sent    %u\n", data->pkts.tx);
135 	PR("Frames dropped %u\n", data->drop);
136 	PR("Bad FCS        %u\n", data->chkerr);
137 }
138 #endif /* CONFIG_NET_STATISTICS_PPP && CONFIG_NET_STATISTICS_USER_API */
139 
140 #if !defined(CONFIG_NET_NATIVE)
141 #define GET_STAT(a, b) 0
142 #endif
143 
144 #if defined(CONFIG_NET_PKT_TXTIME_STATS_DETAIL) || \
145 	defined(CONFIG_NET_PKT_RXTIME_STATS_DETAIL)
146 #if (NET_TC_TX_COUNT > 1) || (NET_TC_RX_COUNT > 1)
get_net_pkt_tc_stats_detail(struct net_if * iface,int i,bool is_tx)147 static char *get_net_pkt_tc_stats_detail(struct net_if *iface, int i,
148 					  bool is_tx)
149 {
150 	static char extra_stats[sizeof("\t[0=xxxx us]") +
151 				sizeof("->xxxx") *
152 				NET_PKT_DETAIL_STATS_COUNT];
153 	int j, total = 0, pos = 0;
154 
155 	pos += snprintk(extra_stats, sizeof(extra_stats), "\t[0");
156 
157 	for (j = 0; j < NET_PKT_DETAIL_STATS_COUNT; j++) {
158 		net_stats_t count = 0;
159 		uint32_t avg;
160 
161 		if (is_tx) {
162 #if defined(CONFIG_NET_PKT_TXTIME_STATS_DETAIL) && (NET_TC_TX_COUNT > 1)
163 			count = GET_STAT(iface,
164 					 tc.sent[i].tx_time_detail[j].count);
165 #endif
166 		} else {
167 #if defined(CONFIG_NET_PKT_RXTIME_STATS_DETAIL) && (NET_TC_RX_COUNT > 1)
168 			count = GET_STAT(iface,
169 					 tc.recv[i].rx_time_detail[j].count);
170 #endif
171 		}
172 
173 		if (count == 0) {
174 			break;
175 		}
176 
177 		if (is_tx) {
178 #if defined(CONFIG_NET_PKT_TXTIME_STATS_DETAIL) && (NET_TC_TX_COUNT > 1)
179 			avg = (uint32_t)(GET_STAT(iface,
180 					   tc.sent[i].tx_time_detail[j].sum) /
181 				      (uint64_t)count);
182 #endif
183 		} else {
184 #if defined(CONFIG_NET_PKT_RXTIME_STATS_DETAIL) && (NET_TC_RX_COUNT > 1)
185 			avg = (uint32_t)(GET_STAT(iface,
186 					   tc.recv[i].rx_time_detail[j].sum) /
187 				      (uint64_t)count);
188 #endif
189 		}
190 
191 		if (avg == 0) {
192 			continue;
193 		}
194 
195 		total += avg;
196 
197 		pos += snprintk(extra_stats + pos, sizeof(extra_stats) - pos,
198 				"->%u", avg);
199 	}
200 
201 	if (total == 0U) {
202 		return "\0";
203 	}
204 
205 	pos += snprintk(extra_stats + pos, sizeof(extra_stats) - pos,
206 				"=%u us]", total);
207 
208 	return extra_stats;
209 }
210 #endif /* (NET_TC_TX_COUNT > 1) || (NET_TC_RX_COUNT > 1) */
211 
212 #if (NET_TC_TX_COUNT <= 1) || (NET_TC_RX_COUNT <= 1)
get_net_pkt_stats_detail(struct net_if * iface,bool is_tx)213 static char *get_net_pkt_stats_detail(struct net_if *iface, bool is_tx)
214 {
215 	static char extra_stats[sizeof("\t[0=xxxx us]") + sizeof("->xxxx") *
216 				NET_PKT_DETAIL_STATS_COUNT];
217 	int j, total = 0, pos = 0;
218 
219 	pos += snprintk(extra_stats, sizeof(extra_stats), "\t[0");
220 
221 	for (j = 0; j < NET_PKT_DETAIL_STATS_COUNT; j++) {
222 		net_stats_t count;
223 		uint32_t avg;
224 
225 		if (is_tx) {
226 #if defined(CONFIG_NET_PKT_TXTIME_STATS_DETAIL)
227 			count = GET_STAT(iface, tx_time_detail[j].count);
228 #endif
229 		} else {
230 #if defined(CONFIG_NET_PKT_RXTIME_STATS_DETAIL)
231 			count = GET_STAT(iface, rx_time_detail[j].count);
232 #endif
233 		}
234 
235 		if (count == 0) {
236 			break;
237 		}
238 
239 		if (is_tx) {
240 #if defined(CONFIG_NET_PKT_TXTIME_STATS_DETAIL)
241 			avg = (uint32_t)(GET_STAT(iface,
242 					       tx_time_detail[j].sum) /
243 				      (uint64_t)count);
244 #endif
245 		} else {
246 #if defined(CONFIG_NET_PKT_RXTIME_STATS_DETAIL)
247 			avg = (uint32_t)(GET_STAT(iface,
248 					       rx_time_detail[j].sum) /
249 				      (uint64_t)count);
250 #endif
251 		}
252 
253 		if (avg == 0) {
254 			continue;
255 		}
256 
257 		total += avg;
258 
259 		pos += snprintk(extra_stats + pos,
260 				sizeof(extra_stats) - pos,
261 				"->%u", avg);
262 	}
263 
264 	if (total == 0U) {
265 		return "\0";
266 	}
267 
268 	pos += snprintk(extra_stats + pos, sizeof(extra_stats) - pos,
269 			"=%u us]", total);
270 
271 	return extra_stats;
272 }
273 #endif /* (NET_TC_TX_COUNT == 1) || (NET_TC_RX_COUNT == 1) */
274 
275 #else /* CONFIG_NET_PKT_TXTIME_STATS_DETAIL || CONFIG_NET_PKT_RXTIME_STATS_DETAIL */
276 
277 #if defined(CONFIG_NET_PKT_TXTIME_STATS) || \
278 	defined(CONFIG_NET_PKT_RXTIME_STATS)
279 
280 #if (NET_TC_TX_COUNT > 1) || (NET_TC_RX_COUNT > 1)
get_net_pkt_tc_stats_detail(struct net_if * iface,int i,bool is_tx)281 static char *get_net_pkt_tc_stats_detail(struct net_if *iface, int i,
282 					 bool is_tx)
283 {
284 	ARG_UNUSED(iface);
285 	ARG_UNUSED(i);
286 	ARG_UNUSED(is_tx);
287 
288 	return "\0";
289 }
290 #endif
291 
292 #if (NET_TC_TX_COUNT == 1) || (NET_TC_RX_COUNT == 1)
get_net_pkt_stats_detail(struct net_if * iface,bool is_tx)293 static char *get_net_pkt_stats_detail(struct net_if *iface, bool is_tx)
294 {
295 	ARG_UNUSED(iface);
296 	ARG_UNUSED(is_tx);
297 
298 	return "\0";
299 }
300 #endif
301 #endif /* CONFIG_NET_PKT_TXTIME_STATS) || CONFIG_NET_PKT_RXTIME_STATS */
302 #endif /* CONFIG_NET_PKT_TXTIME_STATS_DETAIL || CONFIG_NET_PKT_RXTIME_STATS_DETAIL */
303 
print_tc_tx_stats(const struct shell * sh,struct net_if * iface)304 static void print_tc_tx_stats(const struct shell *sh, struct net_if *iface)
305 {
306 #if NET_TC_TX_COUNT > 1
307 	int i;
308 
309 	PR("TX traffic class statistics:\n");
310 
311 #if defined(CONFIG_NET_PKT_TXTIME_STATS)
312 	PR("TC  Priority\tSent pkts\tbytes\ttime\n");
313 
314 	for (i = 0; i < NET_TC_TX_COUNT; i++) {
315 		net_stats_t count = GET_STAT(iface,
316 					     tc.sent[i].tx_time.count);
317 		if (count == 0) {
318 			PR("[%d] %s (%d)\t%d\t\t%d\t-\n", i,
319 			   priority2str(GET_STAT(iface, tc.sent[i].priority)),
320 			   GET_STAT(iface, tc.sent[i].priority),
321 			   GET_STAT(iface, tc.sent[i].pkts),
322 			   GET_STAT(iface, tc.sent[i].bytes));
323 		} else {
324 			PR("[%d] %s (%d)\t%d\t\t%d\t%u us%s\n", i,
325 			   priority2str(GET_STAT(iface, tc.sent[i].priority)),
326 			   GET_STAT(iface, tc.sent[i].priority),
327 			   GET_STAT(iface, tc.sent[i].pkts),
328 			   GET_STAT(iface, tc.sent[i].bytes),
329 			   (uint32_t)(GET_STAT(iface,
330 					    tc.sent[i].tx_time.sum) /
331 				   (uint64_t)count),
332 			   get_net_pkt_tc_stats_detail(iface, i, true));
333 		}
334 	}
335 #else
336 	PR("TC  Priority\tSent pkts\tbytes\n");
337 
338 	for (i = 0; i < NET_TC_TX_COUNT; i++) {
339 		PR("[%d] %s (%d)\t%d\t\t%d\n", i,
340 		   priority2str(GET_STAT(iface, tc.sent[i].priority)),
341 		   GET_STAT(iface, tc.sent[i].priority),
342 		   GET_STAT(iface, tc.sent[i].pkts),
343 		   GET_STAT(iface, tc.sent[i].bytes));
344 	}
345 #endif /* CONFIG_NET_PKT_TXTIME_STATS */
346 #else
347 	ARG_UNUSED(sh);
348 
349 #if defined(CONFIG_NET_PKT_TXTIME_STATS)
350 	net_stats_t count = GET_STAT(iface, tx_time.count);
351 
352 	if (count != 0) {
353 		PR("Avg %s net_pkt (%u) time %" PRIu32 " us%s\n", "TX", count,
354 		   (uint32_t)(GET_STAT(iface, tx_time.sum) / (uint64_t)count),
355 		   get_net_pkt_stats_detail(iface, true));
356 	}
357 #else
358 	ARG_UNUSED(iface);
359 #endif /* CONFIG_NET_PKT_TXTIME_STATS */
360 #endif /* NET_TC_TX_COUNT > 1 */
361 }
362 
print_tc_rx_stats(const struct shell * sh,struct net_if * iface)363 static void print_tc_rx_stats(const struct shell *sh, struct net_if *iface)
364 {
365 #if NET_TC_RX_COUNT > 1
366 	int i;
367 
368 	PR("RX traffic class statistics:\n");
369 
370 #if defined(CONFIG_NET_PKT_RXTIME_STATS)
371 	PR("TC  Priority\tRecv pkts\tDrop pkts\tbytes\ttime\n");
372 
373 	for (i = 0; i < NET_TC_RX_COUNT; i++) {
374 		net_stats_t count = GET_STAT(iface,
375 					     tc.recv[i].rx_time.count);
376 		if (count == 0) {
377 			PR("[%d] %s (%d)\t%d\t%d\t\t%d\t-\n", i,
378 			   priority2str(GET_STAT(iface, tc.recv[i].priority)),
379 			   GET_STAT(iface, tc.recv[i].priority),
380 			   GET_STAT(iface, tc.recv[i].pkts),
381 			   GET_STAT(iface, tc.recv[i].dropped),
382 			   GET_STAT(iface, tc.recv[i].bytes));
383 		} else {
384 			PR("[%d] %s (%d)\t%d\t%d\t\t%d\t%u us%s\n", i,
385 			   priority2str(GET_STAT(iface, tc.recv[i].priority)),
386 			   GET_STAT(iface, tc.recv[i].priority),
387 			   GET_STAT(iface, tc.recv[i].pkts),
388 			   GET_STAT(iface, tc.recv[i].dropped),
389 			   GET_STAT(iface, tc.recv[i].bytes),
390 			   (uint32_t)(GET_STAT(iface,
391 					    tc.recv[i].rx_time.sum) /
392 				   (uint64_t)count),
393 			   get_net_pkt_tc_stats_detail(iface, i, false));
394 		}
395 	}
396 #else
397 	PR("TC  Priority\tRecv pkts\tDrop pkts\tbytes\n");
398 
399 	for (i = 0; i < NET_TC_RX_COUNT; i++) {
400 		PR("[%d] %s (%d)\t%d\t%d\t\t%d\n", i,
401 		   priority2str(GET_STAT(iface, tc.recv[i].priority)),
402 		   GET_STAT(iface, tc.recv[i].priority),
403 		   GET_STAT(iface, tc.recv[i].pkts),
404 		   GET_STAT(iface, tc.recv[i].dropped),
405 		   GET_STAT(iface, tc.recv[i].bytes));
406 	}
407 #endif /* CONFIG_NET_PKT_RXTIME_STATS */
408 #else
409 	ARG_UNUSED(sh);
410 
411 #if defined(CONFIG_NET_PKT_RXTIME_STATS)
412 	net_stats_t count = GET_STAT(iface, rx_time.count);
413 
414 	if (count != 0) {
415 		PR("Avg %s net_pkt (%u) time %" PRIu32 " us%s\n", "RX", count,
416 		   (uint32_t)(GET_STAT(iface, rx_time.sum) / (uint64_t)count),
417 		   get_net_pkt_stats_detail(iface, false));
418 	}
419 #else
420 	ARG_UNUSED(iface);
421 #endif /* CONFIG_NET_PKT_RXTIME_STATS */
422 
423 #endif /* NET_TC_RX_COUNT > 1 */
424 }
425 
print_net_pm_stats(const struct shell * sh,struct net_if * iface)426 static void print_net_pm_stats(const struct shell *sh, struct net_if *iface)
427 {
428 #if defined(CONFIG_NET_STATISTICS_POWER_MANAGEMENT)
429 	PR("PM suspend stats:\n");
430 	PR("\tLast time     : %u ms\n",
431 	   GET_STAT(iface, pm.last_suspend_time));
432 	PR("\tAverage time  : %u ms\n",
433 	   (uint32_t)(GET_STAT(iface, pm.overall_suspend_time) /
434 		   GET_STAT(iface, pm.suspend_count)));
435 	PR("\tTotal time    : %" PRIu64 " ms\n",
436 	   GET_STAT(iface, pm.overall_suspend_time));
437 	PR("\tHow many times: %u\n",
438 	   GET_STAT(iface, pm.suspend_count));
439 #else
440 	ARG_UNUSED(sh);
441 	ARG_UNUSED(iface);
442 #endif
443 }
444 
net_shell_print_statistics(struct net_if * iface,void * user_data)445 static void net_shell_print_statistics(struct net_if *iface, void *user_data)
446 {
447 	struct net_shell_user_data *data = user_data;
448 	const struct shell *sh = data->sh;
449 
450 	if (iface) {
451 		const char *extra;
452 
453 		PR("\nInterface %p (%s) [%d]\n", iface,
454 		   iface2str(iface, &extra), net_if_get_by_iface(iface));
455 		PR("===========================%s\n", extra);
456 	} else {
457 		PR("\nGlobal statistics\n");
458 		PR("=================\n");
459 	}
460 
461 #if defined(CONFIG_NET_STATISTICS_IPV6) && defined(CONFIG_NET_NATIVE_IPV6)
462 	PR("IPv6 recv      %d\tsent\t%d\tdrop\t%d\tforwarded\t%d\n",
463 	   GET_STAT(iface, ipv6.recv),
464 	   GET_STAT(iface, ipv6.sent),
465 	   GET_STAT(iface, ipv6.drop),
466 	   GET_STAT(iface, ipv6.forwarded));
467 #if defined(CONFIG_NET_STATISTICS_IPV6_ND)
468 	PR("IPv6 ND recv   %d\tsent\t%d\tdrop\t%d\n",
469 	   GET_STAT(iface, ipv6_nd.recv),
470 	   GET_STAT(iface, ipv6_nd.sent),
471 	   GET_STAT(iface, ipv6_nd.drop));
472 #endif /* CONFIG_NET_STATISTICS_IPV6_ND */
473 #if defined(CONFIG_NET_STATISTICS_IPV6_PMTU)
474 	PR("IPv6 PMTU recv %d\tsent\t%d\tdrop\t%d\n",
475 	   GET_STAT(iface, ipv6_pmtu.recv),
476 	   GET_STAT(iface, ipv6_pmtu.sent),
477 	   GET_STAT(iface, ipv6_pmtu.drop));
478 #endif /* CONFIG_NET_STATISTICS_IPV6_PMTU */
479 #if defined(CONFIG_NET_STATISTICS_MLD)
480 	PR("IPv6 MLD recv  %d\tsent\t%d\tdrop\t%d\n",
481 	   GET_STAT(iface, ipv6_mld.recv),
482 	   GET_STAT(iface, ipv6_mld.sent),
483 	   GET_STAT(iface, ipv6_mld.drop));
484 #endif /* CONFIG_NET_STATISTICS_MLD */
485 #endif /* CONFIG_NET_STATISTICS_IPV6 */
486 
487 #if defined(CONFIG_NET_STATISTICS_IPV4) && defined(CONFIG_NET_NATIVE_IPV4)
488 	PR("IPv4 recv      %d\tsent\t%d\tdrop\t%d\tforwarded\t%d\n",
489 	   GET_STAT(iface, ipv4.recv),
490 	   GET_STAT(iface, ipv4.sent),
491 	   GET_STAT(iface, ipv4.drop),
492 	   GET_STAT(iface, ipv4.forwarded));
493 #endif /* CONFIG_NET_STATISTICS_IPV4 */
494 
495 	PR("IP vhlerr      %d\thblener\t%d\tlblener\t%d\n",
496 	   GET_STAT(iface, ip_errors.vhlerr),
497 	   GET_STAT(iface, ip_errors.hblenerr),
498 	   GET_STAT(iface, ip_errors.lblenerr));
499 	PR("IP fragerr     %d\tchkerr\t%d\tprotoer\t%d\n",
500 	   GET_STAT(iface, ip_errors.fragerr),
501 	   GET_STAT(iface, ip_errors.chkerr),
502 	   GET_STAT(iface, ip_errors.protoerr));
503 
504 #if defined(CONFIG_NET_STATISTICS_IPV4_PMTU)
505 	PR("IPv4 PMTU recv %d\tsent\t%d\tdrop\t%d\n",
506 	   GET_STAT(iface, ipv4_pmtu.recv),
507 	   GET_STAT(iface, ipv4_pmtu.sent),
508 	   GET_STAT(iface, ipv4_pmtu.drop));
509 #endif /* CONFIG_NET_STATISTICS_IPV4_PMTU */
510 
511 #if defined(CONFIG_NET_STATISTICS_ICMP) && defined(CONFIG_NET_NATIVE_IPV4)
512 	PR("ICMP recv      %d\tsent\t%d\tdrop\t%d\n",
513 	   GET_STAT(iface, icmp.recv),
514 	   GET_STAT(iface, icmp.sent),
515 	   GET_STAT(iface, icmp.drop));
516 	PR("ICMP typeer    %d\tchkerr\t%d\n",
517 	   GET_STAT(iface, icmp.typeerr),
518 	   GET_STAT(iface, icmp.chkerr));
519 #endif
520 #if defined(CONFIG_NET_STATISTICS_IGMP)
521 	PR("IGMP recv      %d\tsent\t%d\tdrop\t%d\n",
522 	   GET_STAT(iface, ipv4_igmp.recv),
523 	   GET_STAT(iface, ipv4_igmp.sent),
524 	   GET_STAT(iface, ipv4_igmp.drop));
525 #endif /* CONFIG_NET_STATISTICS_IGMP */
526 #if defined(CONFIG_NET_STATISTICS_UDP) && defined(CONFIG_NET_NATIVE_UDP)
527 	PR("UDP recv       %d\tsent\t%d\tdrop\t%d\n",
528 	   GET_STAT(iface, udp.recv),
529 	   GET_STAT(iface, udp.sent),
530 	   GET_STAT(iface, udp.drop));
531 	PR("UDP chkerr     %d\n",
532 	   GET_STAT(iface, udp.chkerr));
533 #endif
534 
535 #if defined(CONFIG_NET_STATISTICS_TCP) && defined(CONFIG_NET_NATIVE_TCP)
536 	PR("TCP bytes recv %u\tsent\t%d\tresent\t%d\n",
537 	   GET_STAT(iface, tcp.bytes.received),
538 	   GET_STAT(iface, tcp.bytes.sent),
539 	   GET_STAT(iface, tcp.resent));
540 	PR("TCP seg recv   %d\tsent\t%d\tdrop\t%d\n",
541 	   GET_STAT(iface, tcp.recv),
542 	   GET_STAT(iface, tcp.sent),
543 	   GET_STAT(iface, tcp.seg_drop));
544 	PR("TCP seg resent %d\tchkerr\t%d\tackerr\t%d\n",
545 	   GET_STAT(iface, tcp.rexmit),
546 	   GET_STAT(iface, tcp.chkerr),
547 	   GET_STAT(iface, tcp.ackerr));
548 	PR("TCP seg rsterr %d\trst\t%d\n",
549 	   GET_STAT(iface, tcp.rsterr),
550 	   GET_STAT(iface, tcp.rst));
551 	PR("TCP conn drop  %d\tconnrst\t%d\n",
552 	   GET_STAT(iface, tcp.conndrop),
553 	   GET_STAT(iface, tcp.connrst));
554 	PR("TCP pkt drop   %d\n", GET_STAT(iface, tcp.drop));
555 #endif
556 #if defined(CONFIG_NET_STATISTICS_DNS)
557 	PR("DNS recv       %d\tsent\t%d\tdrop\t%d\n",
558 	   GET_STAT(iface, dns.recv),
559 	   GET_STAT(iface, dns.sent),
560 	   GET_STAT(iface, dns.drop));
561 #endif /* CONFIG_NET_STATISTICS_DNS */
562 
563 	PR("Bytes received %u\n", GET_STAT(iface, bytes.received));
564 	PR("Bytes sent     %u\n", GET_STAT(iface, bytes.sent));
565 	PR("Processing err %d\n", GET_STAT(iface, processing_error));
566 
567 	print_tc_tx_stats(sh, iface);
568 	print_tc_rx_stats(sh, iface);
569 
570 #if defined(CONFIG_NET_STATISTICS_ETHERNET) && \
571 					defined(CONFIG_NET_STATISTICS_USER_API)
572 	if (iface && net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) {
573 		struct net_stats_eth eth_data;
574 		int ret;
575 
576 		ret = net_mgmt(NET_REQUEST_STATS_GET_ETHERNET, iface,
577 			       &eth_data, sizeof(eth_data));
578 		if (!ret) {
579 			print_eth_stats(iface, &eth_data, sh);
580 		}
581 	}
582 #endif /* CONFIG_NET_STATISTICS_ETHERNET && CONFIG_NET_STATISTICS_USER_API */
583 
584 #if defined(CONFIG_NET_STATISTICS_PPP) && \
585 					defined(CONFIG_NET_STATISTICS_USER_API)
586 	if (iface && net_if_l2(iface) == &NET_L2_GET_NAME(PPP)) {
587 		struct net_stats_ppp ppp_data;
588 		int ret;
589 
590 		ret = net_mgmt(NET_REQUEST_STATS_GET_PPP, iface,
591 			       &ppp_data, sizeof(ppp_data));
592 		if (!ret) {
593 			print_ppp_stats(iface, &ppp_data, sh);
594 		}
595 	}
596 #endif /* CONFIG_NET_STATISTICS_PPP && CONFIG_NET_STATISTICS_USER_API */
597 
598 	print_net_pm_stats(sh, iface);
599 }
600 #endif /* CONFIG_NET_STATISTICS */
601 
602 #if defined(CONFIG_NET_STATISTICS_PER_INTERFACE)
net_shell_print_statistics_all(struct net_shell_user_data * data)603 static void net_shell_print_statistics_all(struct net_shell_user_data *data)
604 {
605 	net_if_foreach(net_shell_print_statistics, data);
606 }
607 #endif
608 
cmd_net_stats_all(const struct shell * sh,size_t argc,char * argv[])609 int cmd_net_stats_all(const struct shell *sh, size_t argc, char *argv[])
610 {
611 #if defined(CONFIG_NET_STATISTICS)
612 	struct net_shell_user_data user_data;
613 #endif
614 
615 #if defined(CONFIG_NET_STATISTICS)
616 	user_data.sh = sh;
617 
618 	/* Print global network statistics */
619 	net_shell_print_statistics_all(&user_data);
620 #else
621 	ARG_UNUSED(argc);
622 	ARG_UNUSED(argv);
623 
624 	PR_INFO("Set %s to enable %s support.\n", "CONFIG_NET_STATISTICS",
625 		"statistics");
626 #endif
627 
628 	return 0;
629 }
630 
cmd_net_stats_iface(const struct shell * sh,size_t argc,char * argv[])631 int cmd_net_stats_iface(const struct shell *sh, size_t argc, char *argv[])
632 {
633 #if defined(CONFIG_NET_STATISTICS)
634 #if defined(CONFIG_NET_STATISTICS_PER_INTERFACE)
635 	struct net_shell_user_data data;
636 	struct net_if *iface;
637 	char *endptr;
638 	int idx;
639 #endif
640 #endif
641 
642 #if defined(CONFIG_NET_STATISTICS)
643 #if defined(CONFIG_NET_STATISTICS_PER_INTERFACE)
644 	if (argv[1] == NULL) {
645 		PR_WARNING("Network interface index missing!\n");
646 		return -ENOEXEC;
647 	}
648 
649 	idx = strtol(argv[1], &endptr, 10);
650 	if (*endptr != '\0') {
651 		PR_WARNING("Invalid index %s\n", argv[1]);
652 		return -ENOEXEC;
653 	}
654 
655 	iface = net_if_get_by_index(idx);
656 	if (!iface) {
657 		PR_WARNING("No such interface in index %d\n", idx);
658 		return -ENOEXEC;
659 	}
660 
661 	data.sh = sh;
662 
663 	net_shell_print_statistics(iface, &data);
664 #else
665 	PR_INFO("Per network interface statistics not collected.\n");
666 	PR_INFO("Please enable CONFIG_NET_STATISTICS_PER_INTERFACE\n");
667 #endif /* CONFIG_NET_STATISTICS_PER_INTERFACE */
668 #else
669 	ARG_UNUSED(argc);
670 	ARG_UNUSED(argv);
671 
672 	PR_INFO("Set %s to enable %s support.\n", "CONFIG_NET_STATISTICS",
673 		"statistics");
674 #endif
675 
676 	return 0;
677 }
678 
cmd_net_stats(const struct shell * sh,size_t argc,char * argv[])679 static int cmd_net_stats(const struct shell *sh, size_t argc, char *argv[])
680 {
681 #if defined(CONFIG_NET_STATISTICS)
682 	if (!argv[1]) {
683 		cmd_net_stats_all(sh, argc, argv);
684 		return 0;
685 	}
686 
687 	if (strcmp(argv[1], "reset") == 0) {
688 		net_stats_reset(NULL);
689 	} else {
690 		cmd_net_stats_iface(sh, argc, argv);
691 	}
692 #else
693 	ARG_UNUSED(argc);
694 	ARG_UNUSED(argv);
695 
696 	PR_INFO("Set %s to enable %s support.\n", "CONFIG_NET_STATISTICS",
697 		"statistics");
698 #endif
699 
700 	return 0;
701 }
702 
703 #if defined(CONFIG_NET_SHELL_DYN_CMD_COMPLETION)
704 
705 #include "iface_dynamic.h"
706 
707 #endif /* CONFIG_NET_SHELL_DYN_CMD_COMPLETION */
708 
709 SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_stats,
710 	SHELL_CMD(all, NULL,
711 		  "Show network statistics for all network interfaces.",
712 		  cmd_net_stats_all),
713 	SHELL_CMD(iface, IFACE_DYN_CMD,
714 		  "'net stats <index>' shows network statistics for "
715 		  "one specific network interface.",
716 		  cmd_net_stats_iface),
717 	SHELL_SUBCMD_SET_END
718 );
719 
720 SHELL_SUBCMD_ADD((net), stats, &net_cmd_stats,
721 		 "Show network statistics.",
722 		 cmd_net_stats, 1, 1);
723