1 /*
2  * Copyright (c) 2018 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(net_stats_sample, LOG_LEVEL_DBG);
9 
10 #include <zephyr/kernel.h>
11 #include <errno.h>
12 
13 #include <zephyr/net/net_core.h>
14 #include <zephyr/net/net_if.h>
15 #include <zephyr/net/net_stats.h>
16 
17 static struct k_work_delayable stats_timer;
18 
19 #if defined(CONFIG_NET_STATISTICS_PER_INTERFACE)
20 #define GET_STAT(iface, s) (iface ? iface->stats.s : data->s)
21 #else
22 #define GET_STAT(iface, s) data->s
23 #endif
24 
print_stats(struct net_if * iface,struct net_stats * data)25 static void print_stats(struct net_if *iface, struct net_stats *data)
26 {
27 	if (iface) {
28 		printk("Statistics for interface %p [%d]\n", iface,
29 		       net_if_get_by_iface(iface));
30 	} else {
31 		printk("Global network statistics\n");
32 	}
33 
34 #if defined(CONFIG_NET_IPV6)
35 	printk("IPv6 recv      %d\tsent\t%d\tdrop\t%d\tforwarded\t%d\n",
36 	       GET_STAT(iface, ipv6.recv),
37 	       GET_STAT(iface, ipv6.sent),
38 	       GET_STAT(iface, ipv6.drop),
39 	       GET_STAT(iface, ipv6.forwarded));
40 #if defined(CONFIG_NET_IPV6_ND)
41 	printk("IPv6 ND recv   %d\tsent\t%d\tdrop\t%d\n",
42 	       GET_STAT(iface, ipv6_nd.recv),
43 	       GET_STAT(iface, ipv6_nd.sent),
44 	       GET_STAT(iface, ipv6_nd.drop));
45 #endif /* CONFIG_NET_IPV6_ND */
46 #if defined(CONFIG_NET_IPV6_PMTU)
47 	printk("IPv6 PMTU recv %d\tsent\t%d\tdrop\t%d\n",
48 	       GET_STAT(iface, ipv6_pmtu.recv),
49 	       GET_STAT(iface, ipv6_pmtu.sent),
50 	       GET_STAT(iface, ipv6_pmtu.drop));
51 #endif /* CONFIG_NET_IPV6_PMTU */
52 #if defined(CONFIG_NET_STATISTICS_MLD)
53 	printk("IPv6 MLD recv  %d\tsent\t%d\tdrop\t%d\n",
54 	       GET_STAT(iface, ipv6_mld.recv),
55 	       GET_STAT(iface, ipv6_mld.sent),
56 	       GET_STAT(iface, ipv6_mld.drop));
57 #endif /* CONFIG_NET_STATISTICS_MLD */
58 #endif /* CONFIG_NET_IPV6 */
59 
60 #if defined(CONFIG_NET_IPV4)
61 	printk("IPv4 recv      %d\tsent\t%d\tdrop\t%d\tforwarded\t%d\n",
62 	       GET_STAT(iface, ipv4.recv),
63 	       GET_STAT(iface, ipv4.sent),
64 	       GET_STAT(iface, ipv4.drop),
65 	       GET_STAT(iface, ipv4.forwarded));
66 #endif /* CONFIG_NET_IPV4 */
67 
68 	printk("IP vhlerr      %d\thblener\t%d\tlblener\t%d\n",
69 	       GET_STAT(iface, ip_errors.vhlerr),
70 	       GET_STAT(iface, ip_errors.hblenerr),
71 	       GET_STAT(iface, ip_errors.lblenerr));
72 	printk("IP fragerr     %d\tchkerr\t%d\tprotoer\t%d\n",
73 	       GET_STAT(iface, ip_errors.fragerr),
74 	       GET_STAT(iface, ip_errors.chkerr),
75 	       GET_STAT(iface, ip_errors.protoerr));
76 
77 #if defined(CONFIG_NET_IPV4_PMTU)
78 	printk("IPv4 PMTU recv %d\tsent\t%d\tdrop\t%d\n",
79 	       GET_STAT(iface, ipv4_pmtu.recv),
80 	       GET_STAT(iface, ipv4_pmtu.sent),
81 	       GET_STAT(iface, ipv4_pmtu.drop));
82 #endif /* CONFIG_NET_IPV4_PMTU */
83 
84 	printk("ICMP recv      %d\tsent\t%d\tdrop\t%d\n",
85 	       GET_STAT(iface, icmp.recv),
86 	       GET_STAT(iface, icmp.sent),
87 	       GET_STAT(iface, icmp.drop));
88 	printk("ICMP typeer    %d\tchkerr\t%d\n",
89 	       GET_STAT(iface, icmp.typeerr),
90 	       GET_STAT(iface, icmp.chkerr));
91 
92 #if defined(CONFIG_NET_UDP)
93 	printk("UDP recv       %d\tsent\t%d\tdrop\t%d\n",
94 	       GET_STAT(iface, udp.recv),
95 	       GET_STAT(iface, udp.sent),
96 	       GET_STAT(iface, udp.drop));
97 	printk("UDP chkerr     %d\n",
98 	       GET_STAT(iface, udp.chkerr));
99 #endif
100 
101 #if defined(CONFIG_NET_STATISTICS_TCP)
102 	printk("TCP bytes recv %u\tsent\t%d\n",
103 	       GET_STAT(iface, tcp.bytes.received),
104 	       GET_STAT(iface, tcp.bytes.sent));
105 	printk("TCP seg recv   %d\tsent\t%d\tdrop\t%d\n",
106 	       GET_STAT(iface, tcp.recv),
107 	       GET_STAT(iface, tcp.sent),
108 	       GET_STAT(iface, tcp.drop));
109 	printk("TCP seg resent %d\tchkerr\t%d\tackerr\t%d\n",
110 	       GET_STAT(iface, tcp.resent),
111 	       GET_STAT(iface, tcp.chkerr),
112 	       GET_STAT(iface, tcp.ackerr));
113 	printk("TCP seg rsterr %d\trst\t%d\tre-xmit\t%d\n",
114 	       GET_STAT(iface, tcp.rsterr),
115 	       GET_STAT(iface, tcp.rst),
116 	       GET_STAT(iface, tcp.rexmit));
117 	printk("TCP conn drop  %d\tconnrst\t%d\n",
118 	       GET_STAT(iface, tcp.conndrop),
119 	       GET_STAT(iface, tcp.connrst));
120 #endif
121 
122 	printk("Bytes received %u\n", GET_STAT(iface, bytes.received));
123 	printk("Bytes sent     %u\n", GET_STAT(iface, bytes.sent));
124 	printk("Processing err %d\n", GET_STAT(iface, processing_error));
125 }
126 
127 #if defined(CONFIG_NET_STATISTICS_PER_INTERFACE)
iface_cb(struct net_if * iface,void * user_data)128 static void iface_cb(struct net_if *iface, void *user_data)
129 {
130 	struct net_stats *data = user_data;
131 
132 	net_mgmt(NET_REQUEST_STATS_GET_ALL, iface, data, sizeof(*data));
133 
134 	print_stats(iface, data);
135 }
136 #endif
137 
138 #if defined(CONFIG_NET_STATISTICS_ETHERNET)
print_eth_stats(struct net_if * iface,struct net_stats_eth * data)139 static void print_eth_stats(struct net_if *iface, struct net_stats_eth *data)
140 {
141 	printk("Statistics for Ethernet interface %p [%d]\n", iface,
142 	       net_if_get_by_iface(iface));
143 
144 	printk("Bytes received   : %u\n", data->bytes.received);
145 	printk("Bytes sent       : %u\n", data->bytes.sent);
146 	printk("Packets received : %u\n", data->pkts.rx);
147 	printk("Packets sent     : %u\n", data->pkts.tx);
148 	printk("Bcast received   : %u\n", data->broadcast.rx);
149 	printk("Bcast sent       : %u\n", data->broadcast.tx);
150 	printk("Mcast received   : %u\n", data->multicast.rx);
151 	printk("Mcast sent       : %u\n", data->multicast.tx);
152 }
153 
eth_iface_cb(struct net_if * iface,void * user_data)154 static void eth_iface_cb(struct net_if *iface, void *user_data)
155 {
156 	struct net_stats_eth eth_data;
157 	int ret;
158 
159 	if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET)) {
160 		return;
161 	}
162 
163 	ret = net_mgmt(NET_REQUEST_STATS_GET_ETHERNET, iface, &eth_data,
164 		       sizeof(eth_data));
165 	if (ret < 0) {
166 		return;
167 	}
168 
169 	print_eth_stats(iface, &eth_data);
170 }
171 #endif
172 
stats(struct k_work * work)173 static void stats(struct k_work *work)
174 {
175 	struct net_stats data;
176 
177 	/* It is also possible to query some specific statistics by setting
178 	 * the first request parameter properly. See include/net/net_stats.h
179 	 * what requests are available.
180 	 */
181 	net_mgmt(NET_REQUEST_STATS_GET_ALL, NULL, &data, sizeof(data));
182 
183 	print_stats(NULL, &data);
184 
185 #if defined(CONFIG_NET_STATISTICS_PER_INTERFACE)
186 	net_if_foreach(iface_cb, &data);
187 #endif
188 
189 #if defined(CONFIG_NET_STATISTICS_ETHERNET)
190 	net_if_foreach(eth_iface_cb, &data);
191 #endif
192 
193 	k_work_reschedule(&stats_timer, K_SECONDS(CONFIG_SAMPLE_PERIOD));
194 }
195 
init_app(void)196 static void init_app(void)
197 {
198 	k_work_init_delayable(&stats_timer, stats);
199 	k_work_reschedule(&stats_timer, K_SECONDS(CONFIG_SAMPLE_PERIOD));
200 }
201 
main(void)202 int main(void)
203 {
204 	/* Register a timer that will collect statistics after every n seconds.
205 	 */
206 	init_app();
207 	return 0;
208 }
209