xref: /f-stack/tools/netstat/if.c (revision d4a07e70)
11eaf0ac3Slogwang /*-
222ce4affSfengbojiang  * SPDX-License-Identifier: BSD-3-Clause
322ce4affSfengbojiang  *
41eaf0ac3Slogwang  * Copyright (c) 2013 Gleb Smirnoff <[email protected]>
51eaf0ac3Slogwang  * Copyright (c) 1983, 1988, 1993
61eaf0ac3Slogwang  *	The Regents of the University of California.  All rights reserved.
71eaf0ac3Slogwang  *
81eaf0ac3Slogwang  * Redistribution and use in source and binary forms, with or without
91eaf0ac3Slogwang  * modification, are permitted provided that the following conditions
101eaf0ac3Slogwang  * are met:
111eaf0ac3Slogwang  * 1. Redistributions of source code must retain the above copyright
121eaf0ac3Slogwang  *    notice, this list of conditions and the following disclaimer.
131eaf0ac3Slogwang  * 2. Redistributions in binary form must reproduce the above copyright
141eaf0ac3Slogwang  *    notice, this list of conditions and the following disclaimer in the
151eaf0ac3Slogwang  *    documentation and/or other materials provided with the distribution.
1622ce4affSfengbojiang  * 3. Neither the name of the University nor the names of its contributors
171eaf0ac3Slogwang  *    may be used to endorse or promote products derived from this software
181eaf0ac3Slogwang  *    without specific prior written permission.
191eaf0ac3Slogwang  *
201eaf0ac3Slogwang  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211eaf0ac3Slogwang  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221eaf0ac3Slogwang  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231eaf0ac3Slogwang  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241eaf0ac3Slogwang  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251eaf0ac3Slogwang  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261eaf0ac3Slogwang  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271eaf0ac3Slogwang  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281eaf0ac3Slogwang  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291eaf0ac3Slogwang  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301eaf0ac3Slogwang  * SUCH DAMAGE.
311eaf0ac3Slogwang  */
321eaf0ac3Slogwang 
331eaf0ac3Slogwang #if 0
341eaf0ac3Slogwang #ifndef lint
351eaf0ac3Slogwang static char sccsid[] = "@(#)if.c	8.3 (Berkeley) 4/28/95";
361eaf0ac3Slogwang #endif /* not lint */
371eaf0ac3Slogwang #endif
381eaf0ac3Slogwang 
391eaf0ac3Slogwang #include <sys/cdefs.h>
401eaf0ac3Slogwang __FBSDID("$FreeBSD$");
411eaf0ac3Slogwang 
421eaf0ac3Slogwang #include <sys/param.h>
431eaf0ac3Slogwang #include <sys/protosw.h>
441eaf0ac3Slogwang #include <sys/socket.h>
451eaf0ac3Slogwang #include <sys/socketvar.h>
461eaf0ac3Slogwang #include <sys/time.h>
471eaf0ac3Slogwang 
481eaf0ac3Slogwang #include <net/if.h>
491eaf0ac3Slogwang #include <net/if_dl.h>
501eaf0ac3Slogwang #include <net/if_types.h>
511eaf0ac3Slogwang #include <net/ethernet.h>
521eaf0ac3Slogwang #include <netinet/in.h>
531eaf0ac3Slogwang #include <netinet/in_var.h>
541eaf0ac3Slogwang #include <arpa/inet.h>
551eaf0ac3Slogwang #ifdef PF
561eaf0ac3Slogwang #include <net/pfvar.h>
571eaf0ac3Slogwang #include <net/if_pfsync.h>
581eaf0ac3Slogwang #endif
591eaf0ac3Slogwang 
601eaf0ac3Slogwang #include <err.h>
611eaf0ac3Slogwang #include <errno.h>
621eaf0ac3Slogwang #include <ifaddrs.h>
631eaf0ac3Slogwang #include <libutil.h>
641eaf0ac3Slogwang #ifdef INET6
651eaf0ac3Slogwang #include <netdb.h>
661eaf0ac3Slogwang #endif
671eaf0ac3Slogwang #include <signal.h>
681eaf0ac3Slogwang #include <stdbool.h>
691eaf0ac3Slogwang #include <stdint.h>
701eaf0ac3Slogwang #include <stdio.h>
711eaf0ac3Slogwang #include <stdlib.h>
721eaf0ac3Slogwang #include <string.h>
731eaf0ac3Slogwang #include <sysexits.h>
741eaf0ac3Slogwang #include <unistd.h>
751eaf0ac3Slogwang #include <libxo/xo.h>
761eaf0ac3Slogwang 
771eaf0ac3Slogwang #include "netstat.h"
781eaf0ac3Slogwang 
791eaf0ac3Slogwang static void sidewaysintpr(void);
801eaf0ac3Slogwang 
811eaf0ac3Slogwang #ifdef PF
821eaf0ac3Slogwang static const char* pfsyncacts[] = {
831eaf0ac3Slogwang 	/* PFSYNC_ACT_CLR */		"clear all request",
841eaf0ac3Slogwang 	/* PFSYNC_ACT_INS */		"state insert",
851eaf0ac3Slogwang 	/* PFSYNC_ACT_INS_ACK */	"state inserted ack",
861eaf0ac3Slogwang 	/* PFSYNC_ACT_UPD */		"state update",
871eaf0ac3Slogwang 	/* PFSYNC_ACT_UPD_C */		"compressed state update",
881eaf0ac3Slogwang 	/* PFSYNC_ACT_UPD_REQ */	"uncompressed state request",
891eaf0ac3Slogwang 	/* PFSYNC_ACT_DEL */		"state delete",
901eaf0ac3Slogwang 	/* PFSYNC_ACT_DEL_C */		"compressed state delete",
911eaf0ac3Slogwang 	/* PFSYNC_ACT_INS_F */		"fragment insert",
921eaf0ac3Slogwang 	/* PFSYNC_ACT_DEL_F */		"fragment delete",
931eaf0ac3Slogwang 	/* PFSYNC_ACT_BUS */		"bulk update mark",
941eaf0ac3Slogwang 	/* PFSYNC_ACT_TDB */		"TDB replay counter update",
951eaf0ac3Slogwang 	/* PFSYNC_ACT_EOF */		"end of frame mark",
961eaf0ac3Slogwang };
971eaf0ac3Slogwang 
981eaf0ac3Slogwang static const char* pfsyncacts_name[] = {
991eaf0ac3Slogwang 	/* PFSYNC_ACT_CLR */		"clear-all-request",
1001eaf0ac3Slogwang 	/* PFSYNC_ACT_INS */		"state-insert",
1011eaf0ac3Slogwang 	/* PFSYNC_ACT_INS_ACK */	"state-inserted-ack",
1021eaf0ac3Slogwang 	/* PFSYNC_ACT_UPD */		"state-update",
1031eaf0ac3Slogwang 	/* PFSYNC_ACT_UPD_C */		"compressed-state-update",
1041eaf0ac3Slogwang 	/* PFSYNC_ACT_UPD_REQ */	"uncompressed-state-request",
1051eaf0ac3Slogwang 	/* PFSYNC_ACT_DEL */		"state-delete",
1061eaf0ac3Slogwang 	/* PFSYNC_ACT_DEL_C */		"compressed-state-delete",
1071eaf0ac3Slogwang 	/* PFSYNC_ACT_INS_F */		"fragment-insert",
1081eaf0ac3Slogwang 	/* PFSYNC_ACT_DEL_F */		"fragment-delete",
1091eaf0ac3Slogwang 	/* PFSYNC_ACT_BUS */		"bulk-update-mark",
1101eaf0ac3Slogwang 	/* PFSYNC_ACT_TDB */		"TDB-replay-counter-update",
1111eaf0ac3Slogwang 	/* PFSYNC_ACT_EOF */		"end-of-frame-mark",
1121eaf0ac3Slogwang };
1131eaf0ac3Slogwang 
1141eaf0ac3Slogwang static void
pfsync_acts_stats(const char * list,const char * desc,uint64_t * a)1151eaf0ac3Slogwang pfsync_acts_stats(const char *list, const char *desc, uint64_t *a)
1161eaf0ac3Slogwang {
1171eaf0ac3Slogwang 	int i;
1181eaf0ac3Slogwang 
1191eaf0ac3Slogwang 	xo_open_list(list);
1201eaf0ac3Slogwang 	for (i = 0; i < PFSYNC_ACT_MAX; i++, a++) {
1211eaf0ac3Slogwang 		if (*a || sflag <= 1) {
1221eaf0ac3Slogwang 			xo_open_instance(list);
1231eaf0ac3Slogwang 			xo_emit("\t\t{e:name}{:count/%ju} {N:/%s%s %s}\n",
1241eaf0ac3Slogwang 			    pfsyncacts_name[i], (uintmax_t)(*a),
1251eaf0ac3Slogwang 			    pfsyncacts[i], plural(*a), desc);
1261eaf0ac3Slogwang 			xo_close_instance(list);
1271eaf0ac3Slogwang 		}
1281eaf0ac3Slogwang 	}
1291eaf0ac3Slogwang 	xo_close_list(list);
1301eaf0ac3Slogwang }
1311eaf0ac3Slogwang 
1321eaf0ac3Slogwang /*
1331eaf0ac3Slogwang  * Dump pfsync statistics structure.
1341eaf0ac3Slogwang  */
1351eaf0ac3Slogwang void
pfsync_stats(u_long off,const char * name,int af1 __unused,int proto __unused)1361eaf0ac3Slogwang pfsync_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
1371eaf0ac3Slogwang {
1381eaf0ac3Slogwang 	struct pfsyncstats pfsyncstat;
1391eaf0ac3Slogwang 
1401eaf0ac3Slogwang 	if (fetch_stats("net.pfsync.stats", off, &pfsyncstat,
1411eaf0ac3Slogwang 	    sizeof(pfsyncstat), kread) != 0)
1421eaf0ac3Slogwang 		return;
1431eaf0ac3Slogwang 
1441eaf0ac3Slogwang 	xo_emit("{T:/%s}:\n", name);
1451eaf0ac3Slogwang 	xo_open_container(name);
1461eaf0ac3Slogwang 
1471eaf0ac3Slogwang #define	p(f, m) if (pfsyncstat.f || sflag <= 1) \
1481eaf0ac3Slogwang 	xo_emit(m, (uintmax_t)pfsyncstat.f, plural(pfsyncstat.f))
1491eaf0ac3Slogwang 
1501eaf0ac3Slogwang 	p(pfsyncs_ipackets, "\t{:received-inet-packets/%ju} "
1511eaf0ac3Slogwang 	    "{N:/packet%s received (IPv4)}\n");
1521eaf0ac3Slogwang 	p(pfsyncs_ipackets6, "\t{:received-inet6-packets/%ju} "
1531eaf0ac3Slogwang 	    "{N:/packet%s received (IPv6)}\n");
1541eaf0ac3Slogwang 	pfsync_acts_stats("input-histogram", "received",
1551eaf0ac3Slogwang 	    &pfsyncstat.pfsyncs_iacts[0]);
1561eaf0ac3Slogwang 	p(pfsyncs_badif, "\t\t/{:dropped-bad-interface/%ju} "
1571eaf0ac3Slogwang 	    "{N:/packet%s discarded for bad interface}\n");
1581eaf0ac3Slogwang 	p(pfsyncs_badttl, "\t\t{:dropped-bad-ttl/%ju} "
1591eaf0ac3Slogwang 	    "{N:/packet%s discarded for bad ttl}\n");
1601eaf0ac3Slogwang 	p(pfsyncs_hdrops, "\t\t{:dropped-short-header/%ju} "
1611eaf0ac3Slogwang 	    "{N:/packet%s shorter than header}\n");
1621eaf0ac3Slogwang 	p(pfsyncs_badver, "\t\t{:dropped-bad-version/%ju} "
1631eaf0ac3Slogwang 	    "{N:/packet%s discarded for bad version}\n");
1641eaf0ac3Slogwang 	p(pfsyncs_badauth, "\t\t{:dropped-bad-auth/%ju} "
1651eaf0ac3Slogwang 	    "{N:/packet%s discarded for bad HMAC}\n");
1661eaf0ac3Slogwang 	p(pfsyncs_badact,"\t\t{:dropped-bad-action/%ju} "
1671eaf0ac3Slogwang 	    "{N:/packet%s discarded for bad action}\n");
1681eaf0ac3Slogwang 	p(pfsyncs_badlen, "\t\t{:dropped-short/%ju} "
1691eaf0ac3Slogwang 	    "{N:/packet%s discarded for short packet}\n");
1701eaf0ac3Slogwang 	p(pfsyncs_badval, "\t\t{:dropped-bad-values/%ju} "
1711eaf0ac3Slogwang 	    "{N:/state%s discarded for bad values}\n");
1721eaf0ac3Slogwang 	p(pfsyncs_stale, "\t\t{:dropped-stale-state/%ju} "
1731eaf0ac3Slogwang 	    "{N:/stale state%s}\n");
1741eaf0ac3Slogwang 	p(pfsyncs_badstate, "\t\t{:dropped-failed-lookup/%ju} "
1751eaf0ac3Slogwang 	    "{N:/failed state lookup\\/insert%s}\n");
1761eaf0ac3Slogwang 	p(pfsyncs_opackets, "\t{:sent-inet-packets/%ju} "
1771eaf0ac3Slogwang 	    "{N:/packet%s sent (IPv4})\n");
1781eaf0ac3Slogwang 	p(pfsyncs_opackets6, "\t{:send-inet6-packets/%ju} "
1791eaf0ac3Slogwang 	    "{N:/packet%s sent (IPv6})\n");
1801eaf0ac3Slogwang 	pfsync_acts_stats("output-histogram", "sent",
1811eaf0ac3Slogwang 	    &pfsyncstat.pfsyncs_oacts[0]);
1821eaf0ac3Slogwang 	p(pfsyncs_onomem, "\t\t{:discarded-no-memory/%ju} "
1831eaf0ac3Slogwang 	    "{N:/failure%s due to mbuf memory error}\n");
1841eaf0ac3Slogwang 	p(pfsyncs_oerrors, "\t\t{:send-errors/%ju} "
1851eaf0ac3Slogwang 	    "{N:/send error%s}\n");
1861eaf0ac3Slogwang #undef p
1871eaf0ac3Slogwang 	xo_close_container(name);
1881eaf0ac3Slogwang }
1891eaf0ac3Slogwang #endif /* PF */
1901eaf0ac3Slogwang 
1911eaf0ac3Slogwang /*
1921eaf0ac3Slogwang  * Display a formatted value, or a '-' in the same space.
1931eaf0ac3Slogwang  */
1941eaf0ac3Slogwang static void
show_stat(const char * fmt,int width,const char * name,u_long value,short showvalue,int div1000)1951eaf0ac3Slogwang show_stat(const char *fmt, int width, const char *name,
1961eaf0ac3Slogwang     u_long value, short showvalue, int div1000)
1971eaf0ac3Slogwang {
1981eaf0ac3Slogwang 	const char *lsep, *rsep;
1991eaf0ac3Slogwang 	char newfmt[64];
2001eaf0ac3Slogwang 
2011eaf0ac3Slogwang 	lsep = "";
2021eaf0ac3Slogwang 	if (strncmp(fmt, "LS", 2) == 0) {
2031eaf0ac3Slogwang 		lsep = " ";
2041eaf0ac3Slogwang 		fmt += 2;
2051eaf0ac3Slogwang 	}
2061eaf0ac3Slogwang 	rsep = " ";
2071eaf0ac3Slogwang 	if (strncmp(fmt, "NRS", 3) == 0) {
2081eaf0ac3Slogwang 		rsep = "";
2091eaf0ac3Slogwang 		fmt += 3;
2101eaf0ac3Slogwang 	}
2111eaf0ac3Slogwang 	if (showvalue == 0) {
2121eaf0ac3Slogwang 		/* Print just dash. */
2131eaf0ac3Slogwang 		xo_emit("{P:/%s}{D:/%*s}{P:/%s}", lsep, width, "-", rsep);
2141eaf0ac3Slogwang 		return;
2151eaf0ac3Slogwang 	}
2161eaf0ac3Slogwang 
2171eaf0ac3Slogwang 	/*
2181eaf0ac3Slogwang 	 * XXX: workaround {P:} modifier can't be empty and doesn't seem to
2191eaf0ac3Slogwang 	 * take args... so we need to conditionally include it in the format.
2201eaf0ac3Slogwang 	 */
2211eaf0ac3Slogwang #define maybe_pad(pad)	do {						    \
2221eaf0ac3Slogwang 	if (strlen(pad)) {						    \
2231eaf0ac3Slogwang 		snprintf(newfmt, sizeof(newfmt), "{P:%s}", pad);	    \
2241eaf0ac3Slogwang 		xo_emit(newfmt);					    \
2251eaf0ac3Slogwang 	}								    \
2261eaf0ac3Slogwang } while (0)
2271eaf0ac3Slogwang 
2281eaf0ac3Slogwang 	if (hflag) {
2291eaf0ac3Slogwang 		char buf[5];
2301eaf0ac3Slogwang 
2311eaf0ac3Slogwang 		/* Format in human readable form. */
2321eaf0ac3Slogwang 		humanize_number(buf, sizeof(buf), (int64_t)value, "",
2331eaf0ac3Slogwang 		    HN_AUTOSCALE, HN_NOSPACE | HN_DECIMAL | \
2341eaf0ac3Slogwang 		    ((div1000) ? HN_DIVISOR_1000 : 0));
2351eaf0ac3Slogwang 		maybe_pad(lsep);
2361eaf0ac3Slogwang 		snprintf(newfmt, sizeof(newfmt), "{:%s/%%%ds}", name, width);
2371eaf0ac3Slogwang 		xo_emit(newfmt, buf);
2381eaf0ac3Slogwang 		maybe_pad(rsep);
2391eaf0ac3Slogwang 	} else {
2401eaf0ac3Slogwang 		/* Construct the format string. */
2411eaf0ac3Slogwang 		maybe_pad(lsep);
2421eaf0ac3Slogwang 		snprintf(newfmt, sizeof(newfmt), "{:%s/%%%d%s}",
2431eaf0ac3Slogwang 		    name, width, fmt);
2441eaf0ac3Slogwang 		xo_emit(newfmt, value);
2451eaf0ac3Slogwang 		maybe_pad(rsep);
2461eaf0ac3Slogwang 	}
2471eaf0ac3Slogwang }
2481eaf0ac3Slogwang 
2491eaf0ac3Slogwang /*
2501eaf0ac3Slogwang  * Find next multiaddr for a given interface name.
2511eaf0ac3Slogwang  */
2521eaf0ac3Slogwang static struct ifmaddrs *
next_ifma(struct ifmaddrs * ifma,const char * name,const sa_family_t family)2531eaf0ac3Slogwang next_ifma(struct ifmaddrs *ifma, const char *name, const sa_family_t family)
2541eaf0ac3Slogwang {
2551eaf0ac3Slogwang 
2561eaf0ac3Slogwang 	for(; ifma != NULL; ifma = ifma->ifma_next) {
2571eaf0ac3Slogwang 		struct sockaddr_dl *sdl;
2581eaf0ac3Slogwang 
2591eaf0ac3Slogwang 		sdl = (struct sockaddr_dl *)ifma->ifma_name;
2601eaf0ac3Slogwang 		if (ifma->ifma_addr->sa_family == family &&
2611eaf0ac3Slogwang 		    strcmp(sdl->sdl_data, name) == 0)
2621eaf0ac3Slogwang 			break;
2631eaf0ac3Slogwang 	}
2641eaf0ac3Slogwang 
2651eaf0ac3Slogwang 	return (ifma);
2661eaf0ac3Slogwang }
2671eaf0ac3Slogwang 
2681eaf0ac3Slogwang /*
2691eaf0ac3Slogwang  * Print a description of the network interfaces.
2701eaf0ac3Slogwang  */
2711eaf0ac3Slogwang void
intpr(void (* pfunc)(char *),int af)2721eaf0ac3Slogwang intpr(void (*pfunc)(char *), int af)
2731eaf0ac3Slogwang {
2741eaf0ac3Slogwang 	struct ifaddrs *ifap, *ifa;
2751eaf0ac3Slogwang 	struct ifmaddrs *ifmap, *ifma;
2761eaf0ac3Slogwang 	u_int ifn_len_max = 5, ifn_len;
2771eaf0ac3Slogwang 	u_int has_ipv6 = 0, net_len = 13, addr_len = 17;
2781eaf0ac3Slogwang 
2791eaf0ac3Slogwang 	if (interval)
2801eaf0ac3Slogwang 		return sidewaysintpr();
2811eaf0ac3Slogwang 
2821eaf0ac3Slogwang 	if (getifaddrs(&ifap) != 0)
2831eaf0ac3Slogwang 		err(EX_OSERR, "getifaddrs");
2841eaf0ac3Slogwang 	if (aflag && getifmaddrs(&ifmap) != 0)
2851eaf0ac3Slogwang 		err(EX_OSERR, "getifmaddrs");
2861eaf0ac3Slogwang 
2871eaf0ac3Slogwang 	if (Wflag) {
2881eaf0ac3Slogwang 		for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
2891eaf0ac3Slogwang 			if (interface != NULL &&
2901eaf0ac3Slogwang 			    strcmp(ifa->ifa_name, interface) != 0)
2911eaf0ac3Slogwang 				continue;
2921eaf0ac3Slogwang 			if (af != AF_UNSPEC && ifa->ifa_addr->sa_family != af)
2931eaf0ac3Slogwang 				continue;
2941eaf0ac3Slogwang 			ifn_len = strlen(ifa->ifa_name);
2951eaf0ac3Slogwang 			if ((ifa->ifa_flags & IFF_UP) == 0)
2961eaf0ac3Slogwang 				++ifn_len;
2971eaf0ac3Slogwang 			ifn_len_max = MAX(ifn_len_max, ifn_len);
2981eaf0ac3Slogwang 			if (ifa->ifa_addr->sa_family == AF_INET6)
2991eaf0ac3Slogwang 				has_ipv6 = 1;
3001eaf0ac3Slogwang 		}
3011eaf0ac3Slogwang 		if (has_ipv6) {
3021eaf0ac3Slogwang 			net_len = 24;
3031eaf0ac3Slogwang 			addr_len = 39;
3041eaf0ac3Slogwang 		} else
3051eaf0ac3Slogwang 			net_len = 18;
3061eaf0ac3Slogwang 	}
3071eaf0ac3Slogwang 
3081eaf0ac3Slogwang 	xo_open_list("interface");
3091eaf0ac3Slogwang 	if (!pfunc) {
3101eaf0ac3Slogwang 		xo_emit("{T:/%-*.*s}", ifn_len_max, ifn_len_max, "Name");
3111eaf0ac3Slogwang 		xo_emit(" {T:/%5.5s} {T:/%-*.*s} {T:/%-*.*s} {T:/%8.8s} "
3121eaf0ac3Slogwang 		    "{T:/%5.5s} {T:/%5.5s}",
3131eaf0ac3Slogwang 		    "Mtu", net_len, net_len, "Network", addr_len, addr_len,
3141eaf0ac3Slogwang 		    "Address", "Ipkts", "Ierrs", "Idrop");
3151eaf0ac3Slogwang 		if (bflag)
3161eaf0ac3Slogwang 			xo_emit(" {T:/%10.10s}","Ibytes");
3171eaf0ac3Slogwang 		xo_emit(" {T:/%8.8s} {T:/%5.5s}", "Opkts", "Oerrs");
3181eaf0ac3Slogwang 		if (bflag)
3191eaf0ac3Slogwang 			xo_emit(" {T:/%10.10s}","Obytes");
3201eaf0ac3Slogwang 		xo_emit(" {T:/%5s}", "Coll");
3211eaf0ac3Slogwang 		if (dflag)
3221eaf0ac3Slogwang 			xo_emit(" {T:/%5.5s}", "Drop");
3231eaf0ac3Slogwang 		xo_emit("\n");
3241eaf0ac3Slogwang 	}
3251eaf0ac3Slogwang 
3261eaf0ac3Slogwang 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
3271eaf0ac3Slogwang 		bool network = false, link = false;
3281eaf0ac3Slogwang 		char *name, *xname, buf[IFNAMSIZ+1];
3291eaf0ac3Slogwang 		const char *nn, *rn;
3301eaf0ac3Slogwang 
3311eaf0ac3Slogwang 		if (interface != NULL && strcmp(ifa->ifa_name, interface) != 0)
3321eaf0ac3Slogwang 			continue;
3331eaf0ac3Slogwang 
3341eaf0ac3Slogwang 		name = ifa->ifa_name;
3351eaf0ac3Slogwang 
3361eaf0ac3Slogwang 		if (pfunc) {
3371eaf0ac3Slogwang 
3381eaf0ac3Slogwang 			(*pfunc)(name);
3391eaf0ac3Slogwang 
3401eaf0ac3Slogwang 			/*
3411eaf0ac3Slogwang 			 * Skip all ifaddrs belonging to same interface.
3421eaf0ac3Slogwang 			 */
3431eaf0ac3Slogwang 			while(ifa->ifa_next != NULL &&
3441eaf0ac3Slogwang 			    (strcmp(ifa->ifa_next->ifa_name, name) == 0)) {
3451eaf0ac3Slogwang 				ifa = ifa->ifa_next;
3461eaf0ac3Slogwang 			}
3471eaf0ac3Slogwang 			continue;
3481eaf0ac3Slogwang 		}
3491eaf0ac3Slogwang 
3501eaf0ac3Slogwang 		if (af != AF_UNSPEC && ifa->ifa_addr->sa_family != af)
3511eaf0ac3Slogwang 			continue;
3521eaf0ac3Slogwang 
3531eaf0ac3Slogwang 		xo_open_instance("interface");
3541eaf0ac3Slogwang 
3551eaf0ac3Slogwang 		if ((ifa->ifa_flags & IFF_UP) == 0) {
3561eaf0ac3Slogwang 			xname = stpcpy(buf, name);
3571eaf0ac3Slogwang 			*xname++ = '*';
3581eaf0ac3Slogwang 			*xname = '\0';
3591eaf0ac3Slogwang 			xname = buf;
3601eaf0ac3Slogwang 		} else
3611eaf0ac3Slogwang 			xname = name;
3621eaf0ac3Slogwang 
3631eaf0ac3Slogwang 		xo_emit("{d:/%-*.*s}{etk:name}{eq:flags/0x%x}",
3641eaf0ac3Slogwang 		    ifn_len_max, ifn_len_max, xname, name, ifa->ifa_flags);
3651eaf0ac3Slogwang 
3661eaf0ac3Slogwang #define IFA_MTU(ifa)	(((struct if_data *)(ifa)->ifa_data)->ifi_mtu)
3671eaf0ac3Slogwang 		show_stat("lu", 6, "mtu", IFA_MTU(ifa), IFA_MTU(ifa), 0);
3681eaf0ac3Slogwang #undef IFA_MTU
3691eaf0ac3Slogwang 
3701eaf0ac3Slogwang 		switch (ifa->ifa_addr->sa_family) {
3711eaf0ac3Slogwang 		case AF_UNSPEC:
3721eaf0ac3Slogwang 			xo_emit("{:network/%-*.*s} ", net_len, net_len,
3731eaf0ac3Slogwang 			    "none");
3741eaf0ac3Slogwang 			xo_emit("{:address/%-*.*s} ", addr_len, addr_len,
3751eaf0ac3Slogwang 			    "none");
3761eaf0ac3Slogwang 			break;
3771eaf0ac3Slogwang 		case AF_INET:
3781eaf0ac3Slogwang #ifdef INET6
3791eaf0ac3Slogwang 		case AF_INET6:
3801eaf0ac3Slogwang #endif /* INET6 */
3811eaf0ac3Slogwang 			nn = netname(ifa->ifa_addr, ifa->ifa_netmask);
3821eaf0ac3Slogwang 			rn = routename(ifa->ifa_addr, numeric_addr);
3831eaf0ac3Slogwang 			if (Wflag) {
3841eaf0ac3Slogwang 				xo_emit("{t:network/%-*s} ", net_len, nn);
3851eaf0ac3Slogwang 				xo_emit("{t:address/%-*s} ", addr_len, rn);
3861eaf0ac3Slogwang 			} else {
3871eaf0ac3Slogwang 				xo_emit("{d:network/%-*.*s}{et:network} ",
3881eaf0ac3Slogwang 				    net_len, net_len, nn, nn);
3891eaf0ac3Slogwang 				xo_emit("{d:address/%-*.*s}{et:address} ",
3901eaf0ac3Slogwang 				    addr_len, addr_len, rn, rn);
3911eaf0ac3Slogwang 			}
3921eaf0ac3Slogwang 
3931eaf0ac3Slogwang 			network = true;
3941eaf0ac3Slogwang 			break;
3951eaf0ac3Slogwang 		case AF_LINK:
3961eaf0ac3Slogwang 		    {
3971eaf0ac3Slogwang 			struct sockaddr_dl *sdl;
39822ce4affSfengbojiang 			char linknum[sizeof("<Link#32767>")];
3991eaf0ac3Slogwang 
4001eaf0ac3Slogwang 			sdl = (struct sockaddr_dl *)ifa->ifa_addr;
40122ce4affSfengbojiang 			snprintf(linknum, sizeof(linknum), "<Link#%d>", sdl->sdl_index);
4021eaf0ac3Slogwang 			xo_emit("{t:network/%-*.*s} ", net_len, net_len,
4031eaf0ac3Slogwang 			    linknum);
4041eaf0ac3Slogwang 			if (sdl->sdl_nlen == 0 &&
4051eaf0ac3Slogwang 			    sdl->sdl_alen == 0 &&
4061eaf0ac3Slogwang 			    sdl->sdl_slen == 0)
4071eaf0ac3Slogwang 				xo_emit("{P:/%*s} ", addr_len, "");
4081eaf0ac3Slogwang 			else
4091eaf0ac3Slogwang 				xo_emit("{t:address/%-*.*s} ", addr_len,
4101eaf0ac3Slogwang 				    addr_len, routename(ifa->ifa_addr, 1));
4111eaf0ac3Slogwang 			link = true;
4121eaf0ac3Slogwang 			break;
4131eaf0ac3Slogwang 		    }
4141eaf0ac3Slogwang 		}
4151eaf0ac3Slogwang 
4161eaf0ac3Slogwang #define	IFA_STAT(s)	(((struct if_data *)ifa->ifa_data)->ifi_ ## s)
4171eaf0ac3Slogwang 		show_stat("lu", 8, "received-packets", IFA_STAT(ipackets),
4181eaf0ac3Slogwang 		    link|network, 1);
4191eaf0ac3Slogwang 		show_stat("lu", 5, "received-errors", IFA_STAT(ierrors),
4201eaf0ac3Slogwang 		    link, 1);
4211eaf0ac3Slogwang 		show_stat("lu", 5, "dropped-packets", IFA_STAT(iqdrops),
4221eaf0ac3Slogwang 		    link, 1);
4231eaf0ac3Slogwang 		if (bflag)
4241eaf0ac3Slogwang 			show_stat("lu", 10, "received-bytes", IFA_STAT(ibytes),
4251eaf0ac3Slogwang 			    link|network, 0);
4261eaf0ac3Slogwang 		show_stat("lu", 8, "sent-packets", IFA_STAT(opackets),
4271eaf0ac3Slogwang 		    link|network, 1);
4281eaf0ac3Slogwang 		show_stat("lu", 5, "send-errors", IFA_STAT(oerrors), link, 1);
4291eaf0ac3Slogwang 		if (bflag)
4301eaf0ac3Slogwang 			show_stat("lu", 10, "sent-bytes", IFA_STAT(obytes),
4311eaf0ac3Slogwang 			    link|network, 0);
4321eaf0ac3Slogwang 		show_stat("NRSlu", 5, "collisions", IFA_STAT(collisions),
4331eaf0ac3Slogwang 		    link, 1);
4341eaf0ac3Slogwang 		if (dflag)
4351eaf0ac3Slogwang 			show_stat("LSlu", 5, "dropped-packets",
4361eaf0ac3Slogwang 			    IFA_STAT(oqdrops), link, 1);
4371eaf0ac3Slogwang 		xo_emit("\n");
4381eaf0ac3Slogwang 
4391eaf0ac3Slogwang 		if (!aflag) {
4401eaf0ac3Slogwang 			xo_close_instance("interface");
4411eaf0ac3Slogwang 			continue;
4421eaf0ac3Slogwang 		}
4431eaf0ac3Slogwang 
4441eaf0ac3Slogwang 		/*
4451eaf0ac3Slogwang 		 * Print family's multicast addresses.
4461eaf0ac3Slogwang 		 */
4471eaf0ac3Slogwang 		xo_open_list("multicast-address");
4481eaf0ac3Slogwang 		for (ifma = next_ifma(ifmap, ifa->ifa_name,
4491eaf0ac3Slogwang 		    ifa->ifa_addr->sa_family);
4501eaf0ac3Slogwang 		    ifma != NULL;
4511eaf0ac3Slogwang 		    ifma = next_ifma(ifma, ifa->ifa_name,
4521eaf0ac3Slogwang 		    ifa->ifa_addr->sa_family)) {
4531eaf0ac3Slogwang 			const char *fmt = NULL;
4541eaf0ac3Slogwang 
4551eaf0ac3Slogwang 			xo_open_instance("multicast-address");
4561eaf0ac3Slogwang 			switch (ifma->ifma_addr->sa_family) {
4571eaf0ac3Slogwang 			case AF_LINK:
4581eaf0ac3Slogwang 			    {
4591eaf0ac3Slogwang 				struct sockaddr_dl *sdl;
4601eaf0ac3Slogwang 
4611eaf0ac3Slogwang 				sdl = (struct sockaddr_dl *)ifma->ifma_addr;
4621eaf0ac3Slogwang 				if (sdl->sdl_type != IFT_ETHER &&
4631eaf0ac3Slogwang 				    sdl->sdl_type != IFT_FDDI)
4641eaf0ac3Slogwang 					break;
4651eaf0ac3Slogwang 			    }
4661eaf0ac3Slogwang 				/* FALLTHROUGH */
4671eaf0ac3Slogwang 			case AF_INET:
4681eaf0ac3Slogwang #ifdef INET6
4691eaf0ac3Slogwang 			case AF_INET6:
4701eaf0ac3Slogwang #endif /* INET6 */
4711eaf0ac3Slogwang 				fmt = routename(ifma->ifma_addr, numeric_addr);
4721eaf0ac3Slogwang 				break;
4731eaf0ac3Slogwang 			}
4741eaf0ac3Slogwang 			if (fmt) {
4751eaf0ac3Slogwang 				if (Wflag)
4761eaf0ac3Slogwang 					xo_emit("{P:/%27s }"
4771eaf0ac3Slogwang 					    "{t:address/%-17s/}", "", fmt);
4781eaf0ac3Slogwang 				else
4791eaf0ac3Slogwang 					xo_emit("{P:/%25s }"
4801eaf0ac3Slogwang 					    "{t:address/%-17.17s/}", "", fmt);
4811eaf0ac3Slogwang 				if (ifma->ifma_addr->sa_family == AF_LINK) {
4821eaf0ac3Slogwang 					xo_emit(" {:received-packets/%8lu}",
4831eaf0ac3Slogwang 					    IFA_STAT(imcasts));
4841eaf0ac3Slogwang 					xo_emit("{P:/%*s}", bflag? 17 : 6, "");
4851eaf0ac3Slogwang 					xo_emit(" {:sent-packets/%8lu}",
4861eaf0ac3Slogwang 					    IFA_STAT(omcasts));
4871eaf0ac3Slogwang  				}
4881eaf0ac3Slogwang 				xo_emit("\n");
4891eaf0ac3Slogwang 			}
4901eaf0ac3Slogwang 			xo_close_instance("multicast-address");
4911eaf0ac3Slogwang 			ifma = ifma->ifma_next;
4921eaf0ac3Slogwang 		}
4931eaf0ac3Slogwang 		xo_close_list("multicast-address");
4941eaf0ac3Slogwang 		xo_close_instance("interface");
4951eaf0ac3Slogwang 	}
4961eaf0ac3Slogwang 	xo_close_list("interface");
4971eaf0ac3Slogwang 
4981eaf0ac3Slogwang 	freeifaddrs(ifap);
4991eaf0ac3Slogwang 	if (aflag)
5001eaf0ac3Slogwang 		freeifmaddrs(ifmap);
5011eaf0ac3Slogwang }
5021eaf0ac3Slogwang 
5031eaf0ac3Slogwang struct iftot {
5041eaf0ac3Slogwang 	u_long	ift_ip;			/* input packets */
5051eaf0ac3Slogwang 	u_long	ift_ie;			/* input errors */
5061eaf0ac3Slogwang 	u_long	ift_id;			/* input drops */
5071eaf0ac3Slogwang 	u_long	ift_op;			/* output packets */
5081eaf0ac3Slogwang 	u_long	ift_oe;			/* output errors */
5091eaf0ac3Slogwang 	u_long	ift_od;			/* output drops */
5101eaf0ac3Slogwang 	u_long	ift_co;			/* collisions */
5111eaf0ac3Slogwang 	u_long	ift_ib;			/* input bytes */
5121eaf0ac3Slogwang 	u_long	ift_ob;			/* output bytes */
5131eaf0ac3Slogwang };
5141eaf0ac3Slogwang 
5151eaf0ac3Slogwang /*
5161eaf0ac3Slogwang  * Obtain stats for interface(s).
5171eaf0ac3Slogwang  */
5181eaf0ac3Slogwang static void
fill_iftot(struct iftot * st)5191eaf0ac3Slogwang fill_iftot(struct iftot *st)
5201eaf0ac3Slogwang {
5211eaf0ac3Slogwang 	struct ifaddrs *ifap, *ifa;
5221eaf0ac3Slogwang 	bool found = false;
5231eaf0ac3Slogwang 
5241eaf0ac3Slogwang 	if (getifaddrs(&ifap) != 0)
5251eaf0ac3Slogwang 		xo_err(EX_OSERR, "getifaddrs");
5261eaf0ac3Slogwang 
5271eaf0ac3Slogwang 	bzero(st, sizeof(*st));
5281eaf0ac3Slogwang 
5291eaf0ac3Slogwang 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
5301eaf0ac3Slogwang 		if (ifa->ifa_addr->sa_family != AF_LINK)
5311eaf0ac3Slogwang 			continue;
5321eaf0ac3Slogwang 		if (interface) {
5331eaf0ac3Slogwang 			if (strcmp(ifa->ifa_name, interface) == 0)
5341eaf0ac3Slogwang 				found = true;
5351eaf0ac3Slogwang 			else
5361eaf0ac3Slogwang 				continue;
5371eaf0ac3Slogwang 		}
5381eaf0ac3Slogwang 
5391eaf0ac3Slogwang 		st->ift_ip += IFA_STAT(ipackets);
5401eaf0ac3Slogwang 		st->ift_ie += IFA_STAT(ierrors);
5411eaf0ac3Slogwang 		st->ift_id += IFA_STAT(iqdrops);
5421eaf0ac3Slogwang 		st->ift_ib += IFA_STAT(ibytes);
5431eaf0ac3Slogwang 		st->ift_op += IFA_STAT(opackets);
5441eaf0ac3Slogwang 		st->ift_oe += IFA_STAT(oerrors);
5451eaf0ac3Slogwang 		st->ift_od += IFA_STAT(oqdrops);
5461eaf0ac3Slogwang 		st->ift_ob += IFA_STAT(obytes);
5471eaf0ac3Slogwang  		st->ift_co += IFA_STAT(collisions);
5481eaf0ac3Slogwang 	}
5491eaf0ac3Slogwang 
5501eaf0ac3Slogwang 	if (interface && found == false)
5511eaf0ac3Slogwang 		xo_err(EX_DATAERR, "interface %s not found", interface);
5521eaf0ac3Slogwang 
5531eaf0ac3Slogwang 	freeifaddrs(ifap);
5541eaf0ac3Slogwang }
5551eaf0ac3Slogwang 
5561eaf0ac3Slogwang /*
5571eaf0ac3Slogwang  * Set a flag to indicate that a signal from the periodic itimer has been
5581eaf0ac3Slogwang  * caught.
5591eaf0ac3Slogwang  */
5601eaf0ac3Slogwang static sig_atomic_t signalled;
5611eaf0ac3Slogwang static void
catchalarm(int signo __unused)5621eaf0ac3Slogwang catchalarm(int signo __unused)
5631eaf0ac3Slogwang {
5641eaf0ac3Slogwang 	signalled = true;
5651eaf0ac3Slogwang }
5661eaf0ac3Slogwang 
5671eaf0ac3Slogwang /*
5681eaf0ac3Slogwang  * Print a running summary of interface statistics.
5691eaf0ac3Slogwang  * Repeat display every interval seconds, showing statistics
5701eaf0ac3Slogwang  * collected over that interval.  Assumes that interval is non-zero.
5711eaf0ac3Slogwang  * First line printed at top of screen is always cumulative.
5721eaf0ac3Slogwang  */
5731eaf0ac3Slogwang static void
sidewaysintpr(void)5741eaf0ac3Slogwang sidewaysintpr(void)
5751eaf0ac3Slogwang {
5761eaf0ac3Slogwang 	struct iftot ift[2], *new, *old;
5771eaf0ac3Slogwang 	struct itimerval interval_it;
578*d4a07e70Sfengbojiang #ifndef FSTACK
5791eaf0ac3Slogwang 	int oldmask, line;
580*d4a07e70Sfengbojiang #else
581*d4a07e70Sfengbojiang 	int line;
582*d4a07e70Sfengbojiang 	sigset_t oldmask;
583*d4a07e70Sfengbojiang #endif
5841eaf0ac3Slogwang 
5851eaf0ac3Slogwang 	new = &ift[0];
5861eaf0ac3Slogwang 	old = &ift[1];
5871eaf0ac3Slogwang 	fill_iftot(old);
5881eaf0ac3Slogwang 
5891eaf0ac3Slogwang 	(void)signal(SIGALRM, catchalarm);
5901eaf0ac3Slogwang 	signalled = false;
5911eaf0ac3Slogwang 	interval_it.it_interval.tv_sec = interval;
5921eaf0ac3Slogwang 	interval_it.it_interval.tv_usec = 0;
5931eaf0ac3Slogwang 	interval_it.it_value = interval_it.it_interval;
5941eaf0ac3Slogwang 	setitimer(ITIMER_REAL, &interval_it, NULL);
5951eaf0ac3Slogwang 	xo_open_list("interface-statistics");
5961eaf0ac3Slogwang 
5971eaf0ac3Slogwang banner:
5981eaf0ac3Slogwang 	xo_emit("{T:/%17s} {T:/%14s} {T:/%16s}\n", "input",
5991eaf0ac3Slogwang 	    interface != NULL ? interface : "(Total)", "output");
6001eaf0ac3Slogwang 	xo_emit("{T:/%10s} {T:/%5s} {T:/%5s} {T:/%10s} {T:/%10s} {T:/%5s} "
6011eaf0ac3Slogwang 	    "{T:/%10s} {T:/%5s}",
6021eaf0ac3Slogwang 	    "packets", "errs", "idrops", "bytes", "packets", "errs", "bytes",
6031eaf0ac3Slogwang 	    "colls");
6041eaf0ac3Slogwang 	if (dflag)
6051eaf0ac3Slogwang 		xo_emit(" {T:/%5.5s}", "drops");
6061eaf0ac3Slogwang 	xo_emit("\n");
6071eaf0ac3Slogwang 	xo_flush();
6081eaf0ac3Slogwang 	line = 0;
6091eaf0ac3Slogwang 
6101eaf0ac3Slogwang loop:
6111eaf0ac3Slogwang 	if ((noutputs != 0) && (--noutputs == 0)) {
6121eaf0ac3Slogwang 		xo_close_list("interface-statistics");
6131eaf0ac3Slogwang 		return;
6141eaf0ac3Slogwang 	}
615*d4a07e70Sfengbojiang #ifndef FSTACK
6161eaf0ac3Slogwang 	oldmask = sigblock(sigmask(SIGALRM));
6171eaf0ac3Slogwang 	while (!signalled)
6181eaf0ac3Slogwang 		sigpause(0);
6191eaf0ac3Slogwang 	signalled = false;
6201eaf0ac3Slogwang 	sigsetmask(oldmask);
621*d4a07e70Sfengbojiang #else
622*d4a07e70Sfengbojiang 	sigset_t set;
623*d4a07e70Sfengbojiang 	sigemptyset(&set);
624*d4a07e70Sfengbojiang 	sigaddset(&set, SIGALRM);
625*d4a07e70Sfengbojiang 	sigprocmask(SIG_BLOCK, &set, &oldmask);
626*d4a07e70Sfengbojiang 	sigemptyset(&set);
627*d4a07e70Sfengbojiang 
628*d4a07e70Sfengbojiang 	while (!signalled)
629*d4a07e70Sfengbojiang 		sigsuspend(&set);
630*d4a07e70Sfengbojiang 	signalled = false;
631*d4a07e70Sfengbojiang 	sigprocmask(SIG_SETMASK, &oldmask, NULL);
632*d4a07e70Sfengbojiang #endif
6331eaf0ac3Slogwang 	line++;
6341eaf0ac3Slogwang 
6351eaf0ac3Slogwang 	fill_iftot(new);
6361eaf0ac3Slogwang 
6371eaf0ac3Slogwang 	xo_open_instance("stats");
6381eaf0ac3Slogwang 	show_stat("lu", 10, "received-packets",
6391eaf0ac3Slogwang 	    new->ift_ip - old->ift_ip, 1, 1);
6401eaf0ac3Slogwang 	show_stat("lu", 5, "received-errors",
6411eaf0ac3Slogwang 	    new->ift_ie - old->ift_ie, 1, 1);
6421eaf0ac3Slogwang 	show_stat("lu", 5, "dropped-packets",
6431eaf0ac3Slogwang 	    new->ift_id - old->ift_id, 1, 1);
6441eaf0ac3Slogwang 	show_stat("lu", 10, "received-bytes",
6451eaf0ac3Slogwang 	    new->ift_ib - old->ift_ib, 1, 0);
6461eaf0ac3Slogwang 	show_stat("lu", 10, "sent-packets",
6471eaf0ac3Slogwang 	    new->ift_op - old->ift_op, 1, 1);
6481eaf0ac3Slogwang 	show_stat("lu", 5, "send-errors",
6491eaf0ac3Slogwang 	    new->ift_oe - old->ift_oe, 1, 1);
6501eaf0ac3Slogwang 	show_stat("lu", 10, "sent-bytes",
6511eaf0ac3Slogwang 	    new->ift_ob - old->ift_ob, 1, 0);
6521eaf0ac3Slogwang 	show_stat("NRSlu", 5, "collisions",
6531eaf0ac3Slogwang 	    new->ift_co - old->ift_co, 1, 1);
6541eaf0ac3Slogwang 	if (dflag)
6551eaf0ac3Slogwang 		show_stat("LSlu", 5, "dropped-packets",
6561eaf0ac3Slogwang 		    new->ift_od - old->ift_od, 1, 1);
6571eaf0ac3Slogwang 	xo_close_instance("stats");
6581eaf0ac3Slogwang 	xo_emit("\n");
6591eaf0ac3Slogwang 	xo_flush();
6601eaf0ac3Slogwang 
6611eaf0ac3Slogwang 	if (new == &ift[0]) {
6621eaf0ac3Slogwang 		new = &ift[1];
6631eaf0ac3Slogwang 		old = &ift[0];
6641eaf0ac3Slogwang 	} else {
6651eaf0ac3Slogwang 		new = &ift[0];
6661eaf0ac3Slogwang 		old = &ift[1];
6671eaf0ac3Slogwang 	}
6681eaf0ac3Slogwang 
6691eaf0ac3Slogwang 	if (line == 21)
6701eaf0ac3Slogwang 		goto banner;
6711eaf0ac3Slogwang 	else
6721eaf0ac3Slogwang 		goto loop;
6731eaf0ac3Slogwang 
6741eaf0ac3Slogwang 	/* NOTREACHED */
6751eaf0ac3Slogwang }
676