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