Annotation of src/usr.bin/systat/if.c, Revision 1.20
1.20 ! mpf 1: /* $OpenBSD: if.c,v 1.19 2011/03/02 06:48:17 jasper 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.1 markus 18: #include <sys/param.h>
19: #include <sys/types.h>
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;
44:
45: static int nifs = 0;
1.12 canacar 46: static int num_ifs = 0;
1.20 ! mpf 47: static int show_bits = 0;
1.1 markus 48:
1.12 canacar 49: void print_if(void);
50: int read_if(void);
51: int select_if(void);
52: int if_keyboard_callback(int);
53:
1.16 deraadt 54: void fetchifstat(void);
1.12 canacar 55: static void showifstat(struct ifstat *);
56: static void showtotal(void);
1.18 lum 57: static void rt_getaddrinfo(struct sockaddr *, int, struct sockaddr **);
1.12 canacar 58:
59:
60: /* Define fields */
61: field_def fields_if[] = {
62: {"IFACE", 8, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
1.13 deraadt 63: {"STATE", 4, 6, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
1.12 canacar 64: {"IPKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
65: {"IBYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
66: {"IERRS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
67: {"OPKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
68: {"OBYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
69: {"OERRS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
70: {"COLLS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
1.13 deraadt 71: {"DESC", 14, 64, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
1.12 canacar 72: };
73:
74:
1.19 jasper 75: #define FLD_IF_IFACE FIELD_ADDR(fields_if,0)
76: #define FLD_IF_STATE FIELD_ADDR(fields_if,1)
77: #define FLD_IF_IPKTS FIELD_ADDR(fields_if,2)
78: #define FLD_IF_IBYTES FIELD_ADDR(fields_if,3)
79: #define FLD_IF_IERRS FIELD_ADDR(fields_if,4)
80: #define FLD_IF_OPKTS FIELD_ADDR(fields_if,5)
81: #define FLD_IF_OBYTES FIELD_ADDR(fields_if,6)
82: #define FLD_IF_OERRS FIELD_ADDR(fields_if,7)
83: #define FLD_IF_COLLS FIELD_ADDR(fields_if,8)
84: #define FLD_IF_DESC FIELD_ADDR(fields_if,9)
1.12 canacar 85:
86:
87: /* Define views */
88: field_def *view_if_0[] = {
1.13 deraadt 89: FLD_IF_IFACE, FLD_IF_STATE, FLD_IF_DESC, FLD_IF_IPKTS,
90: FLD_IF_IBYTES, FLD_IF_IERRS, FLD_IF_OPKTS, FLD_IF_OBYTES,
91: FLD_IF_OERRS, FLD_IF_COLLS, NULL
1.12 canacar 92: };
93:
94: /* Define view managers */
95:
96: struct view_manager ifstat_mgr = {
97: "Ifstat", select_if, read_if, NULL, print_header,
98: print_if, if_keyboard_callback, NULL, NULL
99: };
100:
101: field_view views_if[] = {
102: {view_if_0, "ifstat", '1', &ifstat_mgr},
103: {NULL, NULL, 0, NULL}
104: };
1.7 claudio 105:
1.1 markus 106:
107: int
108: initifstat(void)
109: {
1.12 canacar 110: field_view *v;
111: read_if();
112: for (v = views_if; v->name != NULL; v++)
113: add_view(v);
1.1 markus 114:
115: return(1);
116: }
117:
118: #define UPDATE(x, y) do { \
1.2 deraadt 119: ifs->ifs_now.x = ifm.y; \
1.1 markus 120: ifs->ifs_cur.x = ifs->ifs_now.x - ifs->ifs_old.x; \
1.4 dlg 121: if (state == TIME) {\
122: ifs->ifs_old.x = ifs->ifs_now.x; \
123: ifs->ifs_cur.x /= naptime; \
124: } \
1.1 markus 125: sum.x += ifs->ifs_cur.x; \
126: } while(0)
127:
128:
129: void
130: rt_getaddrinfo(struct sockaddr *sa, int addrs, struct sockaddr **info)
131: {
132: int i;
133:
134: for (i = 0; i < RTAX_MAX; i++) {
135: if (addrs & (1 << i)) {
136: info[i] = sa;
137: sa = (struct sockaddr *) ((char *)(sa) +
138: roundup(sa->sa_len, sizeof(long)));
139: } else
140: info[i] = NULL;
141: }
142: }
143:
1.12 canacar 144:
145:
146: int
147: select_if(void)
148: {
149: num_disp = num_ifs + 1;
150: return (0);
151: }
152:
153: int
154: read_if(void)
155: {
156: fetchifstat();
157: num_disp = num_ifs + 1;
158:
159: return 0;
160: }
161:
1.1 markus 162: void
1.12 canacar 163: print_if(void)
164: {
165: int n, i, count = 0;
166:
167: for (n = 0, i = 0; n < nifs; n++) {
168: if (ifstats[n].ifs_name[0] == '\0')
169: continue;
170: if (i++ < dispstart)
171: continue;
172: if (i == num_disp)
173: break;
174: showifstat(ifstats + n);
175: if (maxprint > 0 && ++count >= maxprint)
176: return;
177: }
178: showtotal();
179: }
180:
181:
1.16 deraadt 182: void
1.1 markus 183: fetchifstat(void)
184: {
185: struct ifstat *newstats, *ifs;
1.2 deraadt 186: struct if_msghdr ifm;
1.1 markus 187: struct sockaddr *info[RTAX_MAX];
188: struct sockaddr_dl *sdl;
189: char *buf, *next, *lim;
1.17 canacar 190: int mib[6], i;
1.1 markus 191: size_t need;
192:
193: mib[0] = CTL_NET;
194: mib[1] = AF_ROUTE;
195: mib[2] = 0;
196: mib[3] = 0;
197: mib[4] = NET_RT_IFLIST;
198: mib[5] = 0;
199:
200: if (sysctl(mib, 6, NULL, &need, NULL, 0) == -1)
201: return;
202: if ((buf = malloc(need)) == NULL)
203: return;
204: if (sysctl(mib, 6, buf, &need, NULL, 0) == -1) {
205: free(buf);
206: return;
207: }
208:
209: bzero(&sum, sizeof(sum));
1.12 canacar 210: num_ifs = 0;
1.1 markus 211:
212: lim = buf + need;
1.2 deraadt 213: for (next = buf; next < lim; next += ifm.ifm_msglen) {
214: bcopy(next, &ifm, sizeof ifm);
1.14 claudio 215: if (ifm.ifm_version != RTM_VERSION ||
216: ifm.ifm_type != RTM_IFINFO ||
217: !(ifm.ifm_addrs & RTA_IFP))
1.1 markus 218: continue;
1.2 deraadt 219: if (ifm.ifm_index >= nifs) {
1.12 canacar 220: if ((newstats = realloc(ifstats, (ifm.ifm_index + 4)
221: * sizeof(struct ifstat))) == NULL)
1.1 markus 222: continue;
223: ifstats = newstats;
1.2 deraadt 224: for (; nifs < ifm.ifm_index + 4; nifs++)
1.12 canacar 225: bzero(&ifstats[nifs], sizeof(*ifstats));
1.1 markus 226: }
1.2 deraadt 227: ifs = &ifstats[ifm.ifm_index];
1.1 markus 228: if (ifs->ifs_name[0] == '\0') {
229: bzero(&info, sizeof(info));
1.2 deraadt 230: rt_getaddrinfo(
231: (struct sockaddr *)((struct if_msghdr *)next + 1),
232: ifm.ifm_addrs, info);
1.13 deraadt 233: sdl = (struct sockaddr_dl *)info[RTAX_IFP];
234:
235: if (sdl && sdl->sdl_family == AF_LINK &&
236: sdl->sdl_nlen > 0) {
237: struct ifreq ifrdesc;
238: char ifdescr[IFDESCRSIZE];
239: int s;
240:
241: bcopy(sdl->sdl_data, ifs->ifs_name,
242: sdl->sdl_nlen);
243: ifs->ifs_name[sdl->sdl_nlen] = '\0';
244:
245: /* Get the interface description */
246: memset(&ifrdesc, 0, sizeof(ifrdesc));
247: strlcpy(ifrdesc.ifr_name, ifs->ifs_name,
248: sizeof(ifrdesc.ifr_name));
249: ifrdesc.ifr_data = (caddr_t)&ifdescr;
250:
251: s = socket(AF_INET, SOCK_DGRAM, 0);
252: if (s != -1) {
253: if (ioctl(s, SIOCGIFDESCR, &ifrdesc) == 0)
254: strlcpy(ifs->ifs_description,
255: ifrdesc.ifr_data,
256: sizeof(ifs->ifs_description));
257: close(s);
1.3 dlg 258: }
1.1 markus 259: }
260: if (ifs->ifs_name[0] == '\0')
261: continue;
262: }
1.12 canacar 263: num_ifs++;
1.1 markus 264: UPDATE(ifc_ip, ifm_data.ifi_ipackets);
265: UPDATE(ifc_ib, ifm_data.ifi_ibytes);
266: UPDATE(ifc_ie, ifm_data.ifi_ierrors);
267: UPDATE(ifc_op, ifm_data.ifi_opackets);
268: UPDATE(ifc_ob, ifm_data.ifi_obytes);
269: UPDATE(ifc_oe, ifm_data.ifi_oerrors);
270: UPDATE(ifc_co, ifm_data.ifi_collisions);
1.7 claudio 271: ifs->ifs_cur.ifc_flags = ifm.ifm_flags;
272: ifs->ifs_cur.ifc_state = ifm.ifm_data.ifi_link_state;
1.17 canacar 273: ifs->ifs_flag++;
1.1 markus 274: }
1.17 canacar 275:
276: /* remove unreferenced interfaces */
277: for (i = 0; i < nifs; i++) {
278: ifs = &ifstats[i];
279: if (ifs->ifs_flag)
280: ifs->ifs_flag = 0;
281: else
282: ifs->ifs_name[0] = '\0';
283: }
284:
1.1 markus 285: free(buf);
286: }
287:
288:
1.12 canacar 289: static void
290: showifstat(struct ifstat *ifs)
1.1 markus 291: {
1.20 ! mpf 292: int conv = show_bits ? 8 : 1;
! 293: int div = show_bits ? 1000 : 1024;
! 294:
1.12 canacar 295: print_fld_str(FLD_IF_IFACE, ifs->ifs_name);
1.1 markus 296:
1.12 canacar 297: tb_start();
298: tbprintf("%s", ifs->ifs_cur.ifc_flags & IFF_UP ?
299: "up" : "dn");
1.7 claudio 300:
1.12 canacar 301: switch (ifs->ifs_cur.ifc_state) {
1.7 claudio 302: case LINK_STATE_UP:
1.8 reyk 303: case LINK_STATE_HALF_DUPLEX:
304: case LINK_STATE_FULL_DUPLEX:
1.12 canacar 305: tbprintf(":U");
306: break;
1.7 claudio 307: case LINK_STATE_DOWN:
1.12 canacar 308: tbprintf (":D");
309: break;
1.7 claudio 310: }
1.12 canacar 311:
312: print_fld_tb(FLD_IF_STATE);
1.13 deraadt 313:
314: print_fld_str(FLD_IF_DESC, ifs->ifs_description);
1.12 canacar 315:
1.20 ! mpf 316: print_fld_sdiv(FLD_IF_IBYTES, ifs->ifs_cur.ifc_ib * conv, div);
1.12 canacar 317: print_fld_size(FLD_IF_IPKTS, ifs->ifs_cur.ifc_ip);
318: print_fld_size(FLD_IF_IERRS, ifs->ifs_cur.ifc_ie);
319:
1.20 ! mpf 320: print_fld_sdiv(FLD_IF_OBYTES, ifs->ifs_cur.ifc_ob * conv, div);
1.12 canacar 321: print_fld_size(FLD_IF_OPKTS, ifs->ifs_cur.ifc_op);
322: print_fld_size(FLD_IF_OERRS, ifs->ifs_cur.ifc_oe);
323:
324: print_fld_size(FLD_IF_COLLS, ifs->ifs_cur.ifc_co);
325:
326: end_line();
1.7 claudio 327: }
1.6 deraadt 328:
1.12 canacar 329: static void
330: showtotal(void)
1.1 markus 331: {
1.20 ! mpf 332: int conv = show_bits ? 8 : 1;
! 333: int div = show_bits ? 1000 : 1024;
! 334:
1.12 canacar 335: print_fld_str(FLD_IF_IFACE, "Totals");
336:
1.20 ! mpf 337: print_fld_sdiv(FLD_IF_IBYTES, sum.ifc_ib * conv, div);
1.12 canacar 338: print_fld_size(FLD_IF_IPKTS, sum.ifc_ip);
339: print_fld_size(FLD_IF_IERRS, sum.ifc_ie);
340:
1.20 ! mpf 341: print_fld_sdiv(FLD_IF_OBYTES, sum.ifc_ob * conv, div);
1.12 canacar 342: print_fld_size(FLD_IF_OPKTS, sum.ifc_op);
343: print_fld_size(FLD_IF_OERRS, sum.ifc_oe);
344:
345: print_fld_size(FLD_IF_COLLS, sum.ifc_co);
346:
347: end_line();
1.1 markus 348:
349: }
350:
351: int
1.12 canacar 352: if_keyboard_callback(int ch)
1.1 markus 353: {
354: struct ifstat *ifs;
355:
1.12 canacar 356: switch (ch) {
357: case 'r':
358: for (ifs = ifstats; ifs < ifstats + nifs; ifs++)
359: ifs->ifs_old = ifs->ifs_now;
1.1 markus 360: state = RUN;
1.12 canacar 361: gotsig_alarm = 1;
362:
363: break;
364: case 'b':
1.1 markus 365: state = BOOT;
366: for (ifs = ifstats; ifs < ifstats + nifs; ifs++)
367: bzero(&ifs->ifs_old, sizeof(ifs->ifs_old));
1.20 ! mpf 368: gotsig_alarm = 1;
! 369: break;
! 370: case 'B':
! 371: show_bits = !show_bits;
! 372: if (show_bits) {
! 373: FLD_IF_IBYTES->title = "IBITS";
! 374: FLD_IF_OBYTES->title = "OBITS";
! 375: } else {
! 376: FLD_IF_IBYTES->title = "IBYTES";
! 377: FLD_IF_OBYTES->title = "OBYTES";
! 378: }
1.12 canacar 379: gotsig_alarm = 1;
380: break;
381: case 't':
1.1 markus 382: state = TIME;
1.12 canacar 383: gotsig_alarm = 1;
384: break;
385: default:
386: return keyboard_callback(ch);
387: };
388:
389: return 1;
1.1 markus 390: }
1.12 canacar 391: