1/*
2 * Copyright (c) 2008-2013 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
67#include <net/if.h>
68#include <net/if_var.h>
69#include <net/if_dl.h>
70#include <net/if_types.h>
71#include <net/if_mib.h>
72#include <net/if_llreach.h>
73#include <net/ethernet.h>
74#include <net/route.h>
75
76#include <net/pktsched/pktsched.h>
77#include <net/classq/if_classq.h>
78
79#include <netinet/in.h>
80#include <netinet/in_var.h>
81
82#include <arpa/inet.h>
83
84#include <signal.h>
85#include <stdio.h>
86#include <string.h>
87#include <unistd.h>
88#include <stdlib.h>
89#include <err.h>
90#include <errno.h>
91
92#include "netstat.h"
93
94#define	YES	1
95#define	NO	0
96
97#define ROUNDUP(a, size) (((a) & ((size) - 1)) ? (1 + ((a)|(size - 1))) : (a))
98
99#define NEXT_SA(p) (struct sockaddr *) \
100    ((caddr_t)p + (p->sa_len ? ROUNDUP(p->sa_len, sizeof(uint32_t)) : \
101    sizeof(uint32_t)))
102
103static void sidewaysintpr ();
104static void catchalarm (int);
105static char *sec2str(time_t);
106static void llreach_sysctl(uint32_t);
107static char *nsec_to_str(unsigned long long);
108static char *qtype2str(classq_type_t);
109static char *sched2str(unsigned int);
110static char *qid2str(unsigned int);
111static char *qstate2str(unsigned int);
112static char *tcqslot2str(unsigned int);
113static char *rate2str(long double);
114
115#define AVGN_MAX	8
116
117struct queue_stats {
118	int			 avgn;
119	double			 avg_bytes;
120	double			 avg_packets;
121	u_int64_t		 prev_bytes;
122	u_int64_t		 prev_packets;
123	unsigned int		 printed;
124	unsigned int		 handle;
125};
126
127static void print_cbqstats(int slot, struct cbq_classstats *,
128    struct queue_stats *);
129static void print_priqstats(int slot, struct priq_classstats *,
130    struct queue_stats *);
131static void print_hfscstats(int slot, struct hfsc_classstats *,
132    struct queue_stats *);
133static void print_fairqstats(int slot, struct fairq_classstats *,
134    struct queue_stats *);
135static void print_tcqstats(int slot, struct tcq_classstats *,
136    struct queue_stats *);
137static void print_qfqstats(int slot, struct qfq_classstats *,
138    struct queue_stats *);
139static void print_sfbstats(struct sfb_stats *);
140static void update_avg(struct if_ifclassq_stats *, struct queue_stats *);
141
142struct queue_stats qstats[IFCQ_SC_MAX];
143
144#ifdef INET6
145char *netname6 (struct sockaddr_in6 *, struct sockaddr *);
146static char ntop_buf[INET6_ADDRSTRLEN];		/* for inet_ntop() */
147#endif
148
149/*
150 * Display a formatted value, or a '-' in the same space.
151 */
152static void
153show_stat(const char *fmt, int width, u_int64_t value, short showvalue)
154{
155	char newfmt[32];
156
157	/* Construct the format string */
158	if (showvalue) {
159		snprintf(newfmt, sizeof(newfmt), "%%%d%s", width, fmt);
160		printf(newfmt, value);
161	} else {
162		snprintf(newfmt, sizeof(newfmt), "%%%ds", width);
163		printf(newfmt, "-");
164	}
165}
166
167size_t
168get_rti_info(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
169{
170    int			i;
171    size_t		len = 0;
172
173    for (i = 0; i < RTAX_MAX; i++) {
174        if (addrs & (1 << i)) {
175            rti_info[i] = sa;
176            if (sa->sa_len < sizeof(struct sockaddr))
177                len += sizeof(struct sockaddr);
178            else
179                len += sa->sa_len;
180            sa = NEXT_SA(sa);
181        } else {
182            rti_info[i] = NULL;
183        }
184    }
185    return len;
186}
187
188static void
189multipr(int family, char *buf, char *lim)
190{
191    char  *next;
192
193    for (next = buf; next < lim; ) {
194		struct ifma_msghdr2	*ifmam = (struct ifma_msghdr2 *)next;
195		struct sockaddr *rti_info[RTAX_MAX];
196		struct sockaddr *sa;
197		const char *fmt = 0;
198
199		next += ifmam->ifmam_msglen;
200		if (ifmam->ifmam_type == RTM_IFINFO2)
201			break;
202		else if (ifmam->ifmam_type != RTM_NEWMADDR2)
203			continue;
204		get_rti_info(ifmam->ifmam_addrs, (struct sockaddr*)(ifmam + 1), rti_info);
205		sa = rti_info[RTAX_IFA];
206
207		if (sa->sa_family != family)
208			continue;
209		switch (sa->sa_family) {
210			case AF_INET: {
211				struct sockaddr_in *sin = (struct sockaddr_in *)sa;
212
213				fmt = routename(sin->sin_addr.s_addr);
214				break;
215			}
216	#ifdef INET6
217			case AF_INET6: {
218				struct sockaddr_in6 sin6;
219
220				memcpy(&sin6, sa, sizeof(struct sockaddr_in6));
221
222				if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
223					IN6_IS_ADDR_MC_NODELOCAL(&sin6.sin6_addr) ||
224					IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) {
225					sin6.sin6_scope_id = ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
226					sin6.sin6_addr.s6_addr[2] = 0;
227					sin6.sin6_addr.s6_addr[3] = 0;
228				}
229
230				printf("%23s %-19.19s(refs: %d)\n", "",
231				    inet_ntop(AF_INET6, &sin6.sin6_addr,
232				    ntop_buf, sizeof(ntop_buf)),
233						ifmam->ifmam_refcount);
234				break;
235			}
236	#endif /* INET6 */
237			case AF_LINK: {
238				struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
239
240				switch (sdl->sdl_type) {
241				case IFT_ETHER:
242				case IFT_FDDI:
243					fmt = ether_ntoa((struct ether_addr *)
244						LLADDR(sdl));
245					break;
246				}
247				break;
248			}
249		}
250		if (fmt)
251			printf("%23s %s\n", "", fmt);
252	}
253}
254
255/*
256 * Print a description of the network interfaces.
257 */
258void
259intpr(void (*pfunc)(char *))
260{
261	u_int64_t opackets = 0;
262	u_int64_t ipackets = 0;
263	u_int64_t obytes = 0;
264	u_int64_t ibytes = 0;
265	u_int64_t oerrors = 0;
266	u_int64_t ierrors = 0;
267	u_int64_t collisions = 0;
268	u_int64_t fpackets = 0;
269	u_int64_t fbytes = 0;
270	uint32_t mtu = 0;
271	int timer = 0;
272	int drops = 0;
273	struct sockaddr *sa = NULL;
274	char name[32];
275	short network_layer;
276	short link_layer;
277	int mib[6];
278	char *buf = NULL, *lim, *next;
279	size_t len;
280	struct if_msghdr *ifm;
281	struct sockaddr *rti_info[RTAX_MAX];
282	unsigned int ifindex = 0;
283
284	if (interval) {
285		sidewaysintpr();
286		return;
287	}
288
289	if (interface != 0)
290		ifindex = if_nametoindex(interface);
291
292	mib[0]	= CTL_NET;			// networking subsystem
293	mib[1]	= PF_ROUTE;			// type of information
294	mib[2]	= 0;				// protocol (IPPROTO_xxx)
295	mib[3]	= 0;				// address family
296	mib[4]	= NET_RT_IFLIST2;	// operation
297	mib[5]	= 0;
298	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
299		return;
300	if ((buf = malloc(len)) == NULL) {
301		printf("malloc failed\n");
302		exit(1);
303	}
304	if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
305		if (buf)
306			free(buf);
307		return;
308	}
309
310	if (!pfunc) {
311		printf("%-5.5s %-5.5s %-13.13s %-15.15s %8.8s %5.5s",
312		       "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs");
313		if (prioflag >= 0)
314			printf(" %8.8s %8.8s", "Itcpkts", "Ipvpkts");
315		if (bflag) {
316			printf(" %10.10s","Ibytes");
317			if (prioflag >= 0)
318				printf(" %8.8s %8.8s", "Itcbytes", "Ipvbytes");
319		}
320		printf(" %8.8s %5.5s", "Opkts", "Oerrs");
321		if (prioflag >= 0)
322			printf(" %8.8s %8.8s", "Otcpkts", "Opvpkts");
323		if (bflag) {
324			printf(" %10.10s","Obytes");
325			if (prioflag >= 0)
326				printf(" %8.8s %8.8s", "Otcbytes", "Opvbytes");
327		}
328		printf(" %5s", "Coll");
329		if (tflag)
330			printf(" %s", "Time");
331		if (dflag)
332			printf(" %s", "Drop");
333		if (Fflag) {
334			printf(" %8.8s", "Fpkts");
335			if (bflag)
336				printf(" %10.10s", "Fbytes");
337		}
338		putchar('\n');
339	}
340	lim = buf + len;
341	for (next = buf; next < lim; ) {
342		char *cp;
343		int n, m;
344		struct ifmibdata_supplemental ifmsupp;
345		u_int64_t	ift_itcp = 0;	/* input tc packets */
346		u_int64_t	ift_itcb = 0;	/* input tc bytes */
347		u_int64_t	ift_otcp = 0;	/* output tc packets */
348		u_int64_t	ift_otcb = 0;	/* output tc bytes */
349		u_int64_t	ift_ipvp = 0;	/* input priv tc packets */
350		u_int64_t	ift_ipvb = 0;	/* input priv tc bytes */
351		u_int64_t	ift_opvp = 0;	/* output priv tc packets */
352		u_int64_t	ift_opvb = 0;	/* output priv tc bytes */
353
354		bzero(&ifmsupp, sizeof(struct ifmibdata_supplemental));
355
356		network_layer = 0;
357		link_layer = 0;
358		ifm = (struct if_msghdr *)next;
359		next += ifm->ifm_msglen;
360
361		if (ifm->ifm_type == RTM_IFINFO2) {
362			struct if_msghdr2 *if2m = (struct if_msghdr2 *)ifm;
363			struct sockaddr_dl *sdl =
364			    (struct sockaddr_dl *)(if2m + 1);
365			int mibname[6];
366			size_t miblen = sizeof(struct ifmibdata_supplemental);
367
368			strncpy(name, sdl->sdl_data, sdl->sdl_nlen);
369			name[sdl->sdl_nlen] = 0;
370			if (interface != 0 && if2m->ifm_index != ifindex)
371				continue;
372			cp = index(name, '\0');
373
374			if (pfunc) {
375				(*pfunc)(name);
376				continue;
377			}
378
379			if ((if2m->ifm_flags & IFF_UP) == 0)
380				*cp++ = '*';
381			*cp = '\0';
382
383			/*
384			 * Get the interface stats.  These may get
385			 * overriden below on a per-interface basis.
386			 */
387			opackets = if2m->ifm_data.ifi_opackets;
388			ipackets = if2m->ifm_data.ifi_ipackets;
389			obytes = if2m->ifm_data.ifi_obytes;
390			ibytes = if2m->ifm_data.ifi_ibytes;
391			oerrors =if2m->ifm_data.ifi_oerrors;
392			ierrors = if2m->ifm_data.ifi_ierrors;
393			collisions = if2m->ifm_data.ifi_collisions;
394			timer = if2m->ifm_timer;
395			drops = if2m->ifm_snd_drops;
396			mtu = if2m->ifm_data.ifi_mtu;
397
398			/* Common OID prefix */
399			mibname[0] = CTL_NET;
400			mibname[1] = PF_LINK;
401			mibname[2] = NETLINK_GENERIC;
402			mibname[3] = IFMIB_IFDATA;
403			mibname[4] = if2m->ifm_index;
404			mibname[5] = IFDATA_SUPPLEMENTAL;
405			if (sysctl(mibname, 6, &ifmsupp, &miblen, NULL, 0) == -1)
406				err(1, "sysctl IFDATA_SUPPLEMENTAL");
407
408			fpackets = ifmsupp.ifmd_data_extended.ifi_fpackets;
409			fbytes = ifmsupp.ifmd_data_extended.ifi_fbytes;
410
411			if (prioflag >= 0) {
412				switch (prioflag) {
413				case SO_TC_BE:
414					ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ibepackets;
415					ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ibebytes;
416					ift_otcp = ifmsupp.ifmd_traffic_class.ifi_obepackets;
417					ift_otcb = ifmsupp.ifmd_traffic_class.ifi_obebytes;
418					break;
419				case SO_TC_BK:
420					ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ibkpackets;
421					ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ibkbytes;
422					ift_otcp = ifmsupp.ifmd_traffic_class.ifi_obkpackets;
423					ift_otcb = ifmsupp.ifmd_traffic_class.ifi_obkbytes;
424					break;
425				case SO_TC_VI:
426					ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ivipackets;
427					ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ivibytes;
428					ift_otcp = ifmsupp.ifmd_traffic_class.ifi_ovipackets;
429					ift_otcb = ifmsupp.ifmd_traffic_class.ifi_ovibytes;
430					break;
431				case SO_TC_VO:
432					ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ivopackets;
433					ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ivobytes;
434					ift_otcp = ifmsupp.ifmd_traffic_class.ifi_ovopackets;
435					ift_otcb = ifmsupp.ifmd_traffic_class.ifi_ovobytes;
436					break;
437				default:
438					ift_itcp = 0;
439					ift_itcb = 0;
440					ift_otcp = 0;
441					ift_otcb = 0;
442					ift_ipvp = 0;
443					ift_ipvb = 0;
444					ift_opvp = 0;
445					ift_opvb = 0;
446					break;
447				}
448				ift_ipvp = ifmsupp.ifmd_traffic_class.ifi_ipvpackets;
449				ift_ipvb = ifmsupp.ifmd_traffic_class.ifi_ipvbytes;
450				ift_opvp = ifmsupp.ifmd_traffic_class.ifi_opvpackets;
451				ift_opvb = ifmsupp.ifmd_traffic_class.ifi_opvbytes;
452			}
453
454			get_rti_info(if2m->ifm_addrs,
455			    (struct sockaddr*)(if2m + 1), rti_info);
456			sa = rti_info[RTAX_IFP];
457		} else if (ifm->ifm_type == RTM_NEWADDR) {
458			struct ifa_msghdr *ifam = (struct ifa_msghdr *)ifm;
459
460			if (interface != 0 && ifam->ifam_index != ifindex)
461				continue;
462			get_rti_info(ifam->ifam_addrs,
463			    (struct sockaddr*)(ifam + 1), rti_info);
464			sa = rti_info[RTAX_IFA];
465		} else {
466			continue;
467		}
468		printf("%-5.5s %-5u ", name, mtu);
469
470		if (sa == 0) {
471			printf("%-13.13s ", "none");
472			printf("%-15.15s ", "none");
473		} else {
474			switch (sa->sa_family) {
475			case AF_UNSPEC:
476				printf("%-13.13s ", "none");
477				printf("%-15.15s ", "none");
478				break;
479
480			case AF_INET: {
481				struct sockaddr_in *sin =
482				    (struct sockaddr_in *)sa;
483				struct sockaddr_in mask;
484
485				mask.sin_addr.s_addr = 0;
486				memcpy(&mask, rti_info[RTAX_NETMASK],
487				    ((struct sockaddr_in *)
488				    rti_info[RTAX_NETMASK])->sin_len);
489
490				printf("%-13.13s ",
491				    netname(sin->sin_addr.s_addr &
492				    mask.sin_addr.s_addr,
493				    ntohl(mask.sin_addr.s_addr)));
494
495				printf("%-15.15s ",
496				    routename(sin->sin_addr.s_addr));
497
498				network_layer = 1;
499				break;
500			}
501#ifdef INET6
502			case AF_INET6: {
503				struct sockaddr_in6 *sin6 =
504				    (struct sockaddr_in6 *)sa;
505				struct sockaddr *mask =
506				    (struct sockaddr *)rti_info[RTAX_NETMASK];
507
508				printf("%-11.11s ", netname6(sin6, mask));
509				printf("%-17.17s ", (char *)inet_ntop(AF_INET6,
510				    &sin6->sin6_addr, ntop_buf,
511				    sizeof(ntop_buf)));
512
513				network_layer = 1;
514				break;
515			}
516#endif /*INET6*/
517			case AF_LINK: {
518				struct sockaddr_dl *sdl =
519				    (struct sockaddr_dl *)sa;
520				char linknum[10];
521				cp = (char *)LLADDR(sdl);
522				n = sdl->sdl_alen;
523				snprintf(linknum, sizeof(linknum),
524				    "<Link#%d>", sdl->sdl_index);
525				m = printf("%-11.11s ", linknum);
526				goto hexprint;
527			}
528
529			default:
530				m = printf("(%d)", sa->sa_family);
531				for (cp = sa->sa_len + (char *)sa;
532					--cp > sa->sa_data && (*cp == 0);) {}
533				n = cp - sa->sa_data + 1;
534				cp = sa->sa_data;
535			hexprint:
536				while (--n >= 0)
537					m += printf("%02x%c", *cp++ & 0xff,
538						    n > 0 ? ':' : ' ');
539				m = 30 - m;
540				while (m-- > 0)
541					putchar(' ');
542
543				link_layer = 1;
544				break;
545			}
546		}
547
548		show_stat("llu", 8, ipackets, link_layer|network_layer);
549		printf(" ");
550		show_stat("llu", 5, ierrors, link_layer);
551		printf(" ");
552		if (prioflag >= 0) {
553			show_stat("llu", 8, ift_itcp, link_layer|network_layer);
554			printf(" ");
555			show_stat("llu", 8, ift_ipvp, link_layer|network_layer);
556			printf(" ");
557		}
558		if (bflag) {
559			show_stat("llu", 10, ibytes, link_layer|network_layer);
560			printf(" ");
561			if (prioflag >= 0) {
562				show_stat("llu", 8, ift_itcb, link_layer|network_layer);
563				printf(" ");
564				show_stat("llu", 8, ift_ipvb, link_layer|network_layer);
565				printf(" ");
566			}
567		}
568		show_stat("llu", 8, opackets, link_layer|network_layer);
569		printf(" ");
570		show_stat("llu", 5, oerrors, link_layer);
571		printf(" ");
572		if (prioflag >= 0) {
573			show_stat("llu", 8, ift_otcp, link_layer|network_layer);
574			printf(" ");
575			show_stat("llu", 8, ift_opvp, link_layer|network_layer);
576			printf(" ");
577		}
578		if (bflag) {
579			show_stat("llu", 10, obytes, link_layer|network_layer);
580			printf(" ");
581			if (prioflag >= 0) {
582				show_stat("llu", 8, ift_otcb, link_layer|network_layer);
583				printf(" ");
584				show_stat("llu", 8, ift_opvb, link_layer|network_layer);
585				printf(" ");
586			}
587		}
588		show_stat("llu", 5, collisions, link_layer);
589		if (tflag) {
590			printf(" ");
591			show_stat("d", 3, timer, link_layer);
592		}
593		if (dflag) {
594			printf(" ");
595			show_stat("d", 3, drops, link_layer);
596		}
597		if (Fflag) {
598			printf(" ");
599			show_stat("llu", 8, fpackets, link_layer|network_layer);
600			if (bflag) {
601				printf(" ");
602				show_stat("llu", 10, fbytes,
603				    link_layer|network_layer);
604			}
605		}
606		putchar('\n');
607
608		if (aflag)
609			multipr(sa->sa_family, next, lim);
610	}
611	free(buf);
612}
613
614struct	iftot {
615	SLIST_ENTRY(iftot) chain;
616	char		ift_name[16];	/* interface name */
617	u_int64_t	ift_ip;		/* input packets */
618	u_int64_t	ift_ie;		/* input errors */
619	u_int64_t	ift_op;		/* output packets */
620	u_int64_t	ift_oe;		/* output errors */
621	u_int64_t	ift_co;		/* collisions */
622	u_int64_t	ift_dr;		/* drops */
623	u_int64_t	ift_ib;		/* input bytes */
624	u_int64_t	ift_ob;		/* output bytes */
625	u_int64_t	ift_itcp;	/* input tc packets */
626	u_int64_t	ift_itcb;	/* input tc bytes */
627	u_int64_t	ift_otcp;	/* output tc packets */
628	u_int64_t	ift_otcb;	/* output tc bytes */
629	u_int64_t	ift_ipvp;	/* input priv tc packets */
630	u_int64_t	ift_ipvb;	/* input priv tc bytes */
631	u_int64_t	ift_opvp;	/* output priv tc packets */
632	u_int64_t	ift_opvb;	/* output priv tc bytes */
633	u_int64_t	ift_fp;		/* forwarded packets */
634	u_int64_t	ift_fb;		/* forwarded bytes */
635};
636
637u_char	signalled;			/* set if alarm goes off "early" */
638
639/*
640 * Print a running summary of interface statistics.
641 * Repeat display every interval seconds, showing statistics
642 * collected over that interval.  Assumes that interval is non-zero.
643 * First line printed at top of screen is always cumulative.
644 * XXX - should be rewritten to use ifmib(4).
645 */
646static void
647sidewaysintpr()
648{
649	struct iftot *total, *sum, *interesting;
650	register int line;
651	int first;
652	int name[6];
653	size_t len;
654	unsigned int ifcount, i;
655	struct ifmibdata *ifmdall = 0;
656	int interesting_row;
657	sigset_t sigset, oldsigset;
658	struct itimerval timer_interval;
659
660	/* Common OID prefix */
661	name[0] = CTL_NET;
662	name[1] = PF_LINK;
663	name[2] = NETLINK_GENERIC;
664
665	len = sizeof(int);
666	name[3] = IFMIB_SYSTEM;
667	name[4] = IFMIB_IFCOUNT;
668	if (sysctl(name, 5, &ifcount, &len, 0, 0) == 1)
669		err(1, "sysctl IFMIB_IFCOUNT");
670
671	len = ifcount * sizeof(struct ifmibdata);
672	ifmdall = malloc(len);
673	if (ifmdall == 0)
674		err(1, "malloc failed");
675	name[3] = IFMIB_IFALLDATA;
676	name[4] = 0;
677	name[5] = IFDATA_GENERAL;
678	if (sysctl(name, 6, ifmdall, &len, (void *)0, 0) == -1)
679		err(1, "sysctl IFMIB_IFALLDATA");
680
681	interesting = NULL;
682	interesting_row = 0;
683	for (i = 0; i < ifcount; i++) {
684		struct ifmibdata *ifmd = ifmdall + i;
685
686		if (interface && strcmp(ifmd->ifmd_name, interface) == 0) {
687			if ((interesting = calloc(ifcount,
688			    sizeof(struct iftot))) == NULL)
689				err(1, "malloc failed");
690			interesting_row = if_nametoindex(interface);
691			snprintf(interesting->ift_name, 16, "(%s)",
692			    ifmd->ifmd_name);;
693		}
694	}
695	if ((total = calloc(1, sizeof(struct iftot))) == NULL)
696		err(1, "malloc failed");
697
698	if ((sum = calloc(1, sizeof(struct iftot))) == NULL)
699		err(1, "malloc failed");
700
701	/* create a timer that fires repeatedly every interval seconds */
702	timer_interval.it_value.tv_sec = interval;
703	timer_interval.it_value.tv_usec = 0;
704	timer_interval.it_interval.tv_sec = interval;
705	timer_interval.it_interval.tv_usec = 0;
706	(void)signal(SIGALRM, catchalarm);
707	signalled = NO;
708	(void)setitimer(ITIMER_REAL, &timer_interval, NULL);
709	first = 1;
710banner:
711	if (vflag > 0)
712		printf("%9s", " ");
713
714	if (prioflag >= 0)
715		printf("%39s %39s %36s", "input",
716		    interesting ? interesting->ift_name : "(Total)", "output");
717	else
718		printf("%17s %14s %16s", "input",
719		    interesting ? interesting->ift_name : "(Total)", "output");
720	putchar('\n');
721
722	if (vflag > 0)
723		printf("%9s", " ");
724
725	printf("%10s %5s %10s ", "packets", "errs", "bytes");
726	if (prioflag >= 0)
727		printf(" %10s %10s %10s %10s",
728		    "tcpkts", "tcbytes", "pvpkts", "pvbytes");
729	printf("%10s %5s %10s %5s", "packets", "errs", "bytes", "colls");
730	if (dflag)
731		printf(" %5.5s", "drops");
732	if (prioflag >= 0)
733		printf(" %10s %10s %10s %10s",
734		    "tcpkts", "tcbytes", "pvpkts", "pvbytes");
735	if (Fflag)
736		printf(" %10s %10s", "fpackets", "fbytes");
737	putchar('\n');
738	fflush(stdout);
739	line = 0;
740loop:
741	if (vflag && !first)
742		print_time();
743
744	if (interesting != NULL) {
745		struct ifmibdata ifmd;
746		struct ifmibdata_supplemental ifmsupp;
747
748		len = sizeof(struct ifmibdata);
749		name[3] = IFMIB_IFDATA;
750		name[4] = interesting_row;
751		name[5] = IFDATA_GENERAL;
752		if (sysctl(name, 6, &ifmd, &len, (void *)0, 0) == -1)
753			err(1, "sysctl IFDATA_GENERAL %d", interesting_row);
754
755		len = sizeof(struct ifmibdata_supplemental);
756		name[3] = IFMIB_IFDATA;
757		name[4] = interesting_row;
758		name[5] = IFDATA_SUPPLEMENTAL;
759		if (sysctl(name, 6, &ifmsupp, &len, (void *)0, 0) == -1)
760			err(1, "sysctl IFDATA_SUPPLEMENTAL %d",
761			    interesting_row);
762
763		if (!first) {
764			printf("%10llu %5llu %10llu ",
765			    ifmd.ifmd_data.ifi_ipackets - interesting->ift_ip,
766			    ifmd.ifmd_data.ifi_ierrors - interesting->ift_ie,
767			    ifmd.ifmd_data.ifi_ibytes - interesting->ift_ib);
768			switch (prioflag) {
769			case SO_TC_BE:
770				printf("%10llu %10llu ",
771				    ifmsupp.ifmd_traffic_class.ifi_ibepackets -
772				    interesting->ift_itcp,
773				    ifmsupp.ifmd_traffic_class.ifi_ibebytes -
774				    interesting->ift_itcb);
775				break;
776			case SO_TC_BK:
777				printf("%10llu %10llu ",
778				    ifmsupp.ifmd_traffic_class.ifi_ibkpackets -
779				    interesting->ift_itcp,
780				    ifmsupp.ifmd_traffic_class.ifi_ibkbytes -
781				    interesting->ift_itcb);
782				break;
783			case SO_TC_VI:
784				printf("%10llu %10llu ",
785				    ifmsupp.ifmd_traffic_class.ifi_ivipackets -
786				    interesting->ift_itcp,
787				    ifmsupp.ifmd_traffic_class.ifi_ivibytes -
788				    interesting->ift_itcb);
789				break;
790			case SO_TC_VO:
791				printf("%10llu %10llu ",
792				    ifmsupp.ifmd_traffic_class.ifi_ivopackets -
793				    interesting->ift_itcp,
794				    ifmsupp.ifmd_traffic_class.ifi_ivobytes -
795				    interesting->ift_itcb);
796				break;
797			default:
798				break;
799			}
800			if (prioflag >= 0) {
801				printf("%10llu %10llu ",
802				    ifmsupp.ifmd_traffic_class.ifi_ipvpackets -
803				    interesting->ift_ipvp,
804				    ifmsupp.ifmd_traffic_class.ifi_ipvbytes -
805				    interesting->ift_ipvb);
806			}
807			printf("%10llu %5llu %10llu %5llu",
808			    ifmd.ifmd_data.ifi_opackets - interesting->ift_op,
809			    ifmd.ifmd_data.ifi_oerrors - interesting->ift_oe,
810			    ifmd.ifmd_data.ifi_obytes - interesting->ift_ob,
811			    ifmd.ifmd_data.ifi_collisions - interesting->ift_co);
812			if (dflag)
813				printf(" %5llu",
814				    ifmd.ifmd_snd_drops - interesting->ift_dr);
815			switch (prioflag) {
816			case SO_TC_BE:
817				printf(" %10llu %10llu",
818				    ifmsupp.ifmd_traffic_class.ifi_obepackets -
819				    interesting->ift_otcp,
820				    ifmsupp.ifmd_traffic_class.ifi_obebytes -
821				    interesting->ift_otcb);
822				break;
823			case SO_TC_BK:
824				printf(" %10llu %10llu",
825				    ifmsupp.ifmd_traffic_class.ifi_obkpackets -
826				    interesting->ift_otcp,
827				    ifmsupp.ifmd_traffic_class.ifi_obkbytes -
828				    interesting->ift_otcb);
829				break;
830			case SO_TC_VI:
831				printf(" %10llu %10llu",
832				    ifmsupp.ifmd_traffic_class.ifi_ovipackets -
833				    interesting->ift_otcp,
834				    ifmsupp.ifmd_traffic_class.ifi_ovibytes -
835				    interesting->ift_otcb);
836				break;
837			case SO_TC_VO:
838				printf(" %10llu %10llu",
839				    ifmsupp.ifmd_traffic_class.ifi_ovopackets -
840				    interesting->ift_otcp,
841				    ifmsupp.ifmd_traffic_class.ifi_ovobytes -
842				    interesting->ift_otcb);
843				break;
844			default:
845				break;
846			}
847			if (prioflag >= 0) {
848				printf("%10llu %10llu ",
849				    ifmsupp.ifmd_traffic_class.ifi_opvpackets -
850				    interesting->ift_opvp,
851				    ifmsupp.ifmd_traffic_class.ifi_opvbytes -
852				    interesting->ift_opvb);
853			}
854			if (Fflag) {
855				printf("%10llu %10llu",
856				    ifmsupp.ifmd_data_extended.ifi_fpackets -
857				    interesting->ift_fp,
858				    ifmsupp.ifmd_data_extended.ifi_fbytes -
859				    interesting->ift_fb);
860			}
861		}
862		interesting->ift_ip = ifmd.ifmd_data.ifi_ipackets;
863		interesting->ift_ie = ifmd.ifmd_data.ifi_ierrors;
864		interesting->ift_ib = ifmd.ifmd_data.ifi_ibytes;
865		interesting->ift_op = ifmd.ifmd_data.ifi_opackets;
866		interesting->ift_oe = ifmd.ifmd_data.ifi_oerrors;
867		interesting->ift_ob = ifmd.ifmd_data.ifi_obytes;
868		interesting->ift_co = ifmd.ifmd_data.ifi_collisions;
869		interesting->ift_dr = ifmd.ifmd_snd_drops;
870
871		/* private counters */
872		switch (prioflag) {
873		case SO_TC_BE:
874			interesting->ift_itcp =
875			    ifmsupp.ifmd_traffic_class.ifi_ibepackets;
876			interesting->ift_itcb =
877			    ifmsupp.ifmd_traffic_class.ifi_ibebytes;
878			interesting->ift_otcp =
879			    ifmsupp.ifmd_traffic_class.ifi_obepackets;
880			interesting->ift_otcb =
881			    ifmsupp.ifmd_traffic_class.ifi_obebytes;
882			break;
883		case SO_TC_BK:
884			interesting->ift_itcp =
885			    ifmsupp.ifmd_traffic_class.ifi_ibkpackets;
886			interesting->ift_itcb =
887			    ifmsupp.ifmd_traffic_class.ifi_ibkbytes;
888			interesting->ift_otcp =
889			    ifmsupp.ifmd_traffic_class.ifi_obkpackets;
890			interesting->ift_otcb =
891			    ifmsupp.ifmd_traffic_class.ifi_obkbytes;
892			break;
893		case SO_TC_VI:
894			interesting->ift_itcp =
895			    ifmsupp.ifmd_traffic_class.ifi_ivipackets;
896			interesting->ift_itcb =
897			    ifmsupp.ifmd_traffic_class.ifi_ivibytes;
898			interesting->ift_otcp =
899			    ifmsupp.ifmd_traffic_class.ifi_ovipackets;
900			interesting->ift_otcb =
901			    ifmsupp.ifmd_traffic_class.ifi_ovibytes;
902			break;
903		case SO_TC_VO:
904			interesting->ift_itcp =
905			    ifmsupp.ifmd_traffic_class.ifi_ivopackets;
906			interesting->ift_itcb =
907			    ifmsupp.ifmd_traffic_class.ifi_ivobytes;
908			interesting->ift_otcp =
909			    ifmsupp.ifmd_traffic_class.ifi_ovopackets;
910			interesting->ift_otcb =
911			    ifmsupp.ifmd_traffic_class.ifi_ovobytes;
912			break;
913		default:
914			break;
915		}
916		if (prioflag >= 0) {
917			interesting->ift_ipvp =
918			    ifmsupp.ifmd_traffic_class.ifi_ipvpackets;
919			interesting->ift_ipvb =
920			    ifmsupp.ifmd_traffic_class.ifi_ipvbytes;
921			interesting->ift_opvp =
922			    ifmsupp.ifmd_traffic_class.ifi_opvpackets;
923			interesting->ift_opvb =
924			    ifmsupp.ifmd_traffic_class.ifi_opvbytes;
925		}
926		interesting->ift_fp = ifmsupp.ifmd_data_extended.ifi_fpackets;
927		interesting->ift_fb = ifmsupp.ifmd_data_extended.ifi_fbytes;
928	} else {
929		unsigned int latest_ifcount;
930		struct ifmibdata_supplemental *ifmsuppall = NULL;
931
932		len = sizeof(int);
933		name[3] = IFMIB_SYSTEM;
934		name[4] = IFMIB_IFCOUNT;
935		if (sysctl(name, 5, &latest_ifcount, &len, 0, 0) == 1)
936			err(1, "sysctl IFMIB_IFCOUNT");
937		if (latest_ifcount > ifcount) {
938			ifcount = latest_ifcount;
939			len = ifcount * sizeof(struct ifmibdata);
940			free(ifmdall);
941			ifmdall = malloc(len);
942			if (ifmdall == 0)
943				err(1, "malloc ifmdall failed");
944		} else if (latest_ifcount > ifcount) {
945			ifcount = latest_ifcount;
946			len = ifcount * sizeof(struct ifmibdata);
947		}
948		len = ifcount * sizeof(struct ifmibdata);
949		name[3] = IFMIB_IFALLDATA;
950		name[4] = 0;
951		name[5] = IFDATA_GENERAL;
952		if (sysctl(name, 6, ifmdall, &len, (void *)0, 0) == -1)
953			err(1, "sysctl IFMIB_IFALLDATA");
954
955		len = ifcount * sizeof(struct ifmibdata_supplemental);
956		ifmsuppall = malloc(len);
957		if (ifmsuppall == NULL)
958			err(1, "malloc ifmsuppall failed");
959		name[3] = IFMIB_IFALLDATA;
960		name[4] = 0;
961		name[5] = IFDATA_SUPPLEMENTAL;
962		if (sysctl(name, 6, ifmsuppall, &len, (void *)0, 0) == -1)
963			err(1, "sysctl IFMIB_IFALLDATA SUPPLEMENTAL");
964
965		sum->ift_ip = 0;
966		sum->ift_ie = 0;
967		sum->ift_ib = 0;
968		sum->ift_op = 0;
969		sum->ift_oe = 0;
970		sum->ift_ob = 0;
971		sum->ift_co = 0;
972		sum->ift_dr = 0;
973		sum->ift_itcp = 0;
974		sum->ift_itcb = 0;
975		sum->ift_otcp = 0;
976		sum->ift_otcb = 0;
977		sum->ift_ipvp = 0;
978		sum->ift_ipvb = 0;
979		sum->ift_opvp = 0;
980		sum->ift_opvb = 0;
981		sum->ift_fp = 0;
982		sum->ift_fb = 0;
983		for (i = 0; i < ifcount; i++) {
984			struct ifmibdata *ifmd = ifmdall + i;
985			struct ifmibdata_supplemental *ifmsupp = ifmsuppall + i;
986
987			sum->ift_ip += ifmd->ifmd_data.ifi_ipackets;
988			sum->ift_ie += ifmd->ifmd_data.ifi_ierrors;
989			sum->ift_ib += ifmd->ifmd_data.ifi_ibytes;
990			sum->ift_op += ifmd->ifmd_data.ifi_opackets;
991			sum->ift_oe += ifmd->ifmd_data.ifi_oerrors;
992			sum->ift_ob += ifmd->ifmd_data.ifi_obytes;
993			sum->ift_co += ifmd->ifmd_data.ifi_collisions;
994			sum->ift_dr += ifmd->ifmd_snd_drops;
995			/* private counters */
996			if (prioflag >= 0) {
997				switch (prioflag) {
998				case SO_TC_BE:
999					sum->ift_itcp += ifmsupp->ifmd_traffic_class.ifi_ibepackets;
1000					sum->ift_itcb += ifmsupp->ifmd_traffic_class.ifi_ibebytes;
1001					sum->ift_otcp += ifmsupp->ifmd_traffic_class.ifi_obepackets;
1002					sum->ift_otcb += ifmsupp->ifmd_traffic_class.ifi_obebytes;
1003					break;
1004				case SO_TC_BK:
1005					sum->ift_itcp += ifmsupp->ifmd_traffic_class.ifi_ibkpackets;
1006					sum->ift_itcb += ifmsupp->ifmd_traffic_class.ifi_ibkbytes;
1007					sum->ift_otcp += ifmsupp->ifmd_traffic_class.ifi_obkpackets;
1008					sum->ift_otcb += ifmsupp->ifmd_traffic_class.ifi_obkbytes;
1009					break;
1010				case SO_TC_VI:
1011					sum->ift_itcp += ifmsupp->ifmd_traffic_class.ifi_ivipackets;
1012					sum->ift_itcb += ifmsupp->ifmd_traffic_class.ifi_ivibytes;
1013					sum->ift_otcp += ifmsupp->ifmd_traffic_class.ifi_ovipackets;
1014					sum->ift_otcb += ifmsupp->ifmd_traffic_class.ifi_ovibytes;
1015					break;
1016				case SO_TC_VO:
1017					sum->ift_itcp += ifmsupp->ifmd_traffic_class.ifi_ivopackets;
1018					sum->ift_itcb += ifmsupp->ifmd_traffic_class.ifi_ivobytes;
1019					sum->ift_otcp += ifmsupp->ifmd_traffic_class.ifi_ovopackets;
1020					sum->ift_otcb += ifmsupp->ifmd_traffic_class.ifi_ovobytes;
1021					break;
1022				default:
1023					break;
1024				}
1025				sum->ift_ipvp += ifmsupp->ifmd_traffic_class.ifi_ipvpackets;
1026				sum->ift_ipvb += ifmsupp->ifmd_traffic_class.ifi_ipvbytes;
1027				sum->ift_opvp += ifmsupp->ifmd_traffic_class.ifi_opvpackets;
1028				sum->ift_opvb += ifmsupp->ifmd_traffic_class.ifi_opvbytes;
1029			}
1030			sum->ift_fp += ifmsupp->ifmd_data_extended.ifi_fpackets;
1031			sum->ift_fb += ifmsupp->ifmd_data_extended.ifi_fbytes;
1032		}
1033		if (!first) {
1034			printf("%10llu %5llu %10llu ",
1035				sum->ift_ip - total->ift_ip,
1036				sum->ift_ie - total->ift_ie,
1037				sum->ift_ib - total->ift_ib);
1038			if (prioflag >= 0)
1039				printf(" %10llu %10llu %10llu %10llu",
1040				    sum->ift_itcp - total->ift_itcp,
1041				    sum->ift_itcb - total->ift_itcb,
1042				    sum->ift_ipvp - total->ift_ipvp,
1043				    sum->ift_ipvb - total->ift_ipvb);
1044			printf("%10llu %5llu %10llu %5llu",
1045				sum->ift_op - total->ift_op,
1046				sum->ift_oe - total->ift_oe,
1047				sum->ift_ob - total->ift_ob,
1048				sum->ift_co - total->ift_co);
1049			if (dflag)
1050				printf(" %5llu", sum->ift_dr - total->ift_dr);
1051			if (prioflag >= 0)
1052				printf(" %10llu %10llu %10llu %10llu",
1053				    sum->ift_otcp - total->ift_otcp,
1054				    sum->ift_otcb - total->ift_otcb,
1055				    sum->ift_opvp - total->ift_opvp,
1056				    sum->ift_opvb - total->ift_opvb);
1057			if (Fflag)
1058				printf(" %10llu %10llu",
1059				    sum->ift_fp - total->ift_fp,
1060				    sum->ift_fb - total->ift_fb);
1061		}
1062		*total = *sum;
1063	}
1064	if (!first)
1065		putchar('\n');
1066	fflush(stdout);
1067	sigemptyset(&sigset);
1068	sigaddset(&sigset, SIGALRM);
1069	(void)sigprocmask(SIG_BLOCK, &sigset, &oldsigset);
1070	if (!signalled) {
1071	    sigemptyset(&sigset);
1072	    sigsuspend(&sigset);
1073	}
1074	(void)sigprocmask(SIG_SETMASK, &oldsigset, NULL);
1075
1076	signalled = NO;
1077	line++;
1078	first = 0;
1079	if (line == 21)
1080		goto banner;
1081	else
1082		goto loop;
1083	/*NOTREACHED*/
1084}
1085
1086void
1087intervalpr(void (*pr)(uint32_t, char *, int), uint32_t off, char *name , int af)
1088{
1089	struct itimerval timer_interval;
1090	sigset_t sigset, oldsigset;
1091
1092	/* create a timer that fires repeatedly every interval seconds */
1093	timer_interval.it_value.tv_sec = interval;
1094	timer_interval.it_value.tv_usec = 0;
1095	timer_interval.it_interval.tv_sec = interval;
1096	timer_interval.it_interval.tv_usec = 0;
1097	(void) signal(SIGALRM, catchalarm);
1098	signalled = NO;
1099	(void) setitimer(ITIMER_REAL, &timer_interval, NULL);
1100
1101	for (;;) {
1102		pr(off, name, af);
1103
1104		fflush(stdout);
1105		sigemptyset(&sigset);
1106		sigaddset(&sigset, SIGALRM);
1107		(void) sigprocmask(SIG_BLOCK, &sigset, &oldsigset);
1108		if (!signalled) {
1109			sigemptyset(&sigset);
1110			sigsuspend(&sigset);
1111		}
1112		(void) sigprocmask(SIG_SETMASK, &oldsigset, NULL);
1113		signalled = NO;
1114	}
1115}
1116
1117/*
1118 * Called if an interval expires before sidewaysintpr has completed a loop.
1119 * Sets a flag to not wait for the alarm.
1120 */
1121static void
1122catchalarm(int signo )
1123{
1124	signalled = YES;
1125}
1126
1127static char *
1128sec2str(total)
1129	time_t total;
1130{
1131	static char result[256];
1132	int days, hours, mins, secs;
1133	int first = 1;
1134	char *p = result;
1135
1136	days = total / 3600 / 24;
1137	hours = (total / 3600) % 24;
1138	mins = (total / 60) % 60;
1139	secs = total % 60;
1140
1141	if (days) {
1142		first = 0;
1143		p += snprintf(p, sizeof(result) - (p - result), "%dd", days);
1144	}
1145	if (!first || hours) {
1146		first = 0;
1147		p += snprintf(p, sizeof(result) - (p - result), "%dh", hours);
1148	}
1149	if (!first || mins) {
1150		first = 0;
1151		p += snprintf(p, sizeof(result) - (p - result), "%dm", mins);
1152	}
1153	snprintf(p, sizeof(result) - (p - result), "%ds", secs);
1154
1155	return(result);
1156}
1157
1158void
1159intpr_ri(void (*pfunc)(char *))
1160{
1161	int mib[6];
1162	char *buf = NULL, *lim, *next;
1163	size_t len;
1164	unsigned int ifindex = 0;
1165	struct if_msghdr2 *if2m;
1166
1167	if (interface != 0) {
1168		ifindex = if_nametoindex(interface);
1169		if (ifindex == 0) {
1170			printf("interface name is not valid: %s\n", interface);
1171			exit(1);
1172		}
1173	}
1174
1175	mib[0]	= CTL_NET;		/* networking subsystem */
1176	mib[1]	= PF_ROUTE;		/* type of information */
1177	mib[2]	= 0;			/* protocol (IPPROTO_xxx) */
1178	mib[3]	= 0;			/* address family */
1179	mib[4]	= NET_RT_IFLIST2;	/* operation */
1180	mib[5]	= 0;
1181	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
1182		return;
1183	if ((buf = malloc(len)) == NULL) {
1184		printf("malloc failed\n");
1185		exit(1);
1186	}
1187	if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
1188		free(buf);
1189		return;
1190	}
1191
1192	printf("%-6s %-17s %8.8s %-9.9s %4s %4s",
1193	       "Proto", "Linklayer Address", "Netif", "Expire", "Refs",
1194	       "Prbs");
1195	if (xflag)
1196		printf(" %7s %7s %7s", "RSSI", "LQM", "NPM");
1197	printf("\n");
1198
1199	lim = buf + len;
1200	if2m = (struct if_msghdr2 *)buf;
1201
1202	for (next = buf; next < lim; ) {
1203		if2m = (struct if_msghdr2 *)next;
1204		next += if2m->ifm_msglen;
1205
1206		if (if2m->ifm_type != RTM_IFINFO2)
1207			continue;
1208		else if (interface != 0 && if2m->ifm_index != ifindex)
1209			continue;
1210
1211		llreach_sysctl(if2m->ifm_index);
1212	}
1213	free(buf);
1214}
1215
1216static void
1217llreach_sysctl(uint32_t ifindex)
1218{
1219#define	MAX_SYSCTL_TRY	5
1220	int mib[6], i, ntry = 0;
1221	size_t mibsize, len, needed, cnt;
1222	struct if_llreach_info *lri;
1223	struct timeval time;
1224	char *buf;
1225	char ifname[IF_NAMESIZE];
1226
1227	bzero(&mib, sizeof (mib));
1228	mibsize = sizeof (mib) / sizeof (mib[0]);
1229	if (sysctlnametomib("net.link.generic.system.llreach_info", mib,
1230	    &mibsize) == -1) {
1231		perror("sysctlnametomib");
1232		return;
1233	}
1234
1235	needed = 0;
1236	mib[5] = ifindex;
1237
1238	mibsize = sizeof (mib) / sizeof (mib[0]);
1239	do {
1240		if (sysctl(mib, mibsize, NULL, &needed, NULL, 0) == -1) {
1241			perror("sysctl net.link.generic.system.llreach_info");
1242			return;
1243		}
1244		if ((buf = malloc(needed)) == NULL) {
1245			perror("malloc");
1246			return;
1247		}
1248		if (sysctl(mib, mibsize, buf, &needed, NULL, 0) == -1) {
1249			if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
1250				perror("sysctl");
1251				goto out_free;
1252			}
1253			free(buf);
1254			buf = NULL;
1255		}
1256	} while (buf == NULL);
1257
1258	len = needed;
1259	cnt = len / sizeof (*lri);
1260	lri = (struct if_llreach_info *)buf;
1261
1262	gettimeofday(&time, 0);
1263	if (if_indextoname(ifindex, ifname) == NULL)
1264		snprintf(ifname, sizeof (ifname), "%s", "?");
1265
1266	for (i = 0; i < cnt; i++, lri++) {
1267		printf("0x%-4x %-17s %8.8s ", lri->lri_proto,
1268		    ether_ntoa((struct ether_addr *)lri->lri_addr), ifname);
1269
1270		if (lri->lri_expire > time.tv_sec)
1271			printf("%-9.9s", sec2str(lri->lri_expire - time.tv_sec));
1272		else if (lri->lri_expire == 0)
1273			printf("%-9.9s", "permanent");
1274		else
1275			printf("%-9.9s", "expired");
1276
1277		printf(" %4d", lri->lri_refcnt);
1278		if (lri->lri_probes)
1279			printf(" %4d", lri->lri_probes);
1280
1281		if (xflag) {
1282			if (!lri->lri_probes)
1283				printf(" %-4.4s", "none");
1284
1285			if (lri->lri_rssi != IFNET_RSSI_UNKNOWN)
1286				printf(" %7d", lri->lri_rssi);
1287			else
1288				printf(" %-7.7s", "unknown");
1289
1290			switch (lri->lri_lqm)
1291			{
1292			case IFNET_LQM_THRESH_OFF:
1293				printf(" %-7.7s", "off");
1294				break;
1295			case IFNET_LQM_THRESH_UNKNOWN:
1296				printf(" %-7.7s", "unknown");
1297				break;
1298			case IFNET_LQM_THRESH_POOR:
1299				printf(" %-7.7s", "poor");
1300				break;
1301			case IFNET_LQM_THRESH_GOOD:
1302				printf(" %-7.7s", "good");
1303				break;
1304			default:
1305				printf(" %7d", lri->lri_lqm);
1306				break;
1307			}
1308
1309			switch (lri->lri_npm)
1310			{
1311			case IFNET_NPM_THRESH_UNKNOWN:
1312				printf(" %-7.7s", "unknown");
1313				break;
1314			case IFNET_NPM_THRESH_NEAR:
1315				printf(" %-7.7s", "near");
1316				break;
1317			case IFNET_NPM_THRESH_GENERAL:
1318				printf(" %-7.7s", "general");
1319				break;
1320			case IFNET_NPM_THRESH_FAR:
1321				printf(" %-7.7s", "far");
1322				break;
1323			default:
1324				printf(" %7d", lri->lri_npm);
1325				break;
1326			}
1327		}
1328
1329		printf("\n");
1330		len -= sizeof (*lri);
1331	}
1332
1333	if (len > 0) {
1334		fprintf(stderr, "warning: %u trailing bytes from %s\n",
1335		    (unsigned int)len, "net.link.generic.system.llreach_info");
1336	}
1337
1338out_free:
1339	free(buf);
1340#undef	MAX_SYSCTL_TRY
1341}
1342
1343void
1344aqstatpr(void)
1345{
1346	unsigned int ifindex;
1347	struct itimerval timer_interval;
1348	struct if_qstatsreq ifqr;
1349	struct if_ifclassq_stats *ifcqs;
1350	sigset_t sigset, oldsigset;
1351	u_int32_t scheduler;
1352	int s, n, tcq = 0;
1353
1354	if (cq < -1 || cq >= IFCQ_SC_MAX) {
1355		fprintf(stderr, "Invalid classq index (range is 0-%d)\n",
1356		     IFCQ_SC_MAX-1);
1357		return;
1358	}
1359	ifindex = if_nametoindex(interface);
1360	if (ifindex == 0) {
1361		fprintf(stderr, "Invalid interface name\n");
1362		return;
1363	}
1364
1365	ifcqs = malloc(sizeof (*ifcqs));
1366	if (ifcqs == NULL) {
1367		fprintf(stderr, "Unable to allocate memory\n");
1368		return;
1369	}
1370
1371	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1372		perror("Warning: socket(AF_INET)");
1373		free(ifcqs);
1374		return;
1375	}
1376
1377	bzero(&ifqr, sizeof (ifqr));
1378	strlcpy(ifqr.ifqr_name, interface, sizeof (ifqr.ifqr_name));
1379	ifqr.ifqr_buf = ifcqs;
1380	ifqr.ifqr_len = sizeof (*ifcqs);
1381
1382loop:
1383	if (interval > 0) {
1384		/* create a timer that fires repeatedly every interval seconds */
1385		timer_interval.it_value.tv_sec = interval;
1386		timer_interval.it_value.tv_usec = 0;
1387		timer_interval.it_interval.tv_sec = interval;
1388		timer_interval.it_interval.tv_usec = 0;
1389		(void) signal(SIGALRM, catchalarm);
1390		signalled = NO;
1391		(void) setitimer(ITIMER_REAL, &timer_interval, NULL);
1392	}
1393
1394	ifqr.ifqr_slot = 0;
1395	if (ioctl(s, SIOCGIFQUEUESTATS, (char *)&ifqr) < 0) {
1396		if (errno == ENXIO) {
1397			printf("Queue statistics are not available on %s\n",
1398			    interface);
1399		} else {
1400			perror("Warning: ioctl(SIOCGIFQUEUESTATS)");
1401		}
1402		goto done;
1403	}
1404	scheduler = ifcqs->ifqs_scheduler;
1405	tcq = (scheduler == PKTSCHEDT_TCQ);
1406
1407	printf("%s:\n"
1408	    "%s     [ sched: %9s %sqlength:  %3d/%3d ]\n",
1409	    interface, tcq ? "  " : "", sched2str(ifcqs->ifqs_scheduler),
1410	    tcq ? "" : " ", ifcqs->ifqs_len, ifcqs->ifqs_maxlen);
1411	printf("%s     [ pkts: %10llu %sbytes: %10llu "
1412	    "%sdropped pkts: %6llu bytes: %6llu ]\n",
1413	    (scheduler != PKTSCHEDT_TCQ) ? "" : "  ",
1414	    ifcqs->ifqs_xmitcnt.packets, tcq ? "" : " ",
1415	    ifcqs->ifqs_xmitcnt.bytes, tcq ? "" : " ",
1416	    ifcqs->ifqs_dropcnt.packets, ifcqs->ifqs_dropcnt.bytes);
1417
1418	for (n = 0; n < IFCQ_SC_MAX; n++) {
1419		qstats[n].printed = 0;
1420		if (!tcq)
1421			continue;
1422		ifqr.ifqr_slot = n;
1423		if (ioctl(s, SIOCGIFQUEUESTATS, (char *)&ifqr) < 0) {
1424			perror("Warning: ioctl(SIOCGIFQUEUESTATS)");
1425			goto done;
1426		}
1427		qstats[n].handle = ifcqs->ifqs_tcq_stats.class_handle;
1428	}
1429
1430	for (n = 0; n < IFCQ_SC_MAX && scheduler != PKTSCHEDT_NONE; n++) {
1431		if (cq >= 0 && cq != n)
1432			continue;
1433
1434		ifqr.ifqr_slot = n;
1435		if (ioctl(s, SIOCGIFQUEUESTATS, (char *)&ifqr) < 0) {
1436			perror("Warning: ioctl(SIOCGIFQUEUESTATS)");
1437			goto done;
1438		}
1439
1440		update_avg(ifcqs, &qstats[n]);
1441
1442		switch (scheduler) {
1443			case PKTSCHEDT_CBQ:
1444				print_cbqstats(n, &ifcqs->ifqs_cbq_stats,
1445				    &qstats[n]);
1446				break;
1447			case PKTSCHEDT_HFSC:
1448				print_hfscstats(n, &ifcqs->ifqs_hfsc_stats,
1449				    &qstats[n]);
1450				break;
1451			case PKTSCHEDT_PRIQ:
1452				print_priqstats(n, &ifcqs->ifqs_priq_stats,
1453				    &qstats[n]);
1454				break;
1455			case PKTSCHEDT_FAIRQ:
1456				print_fairqstats(n, &ifcqs->ifqs_fairq_stats,
1457				    &qstats[n]);
1458				break;
1459			case PKTSCHEDT_TCQ:
1460				print_tcqstats(n, &ifcqs->ifqs_tcq_stats,
1461				    &qstats[n]);
1462				break;
1463			case PKTSCHEDT_QFQ:
1464				print_qfqstats(n, &ifcqs->ifqs_qfq_stats,
1465				    &qstats[n]);
1466				break;
1467			case PKTSCHEDT_NONE:
1468			default:
1469				break;
1470		}
1471	}
1472
1473	fflush(stdout);
1474
1475	if (interval > 0) {
1476		sigemptyset(&sigset);
1477		sigaddset(&sigset, SIGALRM);
1478		(void) sigprocmask(SIG_BLOCK, &sigset, &oldsigset);
1479		if (!signalled) {
1480			sigemptyset(&sigset);
1481			sigsuspend(&sigset);
1482		}
1483		(void) sigprocmask(SIG_SETMASK, &oldsigset, NULL);
1484
1485		signalled = NO;
1486		goto loop;
1487	}
1488
1489done:
1490	free(ifcqs);
1491	close(s);
1492}
1493
1494static void
1495print_cbqstats(int slot, struct cbq_classstats *cs, struct queue_stats *qs)
1496{
1497	printf(" %2d: [ pkts: %10llu  bytes: %10llu  "
1498	    "dropped pkts: %6llu bytes: %6llu ]\n", slot,
1499	    (unsigned long long)cs->xmit_cnt.packets,
1500	    (unsigned long long)cs->xmit_cnt.bytes,
1501	    (unsigned long long)cs->drop_cnt.packets,
1502	    (unsigned long long)cs->drop_cnt.bytes);
1503	printf("     [ qlength: %3d/%3d  borrows: %6u  "
1504	    "suspends: %6u  qalg: %s ]\n", cs->qcnt, cs->qmax,
1505	    cs->borrows, cs->delays, qtype2str(cs->qtype));
1506	printf("     [ service class: %5s ]\n", qid2str(cs->handle));
1507
1508	if (qs->avgn >= 2) {
1509		printf("     [ measured: %7.1f packets/s, %s/s ]\n",
1510		    qs->avg_packets / interval,
1511		    rate2str((8 * qs->avg_bytes) / interval));
1512	}
1513
1514	if (qflag < 2)
1515		return;
1516
1517	switch (cs->qtype) {
1518	case Q_SFB:
1519		print_sfbstats(&cs->sfb);
1520		break;
1521	default:
1522		break;
1523	}
1524}
1525
1526static void
1527print_priqstats(int slot, struct priq_classstats *cs, struct queue_stats *qs)
1528{
1529	printf(" %2d: [ pkts: %10llu  bytes: %10llu  "
1530	    "dropped pkts: %6llu bytes: %6llu ]\n", slot,
1531	    (unsigned long long)cs->xmitcnt.packets,
1532	    (unsigned long long)cs->xmitcnt.bytes,
1533	    (unsigned long long)cs->dropcnt.packets,
1534	    (unsigned long long)cs->dropcnt.bytes);
1535	printf("     [ qlength: %3d/%3d  qalg: %11s  service class: %5s ]\n",
1536	     cs->qlength, cs->qlimit, qtype2str(cs->qtype),
1537	     qid2str(cs->class_handle));
1538
1539	if (qs->avgn >= 2) {
1540		printf("     [ measured: %7.1f packets/s, %s/s ]\n",
1541		    qs->avg_packets / interval,
1542		    rate2str((8 * qs->avg_bytes) / interval));
1543	}
1544
1545	if (qflag < 2)
1546		return;
1547
1548	switch (cs->qtype) {
1549	case Q_SFB:
1550		print_sfbstats(&cs->sfb);
1551		break;
1552	default:
1553		break;
1554	}
1555}
1556
1557static void
1558print_hfscstats(int slot, struct hfsc_classstats *cs, struct queue_stats *qs)
1559{
1560	printf(" %2d: [ pkts: %10llu  bytes: %10llu  "
1561	    "dropped pkts: %6llu bytes: %6llu ]\n", slot,
1562	    (unsigned long long)cs->xmit_cnt.packets,
1563	    (unsigned long long)cs->xmit_cnt.bytes,
1564	    (unsigned long long)cs->drop_cnt.packets,
1565	    (unsigned long long)cs->drop_cnt.bytes);
1566	printf("     [ qlength: %3d/%3d  qalg: %11s  service class: %5s ]\n",
1567	     cs->qlength, cs->qlimit, qtype2str(cs->qtype),
1568	     qid2str(cs->class_handle));
1569
1570	if (qs->avgn >= 2) {
1571		printf("     [ measured: %7.1f packets/s, %s/s ]\n",
1572		    qs->avg_packets / interval,
1573		    rate2str((8 * qs->avg_bytes) / interval));
1574	}
1575
1576	if (qflag < 2)
1577		return;
1578
1579	switch (cs->qtype) {
1580	case Q_SFB:
1581		print_sfbstats(&cs->sfb);
1582		break;
1583	default:
1584		break;
1585	}
1586}
1587
1588static void
1589print_fairqstats(int slot, struct fairq_classstats *cs, struct queue_stats *qs)
1590{
1591	printf(" %2d: [ pkts: %10llu  bytes: %10llu  "
1592	    "dropped pkts: %6llu bytes: %6llu ]\n", slot,
1593	    (unsigned long long)cs->xmit_cnt.packets,
1594	    (unsigned long long)cs->xmit_cnt.bytes,
1595	    (unsigned long long)cs->drop_cnt.packets,
1596	    (unsigned long long)cs->drop_cnt.bytes);
1597	printf("     [ qlength: %3d/%3d  qalg: %11s  service class: %5s ]]\n",
1598	    cs->qlength, cs->qlimit, qtype2str(cs->qtype),
1599	    qid2str(cs->class_handle));
1600
1601	if (qs->avgn >= 2) {
1602		printf("     [ measured: %7.1f packets/s, %s/s ]\n",
1603		    qs->avg_packets / interval,
1604		    rate2str((8 * qs->avg_bytes) / interval));
1605	}
1606
1607	if (qflag < 2)
1608		return;
1609
1610	switch (cs->qtype) {
1611	case Q_SFB:
1612		print_sfbstats(&cs->sfb);
1613		break;
1614	default:
1615		break;
1616	}
1617}
1618
1619static void
1620print_tcqstats(int slot, struct tcq_classstats *cs, struct queue_stats *qs)
1621{
1622	int n;
1623
1624	if (qs->printed)
1625		return;
1626
1627	qs->handle = cs->class_handle;
1628	qs->printed++;
1629
1630	for (n = 0; n < IFCQ_SC_MAX; n++) {
1631		if (&qstats[n] != qs && qstats[n].handle == qs->handle)
1632			qstats[n].printed++;
1633	}
1634
1635	printf("%5s: [ pkts: %10llu bytes: %10llu "
1636	    "dropped pkts: %6llu bytes: %6llu ]\n", tcqslot2str(slot),
1637	    (unsigned long long)cs->xmitcnt.packets,
1638	    (unsigned long long)cs->xmitcnt.bytes,
1639	    (unsigned long long)cs->dropcnt.packets,
1640	    (unsigned long long)cs->dropcnt.bytes);
1641	printf("       [ qlength: %3d/%3d qalg: %11s "
1642	    "svc class: %9s %-13s ]\n", cs->qlength, cs->qlimit,
1643	    qtype2str(cs->qtype), qid2str(cs->class_handle),
1644	    qstate2str(cs->qstate));
1645
1646	if (qs->avgn >= 2) {
1647		printf("       [ measured: %7.1f packets/s, %s/s ]\n",
1648		    qs->avg_packets / interval,
1649		    rate2str((8 * qs->avg_bytes) / interval));
1650	}
1651
1652	if (qflag < 2)
1653		return;
1654
1655	switch (cs->qtype) {
1656	case Q_SFB:
1657		print_sfbstats(&cs->sfb);
1658		break;
1659	default:
1660		break;
1661	}
1662}
1663
1664static void
1665print_qfqstats(int slot, struct qfq_classstats *cs, struct queue_stats *qs)
1666{
1667	printf(" %2d: [ pkts: %10llu  bytes: %10llu  "
1668	    "dropped pkts: %6llu bytes: %6llu ]\n", slot,
1669	    (unsigned long long)cs->xmitcnt.packets,
1670	    (unsigned long long)cs->xmitcnt.bytes,
1671	    (unsigned long long)cs->dropcnt.packets,
1672	    (unsigned long long)cs->dropcnt.bytes);
1673	printf("     [ qlength: %3d/%3d  index: %10u  weight: %12u "
1674	    "lmax: %7u ]\n", cs->qlength, cs->qlimit, cs->index,
1675	    cs->weight, cs->lmax);
1676	printf("     [ qalg: %10s  svc class: %6s %-35s ]\n",
1677	    qtype2str(cs->qtype), qid2str(cs->class_handle),
1678	    qstate2str(cs->qstate));
1679
1680	if (qs->avgn >= 2) {
1681		printf("     [ measured: %7.1f packets/s, %s/s ]\n",
1682		    qs->avg_packets / interval,
1683		    rate2str((8 * qs->avg_bytes) / interval));
1684	}
1685
1686	if (qflag < 2)
1687		return;
1688
1689	switch (cs->qtype) {
1690	case Q_SFB:
1691		print_sfbstats(&cs->sfb);
1692		break;
1693	default:
1694		break;
1695	}
1696}
1697
1698static void
1699print_sfbstats(struct sfb_stats *sfb)
1700{
1701	struct sfbstats *sp = &sfb->sfbstats;
1702	int i, j, cur = sfb->current;
1703
1704	printf("\n");
1705	printf("     [target delay: %14s   ",
1706	    nsec_to_str(sfb->target_qdelay));
1707	printf("update interval: %14s]\n",
1708	    nsec_to_str(sfb->update_interval));
1709	printf("     [ early drop: %12llu  rlimit drop: %11llu  "
1710	    "marked: %11llu ]\n",
1711	    sp->drop_early, sp->drop_pbox, sp->marked_packets);
1712	printf("     [ penalized: %13llu  rehash cnt: %12llu  "
1713	    "current: %10u ]\n", sp->pbox_packets, sp->num_rehash, cur);
1714	printf("     [ deque avg: %13s  ", nsec_to_str(sp->dequeue_avg));
1715	printf("rehash intvl: %11s]\n", nsec_to_str(sp->rehash_intval));
1716	printf("     [ holdtime: %14s  ", nsec_to_str(sp->hold_time));
1717	printf("pboxtime: %14s ]\n", nsec_to_str(sp->pbox_time));
1718	printf("     [ allocation: %12u  drop thresh: %11u ]\n",
1719	    sfb->allocation, sfb->dropthresh);
1720	printf("     [ flow controlled: %7llu  adv feedback: %10llu ]\n",
1721	    sp->flow_controlled, sp->flow_feedback);
1722	printf("     [ min queue delay: %10s   delay_fcthreshold: %12llu]\n "
1723	    "     [stalls: %12lu]\n",
1724	    nsec_to_str(sfb->min_estdelay), sfb->delay_fcthreshold,
1725	    sp->dequeue_stall);
1726
1727	printf("\n\t\t\t\tCurrent bins (set %d)", cur);
1728	for (i = 0; i < SFB_LEVELS; ++i) {
1729		unsigned int q;
1730		double p;
1731
1732		printf("\n\tLevel: %d\n", i);
1733		for (j = 0; j < SFB_BINS; ++j) {
1734			if ((j % 4) == 0)
1735				printf("\t%6d:\t", j + 1);
1736			p = sfb->binstats[cur].stats[i][j].pmark;
1737			q = sfb->binstats[cur].stats[i][j].pkts;
1738			if (p > 0) {
1739				p /= (1 << SFB_FP_SHIFT);
1740				printf("[%1.4f %4u]", p, q);
1741			} else {
1742				printf("[           ]");
1743			}
1744			if (j > 0 && ((j + 1) % 4) == 0)
1745				printf("\n");
1746		}
1747	}
1748
1749	cur ^= 1;
1750	printf("\n\t\t\t\tWarm up bins (set %d)", cur);
1751	for (i = 0; i < SFB_LEVELS; ++i) {
1752		unsigned int q;
1753		double p;
1754
1755		printf("\n\tLevel: %d\n", i);
1756		for (j = 0; j < SFB_BINS; ++j) {
1757			if ((j % 4) == 0)
1758				printf("\t%6d:\t", j + 1);
1759			p = sfb->binstats[cur].stats[i][j].pmark;
1760			q = sfb->binstats[cur].stats[i][j].pkts;
1761			if (p > 0) {
1762				p /= (1 << SFB_FP_SHIFT);
1763				printf("[%1.4f %4u]", p, q);
1764			} else {
1765				printf("[           ]");
1766			}
1767			if (j > 0 && ((j + 1) % 4) == 0)
1768				printf("\n");
1769		}
1770	}
1771	printf("\n");
1772}
1773
1774static void
1775update_avg(struct if_ifclassq_stats *ifcqs, struct queue_stats *qs)
1776{
1777	u_int64_t		 b, p;
1778	int			 n;
1779
1780	n = qs->avgn;
1781
1782	switch (ifcqs->ifqs_scheduler) {
1783	case PKTSCHEDT_CBQ:
1784		b = ifcqs->ifqs_cbq_stats.xmit_cnt.bytes;
1785		p = ifcqs->ifqs_cbq_stats.xmit_cnt.packets;
1786		break;
1787	case PKTSCHEDT_PRIQ:
1788		b = ifcqs->ifqs_priq_stats.xmitcnt.bytes;
1789		p = ifcqs->ifqs_priq_stats.xmitcnt.packets;
1790		break;
1791	case PKTSCHEDT_HFSC:
1792		b = ifcqs->ifqs_hfsc_stats.xmit_cnt.bytes;
1793		p = ifcqs->ifqs_hfsc_stats.xmit_cnt.packets;
1794		break;
1795	case PKTSCHEDT_FAIRQ:
1796		b = ifcqs->ifqs_fairq_stats.xmit_cnt.bytes;
1797		p = ifcqs->ifqs_fairq_stats.xmit_cnt.packets;
1798		break;
1799	case PKTSCHEDT_TCQ:
1800		b = ifcqs->ifqs_tcq_stats.xmitcnt.bytes;
1801		p = ifcqs->ifqs_tcq_stats.xmitcnt.packets;
1802		break;
1803	case PKTSCHEDT_QFQ:
1804		b = ifcqs->ifqs_qfq_stats.xmitcnt.bytes;
1805		p = ifcqs->ifqs_qfq_stats.xmitcnt.packets;
1806		break;
1807	default:
1808		b = 0;
1809		p = 0;
1810		break;
1811	}
1812
1813	if (n == 0) {
1814		qs->prev_bytes = b;
1815		qs->prev_packets = p;
1816		qs->avgn++;
1817		return;
1818	}
1819
1820	if (b >= qs->prev_bytes)
1821		qs->avg_bytes = ((qs->avg_bytes * (n - 1)) +
1822		    (b - qs->prev_bytes)) / n;
1823
1824	if (p >= qs->prev_packets)
1825		qs->avg_packets = ((qs->avg_packets * (n - 1)) +
1826		    (p - qs->prev_packets)) / n;
1827
1828	qs->prev_bytes = b;
1829	qs->prev_packets = p;
1830	if (n < AVGN_MAX)
1831		qs->avgn++;
1832}
1833
1834static char *
1835qtype2str(classq_type_t t)
1836{
1837	char *c;
1838
1839	switch (t) {
1840        case Q_DROPHEAD:
1841		c = "DROPHEAD";
1842		break;
1843        case Q_DROPTAIL:
1844		c = "DROPTAIL";
1845		break;
1846        case Q_RED:
1847		c = "RED";
1848		break;
1849        case Q_RIO:
1850		c = "RIO";
1851		break;
1852        case Q_BLUE:
1853		c = "BLUE";
1854		break;
1855        case Q_SFB:
1856		c = "SFB";
1857		break;
1858	default:
1859		c = "UNKNOWN";
1860		break;
1861	}
1862
1863	return (c);
1864}
1865
1866#define NSEC_PER_SEC    1000000000      /* nanoseconds per second */
1867#define USEC_PER_SEC    1000000		/* nanoseconds per second */
1868#define MSEC_PER_SEC    1000		/* nanoseconds per second */
1869
1870static char *
1871nsec_to_str(unsigned long long nsec)
1872{
1873	static char buf[32];
1874	const char *u;
1875	long double n = nsec, t;
1876
1877	if (nsec >= NSEC_PER_SEC) {
1878		t = n / NSEC_PER_SEC;
1879		u = "sec ";
1880	} else if (n >= USEC_PER_SEC) {
1881		t = n / USEC_PER_SEC;
1882		u = "msec";
1883	} else if (n >= MSEC_PER_SEC) {
1884		t = n / MSEC_PER_SEC;
1885		u = "usec";
1886	} else {
1887		t = n;
1888		u = "nsec";
1889	}
1890
1891	snprintf(buf, sizeof (buf), "%-4.2Lf %4s", t, u);
1892	return (buf);
1893}
1894
1895static char *
1896sched2str(unsigned int s)
1897{
1898	char *c;
1899
1900	switch (s) {
1901	case PKTSCHEDT_NONE:
1902		c = "NONE";
1903		break;
1904	case PKTSCHEDT_CBQ:
1905		c = "CBQ";
1906		break;
1907	case PKTSCHEDT_HFSC:
1908		c = "HFSC";
1909		break;
1910	case PKTSCHEDT_PRIQ:
1911		c = "PRIQ";
1912		break;
1913	case PKTSCHEDT_FAIRQ:
1914		c = "FAIRQ";
1915		break;
1916	case PKTSCHEDT_TCQ:
1917		c = "TCQ";
1918		break;
1919	case PKTSCHEDT_QFQ:
1920		c = "QFQ";
1921		break;
1922	default:
1923		c = "UNKNOWN";
1924		break;
1925	}
1926
1927	return (c);
1928}
1929
1930static char *
1931qid2str(unsigned int s)
1932{
1933	char *c;
1934
1935	switch (s) {
1936	case 0:
1937		c = "BE";
1938		break;
1939	case 1:
1940		c = "BK_SYS";
1941		break;
1942	case 2:
1943		c = "BK";
1944		break;
1945	case 3:
1946		c = "RD";
1947		break;
1948	case 4:
1949		c = "OAM";
1950		break;
1951	case 5:
1952		c = "AV";
1953		break;
1954	case 6:
1955		c = "RV";
1956		break;
1957	case 7:
1958		c = "VI";
1959		break;
1960	case 8:
1961		c = "VO";
1962		break;
1963	case 9:
1964		c = "CTL";
1965		break;
1966	default:
1967		c = "UNKNOWN";
1968		break;
1969	}
1970
1971	return (c);
1972}
1973
1974static char *
1975tcqslot2str(unsigned int s)
1976{
1977	char *c;
1978
1979	switch (s) {
1980	case 0:
1981	case 3:
1982	case 4:
1983		c = "0,3,4";
1984		break;
1985	case 1:
1986	case 2:
1987		c = "1,2";
1988		break;
1989	case 5:
1990	case 6:
1991	case 7:
1992		c = "5-7";
1993		break;
1994	case 8:
1995	case 9:
1996		c = "8,9";
1997		break;
1998	default:
1999		c = "?";
2000		break;
2001	}
2002
2003	return (c);
2004}
2005
2006static char *
2007qstate2str(unsigned int s)
2008{
2009	char *c;
2010
2011	switch (s) {
2012	case QS_RUNNING:
2013		c = "(RUNNING)";
2014		break;
2015	case QS_SUSPENDED:
2016		c = "(SUSPENDED)";
2017		break;
2018	default:
2019		c = "(UNKNOWN)";
2020		break;
2021	}
2022
2023	return (c);
2024}
2025
2026#define	R2S_BUFS	8
2027#define	RATESTR_MAX	16
2028
2029static char *
2030rate2str(long double rate)
2031{
2032	char		*buf;
2033	static char	 r2sbuf[R2S_BUFS][RATESTR_MAX];  /* ring bufer */
2034	static int	 idx = 0;
2035	int		 i;
2036	static const char unit[] = " KMG";
2037
2038	buf = r2sbuf[idx++];
2039	if (idx == R2S_BUFS)
2040		idx = 0;
2041
2042	for (i = 0; rate >= 1000 && i <= 3; i++)
2043		rate /= 1000;
2044
2045	if ((int)(rate * 100) % 100)
2046		snprintf(buf, RATESTR_MAX, "%.2Lf%cb", rate, unit[i]);
2047	else
2048		snprintf(buf, RATESTR_MAX, "%lld%cb", (int64_t)rate, unit[i]);
2049
2050	return (buf);
2051}
2052
2053void
2054rxpollstatpr(void)
2055{
2056	struct ifmibdata_supplemental ifmsupp;
2057	size_t miblen = sizeof (ifmsupp);
2058	struct itimerval timer_interval;
2059	struct if_rxpoll_stats *sp;
2060	sigset_t sigset, oldsigset;
2061	unsigned int ifindex;
2062	int name[6];
2063
2064	ifindex = if_nametoindex(interface);
2065	if (ifindex == 0) {
2066		fprintf(stderr, "Invalid interface name\n");
2067		return;
2068	}
2069
2070	bzero(&ifmsupp, sizeof (struct ifmibdata_supplemental));
2071
2072loop:
2073	if (interval > 0) {
2074		/* create a timer that fires repeatedly every interval seconds */
2075		timer_interval.it_value.tv_sec = interval;
2076		timer_interval.it_value.tv_usec = 0;
2077		timer_interval.it_interval.tv_sec = interval;
2078		timer_interval.it_interval.tv_usec = 0;
2079		(void) signal(SIGALRM, catchalarm);
2080		signalled = NO;
2081		(void) setitimer(ITIMER_REAL, &timer_interval, NULL);
2082	}
2083
2084	/* Common OID prefix */
2085	name[0] = CTL_NET;
2086	name[1] = PF_LINK;
2087	name[2] = NETLINK_GENERIC;
2088	name[3] = IFMIB_IFDATA;
2089	name[4] = ifindex;
2090	name[5] = IFDATA_SUPPLEMENTAL;
2091	if (sysctl(name, 6, &ifmsupp, &miblen, NULL, 0) == -1)
2092		err(1, "sysctl IFDATA_SUPPLEMENTAL");
2093
2094	sp = &ifmsupp.ifmd_rxpoll_stats;
2095
2096	printf("%-4s [ poll on requests:  %15u  errors: %27u ]\n",
2097	    interface, sp->ifi_poll_on_req, sp->ifi_poll_on_err);
2098	printf("     [ poll off requests: %15u  errors: %27u ]\n",
2099	    sp->ifi_poll_off_req, sp->ifi_poll_off_err);
2100	printf("     [ polled packets: %18llu  polled bytes: %21llu ]\n",
2101	    sp->ifi_poll_packets, sp->ifi_poll_bytes);
2102	printf("     [ sampled packets avg/min/max: %12u / %12u / %12u ]\n",
2103	    sp->ifi_poll_packets_avg, sp->ifi_poll_packets_min,
2104	    sp->ifi_poll_packets_max);
2105	printf("     [ sampled bytes avg/min/max:   %12u / %12u / %12u ]\n",
2106	    sp->ifi_poll_bytes_avg, sp->ifi_poll_bytes_min,
2107	    sp->ifi_poll_bytes_max);
2108	printf("     [ sampled wakeups avg:         %12u ]\n",
2109	    sp->ifi_poll_wakeups_avg);
2110	printf("     [ packets lowat/hiwat threshold: %10u / %10u ]\n",
2111	    sp->ifi_poll_packets_lowat, sp->ifi_poll_packets_hiwat);
2112	printf("     [ bytes lowat/hiwat threshold:   %10u / %10u ]\n",
2113	    sp->ifi_poll_bytes_lowat, sp->ifi_poll_bytes_hiwat);
2114	printf("     [ wakeups lowat/hiwat threshold: %10u / %10u ]\n",
2115	    sp->ifi_poll_wakeups_lowat, sp->ifi_poll_wakeups_hiwat);
2116
2117	fflush(stdout);
2118
2119	if (interval > 0) {
2120		sigemptyset(&sigset);
2121		sigaddset(&sigset, SIGALRM);
2122		(void) sigprocmask(SIG_BLOCK, &sigset, &oldsigset);
2123		if (!signalled) {
2124			sigemptyset(&sigset);
2125			sigsuspend(&sigset);
2126		}
2127		(void) sigprocmask(SIG_SETMASK, &oldsigset, NULL);
2128
2129		signalled = NO;
2130		goto loop;
2131	}
2132}
2133