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