Annotation of src/usr.bin/systat/if.c, Revision 1.27
1.27 ! deraadt 1: /* $OpenBSD: if.c,v 1.26 2021/01/18 00:49:09 mortimer Exp $ */
1.1 markus 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: */
1.15 jasper 17:
1.27 ! deraadt 18: #include <sys/types.h>
1.23 deraadt 19: #include <sys/signal.h>
1.1 markus 20: #include <sys/socket.h>
21: #include <sys/sysctl.h>
22: #include <net/if.h>
23: #include <net/if_dl.h>
24: #include <net/route.h>
1.13 deraadt 25: #include <sys/sockio.h>
1.15 jasper 26: #include <sys/ioctl.h>
1.1 markus 27:
28: #include <stdlib.h>
1.5 deraadt 29: #include <string.h>
1.15 jasper 30: #include <unistd.h>
1.27 ! deraadt 31:
! 32: #define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
1.1 markus 33:
34: #include "systat.h"
35:
36: static enum state { BOOT, TIME, RUN } state = TIME;
37:
38: struct ifstat {
39: char ifs_name[IFNAMSIZ]; /* interface name */
1.13 deraadt 40: char ifs_description[IFDESCRSIZE];
1.1 markus 41: struct ifcount ifs_cur;
42: struct ifcount ifs_old;
43: struct ifcount ifs_now;
1.17 canacar 44: char ifs_flag;
1.1 markus 45: } *ifstats;
1.26 mortimer 46:
47: struct ifcount sum;
1.1 markus 48:
49: static int nifs = 0;
1.12 canacar 50: static int num_ifs = 0;
1.20 mpf 51: static int show_bits = 0;
1.1 markus 52:
1.12 canacar 53: void print_if(void);
54: int read_if(void);
55: int select_if(void);
56: int if_keyboard_callback(int);
57:
1.16 deraadt 58: void fetchifstat(void);
1.12 canacar 59: static void showifstat(struct ifstat *);
60: static void showtotal(void);
1.18 lum 61: static void rt_getaddrinfo(struct sockaddr *, int, struct sockaddr **);
1.12 canacar 62:
1.24 dlg 63: const char ifails[] = "IFAILS";
64: const char ofails[] = "OFAILS";
65:
66: #define IF_ERR_SUM 0
67: #define IF_ERR_ERRORS 1
68: #define IF_ERR_QDROPS 2
69:
70: struct if_err_view {
71: const char *iname;
72: const char *oname;
73: uint64_t (*icount)(const struct ifcount *);
74: uint64_t (*ocount)(const struct ifcount *);
75: };
76:
77: static uint64_t if_err_ifails(const struct ifcount *);
78: static uint64_t if_err_ofails(const struct ifcount *);
79: static uint64_t if_err_ierrors(const struct ifcount *);
80: static uint64_t if_err_oerrors(const struct ifcount *);
81: static uint64_t if_err_iqdrops(const struct ifcount *);
82: static uint64_t if_err_oqdrops(const struct ifcount *);
83:
84: static const struct if_err_view if_err_views[] = {
85: [IF_ERR_SUM] = {
86: .iname = ifails,
87: .oname = ofails,
88: .icount = if_err_ifails,
89: .ocount = if_err_ofails,
90: },
91: [IF_ERR_ERRORS] = {
92: .iname = "IERRS",
93: .oname = "OERRS",
94: .icount = if_err_ierrors,
95: .ocount = if_err_oerrors,
96: },
97: [IF_ERR_QDROPS] = {
98: .iname = "IQDROPS",
99: .oname = "OQDROPS",
100: .icount = if_err_iqdrops,
101: .ocount = if_err_oqdrops,
102: },
103: };
104:
105: static const struct if_err_view *if_err_view = &if_err_views[IF_ERR_SUM];
1.12 canacar 106:
107: /* Define fields */
108: field_def fields_if[] = {
109: {"IFACE", 8, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
1.13 deraadt 110: {"STATE", 4, 6, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
1.12 canacar 111: {"IPKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
112: {"IBYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
1.24 dlg 113: {ifails, 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
1.12 canacar 114: {"OPKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
115: {"OBYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
1.24 dlg 116: {ofails, 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
1.12 canacar 117: {"COLLS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
1.13 deraadt 118: {"DESC", 14, 64, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
1.12 canacar 119: };
120:
121:
1.19 jasper 122: #define FLD_IF_IFACE FIELD_ADDR(fields_if,0)
123: #define FLD_IF_STATE FIELD_ADDR(fields_if,1)
124: #define FLD_IF_IPKTS FIELD_ADDR(fields_if,2)
125: #define FLD_IF_IBYTES FIELD_ADDR(fields_if,3)
126: #define FLD_IF_IERRS FIELD_ADDR(fields_if,4)
127: #define FLD_IF_OPKTS FIELD_ADDR(fields_if,5)
128: #define FLD_IF_OBYTES FIELD_ADDR(fields_if,6)
129: #define FLD_IF_OERRS FIELD_ADDR(fields_if,7)
130: #define FLD_IF_COLLS FIELD_ADDR(fields_if,8)
131: #define FLD_IF_DESC FIELD_ADDR(fields_if,9)
1.12 canacar 132:
133:
134: /* Define views */
135: field_def *view_if_0[] = {
1.13 deraadt 136: FLD_IF_IFACE, FLD_IF_STATE, FLD_IF_DESC, FLD_IF_IPKTS,
137: FLD_IF_IBYTES, FLD_IF_IERRS, FLD_IF_OPKTS, FLD_IF_OBYTES,
138: FLD_IF_OERRS, FLD_IF_COLLS, NULL
1.12 canacar 139: };
140:
141: /* Define view managers */
142:
143: struct view_manager ifstat_mgr = {
144: "Ifstat", select_if, read_if, NULL, print_header,
145: print_if, if_keyboard_callback, NULL, NULL
146: };
147:
148: field_view views_if[] = {
149: {view_if_0, "ifstat", '1', &ifstat_mgr},
150: {NULL, NULL, 0, NULL}
151: };
1.7 claudio 152:
1.1 markus 153:
154: int
155: initifstat(void)
156: {
1.12 canacar 157: field_view *v;
158: read_if();
159: for (v = views_if; v->name != NULL; v++)
160: add_view(v);
1.1 markus 161:
162: return(1);
163: }
164:
165: #define UPDATE(x, y) do { \
1.2 deraadt 166: ifs->ifs_now.x = ifm.y; \
1.1 markus 167: ifs->ifs_cur.x = ifs->ifs_now.x - ifs->ifs_old.x; \
1.4 dlg 168: if (state == TIME) {\
169: ifs->ifs_old.x = ifs->ifs_now.x; \
170: ifs->ifs_cur.x /= naptime; \
171: } \
1.1 markus 172: sum.x += ifs->ifs_cur.x; \
173: } while(0)
174:
175:
176: void
177: rt_getaddrinfo(struct sockaddr *sa, int addrs, struct sockaddr **info)
178: {
179: int i;
180:
181: for (i = 0; i < RTAX_MAX; i++) {
182: if (addrs & (1 << i)) {
183: info[i] = sa;
184: sa = (struct sockaddr *) ((char *)(sa) +
185: roundup(sa->sa_len, sizeof(long)));
186: } else
187: info[i] = NULL;
188: }
189: }
190:
1.12 canacar 191:
192:
193: int
194: select_if(void)
195: {
196: num_disp = num_ifs + 1;
197: return (0);
198: }
199:
200: int
201: read_if(void)
202: {
203: fetchifstat();
204: num_disp = num_ifs + 1;
205:
206: return 0;
207: }
208:
1.1 markus 209: void
1.12 canacar 210: print_if(void)
211: {
212: int n, i, count = 0;
213:
214: for (n = 0, i = 0; n < nifs; n++) {
215: if (ifstats[n].ifs_name[0] == '\0')
216: continue;
217: if (i++ < dispstart)
218: continue;
219: if (i == num_disp)
220: break;
221: showifstat(ifstats + n);
222: if (maxprint > 0 && ++count >= maxprint)
223: return;
224: }
225: showtotal();
226: }
227:
228:
1.16 deraadt 229: void
1.1 markus 230: fetchifstat(void)
231: {
232: struct ifstat *newstats, *ifs;
1.2 deraadt 233: struct if_msghdr ifm;
1.1 markus 234: struct sockaddr *info[RTAX_MAX];
235: struct sockaddr_dl *sdl;
236: char *buf, *next, *lim;
1.17 canacar 237: int mib[6], i;
1.1 markus 238: size_t need;
239:
240: mib[0] = CTL_NET;
1.21 guenther 241: mib[1] = PF_ROUTE;
1.1 markus 242: mib[2] = 0;
243: mib[3] = 0;
244: mib[4] = NET_RT_IFLIST;
245: mib[5] = 0;
246:
247: if (sysctl(mib, 6, NULL, &need, NULL, 0) == -1)
248: return;
249: if ((buf = malloc(need)) == NULL)
250: return;
251: if (sysctl(mib, 6, buf, &need, NULL, 0) == -1) {
252: free(buf);
253: return;
254: }
255:
256: bzero(&sum, sizeof(sum));
1.12 canacar 257: num_ifs = 0;
1.1 markus 258:
259: lim = buf + need;
1.2 deraadt 260: for (next = buf; next < lim; next += ifm.ifm_msglen) {
261: bcopy(next, &ifm, sizeof ifm);
1.14 claudio 262: if (ifm.ifm_version != RTM_VERSION ||
263: ifm.ifm_type != RTM_IFINFO ||
264: !(ifm.ifm_addrs & RTA_IFP))
1.1 markus 265: continue;
1.2 deraadt 266: if (ifm.ifm_index >= nifs) {
1.22 doug 267: if ((newstats = reallocarray(ifstats, ifm.ifm_index + 4,
268: sizeof(struct ifstat))) == NULL)
1.1 markus 269: continue;
270: ifstats = newstats;
1.2 deraadt 271: for (; nifs < ifm.ifm_index + 4; nifs++)
1.12 canacar 272: bzero(&ifstats[nifs], sizeof(*ifstats));
1.1 markus 273: }
1.2 deraadt 274: ifs = &ifstats[ifm.ifm_index];
1.1 markus 275: if (ifs->ifs_name[0] == '\0') {
276: bzero(&info, sizeof(info));
1.2 deraadt 277: rt_getaddrinfo(
278: (struct sockaddr *)((struct if_msghdr *)next + 1),
279: ifm.ifm_addrs, info);
1.13 deraadt 280: sdl = (struct sockaddr_dl *)info[RTAX_IFP];
281:
282: if (sdl && sdl->sdl_family == AF_LINK &&
283: sdl->sdl_nlen > 0) {
284: struct ifreq ifrdesc;
285: char ifdescr[IFDESCRSIZE];
286: int s;
287:
288: bcopy(sdl->sdl_data, ifs->ifs_name,
289: sdl->sdl_nlen);
290: ifs->ifs_name[sdl->sdl_nlen] = '\0';
291:
292: /* Get the interface description */
293: memset(&ifrdesc, 0, sizeof(ifrdesc));
294: strlcpy(ifrdesc.ifr_name, ifs->ifs_name,
295: sizeof(ifrdesc.ifr_name));
296: ifrdesc.ifr_data = (caddr_t)&ifdescr;
297:
298: s = socket(AF_INET, SOCK_DGRAM, 0);
299: if (s != -1) {
300: if (ioctl(s, SIOCGIFDESCR, &ifrdesc) == 0)
301: strlcpy(ifs->ifs_description,
302: ifrdesc.ifr_data,
303: sizeof(ifs->ifs_description));
304: close(s);
1.3 dlg 305: }
1.1 markus 306: }
307: if (ifs->ifs_name[0] == '\0')
308: continue;
309: }
1.12 canacar 310: num_ifs++;
1.1 markus 311: UPDATE(ifc_ip, ifm_data.ifi_ipackets);
312: UPDATE(ifc_ib, ifm_data.ifi_ibytes);
313: UPDATE(ifc_ie, ifm_data.ifi_ierrors);
1.24 dlg 314: UPDATE(ifc_iq, ifm_data.ifi_iqdrops);
1.1 markus 315: UPDATE(ifc_op, ifm_data.ifi_opackets);
316: UPDATE(ifc_ob, ifm_data.ifi_obytes);
317: UPDATE(ifc_oe, ifm_data.ifi_oerrors);
1.24 dlg 318: UPDATE(ifc_oq, ifm_data.ifi_oqdrops);
1.1 markus 319: UPDATE(ifc_co, ifm_data.ifi_collisions);
1.7 claudio 320: ifs->ifs_cur.ifc_flags = ifm.ifm_flags;
321: ifs->ifs_cur.ifc_state = ifm.ifm_data.ifi_link_state;
1.17 canacar 322: ifs->ifs_flag++;
1.1 markus 323: }
1.17 canacar 324:
325: /* remove unreferenced interfaces */
326: for (i = 0; i < nifs; i++) {
327: ifs = &ifstats[i];
328: if (ifs->ifs_flag)
329: ifs->ifs_flag = 0;
330: else
331: ifs->ifs_name[0] = '\0';
332: }
333:
1.1 markus 334: free(buf);
335: }
336:
337:
1.12 canacar 338: static void
339: showifstat(struct ifstat *ifs)
1.1 markus 340: {
1.20 mpf 341: int conv = show_bits ? 8 : 1;
342: int div = show_bits ? 1000 : 1024;
343:
1.12 canacar 344: print_fld_str(FLD_IF_IFACE, ifs->ifs_name);
1.1 markus 345:
1.12 canacar 346: tb_start();
347: tbprintf("%s", ifs->ifs_cur.ifc_flags & IFF_UP ?
348: "up" : "dn");
1.7 claudio 349:
1.12 canacar 350: switch (ifs->ifs_cur.ifc_state) {
1.7 claudio 351: case LINK_STATE_UP:
1.8 reyk 352: case LINK_STATE_HALF_DUPLEX:
353: case LINK_STATE_FULL_DUPLEX:
1.12 canacar 354: tbprintf(":U");
355: break;
1.7 claudio 356: case LINK_STATE_DOWN:
1.12 canacar 357: tbprintf (":D");
358: break;
1.7 claudio 359: }
1.12 canacar 360:
361: print_fld_tb(FLD_IF_STATE);
1.13 deraadt 362:
363: print_fld_str(FLD_IF_DESC, ifs->ifs_description);
1.12 canacar 364:
1.20 mpf 365: print_fld_sdiv(FLD_IF_IBYTES, ifs->ifs_cur.ifc_ib * conv, div);
1.12 canacar 366: print_fld_size(FLD_IF_IPKTS, ifs->ifs_cur.ifc_ip);
1.24 dlg 367: print_fld_size(FLD_IF_IERRS, if_err_view->icount(&ifs->ifs_cur));
1.12 canacar 368:
1.20 mpf 369: print_fld_sdiv(FLD_IF_OBYTES, ifs->ifs_cur.ifc_ob * conv, div);
1.12 canacar 370: print_fld_size(FLD_IF_OPKTS, ifs->ifs_cur.ifc_op);
1.24 dlg 371: print_fld_size(FLD_IF_OERRS, if_err_view->ocount(&ifs->ifs_cur));
1.12 canacar 372:
373: print_fld_size(FLD_IF_COLLS, ifs->ifs_cur.ifc_co);
374:
375: end_line();
1.7 claudio 376: }
1.6 deraadt 377:
1.12 canacar 378: static void
379: showtotal(void)
1.1 markus 380: {
1.20 mpf 381: int conv = show_bits ? 8 : 1;
382: int div = show_bits ? 1000 : 1024;
383:
1.12 canacar 384: print_fld_str(FLD_IF_IFACE, "Totals");
385:
1.20 mpf 386: print_fld_sdiv(FLD_IF_IBYTES, sum.ifc_ib * conv, div);
1.12 canacar 387: print_fld_size(FLD_IF_IPKTS, sum.ifc_ip);
1.24 dlg 388: print_fld_size(FLD_IF_IERRS, if_err_view->icount(&sum));
1.12 canacar 389:
1.20 mpf 390: print_fld_sdiv(FLD_IF_OBYTES, sum.ifc_ob * conv, div);
1.12 canacar 391: print_fld_size(FLD_IF_OPKTS, sum.ifc_op);
1.24 dlg 392: print_fld_size(FLD_IF_OERRS, if_err_view->ocount(&sum));
1.12 canacar 393:
394: print_fld_size(FLD_IF_COLLS, sum.ifc_co);
395:
396: end_line();
1.1 markus 397:
398: }
399:
1.24 dlg 400: static uint64_t
401: if_err_ifails(const struct ifcount *ifc)
402: {
403: return (ifc->ifc_ie + ifc->ifc_iq);
404: }
405:
406: static uint64_t
407: if_err_ofails(const struct ifcount *ifc)
408: {
409: return (ifc->ifc_oe + ifc->ifc_oq);
410: }
411:
412: static uint64_t
413: if_err_ierrors(const struct ifcount *ifc)
414: {
415: return (ifc->ifc_ie);
416: }
417:
418: static uint64_t
419: if_err_oerrors(const struct ifcount *ifc)
420: {
421: return (ifc->ifc_oe);
422: }
423:
424: static uint64_t
425: if_err_iqdrops(const struct ifcount *ifc)
426: {
427: return (ifc->ifc_iq);
428: }
429:
430: static uint64_t
431: if_err_oqdrops(const struct ifcount *ifc)
432: {
433: return (ifc->ifc_oq);
434: }
435:
436: static void
437: if_set_errs(unsigned int v)
438: {
439: if_err_view = &if_err_views[v];
440: FLD_IF_IERRS->title = if_err_view->iname;
1.25 dlg 441: FLD_IF_OERRS->title = if_err_view->oname;
1.24 dlg 442: gotsig_alarm = 1;
443: }
444:
1.1 markus 445: int
1.12 canacar 446: if_keyboard_callback(int ch)
1.1 markus 447: {
448: struct ifstat *ifs;
449:
1.12 canacar 450: switch (ch) {
1.24 dlg 451: case 'd':
452: if_set_errs(IF_ERR_QDROPS);
453: break;
454: case 'e':
455: if_set_errs(IF_ERR_ERRORS);
456: break;
457: case 'f':
458: if_set_errs(IF_ERR_SUM);
459: break;
460:
1.12 canacar 461: case 'r':
462: for (ifs = ifstats; ifs < ifstats + nifs; ifs++)
463: ifs->ifs_old = ifs->ifs_now;
1.1 markus 464: state = RUN;
1.12 canacar 465: gotsig_alarm = 1;
466:
467: break;
468: case 'b':
1.1 markus 469: state = BOOT;
470: for (ifs = ifstats; ifs < ifstats + nifs; ifs++)
471: bzero(&ifs->ifs_old, sizeof(ifs->ifs_old));
1.20 mpf 472: gotsig_alarm = 1;
473: break;
474: case 'B':
475: show_bits = !show_bits;
476: if (show_bits) {
477: FLD_IF_IBYTES->title = "IBITS";
478: FLD_IF_OBYTES->title = "OBITS";
479: } else {
480: FLD_IF_IBYTES->title = "IBYTES";
481: FLD_IF_OBYTES->title = "OBYTES";
482: }
1.12 canacar 483: gotsig_alarm = 1;
484: break;
485: case 't':
1.1 markus 486: state = TIME;
1.12 canacar 487: gotsig_alarm = 1;
488: break;
489: default:
490: return keyboard_callback(ch);
491: };
492:
493: return 1;
1.1 markus 494: }
1.12 canacar 495: