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