xref: /openbsd-src/usr.bin/systat/if.c (revision 850e275390052b330d93020bf619a739a3c277ac)
1 /*	$OpenBSD: if.c,v 1.12 2008/06/12 22:26:01 canacar Exp $ */
2 /*
3  * Copyright (c) 2004 Markus Friedl <markus@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 #include <sys/param.h>
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <sys/sysctl.h>
21 #include <net/if.h>
22 #include <net/if_dl.h>
23 #include <net/route.h>
24 
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "systat.h"
29 
30 static  enum state { BOOT, TIME, RUN } state = TIME;
31 
32 struct ifcount {
33 	u_int64_t	ifc_ib;			/* input bytes */
34 	u_int64_t	ifc_ip;			/* input packets */
35 	u_int64_t	ifc_ie;			/* input errors */
36 	u_int64_t	ifc_ob;			/* output bytes */
37 	u_int64_t	ifc_op;			/* output packets */
38 	u_int64_t	ifc_oe;			/* output errors */
39 	u_int64_t	ifc_co;			/* collisions */
40 	int		ifc_flags;		/* up / down */
41 	int		ifc_state;		/* link state */
42 } sum;
43 
44 struct ifstat {
45 	char		ifs_name[IFNAMSIZ];	/* interface name */
46 	struct ifcount	ifs_cur;
47 	struct ifcount	ifs_old;
48 	struct ifcount	ifs_now;
49 } *ifstats;
50 
51 static	int nifs = 0;
52 static int num_ifs = 0;
53 
54 void print_if(void);
55 int read_if(void);
56 int select_if(void);
57 int if_keyboard_callback(int);
58 
59 static void fetchifstat(void);
60 static void showifstat(struct ifstat *);
61 static void showtotal(void);
62 
63 
64 /* Define fields */
65 field_def fields_if[] = {
66 	{"IFACE", 8, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
67 	{"STATE", 10, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
68 	{"IPKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
69 	{"IBYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
70 	{"IERRS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
71 	{"OPKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
72 	{"OBYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
73 	{"OERRS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
74 	{"COLLS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
75 };
76 
77 
78 #define FIELD_ADDR(x) (&fields_if[x])
79 
80 #define FLD_IF_IFACE	FIELD_ADDR(0)
81 #define FLD_IF_STATE	FIELD_ADDR(1)
82 #define FLD_IF_IPKTS	FIELD_ADDR(2)
83 #define FLD_IF_IBYTES	FIELD_ADDR(3)
84 #define FLD_IF_IERRS	FIELD_ADDR(4)
85 #define FLD_IF_OPKTS	FIELD_ADDR(5)
86 #define FLD_IF_OBYTES	FIELD_ADDR(6)
87 #define FLD_IF_OERRS	FIELD_ADDR(7)
88 #define FLD_IF_COLLS	FIELD_ADDR(8)
89 
90 
91 /* Define views */
92 field_def *view_if_0[] = {
93 	FLD_IF_IFACE, FLD_IF_STATE, FLD_IF_IPKTS, FLD_IF_IBYTES,
94 	FLD_IF_IERRS, FLD_IF_OPKTS, FLD_IF_OBYTES, FLD_IF_OERRS,
95 	FLD_IF_COLLS, NULL
96 };
97 
98 /* Define view managers */
99 
100 struct view_manager ifstat_mgr = {
101 	"Ifstat", select_if, read_if, NULL, print_header,
102 	print_if, if_keyboard_callback, NULL, NULL
103 };
104 
105 field_view views_if[] = {
106 	{view_if_0, "ifstat", '1', &ifstat_mgr},
107 	{NULL, NULL, 0, NULL}
108 };
109 
110 
111 int
112 initifstat(void)
113 {
114 	field_view *v;
115 	read_if();
116 	for (v = views_if; v->name != NULL; v++)
117 		add_view(v);
118 
119 	return(1);
120 }
121 
122 #define UPDATE(x, y) do { \
123 		ifs->ifs_now.x = ifm.y; \
124 		ifs->ifs_cur.x = ifs->ifs_now.x - ifs->ifs_old.x; \
125 		if (state == TIME) {\
126 			ifs->ifs_old.x = ifs->ifs_now.x; \
127 			ifs->ifs_cur.x /= naptime; \
128 		} \
129 		sum.x += ifs->ifs_cur.x; \
130 	} while(0)
131 
132 
133 void
134 rt_getaddrinfo(struct sockaddr *sa, int addrs, struct sockaddr **info)
135 {
136 	int i;
137 
138 	for (i = 0; i < RTAX_MAX; i++) {
139 		if (addrs & (1 << i)) {
140 			info[i] = sa;
141 			sa = (struct sockaddr *) ((char *)(sa) +
142 			    roundup(sa->sa_len, sizeof(long)));
143 		} else
144 			info[i] = NULL;
145 	}
146 }
147 
148 
149 
150 int
151 select_if(void)
152 {
153 	num_disp = num_ifs + 1;
154 	return (0);
155 }
156 
157 int
158 read_if(void)
159 {
160 	fetchifstat();
161 	num_disp = num_ifs + 1;
162 
163 	return 0;
164 }
165 
166 void
167 print_if(void)
168 {
169 	int n, i, count = 0;
170 
171 	for (n = 0, i = 0; n < nifs; n++) {
172 		if (ifstats[n].ifs_name[0] == '\0')
173 			continue;
174 		if (i++ < dispstart)
175 			continue;
176 		if (i == num_disp)
177 			break;
178 		showifstat(ifstats + n);
179 		if (maxprint > 0 && ++count >= maxprint)
180 			return;
181 	}
182 	showtotal();
183 }
184 
185 
186 static void
187 fetchifstat(void)
188 {
189 	struct ifstat *newstats, *ifs;
190 	struct if_msghdr ifm;
191 	struct sockaddr *info[RTAX_MAX];
192 	struct sockaddr_dl *sdl;
193 	char *buf, *next, *lim;
194 	int mib[6];
195 	size_t need;
196 
197 	mib[0] = CTL_NET;
198 	mib[1] = AF_ROUTE;
199 	mib[2] = 0;
200 	mib[3] = 0;
201 	mib[4] = NET_RT_IFLIST;
202 	mib[5] = 0;
203 
204 	if (sysctl(mib, 6, NULL, &need, NULL, 0) == -1)
205 		return;
206 	if ((buf = malloc(need)) == NULL)
207 		return;
208 	if (sysctl(mib, 6, buf, &need, NULL, 0) == -1) {
209 		free(buf);
210 		return;
211 	}
212 
213 	bzero(&sum, sizeof(sum));
214 	num_ifs = 0;
215 
216 	lim = buf + need;
217 	for (next = buf; next < lim; next += ifm.ifm_msglen) {
218 		bcopy(next, &ifm, sizeof ifm);
219 		if (ifm.ifm_type != RTM_IFINFO ||
220 		   !(ifm.ifm_addrs & RTA_IFP))
221 			continue;
222 		if (ifm.ifm_index >= nifs) {
223 			if ((newstats = realloc(ifstats, (ifm.ifm_index + 4)
224 			    * sizeof(struct ifstat))) == NULL)
225 				continue;
226 			ifstats = newstats;
227 			for (; nifs < ifm.ifm_index + 4; nifs++)
228 				bzero(&ifstats[nifs], sizeof(*ifstats));
229 		}
230 		ifs = &ifstats[ifm.ifm_index];
231 		if (ifs->ifs_name[0] == '\0') {
232 			bzero(&info, sizeof(info));
233 			rt_getaddrinfo(
234 			    (struct sockaddr *)((struct if_msghdr *)next + 1),
235 			    ifm.ifm_addrs, info);
236 			if ((sdl = (struct sockaddr_dl *)info[RTAX_IFP])) {
237 				if (sdl->sdl_family == AF_LINK &&
238 				    sdl->sdl_nlen > 0) {
239 					bcopy(sdl->sdl_data, ifs->ifs_name,
240 					    sdl->sdl_nlen);
241 					ifs->ifs_name[sdl->sdl_nlen] = '\0';
242 				}
243 			}
244 			if (ifs->ifs_name[0] == '\0')
245 				continue;
246 		}
247 		num_ifs++;
248 		UPDATE(ifc_ip, ifm_data.ifi_ipackets);
249 		UPDATE(ifc_ib, ifm_data.ifi_ibytes);
250 		UPDATE(ifc_ie, ifm_data.ifi_ierrors);
251 		UPDATE(ifc_op, ifm_data.ifi_opackets);
252 		UPDATE(ifc_ob, ifm_data.ifi_obytes);
253 		UPDATE(ifc_oe, ifm_data.ifi_oerrors);
254 		UPDATE(ifc_co, ifm_data.ifi_collisions);
255 		ifs->ifs_cur.ifc_flags = ifm.ifm_flags;
256 		ifs->ifs_cur.ifc_state = ifm.ifm_data.ifi_link_state;
257 	}
258 	free(buf);
259 }
260 
261 
262 static void
263 showifstat(struct ifstat *ifs)
264 {
265 	print_fld_str(FLD_IF_IFACE, ifs->ifs_name);
266 
267 	tb_start();
268 	tbprintf("%s", ifs->ifs_cur.ifc_flags & IFF_UP ?
269 		 "up" : "dn");
270 
271 	switch (ifs->ifs_cur.ifc_state) {
272 	case LINK_STATE_UP:
273 	case LINK_STATE_HALF_DUPLEX:
274 	case LINK_STATE_FULL_DUPLEX:
275 		tbprintf(":U");
276 		break;
277 	case LINK_STATE_DOWN:
278 		tbprintf (":D");
279 		break;
280 	}
281 
282 	print_fld_tb(FLD_IF_STATE);
283 
284 	print_fld_size(FLD_IF_IBYTES, ifs->ifs_cur.ifc_ib);
285 	print_fld_size(FLD_IF_IPKTS, ifs->ifs_cur.ifc_ip);
286 	print_fld_size(FLD_IF_IERRS, ifs->ifs_cur.ifc_ie);
287 
288 	print_fld_size(FLD_IF_OBYTES, ifs->ifs_cur.ifc_ob);
289 	print_fld_size(FLD_IF_OPKTS, ifs->ifs_cur.ifc_op);
290 	print_fld_size(FLD_IF_OERRS, ifs->ifs_cur.ifc_oe);
291 
292 	print_fld_size(FLD_IF_COLLS, ifs->ifs_cur.ifc_co);
293 
294 	end_line();
295 }
296 
297 static void
298 showtotal(void)
299 {
300 	print_fld_str(FLD_IF_IFACE, "Totals");
301 
302 	print_fld_size(FLD_IF_IBYTES, sum.ifc_ib);
303 	print_fld_size(FLD_IF_IPKTS, sum.ifc_ip);
304 	print_fld_size(FLD_IF_IERRS, sum.ifc_ie);
305 
306 	print_fld_size(FLD_IF_OBYTES, sum.ifc_ob);
307 	print_fld_size(FLD_IF_OPKTS, sum.ifc_op);
308 	print_fld_size(FLD_IF_OERRS, sum.ifc_oe);
309 
310 	print_fld_size(FLD_IF_COLLS, sum.ifc_co);
311 
312 	end_line();
313 
314 }
315 
316 int
317 if_keyboard_callback(int ch)
318 {
319 	struct ifstat *ifs;
320 
321 	switch (ch) {
322 	case 'r':
323 		for (ifs = ifstats; ifs < ifstats + nifs; ifs++)
324 			ifs->ifs_old = ifs->ifs_now;
325 		state = RUN;
326 		gotsig_alarm = 1;
327 
328 		break;
329 	case 'b':
330 		state = BOOT;
331 		for (ifs = ifstats; ifs < ifstats + nifs; ifs++)
332 			bzero(&ifs->ifs_old, sizeof(ifs->ifs_old));
333 		gotsig_alarm = 1;
334 		break;
335 	case 't':
336 		state = TIME;
337 		gotsig_alarm = 1;
338 		break;
339 	default:
340 		return keyboard_callback(ch);
341 	};
342 
343 	return 1;
344 }
345 
346