]>
Commit | Line | Data |
---|---|---|
9c859447 | 1 | /* |
e0b07f2d | 2 | * Copyright (c) 2008-2019 Apple Inc. All rights reserved. |
9c859447 A |
3 | * |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
b7080c8e A |
28 | /* |
29 | * Copyright (c) 1983, 1988, 1993 | |
30 | * The Regents of the University of California. All rights reserved. | |
31 | * | |
32 | * Redistribution and use in source and binary forms, with or without | |
33 | * modification, are permitted provided that the following conditions | |
34 | * are met: | |
35 | * 1. Redistributions of source code must retain the above copyright | |
36 | * notice, this list of conditions and the following disclaimer. | |
37 | * 2. Redistributions in binary form must reproduce the above copyright | |
38 | * notice, this list of conditions and the following disclaimer in the | |
39 | * documentation and/or other materials provided with the distribution. | |
40 | * 3. All advertising materials mentioning features or use of this software | |
41 | * must display the following acknowledgement: | |
42 | * This product includes software developed by the University of | |
43 | * California, Berkeley and its contributors. | |
44 | * 4. Neither the name of the University nor the names of its contributors | |
45 | * may be used to endorse or promote products derived from this software | |
46 | * without specific prior written permission. | |
47 | * | |
48 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
49 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
50 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
51 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
52 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
53 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
54 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
55 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
56 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
57 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
58 | * SUCH DAMAGE. | |
59 | */ | |
60 | ||
b7080c8e | 61 | #include <sys/types.h> |
b7080c8e | 62 | #include <sys/socket.h> |
7ba0088d | 63 | #include <sys/sysctl.h> |
7af5ce03 | 64 | #include <sys/ioctl.h> |
b7080c8e | 65 | #include <sys/time.h> |
89c4ed63 | 66 | #include <sys/kern_control.h> |
b7080c8e A |
67 | |
68 | #include <net/if.h> | |
69 | #include <net/if_var.h> | |
70 | #include <net/if_dl.h> | |
71 | #include <net/if_types.h> | |
2b484d24 | 72 | #include <net/if_mib.h> |
fdfd5971 | 73 | #include <net/if_llreach.h> |
b7080c8e | 74 | #include <net/ethernet.h> |
2b484d24 | 75 | #include <net/route.h> |
89c4ed63 | 76 | #include <net/ntstat.h> |
2b484d24 | 77 | |
7af5ce03 A |
78 | #include <net/pktsched/pktsched.h> |
79 | #include <net/classq/if_classq.h> | |
80 | ||
b7080c8e A |
81 | #include <netinet/in.h> |
82 | #include <netinet/in_var.h> | |
83 | ||
b7080c8e A |
84 | #include <arpa/inet.h> |
85 | ||
86 | #include <signal.h> | |
87 | #include <stdio.h> | |
88 | #include <string.h> | |
89 | #include <unistd.h> | |
2b484d24 | 90 | #include <stdlib.h> |
89c4ed63 | 91 | #include <stddef.h> |
2b484d24 | 92 | #include <err.h> |
fdfd5971 | 93 | #include <errno.h> |
89c4ed63 | 94 | #include <fcntl.h> |
b7080c8e | 95 | |
e0b07f2d A |
96 | #include <assert.h> |
97 | ||
b7080c8e A |
98 | #include "netstat.h" |
99 | ||
100 | #define YES 1 | |
101 | #define NO 0 | |
102 | ||
2b484d24 A |
103 | #define ROUNDUP(a, size) (((a) & ((size) - 1)) ? (1 + ((a)|(size - 1))) : (a)) |
104 | ||
105 | #define NEXT_SA(p) (struct sockaddr *) \ | |
9c859447 A |
106 | ((caddr_t)p + (p->sa_len ? ROUNDUP(p->sa_len, sizeof(uint32_t)) : \ |
107 | sizeof(uint32_t))) | |
2b484d24 A |
108 | |
109 | static void sidewaysintpr (); | |
7ba0088d | 110 | static void catchalarm (int); |
fdfd5971 A |
111 | static char *sec2str(time_t); |
112 | static void llreach_sysctl(uint32_t); | |
7af5ce03 | 113 | static char *nsec_to_str(unsigned long long); |
7af5ce03 | 114 | static char *sched2str(unsigned int); |
26c66ce9 | 115 | static char *pri2str(unsigned int i); |
7af5ce03 A |
116 | |
117 | #define AVGN_MAX 8 | |
118 | ||
119 | struct queue_stats { | |
120 | int avgn; | |
121 | double avg_bytes; | |
122 | double avg_packets; | |
123 | u_int64_t prev_bytes; | |
124 | u_int64_t prev_packets; | |
7af5ce03 A |
125 | unsigned int handle; |
126 | }; | |
127 | ||
7af5ce03 | 128 | static void update_avg(struct if_ifclassq_stats *, struct queue_stats *); |
26c66ce9 A |
129 | static void print_fq_codel_stats(int slot, struct fq_codel_classstats *, |
130 | struct queue_stats *); | |
7af5ce03 A |
131 | |
132 | struct queue_stats qstats[IFCQ_SC_MAX]; | |
7ba0088d A |
133 | |
134 | #ifdef INET6 | |
2b484d24 | 135 | char *netname6 (struct sockaddr_in6 *, struct sockaddr *); |
7ba0088d | 136 | static char ntop_buf[INET6_ADDRSTRLEN]; /* for inet_ntop() */ |
7ba0088d A |
137 | #endif |
138 | ||
7ba0088d A |
139 | /* |
140 | * Display a formatted value, or a '-' in the same space. | |
141 | */ | |
142 | static void | |
2b484d24 | 143 | show_stat(const char *fmt, int width, u_int64_t value, short showvalue) |
7ba0088d A |
144 | { |
145 | char newfmt[32]; | |
146 | ||
147 | /* Construct the format string */ | |
148 | if (showvalue) { | |
fdfd5971 | 149 | snprintf(newfmt, sizeof(newfmt), "%%%d%s", width, fmt); |
7ba0088d A |
150 | printf(newfmt, value); |
151 | } else { | |
fdfd5971 | 152 | snprintf(newfmt, sizeof(newfmt), "%%%ds", width); |
7ba0088d A |
153 | printf(newfmt, "-"); |
154 | } | |
155 | } | |
156 | ||
2b484d24 A |
157 | size_t |
158 | get_rti_info(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) | |
159 | { | |
160 | int i; | |
161 | size_t len = 0; | |
162 | ||
163 | for (i = 0; i < RTAX_MAX; i++) { | |
164 | if (addrs & (1 << i)) { | |
165 | rti_info[i] = sa; | |
166 | if (sa->sa_len < sizeof(struct sockaddr)) | |
167 | len += sizeof(struct sockaddr); | |
168 | else | |
169 | len += sa->sa_len; | |
170 | sa = NEXT_SA(sa); | |
171 | } else { | |
172 | rti_info[i] = NULL; | |
173 | } | |
174 | } | |
175 | return len; | |
176 | } | |
7ba0088d | 177 | |
2b484d24 A |
178 | static void |
179 | multipr(int family, char *buf, char *lim) | |
180 | { | |
181 | char *next; | |
182 | ||
183 | for (next = buf; next < lim; ) { | |
184 | struct ifma_msghdr2 *ifmam = (struct ifma_msghdr2 *)next; | |
185 | struct sockaddr *rti_info[RTAX_MAX]; | |
186 | struct sockaddr *sa; | |
187 | const char *fmt = 0; | |
a3cc5c72 | 188 | |
2b484d24 A |
189 | next += ifmam->ifmam_msglen; |
190 | if (ifmam->ifmam_type == RTM_IFINFO2) | |
191 | break; | |
192 | else if (ifmam->ifmam_type != RTM_NEWMADDR2) | |
193 | continue; | |
194 | get_rti_info(ifmam->ifmam_addrs, (struct sockaddr*)(ifmam + 1), rti_info); | |
195 | sa = rti_info[RTAX_IFA]; | |
a3cc5c72 | 196 | |
2b484d24 A |
197 | if (sa->sa_family != family) |
198 | continue; | |
199 | switch (sa->sa_family) { | |
200 | case AF_INET: { | |
201 | struct sockaddr_in *sin = (struct sockaddr_in *)sa; | |
a3cc5c72 | 202 | |
2b484d24 A |
203 | fmt = routename(sin->sin_addr.s_addr); |
204 | break; | |
205 | } | |
206 | #ifdef INET6 | |
207 | case AF_INET6: { | |
b8dff150 A |
208 | struct sockaddr_in6 sin6; |
209 | ||
210 | memcpy(&sin6, sa, sizeof(struct sockaddr_in6)); | |
211 | ||
212 | if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) || | |
fdfd5971 | 213 | IN6_IS_ADDR_MC_NODELOCAL(&sin6.sin6_addr) || |
b8dff150 | 214 | IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) { |
9c859447 | 215 | sin6.sin6_scope_id = ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); |
b8dff150 A |
216 | sin6.sin6_addr.s6_addr[2] = 0; |
217 | sin6.sin6_addr.s6_addr[3] = 0; | |
218 | } | |
2b484d24 A |
219 | |
220 | printf("%23s %-19.19s(refs: %d)\n", "", | |
9c859447 A |
221 | inet_ntop(AF_INET6, &sin6.sin6_addr, |
222 | ntop_buf, sizeof(ntop_buf)), | |
2b484d24 A |
223 | ifmam->ifmam_refcount); |
224 | break; | |
225 | } | |
226 | #endif /* INET6 */ | |
227 | case AF_LINK: { | |
228 | struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; | |
a3cc5c72 | 229 | |
2b484d24 A |
230 | switch (sdl->sdl_type) { |
231 | case IFT_ETHER: | |
232 | case IFT_FDDI: | |
9c859447 | 233 | fmt = ether_ntoa((struct ether_addr *) |
2b484d24 A |
234 | LLADDR(sdl)); |
235 | break; | |
236 | } | |
237 | break; | |
238 | } | |
239 | } | |
240 | if (fmt) | |
241 | printf("%23s %s\n", "", fmt); | |
242 | } | |
243 | } | |
b7080c8e A |
244 | |
245 | /* | |
246 | * Print a description of the network interfaces. | |
247 | */ | |
248 | void | |
2b484d24 | 249 | intpr(void (*pfunc)(char *)) |
b7080c8e | 250 | { |
2b484d24 A |
251 | u_int64_t opackets = 0; |
252 | u_int64_t ipackets = 0; | |
253 | u_int64_t obytes = 0; | |
254 | u_int64_t ibytes = 0; | |
255 | u_int64_t oerrors = 0; | |
256 | u_int64_t ierrors = 0; | |
257 | u_int64_t collisions = 0; | |
9dc66a05 A |
258 | u_int64_t fpackets = 0; |
259 | u_int64_t fbytes = 0; | |
9c859447 | 260 | uint32_t mtu = 0; |
9dc66a05 | 261 | int timer = 0; |
2b484d24 | 262 | int drops = 0; |
7ba0088d | 263 | struct sockaddr *sa = NULL; |
2b484d24 | 264 | char name[32]; |
7ba0088d A |
265 | short network_layer; |
266 | short link_layer; | |
9dc66a05 A |
267 | int mib[6]; |
268 | char *buf = NULL, *lim, *next; | |
2b484d24 A |
269 | size_t len; |
270 | struct if_msghdr *ifm; | |
271 | struct sockaddr *rti_info[RTAX_MAX]; | |
272 | unsigned int ifindex = 0; | |
9dc66a05 | 273 | |
b7080c8e | 274 | if (interval) { |
2b484d24 | 275 | sidewaysintpr(); |
b7080c8e A |
276 | return; |
277 | } | |
9dc66a05 | 278 | |
2b484d24 A |
279 | if (interface != 0) |
280 | ifindex = if_nametoindex(interface); | |
9dc66a05 | 281 | |
2b484d24 A |
282 | mib[0] = CTL_NET; // networking subsystem |
283 | mib[1] = PF_ROUTE; // type of information | |
284 | mib[2] = 0; // protocol (IPPROTO_xxx) | |
285 | mib[3] = 0; // address family | |
286 | mib[4] = NET_RT_IFLIST2; // operation | |
287 | mib[5] = 0; | |
288 | if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) | |
b7080c8e | 289 | return; |
2b484d24 A |
290 | if ((buf = malloc(len)) == NULL) { |
291 | printf("malloc failed\n"); | |
292 | exit(1); | |
293 | } | |
294 | if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { | |
295 | if (buf) | |
296 | free(buf); | |
b7080c8e | 297 | return; |
2b484d24 | 298 | } |
fdfd5971 | 299 | |
7ba0088d | 300 | if (!pfunc) { |
e0b07f2d A |
301 | if (lflag) { |
302 | printf("%-10.10s %-5.5s %-39.39s %-39.39s %8.8s %5.5s", | |
303 | "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs"); | |
304 | } else { | |
305 | printf("%-10.10s %-5.5s %-13.13s %-15.15s %8.8s %5.5s", | |
306 | "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs"); | |
307 | } | |
fdfd5971 | 308 | if (prioflag >= 0) |
7af5ce03 | 309 | printf(" %8.8s %8.8s", "Itcpkts", "Ipvpkts"); |
fdfd5971 | 310 | if (bflag) { |
7ba0088d | 311 | printf(" %10.10s","Ibytes"); |
fdfd5971 | 312 | if (prioflag >= 0) |
7af5ce03 | 313 | printf(" %8.8s %8.8s", "Itcbytes", "Ipvbytes"); |
fdfd5971 | 314 | } |
7ba0088d | 315 | printf(" %8.8s %5.5s", "Opkts", "Oerrs"); |
fdfd5971 | 316 | if (prioflag >= 0) |
7af5ce03 | 317 | printf(" %8.8s %8.8s", "Otcpkts", "Opvpkts"); |
fdfd5971 | 318 | if (bflag) { |
7ba0088d | 319 | printf(" %10.10s","Obytes"); |
fdfd5971 | 320 | if (prioflag >= 0) |
7af5ce03 | 321 | printf(" %8.8s %8.8s", "Otcbytes", "Opvbytes"); |
fdfd5971 | 322 | } |
7ba0088d A |
323 | printf(" %5s", "Coll"); |
324 | if (tflag) | |
325 | printf(" %s", "Time"); | |
326 | if (dflag) | |
327 | printf(" %s", "Drop"); | |
9dc66a05 A |
328 | if (Fflag) { |
329 | printf(" %8.8s", "Fpkts"); | |
330 | if (bflag) | |
331 | printf(" %10.10s", "Fbytes"); | |
332 | } | |
7ba0088d A |
333 | putchar('\n'); |
334 | } | |
9dc66a05 A |
335 | lim = buf + len; |
336 | for (next = buf; next < lim; ) { | |
2b484d24 | 337 | char *cp; |
b7080c8e | 338 | int n, m; |
fdfd5971 | 339 | struct ifmibdata_supplemental ifmsupp; |
9dc66a05 A |
340 | u_int64_t ift_itcp = 0; /* input tc packets */ |
341 | u_int64_t ift_itcb = 0; /* input tc bytes */ | |
342 | u_int64_t ift_otcp = 0; /* output tc packets */ | |
343 | u_int64_t ift_otcb = 0; /* output tc bytes */ | |
7af5ce03 A |
344 | u_int64_t ift_ipvp = 0; /* input priv tc packets */ |
345 | u_int64_t ift_ipvb = 0; /* input priv tc bytes */ | |
346 | u_int64_t ift_opvp = 0; /* output priv tc packets */ | |
347 | u_int64_t ift_opvb = 0; /* output priv tc bytes */ | |
348 | ||
fdfd5971 | 349 | bzero(&ifmsupp, sizeof(struct ifmibdata_supplemental)); |
9dc66a05 | 350 | |
7ba0088d A |
351 | network_layer = 0; |
352 | link_layer = 0; | |
9dc66a05 | 353 | ifm = (struct if_msghdr *)next; |
2b484d24 A |
354 | next += ifm->ifm_msglen; |
355 | ||
9dc66a05 | 356 | if (ifm->ifm_type == RTM_IFINFO2) { |
2b484d24 | 357 | struct if_msghdr2 *if2m = (struct if_msghdr2 *)ifm; |
9dc66a05 A |
358 | struct sockaddr_dl *sdl = |
359 | (struct sockaddr_dl *)(if2m + 1); | |
360 | int mibname[6]; | |
361 | size_t miblen = sizeof(struct ifmibdata_supplemental); | |
7ba0088d | 362 | |
2b484d24 | 363 | if (interface != 0 && if2m->ifm_index != ifindex) |
b7080c8e | 364 | continue; |
e0b07f2d A |
365 | |
366 | /* The interface name is not a zero-ended string */ | |
367 | memcpy(name, sdl->sdl_data, MIN(sizeof(name) - 1, sdl->sdl_nlen)); | |
368 | name[MIN(sizeof(name) - 1, sdl->sdl_nlen)] = 0; | |
7ba0088d A |
369 | |
370 | if (pfunc) { | |
371 | (*pfunc)(name); | |
372 | continue; | |
373 | } | |
374 | ||
e0b07f2d | 375 | cp = index(name, '\0'); |
2b484d24 | 376 | if ((if2m->ifm_flags & IFF_UP) == 0) |
b7080c8e A |
377 | *cp++ = '*'; |
378 | *cp = '\0'; | |
2b484d24 A |
379 | |
380 | /* | |
381 | * Get the interface stats. These may get | |
382 | * overriden below on a per-interface basis. | |
383 | */ | |
384 | opackets = if2m->ifm_data.ifi_opackets; | |
385 | ipackets = if2m->ifm_data.ifi_ipackets; | |
386 | obytes = if2m->ifm_data.ifi_obytes; | |
387 | ibytes = if2m->ifm_data.ifi_ibytes; | |
388 | oerrors =if2m->ifm_data.ifi_oerrors; | |
389 | ierrors = if2m->ifm_data.ifi_ierrors; | |
390 | collisions = if2m->ifm_data.ifi_collisions; | |
391 | timer = if2m->ifm_timer; | |
392 | drops = if2m->ifm_snd_drops; | |
393 | mtu = if2m->ifm_data.ifi_mtu; | |
394 | ||
9dc66a05 A |
395 | /* Common OID prefix */ |
396 | mibname[0] = CTL_NET; | |
397 | mibname[1] = PF_LINK; | |
398 | mibname[2] = NETLINK_GENERIC; | |
399 | mibname[3] = IFMIB_IFDATA; | |
400 | mibname[4] = if2m->ifm_index; | |
401 | mibname[5] = IFDATA_SUPPLEMENTAL; | |
402 | if (sysctl(mibname, 6, &ifmsupp, &miblen, NULL, 0) == -1) | |
403 | err(1, "sysctl IFDATA_SUPPLEMENTAL"); | |
fdfd5971 | 404 | |
9dc66a05 A |
405 | fpackets = ifmsupp.ifmd_data_extended.ifi_fpackets; |
406 | fbytes = ifmsupp.ifmd_data_extended.ifi_fbytes; | |
407 | ||
408 | if (prioflag >= 0) { | |
fdfd5971 | 409 | switch (prioflag) { |
9dc66a05 A |
410 | case SO_TC_BE: |
411 | ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ibepackets; | |
412 | ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ibebytes; | |
413 | ift_otcp = ifmsupp.ifmd_traffic_class.ifi_obepackets; | |
414 | ift_otcb = ifmsupp.ifmd_traffic_class.ifi_obebytes; | |
415 | break; | |
416 | case SO_TC_BK: | |
417 | ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ibkpackets; | |
418 | ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ibkbytes; | |
419 | ift_otcp = ifmsupp.ifmd_traffic_class.ifi_obkpackets; | |
420 | ift_otcb = ifmsupp.ifmd_traffic_class.ifi_obkbytes; | |
421 | break; | |
422 | case SO_TC_VI: | |
423 | ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ivipackets; | |
424 | ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ivibytes; | |
425 | ift_otcp = ifmsupp.ifmd_traffic_class.ifi_ovipackets; | |
426 | ift_otcb = ifmsupp.ifmd_traffic_class.ifi_ovibytes; | |
427 | break; | |
428 | case SO_TC_VO: | |
429 | ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ivopackets; | |
430 | ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ivobytes; | |
431 | ift_otcp = ifmsupp.ifmd_traffic_class.ifi_ovopackets; | |
432 | ift_otcb = ifmsupp.ifmd_traffic_class.ifi_ovobytes; | |
433 | break; | |
434 | default: | |
435 | ift_itcp = 0; | |
436 | ift_itcb = 0; | |
437 | ift_otcp = 0; | |
438 | ift_otcb = 0; | |
439 | ift_ipvp = 0; | |
440 | ift_ipvb = 0; | |
441 | ift_opvp = 0; | |
442 | ift_opvb = 0; | |
443 | break; | |
fdfd5971 | 444 | } |
7af5ce03 A |
445 | ift_ipvp = ifmsupp.ifmd_traffic_class.ifi_ipvpackets; |
446 | ift_ipvb = ifmsupp.ifmd_traffic_class.ifi_ipvbytes; | |
447 | ift_opvp = ifmsupp.ifmd_traffic_class.ifi_opvpackets; | |
448 | ift_opvb = ifmsupp.ifmd_traffic_class.ifi_opvbytes; | |
fdfd5971 A |
449 | } |
450 | ||
9dc66a05 A |
451 | get_rti_info(if2m->ifm_addrs, |
452 | (struct sockaddr*)(if2m + 1), rti_info); | |
2b484d24 | 453 | sa = rti_info[RTAX_IFP]; |
9dc66a05 A |
454 | } else if (ifm->ifm_type == RTM_NEWADDR) { |
455 | struct ifa_msghdr *ifam = (struct ifa_msghdr *)ifm; | |
456 | ||
2b484d24 A |
457 | if (interface != 0 && ifam->ifam_index != ifindex) |
458 | continue; | |
9dc66a05 A |
459 | get_rti_info(ifam->ifam_addrs, |
460 | (struct sockaddr*)(ifam + 1), rti_info); | |
2b484d24 | 461 | sa = rti_info[RTAX_IFA]; |
9c859447 | 462 | } else { |
2b484d24 | 463 | continue; |
9c859447 | 464 | } |
e0b07f2d A |
465 | if (lflag) { |
466 | printf("%-10.10s %-5u ", name, mtu); | |
467 | } else { | |
468 | printf("%-5.5s %-5u ", name, mtu); | |
469 | } | |
2b484d24 A |
470 | |
471 | if (sa == 0) { | |
e0b07f2d A |
472 | printf(lflag ? "%-39.39s " : "%-13.13s ", "none"); |
473 | printf(lflag ? "%-39.39s " : "%-15.15s ", "none"); | |
b7080c8e | 474 | } else { |
b7080c8e A |
475 | switch (sa->sa_family) { |
476 | case AF_UNSPEC: | |
e0b07f2d A |
477 | printf(lflag ? "%-39.39s " : "%-13.13s ", "none"); |
478 | printf(lflag ? "%-39.39s " : "%-15.15s ", "none"); | |
b7080c8e | 479 | break; |
9c859447 | 480 | |
2b484d24 | 481 | case AF_INET: { |
9dc66a05 A |
482 | struct sockaddr_in *sin = |
483 | (struct sockaddr_in *)sa; | |
2b484d24 | 484 | struct sockaddr_in mask; |
9dc66a05 | 485 | |
2b484d24 | 486 | mask.sin_addr.s_addr = 0; |
9dc66a05 A |
487 | memcpy(&mask, rti_info[RTAX_NETMASK], |
488 | ((struct sockaddr_in *) | |
489 | rti_info[RTAX_NETMASK])->sin_len); | |
490 | ||
e0b07f2d | 491 | printf(lflag ? "%-39.39s " : "%-13.13s ", |
9dc66a05 A |
492 | netname(sin->sin_addr.s_addr & |
493 | mask.sin_addr.s_addr, | |
3a228055 | 494 | ntohl(mask.sin_addr.s_addr))); |
2b484d24 | 495 | |
e0b07f2d | 496 | printf(lflag ? "%-39.39s " : "%-15.15s ", |
b7080c8e | 497 | routename(sin->sin_addr.s_addr)); |
7ba0088d A |
498 | |
499 | network_layer = 1; | |
b7080c8e | 500 | break; |
2b484d24 | 501 | } |
7ba0088d | 502 | #ifdef INET6 |
2b484d24 | 503 | case AF_INET6: { |
9dc66a05 A |
504 | struct sockaddr_in6 *sin6 = |
505 | (struct sockaddr_in6 *)sa; | |
506 | struct sockaddr *mask = | |
507 | (struct sockaddr *)rti_info[RTAX_NETMASK]; | |
2b484d24 | 508 | |
e0b07f2d A |
509 | printf(lflag ? "%-39.39s " : "%-11.11s ", netname6(sin6, mask)); |
510 | printf(lflag ? "%-39.39s " : "%-17.17s ", (char *)inet_ntop(AF_INET6, | |
9dc66a05 A |
511 | &sin6->sin6_addr, ntop_buf, |
512 | sizeof(ntop_buf))); | |
b7080c8e | 513 | |
7ba0088d A |
514 | network_layer = 1; |
515 | break; | |
2b484d24 | 516 | } |
7ba0088d | 517 | #endif /*INET6*/ |
9c859447 | 518 | case AF_LINK: { |
b7080c8e | 519 | struct sockaddr_dl *sdl = |
9dc66a05 | 520 | (struct sockaddr_dl *)sa; |
7ba0088d A |
521 | char linknum[10]; |
522 | cp = (char *)LLADDR(sdl); | |
523 | n = sdl->sdl_alen; | |
9dc66a05 A |
524 | snprintf(linknum, sizeof(linknum), |
525 | "<Link#%d>", sdl->sdl_index); | |
e0b07f2d | 526 | m = printf(lflag ? "%-39.39s " : "%-11.11s ", linknum); |
b7080c8e | 527 | goto hexprint; |
9c859447 A |
528 | } |
529 | ||
b7080c8e A |
530 | default: |
531 | m = printf("(%d)", sa->sa_family); | |
532 | for (cp = sa->sa_len + (char *)sa; | |
533 | --cp > sa->sa_data && (*cp == 0);) {} | |
534 | n = cp - sa->sa_data + 1; | |
535 | cp = sa->sa_data; | |
536 | hexprint: | |
537 | while (--n >= 0) | |
538 | m += printf("%02x%c", *cp++ & 0xff, | |
7ba0088d | 539 | n > 0 ? ':' : ' '); |
e0b07f2d | 540 | m = (lflag ? 80 : 30) - m; |
b7080c8e A |
541 | while (m-- > 0) |
542 | putchar(' '); | |
7ba0088d A |
543 | |
544 | link_layer = 1; | |
b7080c8e A |
545 | break; |
546 | } | |
9dc66a05 | 547 | } |
7ba0088d | 548 | |
2b484d24 | 549 | show_stat("llu", 8, ipackets, link_layer|network_layer); |
7ba0088d | 550 | printf(" "); |
2b484d24 | 551 | show_stat("llu", 5, ierrors, link_layer); |
7ba0088d | 552 | printf(" "); |
fdfd5971 A |
553 | if (prioflag >= 0) { |
554 | show_stat("llu", 8, ift_itcp, link_layer|network_layer); | |
555 | printf(" "); | |
7af5ce03 A |
556 | show_stat("llu", 8, ift_ipvp, link_layer|network_layer); |
557 | printf(" "); | |
fdfd5971 | 558 | } |
7ba0088d | 559 | if (bflag) { |
2b484d24 | 560 | show_stat("llu", 10, ibytes, link_layer|network_layer); |
7ba0088d | 561 | printf(" "); |
fdfd5971 A |
562 | if (prioflag >= 0) { |
563 | show_stat("llu", 8, ift_itcb, link_layer|network_layer); | |
564 | printf(" "); | |
7af5ce03 A |
565 | show_stat("llu", 8, ift_ipvb, link_layer|network_layer); |
566 | printf(" "); | |
fdfd5971 | 567 | } |
7ba0088d | 568 | } |
2b484d24 | 569 | show_stat("llu", 8, opackets, link_layer|network_layer); |
7ba0088d | 570 | printf(" "); |
2b484d24 | 571 | show_stat("llu", 5, oerrors, link_layer); |
7ba0088d | 572 | printf(" "); |
fdfd5971 A |
573 | if (prioflag >= 0) { |
574 | show_stat("llu", 8, ift_otcp, link_layer|network_layer); | |
575 | printf(" "); | |
7af5ce03 A |
576 | show_stat("llu", 8, ift_opvp, link_layer|network_layer); |
577 | printf(" "); | |
fdfd5971 | 578 | } |
7ba0088d | 579 | if (bflag) { |
2b484d24 | 580 | show_stat("llu", 10, obytes, link_layer|network_layer); |
7ba0088d | 581 | printf(" "); |
fdfd5971 A |
582 | if (prioflag >= 0) { |
583 | show_stat("llu", 8, ift_otcb, link_layer|network_layer); | |
584 | printf(" "); | |
7af5ce03 A |
585 | show_stat("llu", 8, ift_opvb, link_layer|network_layer); |
586 | printf(" "); | |
fdfd5971 | 587 | } |
7ba0088d | 588 | } |
2b484d24 | 589 | show_stat("llu", 5, collisions, link_layer); |
7ba0088d A |
590 | if (tflag) { |
591 | printf(" "); | |
9dc66a05 | 592 | show_stat("d", 3, timer, link_layer); |
7ba0088d A |
593 | } |
594 | if (dflag) { | |
595 | printf(" "); | |
9dc66a05 A |
596 | show_stat("d", 3, drops, link_layer); |
597 | } | |
598 | if (Fflag) { | |
599 | printf(" "); | |
600 | show_stat("llu", 8, fpackets, link_layer|network_layer); | |
601 | if (bflag) { | |
602 | printf(" "); | |
603 | show_stat("llu", 10, fbytes, | |
604 | link_layer|network_layer); | |
605 | } | |
b7080c8e | 606 | } |
b7080c8e | 607 | putchar('\n'); |
2b484d24 | 608 | |
9dc66a05 | 609 | if (aflag) |
2b484d24 | 610 | multipr(sa->sa_family, next, lim); |
b7080c8e | 611 | } |
fdfd5971 | 612 | free(buf); |
b7080c8e A |
613 | } |
614 | ||
b7080c8e | 615 | struct iftot { |
7ba0088d | 616 | SLIST_ENTRY(iftot) chain; |
2b484d24 | 617 | char ift_name[16]; /* interface name */ |
9dc66a05 A |
618 | u_int64_t ift_ip; /* input packets */ |
619 | u_int64_t ift_ie; /* input errors */ | |
620 | u_int64_t ift_op; /* output packets */ | |
621 | u_int64_t ift_oe; /* output errors */ | |
622 | u_int64_t ift_co; /* collisions */ | |
623 | u_int64_t ift_dr; /* drops */ | |
624 | u_int64_t ift_ib; /* input bytes */ | |
625 | u_int64_t ift_ob; /* output bytes */ | |
626 | u_int64_t ift_itcp; /* input tc packets */ | |
627 | u_int64_t ift_itcb; /* input tc bytes */ | |
628 | u_int64_t ift_otcp; /* output tc packets */ | |
629 | u_int64_t ift_otcb; /* output tc bytes */ | |
630 | u_int64_t ift_ipvp; /* input priv tc packets */ | |
631 | u_int64_t ift_ipvb; /* input priv tc bytes */ | |
632 | u_int64_t ift_opvp; /* output priv tc packets */ | |
633 | u_int64_t ift_opvb; /* output priv tc bytes */ | |
634 | u_int64_t ift_fp; /* forwarded packets */ | |
635 | u_int64_t ift_fb; /* forwarded bytes */ | |
7ba0088d | 636 | }; |
b7080c8e A |
637 | |
638 | u_char signalled; /* set if alarm goes off "early" */ | |
639 | ||
640 | /* | |
641 | * Print a running summary of interface statistics. | |
642 | * Repeat display every interval seconds, showing statistics | |
643 | * collected over that interval. Assumes that interval is non-zero. | |
644 | * First line printed at top of screen is always cumulative. | |
645 | * XXX - should be rewritten to use ifmib(4). | |
646 | */ | |
647 | static void | |
2b484d24 | 648 | sidewaysintpr() |
b7080c8e | 649 | { |
2b484d24 | 650 | struct iftot *total, *sum, *interesting; |
b7080c8e | 651 | register int line; |
b8dff150 | 652 | int first; |
2b484d24 A |
653 | int name[6]; |
654 | size_t len; | |
655 | unsigned int ifcount, i; | |
656 | struct ifmibdata *ifmdall = 0; | |
657 | int interesting_row; | |
b8dff150 A |
658 | sigset_t sigset, oldsigset; |
659 | struct itimerval timer_interval; | |
660 | ||
2b484d24 A |
661 | /* Common OID prefix */ |
662 | name[0] = CTL_NET; | |
663 | name[1] = PF_LINK; | |
664 | name[2] = NETLINK_GENERIC; | |
665 | ||
666 | len = sizeof(int); | |
667 | name[3] = IFMIB_SYSTEM; | |
668 | name[4] = IFMIB_IFCOUNT; | |
669 | if (sysctl(name, 5, &ifcount, &len, 0, 0) == 1) | |
670 | err(1, "sysctl IFMIB_IFCOUNT"); | |
671 | ||
672 | len = ifcount * sizeof(struct ifmibdata); | |
673 | ifmdall = malloc(len); | |
674 | if (ifmdall == 0) | |
675 | err(1, "malloc failed"); | |
676 | name[3] = IFMIB_IFALLDATA; | |
677 | name[4] = 0; | |
678 | name[5] = IFDATA_GENERAL; | |
679 | if (sysctl(name, 6, ifmdall, &len, (void *)0, 0) == -1) | |
680 | err(1, "sysctl IFMIB_IFALLDATA"); | |
9dc66a05 | 681 | |
b7080c8e | 682 | interesting = NULL; |
2b484d24 A |
683 | interesting_row = 0; |
684 | for (i = 0; i < ifcount; i++) { | |
685 | struct ifmibdata *ifmd = ifmdall + i; | |
9dc66a05 | 686 | |
2b484d24 | 687 | if (interface && strcmp(ifmd->ifmd_name, interface) == 0) { |
9dc66a05 A |
688 | if ((interesting = calloc(ifcount, |
689 | sizeof(struct iftot))) == NULL) | |
2b484d24 | 690 | err(1, "malloc failed"); |
fdfd5971 | 691 | interesting_row = if_nametoindex(interface); |
9dc66a05 A |
692 | snprintf(interesting->ift_name, 16, "(%s)", |
693 | ifmd->ifmd_name);; | |
7ba0088d | 694 | } |
7ba0088d | 695 | } |
2b484d24 A |
696 | if ((total = calloc(1, sizeof(struct iftot))) == NULL) |
697 | err(1, "malloc failed"); | |
698 | ||
699 | if ((sum = calloc(1, sizeof(struct iftot))) == NULL) | |
700 | err(1, "malloc failed"); | |
7ba0088d | 701 | |
b8dff150 A |
702 | /* create a timer that fires repeatedly every interval seconds */ |
703 | timer_interval.it_value.tv_sec = interval; | |
704 | timer_interval.it_value.tv_usec = 0; | |
705 | timer_interval.it_interval.tv_sec = interval; | |
706 | timer_interval.it_interval.tv_usec = 0; | |
b7080c8e A |
707 | (void)signal(SIGALRM, catchalarm); |
708 | signalled = NO; | |
b8dff150 | 709 | (void)setitimer(ITIMER_REAL, &timer_interval, NULL); |
b7080c8e A |
710 | first = 1; |
711 | banner: | |
9dc66a05 A |
712 | if (vflag > 0) |
713 | printf("%9s", " "); | |
714 | ||
fdfd5971 | 715 | if (prioflag >= 0) |
7af5ce03 | 716 | printf("%39s %39s %36s", "input", |
5902acfc A |
717 | interesting ? interesting->ift_name : "(Total)", "output"); |
718 | else | |
719 | printf("%17s %14s %16s", "input", | |
720 | interesting ? interesting->ift_name : "(Total)", "output"); | |
b7080c8e | 721 | putchar('\n'); |
9dc66a05 A |
722 | |
723 | if (vflag > 0) | |
724 | printf("%9s", " "); | |
725 | ||
726 | printf("%10s %5s %10s ", "packets", "errs", "bytes"); | |
fdfd5971 | 727 | if (prioflag >= 0) |
9dc66a05 A |
728 | printf(" %10s %10s %10s %10s", |
729 | "tcpkts", "tcbytes", "pvpkts", "pvbytes"); | |
730 | printf("%10s %5s %10s %5s", "packets", "errs", "bytes", "colls"); | |
b7080c8e A |
731 | if (dflag) |
732 | printf(" %5.5s", "drops"); | |
fdfd5971 | 733 | if (prioflag >= 0) |
9dc66a05 A |
734 | printf(" %10s %10s %10s %10s", |
735 | "tcpkts", "tcbytes", "pvpkts", "pvbytes"); | |
736 | if (Fflag) | |
737 | printf(" %10s %10s", "fpackets", "fbytes"); | |
b7080c8e A |
738 | putchar('\n'); |
739 | fflush(stdout); | |
740 | line = 0; | |
741 | loop: | |
9dc66a05 A |
742 | if (vflag && !first) |
743 | print_time(); | |
744 | ||
b7080c8e | 745 | if (interesting != NULL) { |
2b484d24 | 746 | struct ifmibdata ifmd; |
5902acfc | 747 | struct ifmibdata_supplemental ifmsupp; |
9dc66a05 | 748 | |
2b484d24 A |
749 | len = sizeof(struct ifmibdata); |
750 | name[3] = IFMIB_IFDATA; | |
751 | name[4] = interesting_row; | |
752 | name[5] = IFDATA_GENERAL; | |
753 | if (sysctl(name, 6, &ifmd, &len, (void *)0, 0) == -1) | |
754 | err(1, "sysctl IFDATA_GENERAL %d", interesting_row); | |
755 | ||
9dc66a05 A |
756 | len = sizeof(struct ifmibdata_supplemental); |
757 | name[3] = IFMIB_IFDATA; | |
758 | name[4] = interesting_row; | |
759 | name[5] = IFDATA_SUPPLEMENTAL; | |
760 | if (sysctl(name, 6, &ifmsupp, &len, (void *)0, 0) == -1) | |
761 | err(1, "sysctl IFDATA_SUPPLEMENTAL %d", | |
762 | interesting_row); | |
7af5ce03 | 763 | |
b7080c8e | 764 | if (!first) { |
5902acfc | 765 | printf("%10llu %5llu %10llu ", |
9dc66a05 A |
766 | ifmd.ifmd_data.ifi_ipackets - interesting->ift_ip, |
767 | ifmd.ifmd_data.ifi_ierrors - interesting->ift_ie, | |
768 | ifmd.ifmd_data.ifi_ibytes - interesting->ift_ib); | |
5902acfc | 769 | switch (prioflag) { |
9dc66a05 A |
770 | case SO_TC_BE: |
771 | printf("%10llu %10llu ", | |
772 | ifmsupp.ifmd_traffic_class.ifi_ibepackets - | |
773 | interesting->ift_itcp, | |
774 | ifmsupp.ifmd_traffic_class.ifi_ibebytes - | |
775 | interesting->ift_itcb); | |
776 | break; | |
777 | case SO_TC_BK: | |
778 | printf("%10llu %10llu ", | |
779 | ifmsupp.ifmd_traffic_class.ifi_ibkpackets - | |
780 | interesting->ift_itcp, | |
781 | ifmsupp.ifmd_traffic_class.ifi_ibkbytes - | |
782 | interesting->ift_itcb); | |
783 | break; | |
784 | case SO_TC_VI: | |
785 | printf("%10llu %10llu ", | |
786 | ifmsupp.ifmd_traffic_class.ifi_ivipackets - | |
787 | interesting->ift_itcp, | |
788 | ifmsupp.ifmd_traffic_class.ifi_ivibytes - | |
789 | interesting->ift_itcb); | |
790 | break; | |
791 | case SO_TC_VO: | |
792 | printf("%10llu %10llu ", | |
793 | ifmsupp.ifmd_traffic_class.ifi_ivopackets - | |
794 | interesting->ift_itcp, | |
795 | ifmsupp.ifmd_traffic_class.ifi_ivobytes - | |
796 | interesting->ift_itcb); | |
797 | break; | |
798 | default: | |
799 | break; | |
5902acfc | 800 | } |
7af5ce03 A |
801 | if (prioflag >= 0) { |
802 | printf("%10llu %10llu ", | |
9dc66a05 A |
803 | ifmsupp.ifmd_traffic_class.ifi_ipvpackets - |
804 | interesting->ift_ipvp, | |
805 | ifmsupp.ifmd_traffic_class.ifi_ipvbytes - | |
806 | interesting->ift_ipvb); | |
7af5ce03 | 807 | } |
5902acfc | 808 | printf("%10llu %5llu %10llu %5llu", |
9dc66a05 A |
809 | ifmd.ifmd_data.ifi_opackets - interesting->ift_op, |
810 | ifmd.ifmd_data.ifi_oerrors - interesting->ift_oe, | |
811 | ifmd.ifmd_data.ifi_obytes - interesting->ift_ob, | |
812 | ifmd.ifmd_data.ifi_collisions - interesting->ift_co); | |
b7080c8e | 813 | if (dflag) |
9dc66a05 A |
814 | printf(" %5llu", |
815 | ifmd.ifmd_snd_drops - interesting->ift_dr); | |
5902acfc | 816 | switch (prioflag) { |
9dc66a05 A |
817 | case SO_TC_BE: |
818 | printf(" %10llu %10llu", | |
819 | ifmsupp.ifmd_traffic_class.ifi_obepackets - | |
820 | interesting->ift_otcp, | |
821 | ifmsupp.ifmd_traffic_class.ifi_obebytes - | |
822 | interesting->ift_otcb); | |
823 | break; | |
824 | case SO_TC_BK: | |
825 | printf(" %10llu %10llu", | |
826 | ifmsupp.ifmd_traffic_class.ifi_obkpackets - | |
827 | interesting->ift_otcp, | |
828 | ifmsupp.ifmd_traffic_class.ifi_obkbytes - | |
829 | interesting->ift_otcb); | |
830 | break; | |
831 | case SO_TC_VI: | |
832 | printf(" %10llu %10llu", | |
833 | ifmsupp.ifmd_traffic_class.ifi_ovipackets - | |
834 | interesting->ift_otcp, | |
835 | ifmsupp.ifmd_traffic_class.ifi_ovibytes - | |
836 | interesting->ift_otcb); | |
837 | break; | |
838 | case SO_TC_VO: | |
839 | printf(" %10llu %10llu", | |
840 | ifmsupp.ifmd_traffic_class.ifi_ovopackets - | |
841 | interesting->ift_otcp, | |
842 | ifmsupp.ifmd_traffic_class.ifi_ovobytes - | |
843 | interesting->ift_otcb); | |
844 | break; | |
845 | default: | |
846 | break; | |
5902acfc | 847 | } |
7af5ce03 A |
848 | if (prioflag >= 0) { |
849 | printf("%10llu %10llu ", | |
9dc66a05 A |
850 | ifmsupp.ifmd_traffic_class.ifi_opvpackets - |
851 | interesting->ift_opvp, | |
852 | ifmsupp.ifmd_traffic_class.ifi_opvbytes - | |
853 | interesting->ift_opvb); | |
854 | } | |
855 | if (Fflag) { | |
856 | printf("%10llu %10llu", | |
857 | ifmsupp.ifmd_data_extended.ifi_fpackets - | |
858 | interesting->ift_fp, | |
859 | ifmsupp.ifmd_data_extended.ifi_fbytes - | |
860 | interesting->ift_fb); | |
7af5ce03 | 861 | } |
b7080c8e | 862 | } |
2b484d24 A |
863 | interesting->ift_ip = ifmd.ifmd_data.ifi_ipackets; |
864 | interesting->ift_ie = ifmd.ifmd_data.ifi_ierrors; | |
865 | interesting->ift_ib = ifmd.ifmd_data.ifi_ibytes; | |
866 | interesting->ift_op = ifmd.ifmd_data.ifi_opackets; | |
867 | interesting->ift_oe = ifmd.ifmd_data.ifi_oerrors; | |
868 | interesting->ift_ob = ifmd.ifmd_data.ifi_obytes; | |
869 | interesting->ift_co = ifmd.ifmd_data.ifi_collisions; | |
870 | interesting->ift_dr = ifmd.ifmd_snd_drops; | |
9dc66a05 | 871 | |
7f5b2e89 | 872 | /* private counters */ |
5902acfc | 873 | switch (prioflag) { |
9dc66a05 A |
874 | case SO_TC_BE: |
875 | interesting->ift_itcp = | |
876 | ifmsupp.ifmd_traffic_class.ifi_ibepackets; | |
877 | interesting->ift_itcb = | |
878 | ifmsupp.ifmd_traffic_class.ifi_ibebytes; | |
879 | interesting->ift_otcp = | |
880 | ifmsupp.ifmd_traffic_class.ifi_obepackets; | |
881 | interesting->ift_otcb = | |
882 | ifmsupp.ifmd_traffic_class.ifi_obebytes; | |
883 | break; | |
884 | case SO_TC_BK: | |
885 | interesting->ift_itcp = | |
886 | ifmsupp.ifmd_traffic_class.ifi_ibkpackets; | |
887 | interesting->ift_itcb = | |
888 | ifmsupp.ifmd_traffic_class.ifi_ibkbytes; | |
889 | interesting->ift_otcp = | |
890 | ifmsupp.ifmd_traffic_class.ifi_obkpackets; | |
891 | interesting->ift_otcb = | |
892 | ifmsupp.ifmd_traffic_class.ifi_obkbytes; | |
893 | break; | |
894 | case SO_TC_VI: | |
895 | interesting->ift_itcp = | |
896 | ifmsupp.ifmd_traffic_class.ifi_ivipackets; | |
897 | interesting->ift_itcb = | |
898 | ifmsupp.ifmd_traffic_class.ifi_ivibytes; | |
899 | interesting->ift_otcp = | |
900 | ifmsupp.ifmd_traffic_class.ifi_ovipackets; | |
901 | interesting->ift_otcb = | |
902 | ifmsupp.ifmd_traffic_class.ifi_ovibytes; | |
903 | break; | |
904 | case SO_TC_VO: | |
905 | interesting->ift_itcp = | |
906 | ifmsupp.ifmd_traffic_class.ifi_ivopackets; | |
907 | interesting->ift_itcb = | |
908 | ifmsupp.ifmd_traffic_class.ifi_ivobytes; | |
909 | interesting->ift_otcp = | |
910 | ifmsupp.ifmd_traffic_class.ifi_ovopackets; | |
911 | interesting->ift_otcb = | |
912 | ifmsupp.ifmd_traffic_class.ifi_ovobytes; | |
913 | break; | |
914 | default: | |
915 | break; | |
5902acfc | 916 | } |
7af5ce03 | 917 | if (prioflag >= 0) { |
9dc66a05 A |
918 | interesting->ift_ipvp = |
919 | ifmsupp.ifmd_traffic_class.ifi_ipvpackets; | |
920 | interesting->ift_ipvb = | |
921 | ifmsupp.ifmd_traffic_class.ifi_ipvbytes; | |
922 | interesting->ift_opvp = | |
923 | ifmsupp.ifmd_traffic_class.ifi_opvpackets; | |
924 | interesting->ift_opvb = | |
925 | ifmsupp.ifmd_traffic_class.ifi_opvbytes; | |
7af5ce03 | 926 | } |
9dc66a05 A |
927 | interesting->ift_fp = ifmsupp.ifmd_data_extended.ifi_fpackets; |
928 | interesting->ift_fb = ifmsupp.ifmd_data_extended.ifi_fbytes; | |
b7080c8e | 929 | } else { |
2b484d24 | 930 | unsigned int latest_ifcount; |
5902acfc | 931 | struct ifmibdata_supplemental *ifmsuppall = NULL; |
9dc66a05 | 932 | |
2b484d24 A |
933 | len = sizeof(int); |
934 | name[3] = IFMIB_SYSTEM; | |
935 | name[4] = IFMIB_IFCOUNT; | |
936 | if (sysctl(name, 5, &latest_ifcount, &len, 0, 0) == 1) | |
937 | err(1, "sysctl IFMIB_IFCOUNT"); | |
938 | if (latest_ifcount > ifcount) { | |
939 | ifcount = latest_ifcount; | |
940 | len = ifcount * sizeof(struct ifmibdata); | |
941 | free(ifmdall); | |
942 | ifmdall = malloc(len); | |
943 | if (ifmdall == 0) | |
5902acfc | 944 | err(1, "malloc ifmdall failed"); |
2b484d24 A |
945 | } else if (latest_ifcount > ifcount) { |
946 | ifcount = latest_ifcount; | |
947 | len = ifcount * sizeof(struct ifmibdata); | |
948 | } | |
949 | len = ifcount * sizeof(struct ifmibdata); | |
950 | name[3] = IFMIB_IFALLDATA; | |
951 | name[4] = 0; | |
952 | name[5] = IFDATA_GENERAL; | |
953 | if (sysctl(name, 6, ifmdall, &len, (void *)0, 0) == -1) | |
954 | err(1, "sysctl IFMIB_IFALLDATA"); | |
9dc66a05 A |
955 | |
956 | len = ifcount * sizeof(struct ifmibdata_supplemental); | |
957 | ifmsuppall = malloc(len); | |
958 | if (ifmsuppall == NULL) | |
959 | err(1, "malloc ifmsuppall failed"); | |
960 | name[3] = IFMIB_IFALLDATA; | |
961 | name[4] = 0; | |
962 | name[5] = IFDATA_SUPPLEMENTAL; | |
963 | if (sysctl(name, 6, ifmsuppall, &len, (void *)0, 0) == -1) | |
964 | err(1, "sysctl IFMIB_IFALLDATA SUPPLEMENTAL"); | |
965 | ||
b7080c8e A |
966 | sum->ift_ip = 0; |
967 | sum->ift_ie = 0; | |
968 | sum->ift_ib = 0; | |
969 | sum->ift_op = 0; | |
970 | sum->ift_oe = 0; | |
971 | sum->ift_ob = 0; | |
972 | sum->ift_co = 0; | |
973 | sum->ift_dr = 0; | |
5902acfc A |
974 | sum->ift_itcp = 0; |
975 | sum->ift_itcb = 0; | |
976 | sum->ift_otcp = 0; | |
977 | sum->ift_otcb = 0; | |
7af5ce03 A |
978 | sum->ift_ipvp = 0; |
979 | sum->ift_ipvb = 0; | |
980 | sum->ift_opvp = 0; | |
981 | sum->ift_opvb = 0; | |
9dc66a05 A |
982 | sum->ift_fp = 0; |
983 | sum->ift_fb = 0; | |
2b484d24 A |
984 | for (i = 0; i < ifcount; i++) { |
985 | struct ifmibdata *ifmd = ifmdall + i; | |
9dc66a05 A |
986 | struct ifmibdata_supplemental *ifmsupp = ifmsuppall + i; |
987 | ||
2b484d24 A |
988 | sum->ift_ip += ifmd->ifmd_data.ifi_ipackets; |
989 | sum->ift_ie += ifmd->ifmd_data.ifi_ierrors; | |
990 | sum->ift_ib += ifmd->ifmd_data.ifi_ibytes; | |
991 | sum->ift_op += ifmd->ifmd_data.ifi_opackets; | |
992 | sum->ift_oe += ifmd->ifmd_data.ifi_oerrors; | |
993 | sum->ift_ob += ifmd->ifmd_data.ifi_obytes; | |
994 | sum->ift_co += ifmd->ifmd_data.ifi_collisions; | |
995 | sum->ift_dr += ifmd->ifmd_snd_drops; | |
7f5b2e89 | 996 | /* private counters */ |
fdfd5971 | 997 | if (prioflag >= 0) { |
5902acfc | 998 | switch (prioflag) { |
9dc66a05 A |
999 | case SO_TC_BE: |
1000 | sum->ift_itcp += ifmsupp->ifmd_traffic_class.ifi_ibepackets; | |
1001 | sum->ift_itcb += ifmsupp->ifmd_traffic_class.ifi_ibebytes; | |
1002 | sum->ift_otcp += ifmsupp->ifmd_traffic_class.ifi_obepackets; | |
1003 | sum->ift_otcb += ifmsupp->ifmd_traffic_class.ifi_obebytes; | |
1004 | break; | |
1005 | case SO_TC_BK: | |
1006 | sum->ift_itcp += ifmsupp->ifmd_traffic_class.ifi_ibkpackets; | |
1007 | sum->ift_itcb += ifmsupp->ifmd_traffic_class.ifi_ibkbytes; | |
1008 | sum->ift_otcp += ifmsupp->ifmd_traffic_class.ifi_obkpackets; | |
1009 | sum->ift_otcb += ifmsupp->ifmd_traffic_class.ifi_obkbytes; | |
1010 | break; | |
1011 | case SO_TC_VI: | |
1012 | sum->ift_itcp += ifmsupp->ifmd_traffic_class.ifi_ivipackets; | |
1013 | sum->ift_itcb += ifmsupp->ifmd_traffic_class.ifi_ivibytes; | |
1014 | sum->ift_otcp += ifmsupp->ifmd_traffic_class.ifi_ovipackets; | |
1015 | sum->ift_otcb += ifmsupp->ifmd_traffic_class.ifi_ovibytes; | |
1016 | break; | |
1017 | case SO_TC_VO: | |
1018 | sum->ift_itcp += ifmsupp->ifmd_traffic_class.ifi_ivopackets; | |
1019 | sum->ift_itcb += ifmsupp->ifmd_traffic_class.ifi_ivobytes; | |
1020 | sum->ift_otcp += ifmsupp->ifmd_traffic_class.ifi_ovopackets; | |
1021 | sum->ift_otcb += ifmsupp->ifmd_traffic_class.ifi_ovobytes; | |
1022 | break; | |
1023 | default: | |
1024 | break; | |
5902acfc | 1025 | } |
7af5ce03 A |
1026 | sum->ift_ipvp += ifmsupp->ifmd_traffic_class.ifi_ipvpackets; |
1027 | sum->ift_ipvb += ifmsupp->ifmd_traffic_class.ifi_ipvbytes; | |
1028 | sum->ift_opvp += ifmsupp->ifmd_traffic_class.ifi_opvpackets; | |
1029 | sum->ift_opvb += ifmsupp->ifmd_traffic_class.ifi_opvbytes; | |
5902acfc | 1030 | } |
9dc66a05 A |
1031 | sum->ift_fp += ifmsupp->ifmd_data_extended.ifi_fpackets; |
1032 | sum->ift_fb += ifmsupp->ifmd_data_extended.ifi_fbytes; | |
b7080c8e A |
1033 | } |
1034 | if (!first) { | |
5902acfc | 1035 | printf("%10llu %5llu %10llu ", |
b7080c8e A |
1036 | sum->ift_ip - total->ift_ip, |
1037 | sum->ift_ie - total->ift_ie, | |
5902acfc | 1038 | sum->ift_ib - total->ift_ib); |
fdfd5971 | 1039 | if (prioflag >= 0) |
7af5ce03 | 1040 | printf(" %10llu %10llu %10llu %10llu", |
5902acfc | 1041 | sum->ift_itcp - total->ift_itcp, |
7af5ce03 A |
1042 | sum->ift_itcb - total->ift_itcb, |
1043 | sum->ift_ipvp - total->ift_ipvp, | |
1044 | sum->ift_ipvb - total->ift_ipvb); | |
5902acfc | 1045 | printf("%10llu %5llu %10llu %5llu", |
b7080c8e A |
1046 | sum->ift_op - total->ift_op, |
1047 | sum->ift_oe - total->ift_oe, | |
1048 | sum->ift_ob - total->ift_ob, | |
1049 | sum->ift_co - total->ift_co); | |
1050 | if (dflag) | |
2b484d24 | 1051 | printf(" %5llu", sum->ift_dr - total->ift_dr); |
fdfd5971 | 1052 | if (prioflag >= 0) |
7af5ce03 | 1053 | printf(" %10llu %10llu %10llu %10llu", |
5902acfc | 1054 | sum->ift_otcp - total->ift_otcp, |
7af5ce03 A |
1055 | sum->ift_otcb - total->ift_otcb, |
1056 | sum->ift_opvp - total->ift_opvp, | |
1057 | sum->ift_opvb - total->ift_opvb); | |
9dc66a05 A |
1058 | if (Fflag) |
1059 | printf(" %10llu %10llu", | |
1060 | sum->ift_fp - total->ift_fp, | |
1061 | sum->ift_fb - total->ift_fb); | |
b7080c8e A |
1062 | } |
1063 | *total = *sum; | |
a3cc5c72 | 1064 | |
26c66ce9 | 1065 | free(ifmsuppall); |
b7080c8e A |
1066 | } |
1067 | if (!first) | |
1068 | putchar('\n'); | |
1069 | fflush(stdout); | |
b8dff150 A |
1070 | sigemptyset(&sigset); |
1071 | sigaddset(&sigset, SIGALRM); | |
1072 | (void)sigprocmask(SIG_BLOCK, &sigset, &oldsigset); | |
1073 | if (!signalled) { | |
1074 | sigemptyset(&sigset); | |
1075 | sigsuspend(&sigset); | |
b7080c8e | 1076 | } |
b8dff150 A |
1077 | (void)sigprocmask(SIG_SETMASK, &oldsigset, NULL); |
1078 | ||
b7080c8e | 1079 | signalled = NO; |
b7080c8e A |
1080 | line++; |
1081 | first = 0; | |
1082 | if (line == 21) | |
1083 | goto banner; | |
1084 | else | |
1085 | goto loop; | |
1086 | /*NOTREACHED*/ | |
1087 | } | |
1088 | ||
b8dff150 | 1089 | void |
9c859447 | 1090 | intervalpr(void (*pr)(uint32_t, char *, int), uint32_t off, char *name , int af) |
b8dff150 A |
1091 | { |
1092 | struct itimerval timer_interval; | |
1093 | sigset_t sigset, oldsigset; | |
1094 | ||
1095 | /* create a timer that fires repeatedly every interval seconds */ | |
1096 | timer_interval.it_value.tv_sec = interval; | |
1097 | timer_interval.it_value.tv_usec = 0; | |
1098 | timer_interval.it_interval.tv_sec = interval; | |
1099 | timer_interval.it_interval.tv_usec = 0; | |
1100 | (void) signal(SIGALRM, catchalarm); | |
1101 | signalled = NO; | |
1102 | (void) setitimer(ITIMER_REAL, &timer_interval, NULL); | |
1103 | ||
1104 | for (;;) { | |
1105 | pr(off, name, af); | |
1106 | ||
1107 | fflush(stdout); | |
1108 | sigemptyset(&sigset); | |
1109 | sigaddset(&sigset, SIGALRM); | |
1110 | (void) sigprocmask(SIG_BLOCK, &sigset, &oldsigset); | |
1111 | if (!signalled) { | |
1112 | sigemptyset(&sigset); | |
1113 | sigsuspend(&sigset); | |
1114 | } | |
1115 | (void) sigprocmask(SIG_SETMASK, &oldsigset, NULL); | |
1116 | signalled = NO; | |
1117 | } | |
1118 | } | |
1119 | ||
b7080c8e A |
1120 | /* |
1121 | * Called if an interval expires before sidewaysintpr has completed a loop. | |
1122 | * Sets a flag to not wait for the alarm. | |
1123 | */ | |
1124 | static void | |
7ba0088d | 1125 | catchalarm(int signo ) |
b7080c8e A |
1126 | { |
1127 | signalled = YES; | |
1128 | } | |
fdfd5971 A |
1129 | |
1130 | static char * | |
1131 | sec2str(total) | |
1132 | time_t total; | |
1133 | { | |
1134 | static char result[256]; | |
1135 | int days, hours, mins, secs; | |
1136 | int first = 1; | |
1137 | char *p = result; | |
1138 | ||
1139 | days = total / 3600 / 24; | |
1140 | hours = (total / 3600) % 24; | |
1141 | mins = (total / 60) % 60; | |
1142 | secs = total % 60; | |
1143 | ||
1144 | if (days) { | |
1145 | first = 0; | |
1146 | p += snprintf(p, sizeof(result) - (p - result), "%dd", days); | |
1147 | } | |
1148 | if (!first || hours) { | |
1149 | first = 0; | |
1150 | p += snprintf(p, sizeof(result) - (p - result), "%dh", hours); | |
1151 | } | |
1152 | if (!first || mins) { | |
1153 | first = 0; | |
1154 | p += snprintf(p, sizeof(result) - (p - result), "%dm", mins); | |
1155 | } | |
1156 | snprintf(p, sizeof(result) - (p - result), "%ds", secs); | |
1157 | ||
1158 | return(result); | |
1159 | } | |
1160 | ||
1161 | void | |
1162 | intpr_ri(void (*pfunc)(char *)) | |
1163 | { | |
1164 | int mib[6]; | |
1165 | char *buf = NULL, *lim, *next; | |
1166 | size_t len; | |
1167 | unsigned int ifindex = 0; | |
1168 | struct if_msghdr2 *if2m; | |
1169 | ||
1170 | if (interface != 0) { | |
1171 | ifindex = if_nametoindex(interface); | |
1172 | if (ifindex == 0) { | |
1173 | printf("interface name is not valid: %s\n", interface); | |
1174 | exit(1); | |
1175 | } | |
1176 | } | |
1177 | ||
1178 | mib[0] = CTL_NET; /* networking subsystem */ | |
1179 | mib[1] = PF_ROUTE; /* type of information */ | |
1180 | mib[2] = 0; /* protocol (IPPROTO_xxx) */ | |
1181 | mib[3] = 0; /* address family */ | |
1182 | mib[4] = NET_RT_IFLIST2; /* operation */ | |
1183 | mib[5] = 0; | |
1184 | if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) | |
1185 | return; | |
1186 | if ((buf = malloc(len)) == NULL) { | |
1187 | printf("malloc failed\n"); | |
1188 | exit(1); | |
1189 | } | |
1190 | if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { | |
1191 | free(buf); | |
1192 | return; | |
1193 | } | |
1194 | ||
7af5ce03 A |
1195 | printf("%-6s %-17s %8.8s %-9.9s %4s %4s", |
1196 | "Proto", "Linklayer Address", "Netif", "Expire", "Refs", | |
1197 | "Prbs"); | |
1198 | if (xflag) | |
1199 | printf(" %7s %7s %7s", "RSSI", "LQM", "NPM"); | |
1200 | printf("\n"); | |
fdfd5971 A |
1201 | |
1202 | lim = buf + len; | |
1203 | if2m = (struct if_msghdr2 *)buf; | |
1204 | ||
1205 | for (next = buf; next < lim; ) { | |
1206 | if2m = (struct if_msghdr2 *)next; | |
1207 | next += if2m->ifm_msglen; | |
1208 | ||
1209 | if (if2m->ifm_type != RTM_IFINFO2) | |
1210 | continue; | |
1211 | else if (interface != 0 && if2m->ifm_index != ifindex) | |
1212 | continue; | |
1213 | ||
1214 | llreach_sysctl(if2m->ifm_index); | |
1215 | } | |
1216 | free(buf); | |
1217 | } | |
1218 | ||
1219 | static void | |
1220 | llreach_sysctl(uint32_t ifindex) | |
1221 | { | |
1222 | #define MAX_SYSCTL_TRY 5 | |
1223 | int mib[6], i, ntry = 0; | |
1224 | size_t mibsize, len, needed, cnt; | |
1225 | struct if_llreach_info *lri; | |
1226 | struct timeval time; | |
1227 | char *buf; | |
1228 | char ifname[IF_NAMESIZE]; | |
1229 | ||
1230 | bzero(&mib, sizeof (mib)); | |
1231 | mibsize = sizeof (mib) / sizeof (mib[0]); | |
1232 | if (sysctlnametomib("net.link.generic.system.llreach_info", mib, | |
1233 | &mibsize) == -1) { | |
1234 | perror("sysctlnametomib"); | |
1235 | return; | |
1236 | } | |
1237 | ||
1238 | needed = 0; | |
1239 | mib[5] = ifindex; | |
1240 | ||
1241 | mibsize = sizeof (mib) / sizeof (mib[0]); | |
1242 | do { | |
1243 | if (sysctl(mib, mibsize, NULL, &needed, NULL, 0) == -1) { | |
1244 | perror("sysctl net.link.generic.system.llreach_info"); | |
1245 | return; | |
1246 | } | |
1247 | if ((buf = malloc(needed)) == NULL) { | |
1248 | perror("malloc"); | |
1249 | return; | |
1250 | } | |
1251 | if (sysctl(mib, mibsize, buf, &needed, NULL, 0) == -1) { | |
1252 | if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { | |
1253 | perror("sysctl"); | |
1254 | goto out_free; | |
1255 | } | |
1256 | free(buf); | |
1257 | buf = NULL; | |
1258 | } | |
1259 | } while (buf == NULL); | |
1260 | ||
1261 | len = needed; | |
1262 | cnt = len / sizeof (*lri); | |
1263 | lri = (struct if_llreach_info *)buf; | |
1264 | ||
1265 | gettimeofday(&time, 0); | |
1266 | if (if_indextoname(ifindex, ifname) == NULL) | |
1267 | snprintf(ifname, sizeof (ifname), "%s", "?"); | |
1268 | ||
1269 | for (i = 0; i < cnt; i++, lri++) { | |
1270 | printf("0x%-4x %-17s %8.8s ", lri->lri_proto, | |
1271 | ether_ntoa((struct ether_addr *)lri->lri_addr), ifname); | |
1272 | ||
1273 | if (lri->lri_expire > time.tv_sec) | |
1274 | printf("%-9.9s", sec2str(lri->lri_expire - time.tv_sec)); | |
1275 | else if (lri->lri_expire == 0) | |
1276 | printf("%-9.9s", "permanent"); | |
1277 | else | |
1278 | printf("%-9.9s", "expired"); | |
1279 | ||
1280 | printf(" %4d", lri->lri_refcnt); | |
1281 | if (lri->lri_probes) | |
1282 | printf(" %4d", lri->lri_probes); | |
7af5ce03 A |
1283 | |
1284 | if (xflag) { | |
1285 | if (!lri->lri_probes) | |
1286 | printf(" %-4.4s", "none"); | |
1287 | ||
1288 | if (lri->lri_rssi != IFNET_RSSI_UNKNOWN) | |
1289 | printf(" %7d", lri->lri_rssi); | |
1290 | else | |
1291 | printf(" %-7.7s", "unknown"); | |
1292 | ||
1293 | switch (lri->lri_lqm) | |
1294 | { | |
1295 | case IFNET_LQM_THRESH_OFF: | |
1296 | printf(" %-7.7s", "off"); | |
1297 | break; | |
1298 | case IFNET_LQM_THRESH_UNKNOWN: | |
1299 | printf(" %-7.7s", "unknown"); | |
1300 | break; | |
1301 | case IFNET_LQM_THRESH_POOR: | |
1302 | printf(" %-7.7s", "poor"); | |
1303 | break; | |
1304 | case IFNET_LQM_THRESH_GOOD: | |
1305 | printf(" %-7.7s", "good"); | |
1306 | break; | |
1307 | default: | |
1308 | printf(" %7d", lri->lri_lqm); | |
1309 | break; | |
1310 | } | |
1311 | ||
1312 | switch (lri->lri_npm) | |
1313 | { | |
1314 | case IFNET_NPM_THRESH_UNKNOWN: | |
1315 | printf(" %-7.7s", "unknown"); | |
1316 | break; | |
1317 | case IFNET_NPM_THRESH_NEAR: | |
1318 | printf(" %-7.7s", "near"); | |
1319 | break; | |
1320 | case IFNET_NPM_THRESH_GENERAL: | |
1321 | printf(" %-7.7s", "general"); | |
1322 | break; | |
1323 | case IFNET_NPM_THRESH_FAR: | |
1324 | printf(" %-7.7s", "far"); | |
1325 | break; | |
1326 | default: | |
1327 | printf(" %7d", lri->lri_npm); | |
1328 | break; | |
1329 | } | |
1330 | } | |
1331 | ||
fdfd5971 A |
1332 | printf("\n"); |
1333 | len -= sizeof (*lri); | |
1334 | } | |
7af5ce03 | 1335 | |
fdfd5971 A |
1336 | if (len > 0) { |
1337 | fprintf(stderr, "warning: %u trailing bytes from %s\n", | |
1338 | (unsigned int)len, "net.link.generic.system.llreach_info"); | |
1339 | } | |
1340 | ||
1341 | out_free: | |
1342 | free(buf); | |
1343 | #undef MAX_SYSCTL_TRY | |
1344 | } | |
7af5ce03 A |
1345 | |
1346 | void | |
1347 | aqstatpr(void) | |
1348 | { | |
1349 | unsigned int ifindex; | |
1350 | struct itimerval timer_interval; | |
1351 | struct if_qstatsreq ifqr; | |
1352 | struct if_ifclassq_stats *ifcqs; | |
1353 | sigset_t sigset, oldsigset; | |
1354 | u_int32_t scheduler; | |
a3cc5c72 | 1355 | int s, n; |
7af5ce03 A |
1356 | |
1357 | if (cq < -1 || cq >= IFCQ_SC_MAX) { | |
1358 | fprintf(stderr, "Invalid classq index (range is 0-%d)\n", | |
1359 | IFCQ_SC_MAX-1); | |
1360 | return; | |
1361 | } | |
1362 | ifindex = if_nametoindex(interface); | |
1363 | if (ifindex == 0) { | |
1364 | fprintf(stderr, "Invalid interface name\n"); | |
1365 | return; | |
1366 | } | |
1367 | ||
1368 | ifcqs = malloc(sizeof (*ifcqs)); | |
1369 | if (ifcqs == NULL) { | |
1370 | fprintf(stderr, "Unable to allocate memory\n"); | |
1371 | return; | |
1372 | } | |
1373 | ||
1374 | if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { | |
1375 | perror("Warning: socket(AF_INET)"); | |
1376 | free(ifcqs); | |
1377 | return; | |
1378 | } | |
1379 | ||
1380 | bzero(&ifqr, sizeof (ifqr)); | |
1381 | strlcpy(ifqr.ifqr_name, interface, sizeof (ifqr.ifqr_name)); | |
1382 | ifqr.ifqr_buf = ifcqs; | |
1383 | ifqr.ifqr_len = sizeof (*ifcqs); | |
1384 | ||
1385 | loop: | |
1386 | if (interval > 0) { | |
1387 | /* create a timer that fires repeatedly every interval seconds */ | |
1388 | timer_interval.it_value.tv_sec = interval; | |
1389 | timer_interval.it_value.tv_usec = 0; | |
1390 | timer_interval.it_interval.tv_sec = interval; | |
1391 | timer_interval.it_interval.tv_usec = 0; | |
1392 | (void) signal(SIGALRM, catchalarm); | |
1393 | signalled = NO; | |
1394 | (void) setitimer(ITIMER_REAL, &timer_interval, NULL); | |
1395 | } | |
1396 | ||
1397 | ifqr.ifqr_slot = 0; | |
1398 | if (ioctl(s, SIOCGIFQUEUESTATS, (char *)&ifqr) < 0) { | |
1399 | if (errno == ENXIO) { | |
1400 | printf("Queue statistics are not available on %s\n", | |
1401 | interface); | |
1402 | } else { | |
1403 | perror("Warning: ioctl(SIOCGIFQUEUESTATS)"); | |
1404 | } | |
1405 | goto done; | |
1406 | } | |
1407 | scheduler = ifcqs->ifqs_scheduler; | |
7af5ce03 A |
1408 | |
1409 | printf("%s:\n" | |
a3cc5c72 A |
1410 | " [ sched: %9s qlength: %3d/%3d ]\n", |
1411 | interface, sched2str(ifcqs->ifqs_scheduler), | |
1412 | ifcqs->ifqs_len, ifcqs->ifqs_maxlen); | |
1413 | printf(" [ pkts: %10llu bytes: %10llu " | |
1414 | " dropped pkts: %6llu bytes: %6llu ]\n", | |
1415 | ifcqs->ifqs_xmitcnt.packets, ifcqs->ifqs_xmitcnt.bytes, | |
7af5ce03 A |
1416 | ifcqs->ifqs_dropcnt.packets, ifcqs->ifqs_dropcnt.bytes); |
1417 | ||
7af5ce03 A |
1418 | for (n = 0; n < IFCQ_SC_MAX && scheduler != PKTSCHEDT_NONE; n++) { |
1419 | if (cq >= 0 && cq != n) | |
1420 | continue; | |
1421 | ||
1422 | ifqr.ifqr_slot = n; | |
1423 | if (ioctl(s, SIOCGIFQUEUESTATS, (char *)&ifqr) < 0) { | |
1424 | perror("Warning: ioctl(SIOCGIFQUEUESTATS)"); | |
1425 | goto done; | |
1426 | } | |
1427 | ||
1428 | update_avg(ifcqs, &qstats[n]); | |
1429 | ||
1430 | switch (scheduler) { | |
26c66ce9 A |
1431 | case PKTSCHEDT_FQ_CODEL: |
1432 | print_fq_codel_stats(n, | |
1433 | &ifcqs->ifqs_fq_codel_stats, | |
1434 | &qstats[n]); | |
1435 | break; | |
7af5ce03 A |
1436 | case PKTSCHEDT_NONE: |
1437 | default: | |
1438 | break; | |
1439 | } | |
1440 | } | |
1441 | ||
1442 | fflush(stdout); | |
1443 | ||
1444 | if (interval > 0) { | |
1445 | sigemptyset(&sigset); | |
1446 | sigaddset(&sigset, SIGALRM); | |
1447 | (void) sigprocmask(SIG_BLOCK, &sigset, &oldsigset); | |
1448 | if (!signalled) { | |
1449 | sigemptyset(&sigset); | |
1450 | sigsuspend(&sigset); | |
1451 | } | |
1452 | (void) sigprocmask(SIG_SETMASK, &oldsigset, NULL); | |
1453 | ||
1454 | signalled = NO; | |
1455 | goto loop; | |
1456 | } | |
1457 | ||
1458 | done: | |
1459 | free(ifcqs); | |
1460 | close(s); | |
1461 | } | |
1462 | ||
26c66ce9 A |
1463 | static void |
1464 | print_fq_codel_stats(int pri, struct fq_codel_classstats *fqst, | |
1465 | struct queue_stats *qs) | |
1466 | { | |
d9520f62 A |
1467 | int i = 0; |
1468 | ||
1469 | if (fqst->fcls_service_class == 0 && fqst->fcls_pri == 0) | |
1470 | return; | |
1471 | printf("=====================================================\n"); | |
26c66ce9 A |
1472 | printf(" [ pri: %s (%d)\tsrv_cl: 0x%x\tquantum: %d\tdrr_max: %d ]\n", |
1473 | pri2str(fqst->fcls_pri), fqst->fcls_pri, | |
1474 | fqst->fcls_service_class, fqst->fcls_quantum, | |
1475 | fqst->fcls_drr_max); | |
d9520f62 A |
1476 | printf(" [ queued pkts: %llu\tbytes: %llu ]\n", |
1477 | fqst->fcls_pkt_cnt, fqst->fcls_byte_cnt); | |
1478 | printf(" [ dequeued pkts: %llu\tbytes: %llu ]\n", | |
1479 | fqst->fcls_dequeue, fqst->fcls_dequeue_bytes); | |
1480 | printf(" [ budget: %lld\ttarget qdelay: %10s\t", | |
26c66ce9 | 1481 | fqst->fcls_budget, nsec_to_str(fqst->fcls_target_qdelay)); |
d9520f62 A |
1482 | printf("update interval:%10s ]\n", |
1483 | nsec_to_str(fqst->fcls_update_interval)); | |
26c66ce9 A |
1484 | printf(" [ flow control: %u\tfeedback: %u\tstalls: %u\tfailed: %u ]\n", |
1485 | fqst->fcls_flow_control, fqst->fcls_flow_feedback, | |
1486 | fqst->fcls_dequeue_stall, fqst->fcls_flow_control_fail); | |
1487 | printf(" [ drop overflow: %llu\tearly: %llu\tmemfail: %u\tduprexmt:%u ]\n", | |
1488 | fqst->fcls_drop_overflow, fqst->fcls_drop_early, | |
1489 | fqst->fcls_drop_memfailure, fqst->fcls_dup_rexmts); | |
1490 | printf(" [ flows total: %u\tnew: %u\told: %u ]\n", | |
1491 | fqst->fcls_flows_cnt, | |
1492 | fqst->fcls_newflows_cnt, fqst->fcls_oldflows_cnt); | |
26c66ce9 A |
1493 | printf(" [ throttle on: %u\toff: %u\tdrop: %u ]\n", |
1494 | fqst->fcls_throttle_on, fqst->fcls_throttle_off, | |
1495 | fqst->fcls_throttle_drops); | |
a3cc5c72 A |
1496 | printf(" [ compressible pkts: %u compressed pkts: %u]\n", |
1497 | fqst->fcls_pkts_compressible, fqst->fcls_pkts_compressed); | |
d9520f62 A |
1498 | |
1499 | if (qflag < 2) | |
1500 | return; | |
1501 | ||
1502 | if (fqst->fcls_flowstats_cnt > 0) { | |
1503 | printf("Flowhash\tBytes\tMin qdelay\tFlags\t\n"); | |
1504 | for (i = 0; i < fqst->fcls_flowstats_cnt; i++) { | |
1505 | printf("%u\t%u\t%14s\t", | |
1506 | fqst->fcls_flowstats[i].fqst_flowhash, | |
1507 | fqst->fcls_flowstats[i].fqst_bytes, | |
1508 | nsec_to_str(fqst->fcls_flowstats[i].fqst_min_qdelay)); | |
1509 | if (fqst->fcls_flowstats[i].fqst_flags & | |
1510 | FQ_FLOWSTATS_OLD_FLOW) | |
1511 | printf("O"); | |
1512 | if (fqst->fcls_flowstats[i].fqst_flags & | |
1513 | FQ_FLOWSTATS_NEW_FLOW) | |
1514 | printf("N"); | |
1515 | if (fqst->fcls_flowstats[i].fqst_flags & | |
1516 | FQ_FLOWSTATS_LARGE_FLOW) | |
1517 | printf("L"); | |
1518 | if (fqst->fcls_flowstats[i].fqst_flags & | |
1519 | FQ_FLOWSTATS_DELAY_HIGH) | |
1520 | printf("D"); | |
1521 | if (fqst->fcls_flowstats[i].fqst_flags & | |
1522 | FQ_FLOWSTATS_FLOWCTL_ON) | |
1523 | printf("F"); | |
1524 | printf("\n"); | |
1525 | } | |
1526 | } | |
26c66ce9 A |
1527 | } |
1528 | ||
7af5ce03 A |
1529 | static void |
1530 | update_avg(struct if_ifclassq_stats *ifcqs, struct queue_stats *qs) | |
1531 | { | |
1532 | u_int64_t b, p; | |
1533 | int n; | |
1534 | ||
1535 | n = qs->avgn; | |
1536 | ||
1537 | switch (ifcqs->ifqs_scheduler) { | |
26c66ce9 A |
1538 | case PKTSCHEDT_FQ_CODEL: |
1539 | b = ifcqs->ifqs_fq_codel_stats.fcls_dequeue_bytes; | |
1540 | p = ifcqs->ifqs_fq_codel_stats.fcls_dequeue; | |
1541 | break; | |
7af5ce03 A |
1542 | default: |
1543 | b = 0; | |
1544 | p = 0; | |
1545 | break; | |
1546 | } | |
1547 | ||
1548 | if (n == 0) { | |
1549 | qs->prev_bytes = b; | |
1550 | qs->prev_packets = p; | |
1551 | qs->avgn++; | |
1552 | return; | |
1553 | } | |
1554 | ||
1555 | if (b >= qs->prev_bytes) | |
1556 | qs->avg_bytes = ((qs->avg_bytes * (n - 1)) + | |
1557 | (b - qs->prev_bytes)) / n; | |
1558 | ||
1559 | if (p >= qs->prev_packets) | |
1560 | qs->avg_packets = ((qs->avg_packets * (n - 1)) + | |
1561 | (p - qs->prev_packets)) / n; | |
1562 | ||
1563 | qs->prev_bytes = b; | |
1564 | qs->prev_packets = p; | |
1565 | if (n < AVGN_MAX) | |
1566 | qs->avgn++; | |
1567 | } | |
1568 | ||
7af5ce03 | 1569 | #define NSEC_PER_SEC 1000000000 /* nanoseconds per second */ |
26c66ce9 A |
1570 | #define USEC_PER_SEC 1000000 /* microseconds per second */ |
1571 | #define MSEC_PER_SEC 1000 /* milliseconds per second */ | |
7af5ce03 A |
1572 | |
1573 | static char * | |
1574 | nsec_to_str(unsigned long long nsec) | |
1575 | { | |
1576 | static char buf[32]; | |
1577 | const char *u; | |
1578 | long double n = nsec, t; | |
1579 | ||
1580 | if (nsec >= NSEC_PER_SEC) { | |
1581 | t = n / NSEC_PER_SEC; | |
1582 | u = "sec "; | |
1583 | } else if (n >= USEC_PER_SEC) { | |
1584 | t = n / USEC_PER_SEC; | |
1585 | u = "msec"; | |
1586 | } else if (n >= MSEC_PER_SEC) { | |
1587 | t = n / MSEC_PER_SEC; | |
1588 | u = "usec"; | |
1589 | } else { | |
1590 | t = n; | |
1591 | u = "nsec"; | |
1592 | } | |
1593 | ||
1594 | snprintf(buf, sizeof (buf), "%-4.2Lf %4s", t, u); | |
1595 | return (buf); | |
1596 | } | |
1597 | ||
1598 | static char * | |
1599 | sched2str(unsigned int s) | |
1600 | { | |
1601 | char *c; | |
1602 | ||
1603 | switch (s) { | |
1604 | case PKTSCHEDT_NONE: | |
1605 | c = "NONE"; | |
1606 | break; | |
26c66ce9 A |
1607 | case PKTSCHEDT_FQ_CODEL: |
1608 | c = "FQ_CODEL"; | |
1609 | break; | |
7af5ce03 A |
1610 | default: |
1611 | c = "UNKNOWN"; | |
1612 | break; | |
1613 | } | |
1614 | ||
1615 | return (c); | |
1616 | } | |
1617 | ||
26c66ce9 A |
1618 | static char * |
1619 | pri2str(unsigned int i) | |
1620 | { | |
1621 | char *c; | |
1622 | switch (i) { | |
1623 | case 9: | |
1624 | c = "BK_SYS"; | |
1625 | break; | |
1626 | case 8: | |
1627 | c = "BK"; | |
1628 | break; | |
1629 | case 7: | |
1630 | c = "BE"; | |
1631 | break; | |
1632 | case 6: | |
1633 | c = "RD"; | |
1634 | break; | |
1635 | case 5: | |
1636 | c = "OAM"; | |
1637 | break; | |
1638 | case 4: | |
1639 | c = "AV"; | |
1640 | break; | |
1641 | case 3: | |
1642 | c = "RV"; | |
1643 | break; | |
1644 | case 2: | |
1645 | c = "VI"; | |
1646 | break; | |
1647 | case 1: | |
1648 | c = "VO"; | |
1649 | break; | |
1650 | case 0: | |
1651 | c = "CTL"; | |
1652 | break; | |
1653 | default: | |
1654 | c = "?"; | |
1655 | break; | |
1656 | } | |
1657 | return (c); | |
1658 | } | |
1659 | ||
7af5ce03 A |
1660 | void |
1661 | rxpollstatpr(void) | |
1662 | { | |
1663 | struct ifmibdata_supplemental ifmsupp; | |
1664 | size_t miblen = sizeof (ifmsupp); | |
1665 | struct itimerval timer_interval; | |
1666 | struct if_rxpoll_stats *sp; | |
e0b07f2d | 1667 | struct if_netif_stats *np; |
7af5ce03 A |
1668 | sigset_t sigset, oldsigset; |
1669 | unsigned int ifindex; | |
1670 | int name[6]; | |
1671 | ||
1672 | ifindex = if_nametoindex(interface); | |
1673 | if (ifindex == 0) { | |
1674 | fprintf(stderr, "Invalid interface name\n"); | |
1675 | return; | |
1676 | } | |
1677 | ||
1678 | bzero(&ifmsupp, sizeof (struct ifmibdata_supplemental)); | |
1679 | ||
1680 | loop: | |
1681 | if (interval > 0) { | |
1682 | /* create a timer that fires repeatedly every interval seconds */ | |
1683 | timer_interval.it_value.tv_sec = interval; | |
1684 | timer_interval.it_value.tv_usec = 0; | |
1685 | timer_interval.it_interval.tv_sec = interval; | |
1686 | timer_interval.it_interval.tv_usec = 0; | |
1687 | (void) signal(SIGALRM, catchalarm); | |
1688 | signalled = NO; | |
1689 | (void) setitimer(ITIMER_REAL, &timer_interval, NULL); | |
1690 | } | |
1691 | ||
1692 | /* Common OID prefix */ | |
1693 | name[0] = CTL_NET; | |
1694 | name[1] = PF_LINK; | |
1695 | name[2] = NETLINK_GENERIC; | |
1696 | name[3] = IFMIB_IFDATA; | |
1697 | name[4] = ifindex; | |
1698 | name[5] = IFDATA_SUPPLEMENTAL; | |
1699 | if (sysctl(name, 6, &ifmsupp, &miblen, NULL, 0) == -1) | |
1700 | err(1, "sysctl IFDATA_SUPPLEMENTAL"); | |
1701 | ||
1702 | sp = &ifmsupp.ifmd_rxpoll_stats; | |
1703 | ||
1704 | printf("%-4s [ poll on requests: %15u errors: %27u ]\n", | |
1705 | interface, sp->ifi_poll_on_req, sp->ifi_poll_on_err); | |
1706 | printf(" [ poll off requests: %15u errors: %27u ]\n", | |
1707 | sp->ifi_poll_off_req, sp->ifi_poll_off_err); | |
f1dee6ae | 1708 | printf(" [ polled packets: %18llu per poll limit: %19u ]\n", |
e0b07f2d A |
1709 | sp->ifi_poll_packets, sp->ifi_poll_packets_limit); |
1710 | printf(" [ polled bytes: %20llu ]\n", sp->ifi_poll_bytes); | |
1711 | printf(" [ poll interval: %14llu nsec ]\n", | |
1712 | sp->ifi_poll_interval_time); | |
7af5ce03 A |
1713 | printf(" [ sampled packets avg/min/max: %12u / %12u / %12u ]\n", |
1714 | sp->ifi_poll_packets_avg, sp->ifi_poll_packets_min, | |
1715 | sp->ifi_poll_packets_max); | |
1716 | printf(" [ sampled bytes avg/min/max: %12u / %12u / %12u ]\n", | |
1717 | sp->ifi_poll_bytes_avg, sp->ifi_poll_bytes_min, | |
1718 | sp->ifi_poll_bytes_max); | |
1719 | printf(" [ sampled wakeups avg: %12u ]\n", | |
1720 | sp->ifi_poll_wakeups_avg); | |
1721 | printf(" [ packets lowat/hiwat threshold: %10u / %10u ]\n", | |
1722 | sp->ifi_poll_packets_lowat, sp->ifi_poll_packets_hiwat); | |
1723 | printf(" [ bytes lowat/hiwat threshold: %10u / %10u ]\n", | |
1724 | sp->ifi_poll_bytes_lowat, sp->ifi_poll_bytes_hiwat); | |
1725 | printf(" [ wakeups lowat/hiwat threshold: %10u / %10u ]\n", | |
1726 | sp->ifi_poll_wakeups_lowat, sp->ifi_poll_wakeups_hiwat); | |
1727 | ||
e0b07f2d A |
1728 | np = &ifmsupp.ifmd_netif_stats; |
1729 | printf(" [ mit mode: %24U cfg idx: %26u ]\n", | |
1730 | np->ifn_rx_mit_mode, np->ifn_rx_mit_cfg_idx); | |
1731 | printf(" [ cfg packets lo/hi threshold: %12u / %12u ]\n", | |
1732 | np->ifn_rx_mit_cfg_packets_lowat, np->ifn_rx_mit_cfg_packets_hiwat); | |
1733 | printf(" [ cfg bytes lo/hi threshold: %12u / %12u ]\n", | |
1734 | np->ifn_rx_mit_cfg_bytes_lowat, np->ifn_rx_mit_cfg_bytes_hiwat); | |
f1dee6ae | 1735 | printf(" [ cfg interval: %15u nsec ]\n", |
e0b07f2d A |
1736 | np->ifn_rx_mit_cfg_interval); |
1737 | printf(" [ mit interval: %15llu nsec ]\n", | |
1738 | np->ifn_rx_mit_interval); | |
1739 | printf(" [ mit packets avg/min/max: %12u / %12u / %12u ]\n", | |
1740 | np->ifn_rx_mit_packets_avg, np->ifn_rx_mit_packets_min, | |
1741 | np->ifn_rx_mit_packets_max); | |
1742 | printf(" [ mit bytes avg/min/max: %12u / %12u / %12u ]\n", | |
1743 | np->ifn_rx_mit_bytes_avg, np->ifn_rx_mit_bytes_min, | |
1744 | np->ifn_rx_mit_bytes_max); | |
1745 | ||
7af5ce03 A |
1746 | fflush(stdout); |
1747 | ||
1748 | if (interval > 0) { | |
1749 | sigemptyset(&sigset); | |
1750 | sigaddset(&sigset, SIGALRM); | |
1751 | (void) sigprocmask(SIG_BLOCK, &sigset, &oldsigset); | |
1752 | if (!signalled) { | |
1753 | sigemptyset(&sigset); | |
1754 | sigsuspend(&sigset); | |
1755 | } | |
1756 | (void) sigprocmask(SIG_SETMASK, &oldsigset, NULL); | |
1757 | ||
1758 | signalled = NO; | |
1759 | goto loop; | |
1760 | } | |
1761 | } | |
89c4ed63 A |
1762 | |
1763 | static int | |
1764 | create_control_socket(const char *control_name) | |
1765 | { | |
1766 | struct sockaddr_ctl sc; | |
1767 | struct ctl_info ctl; | |
1768 | int fd; | |
1769 | ||
1770 | fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); | |
1771 | if (fd == -1) { | |
1772 | perror("socket(PF_SYSTEM)"); | |
1773 | return fd; | |
1774 | } | |
1775 | ||
1776 | /* Get the control ID for statistics */ | |
1777 | bzero(&ctl, sizeof(ctl)); | |
1778 | strlcpy(ctl.ctl_name, control_name, sizeof(ctl.ctl_name)); | |
1779 | if (ioctl(fd, CTLIOCGINFO, &ctl) == -1) | |
1780 | { | |
1781 | perror("ioctl(CTLIOCGINFO)"); | |
1782 | close(fd); | |
1783 | return -1; | |
1784 | } | |
1785 | ||
1786 | /* Connect to the statistics control */ | |
1787 | bzero(&sc, sizeof(sc)); | |
1788 | sc.sc_len = sizeof(sc); | |
1789 | sc.sc_family = AF_SYSTEM; | |
1790 | sc.ss_sysaddr = SYSPROTO_CONTROL; | |
1791 | sc.sc_id = ctl.ctl_id; | |
1792 | sc.sc_unit = 0; | |
1793 | if (connect(fd, (struct sockaddr*)&sc, sc.sc_len) != 0) | |
1794 | { | |
1795 | perror("connect(SYSPROTO_CONTROL)"); | |
1796 | close(fd); | |
1797 | return -1; | |
1798 | } | |
1799 | ||
1800 | /* Set socket to non-blocking operation */ | |
1801 | if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) == -1) { | |
1802 | perror("fcnt(F_SETFL,O_NONBLOCK)"); | |
1803 | close(fd); | |
1804 | return -1; | |
1805 | } | |
1806 | return fd; | |
1807 | } | |
1808 | ||
1809 | static int | |
1810 | add_nstat_src(int fd, const nstat_ifnet_add_param *ifparam, | |
1811 | nstat_src_ref_t *outsrc) | |
1812 | { | |
1813 | nstat_msg_add_src_req *addreq; | |
1814 | nstat_msg_src_added *addedmsg; | |
1815 | nstat_ifnet_add_param *param; | |
1816 | char buffer[sizeof(*addreq) + sizeof(*param)]; | |
1817 | ssize_t result; | |
1818 | const u_int32_t addreqsize = | |
1819 | offsetof(struct nstat_msg_add_src, param) + sizeof(*param); | |
1820 | ||
1821 | /* Setup the add source request */ | |
1822 | addreq = (nstat_msg_add_src_req *)buffer; | |
1823 | param = (nstat_ifnet_add_param*)addreq->param; | |
1824 | bzero(addreq, addreqsize); | |
1825 | addreq->hdr.context = (uintptr_t)&buffer; | |
1826 | addreq->hdr.type = NSTAT_MSG_TYPE_ADD_SRC; | |
1827 | addreq->provider = NSTAT_PROVIDER_IFNET; | |
1828 | bzero(param, sizeof(*param)); | |
1829 | param->ifindex = ifparam->ifindex; | |
1830 | param->threshold = ifparam->threshold; | |
1831 | ||
1832 | /* Send the add source request */ | |
1833 | result = send(fd, addreq, addreqsize, 0); | |
1834 | if (result != addreqsize) | |
1835 | { | |
1836 | if (result == -1) | |
1837 | perror("send(NSTAT_ADD_SRC_REQ)"); | |
1838 | else | |
1839 | fprintf(stderr, "%s: could only sent %ld out of %d\n", | |
1840 | __func__, result, addreqsize); | |
1841 | return -1; | |
1842 | } | |
1843 | ||
1844 | /* Receive the response */ | |
1845 | addedmsg = (nstat_msg_src_added *)buffer; | |
1846 | result = recv(fd, addedmsg, sizeof(buffer), 0); | |
1847 | if (result < sizeof(*addedmsg)) | |
1848 | { | |
1849 | if (result == -1) | |
1850 | perror("recv(NSTAT_ADD_SRC_RSP)"); | |
1851 | else | |
1852 | fprintf(stderr, "%s: recv too small, received %ld, " | |
1853 | "expected %lu\n", __func__, result, | |
1854 | sizeof(*addedmsg)); | |
1855 | return -1; | |
1856 | } | |
1857 | ||
1858 | if (addedmsg->hdr.type != NSTAT_MSG_TYPE_SRC_ADDED) | |
1859 | { | |
1860 | fprintf(stderr, "%s: received wrong message type, received %u " | |
1861 | "expected %u\n", __func__, addedmsg->hdr.type, | |
1862 | NSTAT_MSG_TYPE_SRC_ADDED); | |
1863 | return -1; | |
1864 | } | |
1865 | ||
1866 | if (addedmsg->hdr.context != (uintptr_t)&buffer) | |
1867 | { | |
1868 | fprintf(stderr, "%s: received wrong context, received %llu " | |
1869 | "expected %lu\n", __func__, addedmsg->hdr.context, | |
1870 | (uintptr_t)&buffer); | |
1871 | return -1; | |
1872 | } | |
1873 | *outsrc = addedmsg->srcref; | |
1874 | return 0; | |
1875 | } | |
1876 | ||
1877 | static int | |
1878 | rem_nstat_src(int fd, nstat_src_ref_t sref) | |
1879 | { | |
1880 | nstat_msg_rem_src_req *remreq; | |
1881 | nstat_msg_src_removed *remrsp; | |
1882 | char buffer[sizeof(*remreq)]; | |
1883 | ssize_t result; | |
1884 | ||
1885 | /* Setup the add source request */ | |
1886 | remreq = (nstat_msg_rem_src_req *)buffer; | |
1887 | bzero(remreq, sizeof(*remreq)); | |
1888 | remreq->hdr.type = NSTAT_MSG_TYPE_REM_SRC; | |
1889 | remreq->srcref = sref; | |
1890 | ||
1891 | /* Send the remove source request */ | |
1892 | result = send(fd, remreq, sizeof(*remreq), 0); | |
1893 | if (result != sizeof(*remreq)) { | |
1894 | if (result == -1) | |
1895 | perror("send(NSTAT_REM_SRC_REQ)"); | |
1896 | else | |
1897 | fprintf(stderr, "%s: could only sent %ld out of %lu\n", | |
1898 | __func__, result, sizeof(*remreq)); | |
1899 | return -1; | |
1900 | } | |
1901 | ||
1902 | /* Receive the response */ | |
1903 | remrsp = (nstat_msg_src_removed *)buffer; | |
1904 | result = recv(fd, remrsp, sizeof(buffer), 0); | |
1905 | if (result < sizeof(*remrsp)) { | |
1906 | if (result == -1) | |
1907 | perror("recv(NSTAT_REM_SRC_RSP)"); | |
1908 | else | |
1909 | fprintf(stderr, "%s: recv too small, received %ld, " | |
1910 | "expected %lu\n", __func__, result, | |
1911 | sizeof(*remrsp)); | |
1912 | return -1; | |
1913 | } | |
1914 | ||
1915 | if (remrsp->hdr.type != NSTAT_MSG_TYPE_SRC_REMOVED) { | |
1916 | fprintf(stderr, "%s: received wrong message type, received %u " | |
1917 | "expected %u\n", __func__, remrsp->hdr.type, | |
1918 | NSTAT_MSG_TYPE_SRC_REMOVED); | |
1919 | return -1; | |
1920 | } | |
1921 | ||
1922 | if (remrsp->srcref != sref) { | |
26c66ce9 A |
1923 | fprintf(stderr, "%s: received invalid srcref, received %llu " |
1924 | "expected %llu\n", __func__, remrsp->srcref, sref); | |
89c4ed63 A |
1925 | } |
1926 | return 0; | |
1927 | } | |
1928 | ||
1929 | static int | |
1930 | get_src_decsription(int fd, nstat_src_ref_t srcref, | |
1931 | struct nstat_ifnet_descriptor *ifdesc) | |
1932 | { | |
1933 | nstat_msg_get_src_description *dreq; | |
1934 | nstat_msg_src_description *drsp; | |
1935 | char buffer[sizeof(*drsp) + sizeof(*ifdesc)]; | |
1936 | ssize_t result; | |
1937 | const u_int32_t descsize = | |
1938 | offsetof(struct nstat_msg_src_description, data) + | |
1939 | sizeof(nstat_ifnet_descriptor); | |
1940 | ||
1941 | dreq = (nstat_msg_get_src_description *)buffer; | |
1942 | bzero(dreq, sizeof(*dreq)); | |
1943 | dreq->hdr.type = NSTAT_MSG_TYPE_GET_SRC_DESC; | |
1944 | dreq->srcref = srcref; | |
1945 | result = send(fd, dreq, sizeof(*dreq), 0); | |
1946 | if (result != sizeof(*dreq)) | |
1947 | { | |
1948 | if (result == -1) | |
1949 | perror("send(NSTAT_GET_SRC_DESC_REQ)"); | |
1950 | else | |
1951 | fprintf(stderr, "%s: sent %ld out of %lu\n", | |
1952 | __func__, result, sizeof(*dreq)); | |
1953 | return -1; | |
1954 | } | |
1955 | ||
1956 | /* Receive the source description response */ | |
1957 | drsp = (nstat_msg_src_description *)buffer; | |
1958 | result = recv(fd, drsp, sizeof(buffer), 0); | |
1959 | if (result < descsize) | |
1960 | { | |
1961 | if (result == -1) | |
1962 | perror("recv(NSTAT_GET_SRC_DESC_RSP"); | |
1963 | else | |
1964 | fprintf(stderr, "%s: recv too small, received %ld, " | |
1965 | "expected %u\n", __func__, result, descsize); | |
1966 | return -1; | |
1967 | } | |
1968 | ||
1969 | if (drsp->hdr.type != NSTAT_MSG_TYPE_SRC_DESC) | |
1970 | { | |
1971 | fprintf(stderr, "%s: received wrong message type, received %u " | |
1972 | "expected %u\n", __func__, drsp->hdr.type, | |
1973 | NSTAT_MSG_TYPE_SRC_DESC); | |
1974 | return -1; | |
1975 | } | |
1976 | ||
1977 | if (drsp->srcref != srcref) | |
1978 | { | |
1979 | fprintf(stderr, "%s: received message for wrong source, " | |
26c66ce9 | 1980 | "received 0x%llx expected 0x%llx\n", |
89c4ed63 A |
1981 | __func__, drsp->srcref, srcref); |
1982 | return -1; | |
1983 | } | |
1984 | ||
1985 | bcopy(drsp->data, ifdesc, sizeof(*ifdesc)); | |
1986 | return 0; | |
1987 | } | |
1988 | ||
1989 | static void | |
1990 | print_wifi_status(nstat_ifnet_desc_wifi_status *status) | |
1991 | { | |
1992 | int tmp; | |
1993 | #define val(x, f) \ | |
1994 | ((status->valid_bitmask & NSTAT_IFNET_DESC_WIFI_ ## f ## _VALID) ?\ | |
1995 | status->x : -1) | |
1996 | #define parg(n, un) #n, val(n, un) | |
1997 | #define pretxtl(n, un) \ | |
1998 | (((tmp = val(n, un)) == -1) ? "(not valid)" : \ | |
1999 | ((tmp == NSTAT_IFNET_DESC_WIFI_UL_RETXT_LEVEL_NONE) ? "(none)" : \ | |
2000 | ((tmp == NSTAT_IFNET_DESC_WIFI_UL_RETXT_LEVEL_LOW) ? "(low)" : \ | |
2001 | ((tmp == NSTAT_IFNET_DESC_WIFI_UL_RETXT_LEVEL_MEDIUM) ? "(medium)" : \ | |
2002 | ((tmp == NSTAT_IFNET_DESC_WIFI_UL_RETXT_LEVEL_HIGH) ? "(high)" : \ | |
2003 | "(?)"))))) | |
2004 | ||
2005 | printf("\nwifi status:\n"); | |
2006 | printf( | |
2007 | "\t%s:\t%d\n" | |
2008 | "\t%s:\t%d\n" | |
2009 | "\t%s:\t%d\n" | |
2010 | "\t%s:\t\t%d\n" | |
2011 | "\t%s:\t%d\n" | |
2012 | "\t%s:\t\t%d\n" | |
2013 | "\t%s:\t\t%d%s\n" | |
2014 | "\t%s:\t\t%d\n" | |
2015 | "\t%s:\t\t%d\n" | |
2016 | "\t%s:\t%d\n" | |
2017 | "\t%s:\t%d\n" | |
2018 | "\t%s:\t\t%d\n" | |
2019 | "\t%s:\t%d\n" | |
2020 | "\t%s:\t\t%d\n" | |
2021 | "\t%s:\t\t%d\n" | |
2022 | "\t%s:\t%d\n" | |
2023 | "\t%s:\t%d\n" | |
2024 | "\t%s:\t\t%d\n" | |
2025 | "\t%s:\t\t%d\n", | |
2026 | parg(link_quality_metric, LINK_QUALITY_METRIC), | |
2027 | parg(ul_effective_bandwidth, UL_EFFECTIVE_BANDWIDTH), | |
2028 | parg(ul_max_bandwidth, UL_MAX_BANDWIDTH), | |
2029 | parg(ul_min_latency, UL_MIN_LATENCY), | |
2030 | parg(ul_effective_latency, UL_EFFECTIVE_LATENCY), | |
2031 | parg(ul_max_latency, UL_MAX_LATENCY), | |
2032 | parg(ul_retxt_level, UL_RETXT_LEVEL), | |
2033 | pretxtl(ul_retxt_level, UL_RETXT_LEVEL), | |
2034 | parg(ul_bytes_lost, UL_BYTES_LOST), | |
2035 | parg(ul_error_rate, UL_ERROR_RATE), | |
2036 | parg(dl_effective_bandwidth, DL_EFFECTIVE_BANDWIDTH), | |
2037 | parg(dl_max_bandwidth, DL_MAX_BANDWIDTH), | |
2038 | parg(dl_min_latency, DL_MIN_LATENCY), | |
2039 | parg(dl_effective_latency, DL_EFFECTIVE_LATENCY), | |
2040 | parg(dl_max_latency, DL_MAX_LATENCY), | |
2041 | parg(dl_error_rate, DL_ERROR_RATE), | |
2042 | parg(config_frequency, CONFIG_FREQUENCY), | |
2043 | parg(config_multicast_rate, CONFIG_MULTICAST_RATE), | |
2044 | parg(scan_count, CONFIG_SCAN_COUNT), | |
2045 | parg(scan_duration, CONFIG_SCAN_DURATION) | |
2046 | ); | |
2047 | #undef pretxtl | |
2048 | #undef parg | |
2049 | #undef val | |
2050 | } | |
2051 | ||
2052 | static void | |
2053 | print_cellular_status(nstat_ifnet_desc_cellular_status *status) | |
2054 | { | |
26c66ce9 | 2055 | int tmp, tmp_mss; |
89c4ed63 A |
2056 | #define val(x, f) \ |
2057 | ((status->valid_bitmask & NSTAT_IFNET_DESC_CELL_ ## f ## _VALID) ?\ | |
2058 | status->x : -1) | |
2059 | #define parg(n, un) #n, val(n, un) | |
2060 | #define pretxtl(n, un) \ | |
2061 | (((tmp = val(n, un)) == -1) ? "(not valid)" : \ | |
2062 | ((tmp == NSTAT_IFNET_DESC_CELL_UL_RETXT_LEVEL_NONE) ? "(none)" : \ | |
2063 | ((tmp == NSTAT_IFNET_DESC_CELL_UL_RETXT_LEVEL_LOW) ? "(low)" : \ | |
2064 | ((tmp == NSTAT_IFNET_DESC_CELL_UL_RETXT_LEVEL_MEDIUM) ? "(medium)" : \ | |
2065 | ((tmp == NSTAT_IFNET_DESC_CELL_UL_RETXT_LEVEL_HIGH) ? "(high)" : \ | |
2066 | "(?)"))))) | |
26c66ce9 A |
2067 | #define pretxtm(n, un) \ |
2068 | (((tmp_mss = val(n,un)) == -1) ? "(not valid)" : \ | |
2069 | ((tmp_mss == NSTAT_IFNET_DESC_MSS_RECOMMENDED_NONE) ? "(none)" : \ | |
2070 | ((tmp_mss == NSTAT_IFNET_DESC_MSS_RECOMMENDED_MEDIUM) ? "(medium)" : \ | |
2071 | ((tmp_mss == NSTAT_IFNET_DESC_MSS_RECOMMENDED_LOW) ? "(low)" : \ | |
2072 | "(?)")))) | |
89c4ed63 A |
2073 | |
2074 | printf("\ncellular status:\n"); | |
2075 | printf( | |
2076 | "\t%s:\t%d\n" | |
2077 | "\t%s:\t%d\n" | |
2078 | "\t%s:\t%d\n" | |
2079 | "\t%s:\t\t%d\n" | |
2080 | "\t%s:\t%d\n" | |
2081 | "\t%s:\t\t%d\n" | |
2082 | "\t%s:\t\t%d%s\n" | |
2083 | "\t%s:\t\t%d\n" | |
2084 | "\t%s:\t%d\n" | |
2085 | "\t%s:\t%d\n" | |
2086 | "\t%s:\t%d\n" | |
2087 | "\t%s:\t%d\n" | |
2088 | "\t%s:\t%d\n" | |
2089 | "\t%s:\t%d\n" | |
26c66ce9 A |
2090 | "\t%s:\t%d\n" |
2091 | "\t%s:\t%d %s\n", | |
89c4ed63 A |
2092 | parg(link_quality_metric, LINK_QUALITY_METRIC), |
2093 | parg(ul_effective_bandwidth, UL_EFFECTIVE_BANDWIDTH), | |
2094 | parg(ul_max_bandwidth, UL_MAX_BANDWIDTH), | |
2095 | parg(ul_min_latency, UL_MIN_LATENCY), | |
2096 | parg(ul_effective_latency, UL_EFFECTIVE_LATENCY), | |
2097 | parg(ul_max_latency, UL_MAX_LATENCY), | |
2098 | parg(ul_retxt_level, UL_RETXT_LEVEL), | |
2099 | pretxtl(ul_retxt_level, UL_RETXT_LEVEL), | |
2100 | parg(ul_bytes_lost, UL_BYTES_LOST), | |
2101 | parg(ul_min_queue_size, UL_MIN_QUEUE_SIZE), | |
2102 | parg(ul_avg_queue_size, UL_AVG_QUEUE_SIZE), | |
2103 | parg(ul_max_queue_size, UL_MAX_QUEUE_SIZE), | |
2104 | parg(dl_effective_bandwidth, DL_EFFECTIVE_BANDWIDTH), | |
2105 | parg(dl_max_bandwidth, DL_MAX_BANDWIDTH), | |
2106 | parg(config_inactivity_time, CONFIG_INACTIVITY_TIME), | |
26c66ce9 A |
2107 | parg(config_backoff_time, CONFIG_BACKOFF_TIME), |
2108 | parg(mss_recommended, MSS_RECOMMENDED), | |
2109 | pretxtm(mss_recommended, MSS_RECOMMENDED) | |
89c4ed63 A |
2110 | ); |
2111 | #undef pretxtl | |
2112 | #undef parg | |
2113 | #undef val | |
2114 | } | |
2115 | ||
2116 | static int | |
2117 | get_interface_state(int fd, const char *ifname, struct ifreq *ifr) | |
2118 | { | |
2119 | bzero(ifr, sizeof(*ifr)); | |
2120 | snprintf(ifr->ifr_name, sizeof(ifr->ifr_name), "%s", ifname); | |
2121 | ||
2122 | if (ioctl(fd, SIOCGIFINTERFACESTATE, ifr) == -1) { | |
2123 | perror("ioctl(CTLIOCGINFO)"); | |
2124 | return -1; | |
2125 | } | |
2126 | return 0; | |
2127 | } | |
2128 | ||
2129 | static void | |
2130 | print_interface_state(struct ifreq *ifr) | |
2131 | { | |
2132 | int lqm, rrc, avail; | |
2133 | ||
2134 | printf("\ninterface state:\n"); | |
2135 | ||
2136 | if (ifr->ifr_interface_state.valid_bitmask & | |
2137 | IF_INTERFACE_STATE_LQM_STATE_VALID) { | |
2138 | printf("\tlqm: "); | |
2139 | lqm = ifr->ifr_interface_state.lqm_state; | |
2140 | if (lqm == IFNET_LQM_THRESH_GOOD) | |
2141 | printf("\"good\""); | |
2142 | else if (lqm == IFNET_LQM_THRESH_POOR) | |
2143 | printf("\"poor\""); | |
2144 | else if (lqm == IFNET_LQM_THRESH_BAD) | |
2145 | printf("\"bad\""); | |
2146 | else if (lqm == IFNET_LQM_THRESH_UNKNOWN) | |
2147 | printf("\"unknown\""); | |
2148 | else if (lqm == IFNET_LQM_THRESH_OFF) | |
2149 | printf("\"off\""); | |
2150 | else | |
2151 | printf("invalid(%d)", lqm); | |
2152 | } | |
2153 | ||
2154 | if (ifr->ifr_interface_state.valid_bitmask & | |
2155 | IF_INTERFACE_STATE_RRC_STATE_VALID) { | |
2156 | printf("\trrc: "); | |
2157 | rrc = ifr->ifr_interface_state.rrc_state; | |
2158 | if (rrc == IF_INTERFACE_STATE_RRC_STATE_CONNECTED) | |
2159 | printf("\"connected\""); | |
2160 | else if (rrc == IF_INTERFACE_STATE_RRC_STATE_IDLE) | |
2161 | printf("\"idle\""); | |
2162 | else | |
2163 | printf("\"invalid(%d)\"", rrc); | |
2164 | } | |
2165 | ||
2166 | if (ifr->ifr_interface_state.valid_bitmask & | |
2167 | IF_INTERFACE_STATE_INTERFACE_AVAILABILITY_VALID) { | |
2168 | printf("\tavailability: "); | |
2169 | avail = ifr->ifr_interface_state.interface_availability; | |
2170 | if (avail == IF_INTERFACE_STATE_INTERFACE_AVAILABLE) | |
2171 | printf("\"true\""); | |
2172 | else if (rrc == IF_INTERFACE_STATE_INTERFACE_UNAVAILABLE) | |
2173 | printf("\"false\""); | |
2174 | else | |
2175 | printf("\"invalid(%d)\"", avail); | |
2176 | } | |
2177 | } | |
2178 | ||
2179 | void | |
2180 | print_link_status(const char *ifname) | |
2181 | { | |
2182 | unsigned int ifindex; | |
2183 | struct itimerval timer_interval; | |
2184 | sigset_t sigset, oldsigset; | |
2185 | struct nstat_ifnet_descriptor ifdesc; | |
2186 | nstat_ifnet_add_param ifparam; | |
2187 | nstat_src_ref_t sref = 0; | |
2188 | struct ifreq ifr; | |
2189 | int ctl_fd; | |
2190 | ||
2191 | ifindex = if_nametoindex(ifname); | |
2192 | if (ifindex == 0) { | |
2193 | fprintf(stderr, "Invalid interface name\n"); | |
2194 | return; | |
2195 | } | |
2196 | ||
2197 | if ((ctl_fd = create_control_socket(NET_STAT_CONTROL_NAME)) < 0) | |
2198 | return; | |
2199 | ||
2200 | ifparam.ifindex = ifindex; | |
2201 | ifparam.threshold = UINT64_MAX; | |
2202 | if (add_nstat_src(ctl_fd, &ifparam, &sref)) | |
2203 | goto done; | |
2204 | loop: | |
2205 | if (interval > 0) { | |
2206 | /* create a timer that fires repeatedly every interval | |
2207 | * seconds */ | |
2208 | timer_interval.it_value.tv_sec = interval; | |
2209 | timer_interval.it_value.tv_usec = 0; | |
2210 | timer_interval.it_interval.tv_sec = interval; | |
2211 | timer_interval.it_interval.tv_usec = 0; | |
2212 | (void) signal(SIGALRM, catchalarm); | |
2213 | signalled = NO; | |
2214 | (void) setitimer(ITIMER_REAL, &timer_interval, NULL); | |
2215 | } | |
2216 | ||
2217 | /* get interface state */ | |
2218 | if (get_interface_state(ctl_fd, ifname, &ifr)) | |
2219 | goto done; | |
2220 | ||
2221 | /* get ntstat interface description */ | |
2222 | if (get_src_decsription(ctl_fd, sref, &ifdesc)) | |
2223 | goto done; | |
2224 | ||
2225 | /* print time */ | |
2226 | printf("\n%s: ", ifname); | |
2227 | print_time(); | |
2228 | ||
2229 | /* print interface state */ | |
2230 | print_interface_state(&ifr); | |
2231 | ||
2232 | /* print ntsat interface link status */ | |
2233 | if (ifdesc.link_status.link_status_type == | |
2234 | NSTAT_IFNET_DESC_LINK_STATUS_TYPE_CELLULAR) | |
2235 | print_cellular_status(&ifdesc.link_status.u.cellular); | |
2236 | else if (ifdesc.link_status.link_status_type == | |
2237 | NSTAT_IFNET_DESC_LINK_STATUS_TYPE_WIFI) | |
2238 | print_wifi_status(&ifdesc.link_status.u.wifi); | |
2239 | ||
2240 | fflush(stdout); | |
2241 | ||
2242 | if (interval > 0) { | |
2243 | sigemptyset(&sigset); | |
2244 | sigaddset(&sigset, SIGALRM); | |
2245 | (void) sigprocmask(SIG_BLOCK, &sigset, &oldsigset); | |
2246 | if (!signalled) { | |
2247 | sigemptyset(&sigset); | |
2248 | sigsuspend(&sigset); | |
2249 | } | |
2250 | (void) sigprocmask(SIG_SETMASK, &oldsigset, NULL); | |
2251 | ||
2252 | signalled = NO; | |
2253 | goto loop; | |
2254 | } | |
2255 | done: | |
2256 | if (sref) | |
2257 | rem_nstat_src(ctl_fd, sref); | |
2258 | close(ctl_fd); | |
2259 | } |