xref: /freebsd-src/usr.bin/systat/ifstat.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
11de7b4b8SPedro F. Giffuni /*-
21de7b4b8SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
31de7b4b8SPedro F. Giffuni  *
4b59ba7dfSPoul-Henning Kamp  * Copyright (c) 2003, Trent Nelson, <trent@arpa.com>.
5b59ba7dfSPoul-Henning Kamp  * All rights reserved.
6b59ba7dfSPoul-Henning Kamp  *
7b59ba7dfSPoul-Henning Kamp  * Redistribution and use in source and binary forms, with or without
8b59ba7dfSPoul-Henning Kamp  * modification, are permitted provided that the following conditions
9b59ba7dfSPoul-Henning Kamp  * are met:
10b59ba7dfSPoul-Henning Kamp  * 1. Redistributions of source code must retain the above copyright
11b59ba7dfSPoul-Henning Kamp  *    notice, this list of conditions and the following disclaimer.
12b59ba7dfSPoul-Henning Kamp  * 2. Redistributions in binary form must reproduce the above copyright
13b59ba7dfSPoul-Henning Kamp  *    notice, this list of conditions and the following disclaimer in the
14b59ba7dfSPoul-Henning Kamp  *    documentation and/or other materials provided with the distribution.
15b59ba7dfSPoul-Henning Kamp  * 3. The name of the author may not be used to endorse or promote products
16b59ba7dfSPoul-Henning Kamp  *    derived from this software without specific prior written permission.
17b59ba7dfSPoul-Henning Kamp  *
18b59ba7dfSPoul-Henning Kamp  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19b59ba7dfSPoul-Henning Kamp  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20b59ba7dfSPoul-Henning Kamp  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21b59ba7dfSPoul-Henning Kamp  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22b59ba7dfSPoul-Henning Kamp  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23b59ba7dfSPoul-Henning Kamp  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24b59ba7dfSPoul-Henning Kamp  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTIFSTAT_ERRUPTION)
25b59ba7dfSPoul-Henning Kamp  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26b59ba7dfSPoul-Henning Kamp  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27b59ba7dfSPoul-Henning Kamp  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28b59ba7dfSPoul-Henning Kamp  * SUCH DAMAGE.
29b59ba7dfSPoul-Henning Kamp  */
30b59ba7dfSPoul-Henning Kamp 
31b59ba7dfSPoul-Henning Kamp #include <sys/types.h>
32b59ba7dfSPoul-Henning Kamp #include <sys/socket.h>
336bff85ffSDag-Erling Smørgrav #include <sys/queue.h>
34b59ba7dfSPoul-Henning Kamp #include <sys/sysctl.h>
35b59ba7dfSPoul-Henning Kamp #include <net/if.h>
36b59ba7dfSPoul-Henning Kamp #include <net/if_mib.h>
37b59ba7dfSPoul-Henning Kamp 
384b9ac8a0SMichael Reifenberger #include <stdbool.h>
39b59ba7dfSPoul-Henning Kamp #include <stdlib.h>
4033dc5491SDavid Malone #include <string.h>
41b59ba7dfSPoul-Henning Kamp #include <err.h>
425abb148fSXin LI #include <errno.h>
43b0214723SAlexander V. Chernikov #include <fnmatch.h>
44b59ba7dfSPoul-Henning Kamp 
45b59ba7dfSPoul-Henning Kamp #include "systat.h"
46b59ba7dfSPoul-Henning Kamp #include "extern.h"
47b59ba7dfSPoul-Henning Kamp #include "convtbl.h"
48b59ba7dfSPoul-Henning Kamp 
49b59ba7dfSPoul-Henning Kamp 				/* Column numbers */
50b59ba7dfSPoul-Henning Kamp 
51b59ba7dfSPoul-Henning Kamp #define C1	0		/*  0-19 */
52b59ba7dfSPoul-Henning Kamp #define C2	20		/* 20-39 */
53b59ba7dfSPoul-Henning Kamp #define C3	40		/* 40-59 */
54b59ba7dfSPoul-Henning Kamp #define C4	60		/* 60-80 */
55b59ba7dfSPoul-Henning Kamp #define C5	80		/* Used for label positioning. */
56b59ba7dfSPoul-Henning Kamp 
5733dc5491SDavid Malone static const int col2 = C2;
5833dc5491SDavid Malone static const int col3 = C3;
5933dc5491SDavid Malone static const int col4 = C4;
60b59ba7dfSPoul-Henning Kamp 
616d88f9feSMateusz Guzik static SLIST_HEAD(, if_stat)		curlist;
62b59ba7dfSPoul-Henning Kamp 
63b59ba7dfSPoul-Henning Kamp struct if_stat {
64b59ba7dfSPoul-Henning Kamp 	SLIST_ENTRY(if_stat)	 link;
654b9ac8a0SMichael Reifenberger 	char	display_name[IF_NAMESIZE];
664b9ac8a0SMichael Reifenberger 	char	dev_name[IFNAMSIZ]; 	/* copied from ifmibdata */
67b59ba7dfSPoul-Henning Kamp 	struct	ifmibdata if_mib;
68b59ba7dfSPoul-Henning Kamp 	struct	timeval tv;
69b59ba7dfSPoul-Henning Kamp 	struct	timeval tv_lastchanged;
709daa89f3SRyan Stone 	uint64_t if_in_curtraffic;
719daa89f3SRyan Stone 	uint64_t if_out_curtraffic;
729daa89f3SRyan Stone 	uint64_t if_in_traffic_peak;
739daa89f3SRyan Stone 	uint64_t if_out_traffic_peak;
749daa89f3SRyan Stone 	uint64_t if_in_curpps;
759daa89f3SRyan Stone 	uint64_t if_out_curpps;
769daa89f3SRyan Stone 	uint64_t if_in_pps_peak;
779daa89f3SRyan Stone 	uint64_t if_out_pps_peak;
78b59ba7dfSPoul-Henning Kamp 	u_int	if_row;			/* Index into ifmib sysctl */
796052df8eSAlexander V. Chernikov 	int 	if_ypos;		/* -1 if not being displayed */
804b9ac8a0SMichael Reifenberger 	bool	display;
81b0214723SAlexander V. Chernikov 	u_int	match;
82b59ba7dfSPoul-Henning Kamp };
83b59ba7dfSPoul-Henning Kamp 
84b0214723SAlexander V. Chernikov static	 int needclear = 0;
854b9ac8a0SMichael Reifenberger static	 bool displayall = false;
86b59ba7dfSPoul-Henning Kamp 
874b9ac8a0SMichael Reifenberger static	 void  format_device_name(struct if_stat *);
884b9ac8a0SMichael Reifenberger static	 int   getifmibdata(const int, struct ifmibdata *);
89b59ba7dfSPoul-Henning Kamp static	 void  sort_interface_list(void);
90b59ba7dfSPoul-Henning Kamp static	 u_int getifnum(void);
914b9ac8a0SMichael Reifenberger static	 void  clearifstat(void);
92b59ba7dfSPoul-Henning Kamp 
93b59ba7dfSPoul-Henning Kamp #define IFSTAT_ERR(n, s)	do {					\
94627d915eSEd Schouten 	putchar('\014');						\
95b59ba7dfSPoul-Henning Kamp 	closeifstat(wnd);						\
96b59ba7dfSPoul-Henning Kamp 	err((n), (s));							\
97b59ba7dfSPoul-Henning Kamp } while (0)
98b59ba7dfSPoul-Henning Kamp 
998aa22952SBruce Evans #define TOPLINE 3
100b59ba7dfSPoul-Henning Kamp #define TOPLABEL \
101b59ba7dfSPoul-Henning Kamp "      Interface           Traffic               Peak                Total"
102b59ba7dfSPoul-Henning Kamp 
1038aa22952SBruce Evans #define STARTING_ROW	(TOPLINE + 1)
1048aa22952SBruce Evans #define ROW_SPACING	(3)
1058aa22952SBruce Evans 
106b0214723SAlexander V. Chernikov #define IN_col2		(showpps ? ifp->if_in_curpps : ifp->if_in_curtraffic)
107b0214723SAlexander V. Chernikov #define OUT_col2	(showpps ? ifp->if_out_curpps : ifp->if_out_curtraffic)
108b0214723SAlexander V. Chernikov #define IN_col3		(showpps ? \
109b0214723SAlexander V. Chernikov 		ifp->if_in_pps_peak : ifp->if_in_traffic_peak)
110b0214723SAlexander V. Chernikov #define OUT_col3	(showpps ? \
111b0214723SAlexander V. Chernikov 		ifp->if_out_pps_peak : ifp->if_out_traffic_peak)
112b0214723SAlexander V. Chernikov #define IN_col4		(showpps ? \
113b0214723SAlexander V. Chernikov 	ifp->if_mib.ifmd_data.ifi_ipackets : ifp->if_mib.ifmd_data.ifi_ibytes)
114b0214723SAlexander V. Chernikov #define OUT_col4	(showpps ? \
115b0214723SAlexander V. Chernikov 	ifp->if_mib.ifmd_data.ifi_opackets : ifp->if_mib.ifmd_data.ifi_obytes)
116b59ba7dfSPoul-Henning Kamp 
117b59ba7dfSPoul-Henning Kamp #define EMPTY_COLUMN 	"                    "
118b59ba7dfSPoul-Henning Kamp #define CLEAR_COLUMN(y, x)	mvprintw((y), (x), "%20s", EMPTY_COLUMN);
119b59ba7dfSPoul-Henning Kamp 
120b59ba7dfSPoul-Henning Kamp #define DOPUTRATE(c, r, d)	do {					\
121b59ba7dfSPoul-Henning Kamp 	CLEAR_COLUMN(r, c);						\
122b0214723SAlexander V. Chernikov 	if (showpps) {							\
123b0214723SAlexander V. Chernikov 		mvprintw(r, (c), "%10.3f %cp%s  ",			\
124b0214723SAlexander V. Chernikov 			 convert(d##_##c, curscale),			\
125b0214723SAlexander V. Chernikov 			 *get_string(d##_##c, curscale),		\
126b0214723SAlexander V. Chernikov 			 "/s");						\
127b0214723SAlexander V. Chernikov 	}								\
128b0214723SAlexander V. Chernikov 	else {								\
129b59ba7dfSPoul-Henning Kamp 		mvprintw(r, (c), "%10.3f %s%s  ",			\
130b59ba7dfSPoul-Henning Kamp 			 convert(d##_##c, curscale),			\
131b59ba7dfSPoul-Henning Kamp 			 get_string(d##_##c, curscale),			\
132b59ba7dfSPoul-Henning Kamp 			 "/s");						\
133b0214723SAlexander V. Chernikov 	}								\
134b59ba7dfSPoul-Henning Kamp } while (0)
135b59ba7dfSPoul-Henning Kamp 
136b59ba7dfSPoul-Henning Kamp #define DOPUTTOTAL(c, r, d)	do {					\
137b59ba7dfSPoul-Henning Kamp 	CLEAR_COLUMN((r), (c));						\
138b0214723SAlexander V. Chernikov 	if (showpps) {							\
139b0214723SAlexander V. Chernikov 		mvprintw((r), (c), "%12.3f %cp  ",			\
140b0214723SAlexander V. Chernikov 			 convert(d##_##c, SC_AUTO),			\
141b0214723SAlexander V. Chernikov 			 *get_string(d##_##c, SC_AUTO));		\
142b0214723SAlexander V. Chernikov 	}								\
143b0214723SAlexander V. Chernikov 	else {								\
144b59ba7dfSPoul-Henning Kamp 		mvprintw((r), (c), "%12.3f %s  ",			\
145b59ba7dfSPoul-Henning Kamp 			 convert(d##_##c, SC_AUTO),			\
146b59ba7dfSPoul-Henning Kamp 			 get_string(d##_##c, SC_AUTO));			\
147b0214723SAlexander V. Chernikov 	}								\
148b59ba7dfSPoul-Henning Kamp } while (0)
149b59ba7dfSPoul-Henning Kamp 
150b59ba7dfSPoul-Henning Kamp #define PUTRATE(c, r)	do {						\
151b59ba7dfSPoul-Henning Kamp 	DOPUTRATE(c, (r), IN);						\
152b59ba7dfSPoul-Henning Kamp 	DOPUTRATE(c, (r)+1, OUT);					\
153b59ba7dfSPoul-Henning Kamp } while (0)
154b59ba7dfSPoul-Henning Kamp 
155b59ba7dfSPoul-Henning Kamp #define PUTTOTAL(c, r)	do {						\
156b59ba7dfSPoul-Henning Kamp 	DOPUTTOTAL(c, (r), IN);						\
157b59ba7dfSPoul-Henning Kamp 	DOPUTTOTAL(c, (r)+1, OUT);					\
158b59ba7dfSPoul-Henning Kamp } while (0)
159b59ba7dfSPoul-Henning Kamp 
160b59ba7dfSPoul-Henning Kamp #define PUTNAME(p) do {							\
1614b9ac8a0SMichael Reifenberger 	mvprintw(p->if_ypos, 0, "%s", p->display_name);			\
162b59ba7dfSPoul-Henning Kamp 	mvprintw(p->if_ypos, col2-3, "%s", (const char *)"in");		\
163b59ba7dfSPoul-Henning Kamp 	mvprintw(p->if_ypos+1, col2-3, "%s", (const char *)"out");	\
164b59ba7dfSPoul-Henning Kamp } while (0)
165b59ba7dfSPoul-Henning Kamp 
166b59ba7dfSPoul-Henning Kamp WINDOW *
openifstat(void)167b59ba7dfSPoul-Henning Kamp openifstat(void)
168b59ba7dfSPoul-Henning Kamp {
1698aa22952SBruce Evans 	return (subwin(stdscr, LINES-3-1, 0, MAINWIN_ROW, 0));
170b59ba7dfSPoul-Henning Kamp }
171b59ba7dfSPoul-Henning Kamp 
172b59ba7dfSPoul-Henning Kamp void
closeifstat(WINDOW * w)173b59ba7dfSPoul-Henning Kamp closeifstat(WINDOW *w)
174b59ba7dfSPoul-Henning Kamp {
175b59ba7dfSPoul-Henning Kamp 	struct if_stat	*node = NULL;
176b59ba7dfSPoul-Henning Kamp 
177b59ba7dfSPoul-Henning Kamp 	while (!SLIST_EMPTY(&curlist)) {
178b59ba7dfSPoul-Henning Kamp 		node = SLIST_FIRST(&curlist);
179b59ba7dfSPoul-Henning Kamp 		SLIST_REMOVE_HEAD(&curlist, link);
180b59ba7dfSPoul-Henning Kamp 		free(node);
181b59ba7dfSPoul-Henning Kamp 	}
182b59ba7dfSPoul-Henning Kamp 
183b59ba7dfSPoul-Henning Kamp 	if (w != NULL) {
184b59ba7dfSPoul-Henning Kamp 		wclear(w);
185b59ba7dfSPoul-Henning Kamp 		wrefresh(w);
186b59ba7dfSPoul-Henning Kamp 		delwin(w);
187b59ba7dfSPoul-Henning Kamp 	}
188b59ba7dfSPoul-Henning Kamp 
189b59ba7dfSPoul-Henning Kamp 	return;
190b59ba7dfSPoul-Henning Kamp }
191b59ba7dfSPoul-Henning Kamp 
192b59ba7dfSPoul-Henning Kamp void
labelifstat(void)193b59ba7dfSPoul-Henning Kamp labelifstat(void)
194b59ba7dfSPoul-Henning Kamp {
195b59ba7dfSPoul-Henning Kamp 
196b59ba7dfSPoul-Henning Kamp 	wmove(wnd, TOPLINE, 0);
197b59ba7dfSPoul-Henning Kamp 	wclrtoeol(wnd);
198b59ba7dfSPoul-Henning Kamp 	mvprintw(TOPLINE, 0, "%s", TOPLABEL);
199b59ba7dfSPoul-Henning Kamp 
200b59ba7dfSPoul-Henning Kamp 	return;
201b59ba7dfSPoul-Henning Kamp }
202b59ba7dfSPoul-Henning Kamp 
203b59ba7dfSPoul-Henning Kamp void
showifstat(void)204b59ba7dfSPoul-Henning Kamp showifstat(void)
205b59ba7dfSPoul-Henning Kamp {
206b59ba7dfSPoul-Henning Kamp 	struct	if_stat *ifp = NULL;
207b0214723SAlexander V. Chernikov 
208b59ba7dfSPoul-Henning Kamp 	SLIST_FOREACH(ifp, &curlist, link) {
2096d88f9feSMateusz Guzik 		if (ifp->if_ypos < LINES - 3 && ifp->if_ypos != -1) {
2104b9ac8a0SMichael Reifenberger 			if (!ifp->display || ifp->match == 0) {
2116052df8eSAlexander V. Chernikov 					wmove(wnd, ifp->if_ypos, 0);
2126052df8eSAlexander V. Chernikov 					wclrtoeol(wnd);
2136052df8eSAlexander V. Chernikov 					wmove(wnd, ifp->if_ypos + 1, 0);
2146052df8eSAlexander V. Chernikov 					wclrtoeol(wnd);
2156d88f9feSMateusz Guzik 			} else {
216b59ba7dfSPoul-Henning Kamp 				PUTNAME(ifp);
217b59ba7dfSPoul-Henning Kamp 				PUTRATE(col2, ifp->if_ypos);
218b59ba7dfSPoul-Henning Kamp 				PUTRATE(col3, ifp->if_ypos);
219b59ba7dfSPoul-Henning Kamp 				PUTTOTAL(col4, ifp->if_ypos);
220b59ba7dfSPoul-Henning Kamp 			}
2216052df8eSAlexander V. Chernikov 		}
2226d88f9feSMateusz Guzik 	}
223b59ba7dfSPoul-Henning Kamp 
224b59ba7dfSPoul-Henning Kamp 	return;
225b59ba7dfSPoul-Henning Kamp }
226b59ba7dfSPoul-Henning Kamp 
227b59ba7dfSPoul-Henning Kamp int
initifstat(void)228b59ba7dfSPoul-Henning Kamp initifstat(void)
229b59ba7dfSPoul-Henning Kamp {
230b59ba7dfSPoul-Henning Kamp 	struct   if_stat *p = NULL;
2314b9ac8a0SMichael Reifenberger 	u_int	 n, i;
232b59ba7dfSPoul-Henning Kamp 
233b59ba7dfSPoul-Henning Kamp 	n = getifnum();
234b59ba7dfSPoul-Henning Kamp 	if (n <= 0)
235297c1ec1SAlexander V. Chernikov 		return (-1);
236b59ba7dfSPoul-Henning Kamp 
237b59ba7dfSPoul-Henning Kamp 	SLIST_INIT(&curlist);
238b59ba7dfSPoul-Henning Kamp 
239b59ba7dfSPoul-Henning Kamp 	for (i = 0; i < n; i++) {
2405abb148fSXin LI 		p = (struct if_stat *)calloc(1, sizeof(struct if_stat));
241b59ba7dfSPoul-Henning Kamp 		if (p == NULL)
242b59ba7dfSPoul-Henning Kamp 			IFSTAT_ERR(1, "out of memory");
243b59ba7dfSPoul-Henning Kamp 		p->if_row = i+1;
2444b9ac8a0SMichael Reifenberger 		if (getifmibdata(p->if_row, &p->if_mib) == -1) {
2454b9ac8a0SMichael Reifenberger 			free(p);
2464b9ac8a0SMichael Reifenberger 			continue;
2474b9ac8a0SMichael Reifenberger 		}
2484b9ac8a0SMichael Reifenberger 		SLIST_INSERT_HEAD(&curlist, p, link);
2494b9ac8a0SMichael Reifenberger 		format_device_name(p);
250b0214723SAlexander V. Chernikov 		p->match = 1;
251b59ba7dfSPoul-Henning Kamp 
252b59ba7dfSPoul-Henning Kamp 		/*
253b59ba7dfSPoul-Henning Kamp 		 * Initially, we only display interfaces that have
2544b9ac8a0SMichael Reifenberger 		 * received some traffic unless display-all is on.
255b59ba7dfSPoul-Henning Kamp 		 */
2564b9ac8a0SMichael Reifenberger 		if (displayall || p->if_mib.ifmd_data.ifi_ibytes != 0)
2574b9ac8a0SMichael Reifenberger 			p->display = true;
258b59ba7dfSPoul-Henning Kamp 	}
259b59ba7dfSPoul-Henning Kamp 
260b59ba7dfSPoul-Henning Kamp 	sort_interface_list();
261b59ba7dfSPoul-Henning Kamp 
262297c1ec1SAlexander V. Chernikov 	return (1);
263b59ba7dfSPoul-Henning Kamp }
264b59ba7dfSPoul-Henning Kamp 
265b59ba7dfSPoul-Henning Kamp void
fetchifstat(void)266b59ba7dfSPoul-Henning Kamp fetchifstat(void)
267b59ba7dfSPoul-Henning Kamp {
2684b9ac8a0SMichael Reifenberger 	struct	if_stat *ifp = NULL, *temp_var;
269b59ba7dfSPoul-Henning Kamp 	struct	timeval tv, new_tv, old_tv;
270b59ba7dfSPoul-Henning Kamp 	double	elapsed = 0.0;
2719daa89f3SRyan Stone 	uint64_t new_inb, new_outb, old_inb, old_outb = 0;
2729daa89f3SRyan Stone 	uint64_t new_inp, new_outp, old_inp, old_outp = 0;
273b59ba7dfSPoul-Henning Kamp 
2744b9ac8a0SMichael Reifenberger 	SLIST_FOREACH_SAFE(ifp, &curlist, link, temp_var) {
275b59ba7dfSPoul-Henning Kamp 		/*
276b59ba7dfSPoul-Henning Kamp 		 * Grab a copy of the old input/output values before we
277b59ba7dfSPoul-Henning Kamp 		 * call getifmibdata().
278b59ba7dfSPoul-Henning Kamp 		 */
279b59ba7dfSPoul-Henning Kamp 		old_inb = ifp->if_mib.ifmd_data.ifi_ibytes;
280b59ba7dfSPoul-Henning Kamp 		old_outb = ifp->if_mib.ifmd_data.ifi_obytes;
281b0214723SAlexander V. Chernikov 		old_inp = ifp->if_mib.ifmd_data.ifi_ipackets;
282b0214723SAlexander V. Chernikov 		old_outp = ifp->if_mib.ifmd_data.ifi_opackets;
283b59ba7dfSPoul-Henning Kamp 		ifp->tv_lastchanged = ifp->if_mib.ifmd_data.ifi_lastchange;
284b59ba7dfSPoul-Henning Kamp 
285902d9eafSEd Schouten 		(void)gettimeofday(&new_tv, NULL);
2864b9ac8a0SMichael Reifenberger 		if (getifmibdata(ifp->if_row, &ifp->if_mib) == -1 ) {
2874b9ac8a0SMichael Reifenberger 			/* if a device was removed */
2884b9ac8a0SMichael Reifenberger 			SLIST_REMOVE(&curlist, ifp, if_stat, link);
2894b9ac8a0SMichael Reifenberger 			free(ifp);
2904b9ac8a0SMichael Reifenberger 			needsort = 1;
291*f6fdf921SJohn Baldwin 			continue;
2924b9ac8a0SMichael Reifenberger 		} else if (strcmp(ifp->dev_name, ifp->if_mib.ifmd_name) != 0 ) {
2934b9ac8a0SMichael Reifenberger 			/* a device was removed and another one was added */
2944b9ac8a0SMichael Reifenberger 			format_device_name(ifp);
2954b9ac8a0SMichael Reifenberger 			/* clear to the current value for the new device */
2964b9ac8a0SMichael Reifenberger 			old_inb = ifp->if_mib.ifmd_data.ifi_ibytes;
2974b9ac8a0SMichael Reifenberger 			old_outb = ifp->if_mib.ifmd_data.ifi_obytes;
2984b9ac8a0SMichael Reifenberger 			old_inp = ifp->if_mib.ifmd_data.ifi_ipackets;
2994b9ac8a0SMichael Reifenberger 			old_outp = ifp->if_mib.ifmd_data.ifi_opackets;
3004b9ac8a0SMichael Reifenberger 			needsort = 1;
3014b9ac8a0SMichael Reifenberger 		}
302b59ba7dfSPoul-Henning Kamp 
303b59ba7dfSPoul-Henning Kamp 		new_inb = ifp->if_mib.ifmd_data.ifi_ibytes;
304b59ba7dfSPoul-Henning Kamp 		new_outb = ifp->if_mib.ifmd_data.ifi_obytes;
305b0214723SAlexander V. Chernikov 		new_inp = ifp->if_mib.ifmd_data.ifi_ipackets;
306b0214723SAlexander V. Chernikov 		new_outp = ifp->if_mib.ifmd_data.ifi_opackets;
307b59ba7dfSPoul-Henning Kamp 
308b59ba7dfSPoul-Henning Kamp 		/* Display interface if it's received some traffic. */
3094b9ac8a0SMichael Reifenberger 		if (!ifp->display && new_inb > 0 && old_inb == 0) {
3104b9ac8a0SMichael Reifenberger 			ifp->display = true;
311b0214723SAlexander V. Chernikov 			needsort = 1;
312b59ba7dfSPoul-Henning Kamp 		}
313b59ba7dfSPoul-Henning Kamp 
314b59ba7dfSPoul-Henning Kamp 		/*
315b59ba7dfSPoul-Henning Kamp 		 * The rest is pretty trivial.  Calculate the new values
316b59ba7dfSPoul-Henning Kamp 		 * for our current traffic rates, and while we're there,
317b59ba7dfSPoul-Henning Kamp 		 * see if we have new peak rates.
318b59ba7dfSPoul-Henning Kamp 		 */
319b59ba7dfSPoul-Henning Kamp 		old_tv = ifp->tv;
320b59ba7dfSPoul-Henning Kamp 		timersub(&new_tv, &old_tv, &tv);
321b59ba7dfSPoul-Henning Kamp 		elapsed = tv.tv_sec + (tv.tv_usec * 1e-6);
322b59ba7dfSPoul-Henning Kamp 
323b59ba7dfSPoul-Henning Kamp 		ifp->if_in_curtraffic = new_inb - old_inb;
324b59ba7dfSPoul-Henning Kamp 		ifp->if_out_curtraffic = new_outb - old_outb;
325b59ba7dfSPoul-Henning Kamp 
326b0214723SAlexander V. Chernikov 		ifp->if_in_curpps = new_inp - old_inp;
327b0214723SAlexander V. Chernikov 		ifp->if_out_curpps = new_outp - old_outp;
328b0214723SAlexander V. Chernikov 
329b59ba7dfSPoul-Henning Kamp 		/*
330b59ba7dfSPoul-Henning Kamp 		 * Rather than divide by the time specified on the comm-
331b59ba7dfSPoul-Henning Kamp 		 * and line, we divide by ``elapsed'' as this is likely
332b59ba7dfSPoul-Henning Kamp 		 * to be more accurate.
333b59ba7dfSPoul-Henning Kamp 		 */
334b59ba7dfSPoul-Henning Kamp 		ifp->if_in_curtraffic /= elapsed;
335b59ba7dfSPoul-Henning Kamp 		ifp->if_out_curtraffic /= elapsed;
336b0214723SAlexander V. Chernikov 		ifp->if_in_curpps /= elapsed;
337b0214723SAlexander V. Chernikov 		ifp->if_out_curpps /= elapsed;
338b59ba7dfSPoul-Henning Kamp 
339b59ba7dfSPoul-Henning Kamp 		if (ifp->if_in_curtraffic > ifp->if_in_traffic_peak)
340b59ba7dfSPoul-Henning Kamp 			ifp->if_in_traffic_peak = ifp->if_in_curtraffic;
341b59ba7dfSPoul-Henning Kamp 
342b59ba7dfSPoul-Henning Kamp 		if (ifp->if_out_curtraffic > ifp->if_out_traffic_peak)
343b59ba7dfSPoul-Henning Kamp 			ifp->if_out_traffic_peak = ifp->if_out_curtraffic;
344b59ba7dfSPoul-Henning Kamp 
345b0214723SAlexander V. Chernikov 		if (ifp->if_in_curpps > ifp->if_in_pps_peak)
346b0214723SAlexander V. Chernikov 			ifp->if_in_pps_peak = ifp->if_in_curpps;
347b0214723SAlexander V. Chernikov 
348b0214723SAlexander V. Chernikov 		if (ifp->if_out_curpps > ifp->if_out_pps_peak)
349b0214723SAlexander V. Chernikov 			ifp->if_out_pps_peak = ifp->if_out_curpps;
350b0214723SAlexander V. Chernikov 
351b59ba7dfSPoul-Henning Kamp 		ifp->tv.tv_sec = new_tv.tv_sec;
352b59ba7dfSPoul-Henning Kamp 		ifp->tv.tv_usec = new_tv.tv_usec;
353b59ba7dfSPoul-Henning Kamp 
354b59ba7dfSPoul-Henning Kamp 	}
355b59ba7dfSPoul-Henning Kamp 
356b0214723SAlexander V. Chernikov 	if (needsort)
357b59ba7dfSPoul-Henning Kamp 		sort_interface_list();
358b59ba7dfSPoul-Henning Kamp 
359b59ba7dfSPoul-Henning Kamp 	return;
360b59ba7dfSPoul-Henning Kamp }
361b59ba7dfSPoul-Henning Kamp 
362b59ba7dfSPoul-Henning Kamp /*
363b59ba7dfSPoul-Henning Kamp  * We want to right justify our interface names against the first column
364b59ba7dfSPoul-Henning Kamp  * (first sixteen or so characters), so we need to do some alignment.
3654b9ac8a0SMichael Reifenberger  * We save original name so that we can find a same spot is take by a
3664b9ac8a0SMichael Reifenberger  * different device.
367b59ba7dfSPoul-Henning Kamp  */
368b59ba7dfSPoul-Henning Kamp static void
format_device_name(struct if_stat * ifp)3694b9ac8a0SMichael Reifenberger format_device_name(struct if_stat *ifp)
370b59ba7dfSPoul-Henning Kamp {
371b59ba7dfSPoul-Henning Kamp 
3724b9ac8a0SMichael Reifenberger 	if (ifp != NULL ) {
3734b9ac8a0SMichael Reifenberger 		snprintf(ifp->display_name, IF_NAMESIZE, "%*s", IF_NAMESIZE-1,
3744b9ac8a0SMichael Reifenberger 		    ifp->if_mib.ifmd_name);
3754b9ac8a0SMichael Reifenberger 		strcpy(ifp->dev_name, ifp->if_mib.ifmd_name);
376b59ba7dfSPoul-Henning Kamp 	}
377b59ba7dfSPoul-Henning Kamp }
378b59ba7dfSPoul-Henning Kamp 
379b0214723SAlexander V. Chernikov static int
check_match(const char * ifname)380b0214723SAlexander V. Chernikov check_match(const char *ifname)
381b0214723SAlexander V. Chernikov {
3826d88f9feSMateusz Guzik 	char *p = matchline, *ch, t;
383b0214723SAlexander V. Chernikov 	int match = 0, mlen;
384b0214723SAlexander V. Chernikov 
385297c1ec1SAlexander V. Chernikov 	if (matchline == NULL)
386297c1ec1SAlexander V. Chernikov 		return (0);
387297c1ec1SAlexander V. Chernikov 
388b0214723SAlexander V. Chernikov 	/* Strip leading whitespaces */
389b0214723SAlexander V. Chernikov 	while (*p == ' ')
390b0214723SAlexander V. Chernikov 		p ++;
391b0214723SAlexander V. Chernikov 
3926d88f9feSMateusz Guzik 	ch = p;
3936d88f9feSMateusz Guzik 	while ((mlen = strcspn(ch, " ;,")) != 0) {
3946d88f9feSMateusz Guzik 		p = ch + mlen;
395b0214723SAlexander V. Chernikov 		t = *p;
3966d88f9feSMateusz Guzik 		if (p - ch > 0) {
397b0214723SAlexander V. Chernikov 			*p = '\0';
3986d88f9feSMateusz Guzik 			if (fnmatch(ch, ifname, FNM_CASEFOLD) == 0) {
399b0214723SAlexander V. Chernikov 				*p = t;
400297c1ec1SAlexander V. Chernikov 				return (1);
401b0214723SAlexander V. Chernikov 			}
402b0214723SAlexander V. Chernikov 			*p = t;
4036d88f9feSMateusz Guzik 			ch = p + strspn(p, " ;,");
404b0214723SAlexander V. Chernikov 		}
405b0214723SAlexander V. Chernikov 		else {
4066d88f9feSMateusz Guzik 			ch = p + strspn(p, " ;,");
407b0214723SAlexander V. Chernikov 		}
408b0214723SAlexander V. Chernikov 	}
409b0214723SAlexander V. Chernikov 
410297c1ec1SAlexander V. Chernikov 	return (match);
411b0214723SAlexander V. Chernikov }
412b0214723SAlexander V. Chernikov 
413b59ba7dfSPoul-Henning Kamp /*
414b59ba7dfSPoul-Henning Kamp  * This function iterates through our list of interfaces, identifying
415b59ba7dfSPoul-Henning Kamp  * those that are to be displayed (ifp->display = 1).  For each interf-
416b59ba7dfSPoul-Henning Kamp  * rface that we're displaying, we generate an appropriate position for
417b59ba7dfSPoul-Henning Kamp  * it on the screen (ifp->if_ypos).
418b59ba7dfSPoul-Henning Kamp  *
419b59ba7dfSPoul-Henning Kamp  * This function is called any time a change is made to an interface's
420b59ba7dfSPoul-Henning Kamp  * ``display'' state.
421b59ba7dfSPoul-Henning Kamp  */
422b59ba7dfSPoul-Henning Kamp void
sort_interface_list(void)423b59ba7dfSPoul-Henning Kamp sort_interface_list(void)
424b59ba7dfSPoul-Henning Kamp {
425b59ba7dfSPoul-Henning Kamp 	struct	if_stat	*ifp = NULL;
426b59ba7dfSPoul-Henning Kamp 	u_int	y = 0;
427b59ba7dfSPoul-Henning Kamp 
428b59ba7dfSPoul-Henning Kamp 	y = STARTING_ROW;
429b59ba7dfSPoul-Henning Kamp 	SLIST_FOREACH(ifp, &curlist, link) {
430b0214723SAlexander V. Chernikov 		if (matchline && !check_match(ifp->if_mib.ifmd_name))
431b0214723SAlexander V. Chernikov 			ifp->match = 0;
432b0214723SAlexander V. Chernikov 		else
433b0214723SAlexander V. Chernikov 			ifp->match = 1;
434b0214723SAlexander V. Chernikov 		if (ifp->display && ifp->match) {
435b59ba7dfSPoul-Henning Kamp 			ifp->if_ypos = y;
436b59ba7dfSPoul-Henning Kamp 			y += ROW_SPACING;
437b59ba7dfSPoul-Henning Kamp 		}
4386052df8eSAlexander V. Chernikov 		else
4396052df8eSAlexander V. Chernikov 			ifp->if_ypos = -1;
440b59ba7dfSPoul-Henning Kamp 	}
441b0214723SAlexander V. Chernikov 
442b0214723SAlexander V. Chernikov 	needsort = 0;
443b0214723SAlexander V. Chernikov 	needclear = 1;
444b59ba7dfSPoul-Henning Kamp }
445b59ba7dfSPoul-Henning Kamp 
446b59ba7dfSPoul-Henning Kamp static
447b59ba7dfSPoul-Henning Kamp unsigned int
getifnum(void)448b59ba7dfSPoul-Henning Kamp getifnum(void)
449b59ba7dfSPoul-Henning Kamp {
450b59ba7dfSPoul-Henning Kamp 	u_int	data    = 0;
451b59ba7dfSPoul-Henning Kamp 	size_t	datalen = 0;
452b59ba7dfSPoul-Henning Kamp 	static	int name[] = { CTL_NET,
453b59ba7dfSPoul-Henning Kamp 			       PF_LINK,
454b59ba7dfSPoul-Henning Kamp 			       NETLINK_GENERIC,
455b59ba7dfSPoul-Henning Kamp 			       IFMIB_SYSTEM,
456b59ba7dfSPoul-Henning Kamp 			       IFMIB_IFCOUNT };
457b59ba7dfSPoul-Henning Kamp 
458b59ba7dfSPoul-Henning Kamp 	datalen = sizeof(data);
45933dc5491SDavid Malone 	if (sysctl(name, 5, (void *)&data, (size_t *)&datalen, (void *)NULL,
46033dc5491SDavid Malone 	    (size_t)0) != 0)
461b59ba7dfSPoul-Henning Kamp 		IFSTAT_ERR(1, "sysctl error");
462297c1ec1SAlexander V. Chernikov 	return (data);
463b59ba7dfSPoul-Henning Kamp }
464b59ba7dfSPoul-Henning Kamp 
4654b9ac8a0SMichael Reifenberger static int
getifmibdata(int row,struct ifmibdata * data)466b59ba7dfSPoul-Henning Kamp getifmibdata(int row, struct ifmibdata *data)
467b59ba7dfSPoul-Henning Kamp {
4684b9ac8a0SMichael Reifenberger 	int	ret = 0;
469b59ba7dfSPoul-Henning Kamp 	size_t	datalen = 0;
470b59ba7dfSPoul-Henning Kamp 	static	int name[] = { CTL_NET,
471b59ba7dfSPoul-Henning Kamp 			       PF_LINK,
472b59ba7dfSPoul-Henning Kamp 			       NETLINK_GENERIC,
473b59ba7dfSPoul-Henning Kamp 			       IFMIB_IFDATA,
474b59ba7dfSPoul-Henning Kamp 			       0,
475b59ba7dfSPoul-Henning Kamp 			       IFDATA_GENERAL };
476b59ba7dfSPoul-Henning Kamp 	datalen = sizeof(*data);
477b59ba7dfSPoul-Henning Kamp 	name[4] = row;
478b59ba7dfSPoul-Henning Kamp 
4794b9ac8a0SMichael Reifenberger 	ret = sysctl(name, 6, (void *)data, (size_t *)&datalen, (void *)NULL,
4804b9ac8a0SMichael Reifenberger 	    (size_t)0);
4814b9ac8a0SMichael Reifenberger 	if ((ret != 0) && (errno != ENOENT))
482b59ba7dfSPoul-Henning Kamp 		IFSTAT_ERR(2, "sysctl error getting interface data");
4834b9ac8a0SMichael Reifenberger 
4844b9ac8a0SMichael Reifenberger 	return (ret);
485b59ba7dfSPoul-Henning Kamp }
486b59ba7dfSPoul-Henning Kamp 
487b59ba7dfSPoul-Henning Kamp int
cmdifstat(const char * cmd,const char * args)488b59ba7dfSPoul-Henning Kamp cmdifstat(const char *cmd, const char *args)
489b59ba7dfSPoul-Henning Kamp {
490b59ba7dfSPoul-Henning Kamp 	int	retval = 0;
491b59ba7dfSPoul-Henning Kamp 
492b59ba7dfSPoul-Henning Kamp 	retval = ifcmd(cmd, args);
493b59ba7dfSPoul-Henning Kamp 	/* ifcmd() returns 1 on success */
494b59ba7dfSPoul-Henning Kamp 	if (retval == 1) {
4954b9ac8a0SMichael Reifenberger 		if (needclear)
4964b9ac8a0SMichael Reifenberger 			clearifstat();
4974b9ac8a0SMichael Reifenberger 	}
4984b9ac8a0SMichael Reifenberger 	else if (prefix(cmd, "all")) {
4994b9ac8a0SMichael Reifenberger 		retval = 1;
5004b9ac8a0SMichael Reifenberger 		displayall = true;
5014b9ac8a0SMichael Reifenberger 	}
5024b9ac8a0SMichael Reifenberger 	return (retval);
5034b9ac8a0SMichael Reifenberger }
5044b9ac8a0SMichael Reifenberger 
5054b9ac8a0SMichael Reifenberger static void
clearifstat(void)5064b9ac8a0SMichael Reifenberger clearifstat(void)
5074b9ac8a0SMichael Reifenberger {
5084b9ac8a0SMichael Reifenberger 
509b59ba7dfSPoul-Henning Kamp 	showifstat();
510b59ba7dfSPoul-Henning Kamp 	refresh();
511b0214723SAlexander V. Chernikov 	werase(wnd);
512b0214723SAlexander V. Chernikov 	labelifstat();
513b0214723SAlexander V. Chernikov 	needclear = 0;
514b0214723SAlexander V. Chernikov }
515