Annotation of src/usr.bin/systat/mbufs.c, Revision 1.43
1.43 ! dlg 1: /* $OpenBSD: mbufs.c,v 1.42 2019/06/28 13:35:04 deraadt Exp $ */
1.19 canacar 2: /*
3: * Copyright (c) 2008 Can Erkin Acar <canacar@openbsd.org>
1.1 deraadt 4: *
1.19 canacar 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.
1.1 deraadt 8: *
1.19 canacar 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.
1.1 deraadt 16: */
1.38 deraadt 17:
18: #include <sys/signal.h>
1.19 canacar 19: #include <sys/socket.h>
20: #include <sys/sysctl.h>
1.41 sthen 21: #include <sys/queue.h>
1.1 deraadt 22: #include <sys/mbuf.h>
1.28 blambert 23: #include <sys/pool.h>
1.19 canacar 24: #include <net/if.h>
1.35 dlg 25: #include <sys/sockio.h>
26: #include <sys/ioctl.h>
1.1 deraadt 27:
1.19 canacar 28: #include <err.h>
29: #include <errno.h>
30: #include <ifaddrs.h>
1.1 deraadt 31: #include <stdlib.h>
32: #include <string.h>
1.19 canacar 33:
1.1 deraadt 34: #include "systat.h"
1.18 canacar 35:
1.35 dlg 36: /* pool info */
37: int mbpool_index = -1;
38: int mclpools_index[MCLPOOLS];
1.19 canacar 39: int mclpool_count = 0;
1.34 dlg 40: struct kinfo_pool mbpool;
1.31 claudio 41: u_int mcllivelocks, mcllivelocks_cur, mcllivelocks_diff;
1.19 canacar 42:
43: /* interfaces */
1.35 dlg 44: static int num_ifs = 0;
1.19 canacar 45: struct if_info {
46: char name[16];
1.35 dlg 47: struct if_rxrinfo data;
1.19 canacar 48: } *interfaces = NULL;
49:
1.35 dlg 50: static int sock;
51:
1.18 canacar 52: void print_mb(void);
53: int read_mb(void);
54: int select_mb(void);
1.23 kettenis 55: static void showmbuf(struct if_info *, int, int);
1.1 deraadt 56:
1.19 canacar 57: /* Define fields */
58: field_def fields_mbuf[] = {
59: {"IFACE", 8, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
1.43 ! dlg 60: {"RING", 8, 8, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
1.19 canacar 61: {"RXDELAY", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
62: {"TXDELAY", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
63: {"LIVELOCKS", 5, 10, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
64: {"SIZE", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
65: {"ALIVE", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
66: {"LWM", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
67: {"HWM", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
1.22 dlg 68: {"CWM", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
1.1 deraadt 69: };
70:
71:
1.32 jasper 72: #define FLD_MB_IFACE FIELD_ADDR(fields_mbuf,0)
1.43 ! dlg 73: #define FLD_MB_RING FIELD_ADDR(fields_mbuf,1)
! 74: #define FLD_MB_RXDELAY FIELD_ADDR(fields_mbuf,2)
! 75: #define FLD_MB_TXDELAY FIELD_ADDR(fields_mbuf,3)
! 76: #define FLD_MB_LLOCKS FIELD_ADDR(fields_mbuf,4)
! 77: #define FLD_MB_MSIZE FIELD_ADDR(fields_mbuf,5)
! 78: #define FLD_MB_MALIVE FIELD_ADDR(fields_mbuf,6)
! 79: #define FLD_MB_MLWM FIELD_ADDR(fields_mbuf,7)
! 80: #define FLD_MB_MHWM FIELD_ADDR(fields_mbuf,8)
! 81: #define FLD_MB_MCWM FIELD_ADDR(fields_mbuf,9)
1.18 canacar 82:
83:
84: /* Define views */
1.19 canacar 85: field_def *view_mbuf[] = {
1.43 ! dlg 86: FLD_MB_IFACE, FLD_MB_RING,
1.26 henning 87: FLD_MB_LLOCKS, FLD_MB_MSIZE, FLD_MB_MALIVE, FLD_MB_MLWM, FLD_MB_MHWM,
88: FLD_MB_MCWM, NULL
1.18 canacar 89: };
90:
1.19 canacar 91: /* Define view managers */
1.18 canacar 92:
93: struct view_manager mbuf_mgr = {
94: "Mbufs", select_mb, read_mb, NULL, print_header,
95: print_mb, keyboard_callback, NULL, NULL
96: };
97:
98: field_view views_mb[] = {
1.19 canacar 99: {view_mbuf, "mbufs", '4', &mbuf_mgr},
1.18 canacar 100: {NULL, NULL, 0, NULL}
101: };
102:
103:
104: int
1.19 canacar 105: initmembufs(void)
1.1 deraadt 106: {
1.35 dlg 107: struct if_rxring_info *ifr;
1.19 canacar 108: field_view *v;
109: int i, mib[4], npools;
1.34 dlg 110: struct kinfo_pool pool;
1.19 canacar 111: char pname[32];
112: size_t size;
113:
1.35 dlg 114: sock = socket(AF_INET, SOCK_DGRAM, 0);
115: if (sock == -1) {
116: err(1, "socket()");
117: /* NOTREACHED */
118: }
119:
120: /* set up the "System" interface */
121:
122: interfaces = calloc(1, sizeof(*interfaces));
123: if (interfaces == NULL)
124: err(1, "calloc: interfaces");
125:
126: ifr = calloc(MCLPOOLS, sizeof(*ifr));
127: if (ifr == NULL)
128: err(1, "calloc: system pools");
129:
130: strlcpy(interfaces[0].name, "System", sizeof(interfaces[0].name));
131: interfaces[0].data.ifri_total = MCLPOOLS;
132: interfaces[0].data.ifri_entries = ifr;
133: num_ifs = 1;
134:
1.19 canacar 135: /* go through all pools to identify mbuf and cluster pools */
1.18 canacar 136:
1.19 canacar 137: mib[0] = CTL_KERN;
138: mib[1] = KERN_POOL;
139: mib[2] = KERN_POOL_NPOOLS;
140: size = sizeof(npools);
141:
1.42 deraadt 142: if (sysctl(mib, 3, &npools, &size, NULL, 0) == -1) {
1.19 canacar 143: err(1, "sysctl(KERN_POOL_NPOOLS)");
144: /* NOTREACHED */
145: }
146:
147: for (i = 1; i <= npools; i++) {
148: mib[0] = CTL_KERN;
149: mib[1] = KERN_POOL;
150: mib[2] = KERN_POOL_NAME;
151: mib[3] = i;
152: size = sizeof(pname);
1.42 deraadt 153: if (sysctl(mib, 4, &pname, &size, NULL, 0) == -1) {
1.21 canacar 154: continue;
1.19 canacar 155: }
156:
1.37 dlg 157: if (strcmp(pname, "mbufpl") == 0) {
1.19 canacar 158: mbpool_index = i;
159: continue;
160: }
161:
162: if (strncmp(pname, "mcl", 3) != 0)
163: continue;
164:
165: if (mclpool_count == MCLPOOLS) {
1.24 chl 166: warnx("mbufs: Too many mcl* pools");
1.19 canacar 167: break;
168: }
169:
170: mib[2] = KERN_POOL_POOL;
1.34 dlg 171: size = sizeof(pool);
1.19 canacar 172:
1.42 deraadt 173: if (sysctl(mib, 4, &pool, &size, NULL, 0) == -1) {
1.19 canacar 174: err(1, "sysctl(KERN_POOL_POOL, %d)", i);
175: /* NOTREACHED */
176: }
177:
1.43 ! dlg 178: strlcpy(ifr[mclpool_count].ifr_name, pname,
! 179: sizeof(ifr[mclpool_count].ifr_name));
1.35 dlg 180: ifr[mclpool_count].ifr_size = pool.pr_size;
1.19 canacar 181:
1.35 dlg 182: mclpools_index[mclpool_count++] = i;
1.19 canacar 183: }
184:
185: if (mclpool_count != MCLPOOLS)
186: warnx("mbufs: Unable to read all %d mcl* pools", MCLPOOLS);
187:
188: /* add view to the engine */
189: for (v = views_mb; v->name != NULL; v++)
190: add_view(v);
191:
192: /* finally read it once */
1.18 canacar 193: read_mb();
194:
1.19 canacar 195: return(1);
196: }
1.18 canacar 197:
1.19 canacar 198: int
199: select_mb(void)
200: {
201: num_disp = 0;
1.18 canacar 202: return (0);
1.1 deraadt 203: }
204:
1.18 canacar 205: int
206: read_mb(void)
1.1 deraadt 207: {
1.34 dlg 208: struct kinfo_pool pool;
1.40 jsg 209: struct ifaddrs *ifap = NULL, *ifa;
1.19 canacar 210: struct if_info *ifi;
1.35 dlg 211: struct if_rxring_info *ifr;
1.19 canacar 212: int mib[4];
1.35 dlg 213: int i, p, nif, ret = 1, rv;
214: u_int rings;
1.19 canacar 215: size_t size;
216:
1.30 dlg 217: mib[0] = CTL_KERN;
218: mib[1] = KERN_NETLIVELOCKS;
1.31 claudio 219: size = sizeof(mcllivelocks_cur);
1.42 deraadt 220: if (sysctl(mib, 2, &mcllivelocks_cur, &size, NULL, 0) == -1 &&
1.30 dlg 221: errno != EOPNOTSUPP) {
222: error("sysctl(KERN_NETLIVELOCKS)");
223: goto exit;
224: }
1.31 claudio 225: mcllivelocks_diff = mcllivelocks_cur - mcllivelocks;
226: mcllivelocks = mcllivelocks_cur;
1.30 dlg 227:
1.19 canacar 228: num_disp = 0;
229: if (getifaddrs(&ifap)) {
230: error("getifaddrs: %s", strerror(errno));
231: return (1);
232: }
233:
234: nif = 1;
1.35 dlg 235: for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
236: if (ifa->ifa_addr == NULL ||
237: ifa->ifa_addr->sa_family != AF_LINK)
238: continue;
239:
240: nif++;
241: }
1.19 canacar 242:
1.35 dlg 243: if (num_ifs < nif) {
244: ifi = reallocarray(interfaces, nif, sizeof(*interfaces));
1.19 canacar 245: if (ifi == NULL) {
1.35 dlg 246: error("reallocarray: %d interfaces", nif);
1.19 canacar 247: goto exit;
248: }
249:
250: interfaces = ifi;
1.35 dlg 251: while (num_ifs < nif)
252: memset(&interfaces[num_ifs++], 0, sizeof(*interfaces));
1.19 canacar 253: }
254:
255: /* Fill in the "real" interfaces */
256: ifi = interfaces + 1;
257:
258: for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
259: if (ifa->ifa_addr == NULL ||
260: ifa->ifa_addr->sa_family != AF_LINK)
261: continue;
262:
263: strlcpy(ifi->name, ifa->ifa_name, sizeof(ifi->name));
1.35 dlg 264: for (;;) {
265: struct ifreq ifreq;
266: rings = ifi->data.ifri_total;
267:
268: memset(&ifreq, 0, sizeof(ifreq));
269: strlcpy(ifreq.ifr_name, ifa->ifa_name,
270: sizeof(ifreq.ifr_name));
271: ifreq.ifr_data = (caddr_t)&ifi->data;
272:
273: rv = ioctl(sock, SIOCGIFRXR, &ifreq);
274: if (rv == -1) {
275: if (errno == ENOTTY) {
276: free(ifi->data.ifri_entries);
277: ifi->data.ifri_total = 0;
278: ifi->data.ifri_entries = NULL;
279: break;
280: }
281:
282: error("ioctl(SIOCGIFRXR) %s", strerror(errno));
283: break;
284: }
285:
286: if (rings >= ifi->data.ifri_total)
287: break;
288:
289: ifr = reallocarray(ifi->data.ifri_entries,
290: ifi->data.ifri_total, sizeof(*ifr));
291: if (ifr == NULL) {
292: ifi->data.ifri_total = rings;
293: error("reallocarray: %u rings",
294: ifi->data.ifri_total);
295: goto exit;
296: }
297:
298: ifi->data.ifri_entries = ifr;
299: }
1.19 canacar 300:
301: ifi++;
302: }
303:
304: /* Fill in the "System" entry from pools */
1.18 canacar 305:
306: mib[0] = CTL_KERN;
1.19 canacar 307: mib[1] = KERN_POOL;
308: mib[2] = KERN_POOL_POOL;
309: mib[3] = mbpool_index;
1.34 dlg 310: size = sizeof(mbpool);
1.19 canacar 311:
1.42 deraadt 312: if (sysctl(mib, 4, &mbpool, &size, NULL, 0) == -1) {
1.27 chl 313: error("sysctl(KERN_POOL_POOL, %d)", mib[3]);
1.19 canacar 314: goto exit;
315: }
316:
317: for (i = 0; i < mclpool_count; i++) {
1.35 dlg 318: ifr = &interfaces[0].data.ifri_entries[i];
1.19 canacar 319:
1.35 dlg 320: mib[3] = mclpools_index[i];
1.34 dlg 321: size = sizeof(pool);
1.18 canacar 322:
1.42 deraadt 323: if (sysctl(mib, 4, &pool, &size, NULL, 0) == -1) {
1.19 canacar 324: error("sysctl(KERN_POOL_POOL, %d)", mib[3]);
325: continue;
326: }
327:
1.35 dlg 328: ifr->ifr_info.rxr_alive = pool.pr_nget - pool.pr_nput;
329: ifr->ifr_info.rxr_hwm = pool.pr_hiwat;
1.18 canacar 330: }
331:
1.19 canacar 332: num_disp = 1;
333: ret = 0;
1.18 canacar 334:
1.19 canacar 335: for (i = 0; i < num_ifs; i++) {
336: struct if_info *ifi = &interfaces[i];
337: int pnd = num_disp;
1.35 dlg 338: for (p = 0; p < ifi->data.ifri_total; p++) {
339: ifr = &ifi->data.ifri_entries[p];
1.36 jsg 340: if (ifr->ifr_info.rxr_alive == 0)
1.19 canacar 341: continue;
342: num_disp++;
343: }
344: if (i && pnd == num_disp)
345: num_disp++;
1.18 canacar 346: }
347:
1.19 canacar 348: exit:
1.40 jsg 349: if (ifap)
350: freeifaddrs(ifap);
1.19 canacar 351: return (ret);
1.1 deraadt 352: }
353:
354: void
1.18 canacar 355: print_mb(void)
1.1 deraadt 356: {
1.19 canacar 357: int i, p, n, count = 0;
1.1 deraadt 358:
1.23 kettenis 359: showmbuf(interfaces, -1, 1);
1.19 canacar 360:
361: for (n = i = 0; i < num_ifs; i++) {
362: struct if_info *ifi = &interfaces[i];
363: int pcnt = count;
1.23 kettenis 364: int showif = i;
365:
1.18 canacar 366: if (maxprint > 0 && count >= maxprint)
1.19 canacar 367: return;
1.1 deraadt 368:
1.35 dlg 369: for (p = 0; p < ifi->data.ifri_total; p++) {
370: struct if_rxring_info *ifr = &ifi->data.ifri_entries[p];
1.43 ! dlg 371: if (ifr->ifr_info.rxr_hwm == 0)
1.19 canacar 372: continue;
373: if (n++ >= dispstart) {
1.23 kettenis 374: showmbuf(ifi, p, showif);
375: showif = 0;
1.19 canacar 376: count++;
377: }
378: }
379:
380: if (i && pcnt == count) {
381: /* only print the first line */
382: if (n++ >= dispstart) {
1.23 kettenis 383: showmbuf(ifi, -1, 1);
1.19 canacar 384: count++;
385: }
386: }
387: }
1.1 deraadt 388: }
389:
1.18 canacar 390:
391: static void
1.23 kettenis 392: showmbuf(struct if_info *ifi, int p, int showif)
1.1 deraadt 393: {
1.23 kettenis 394: if (showif)
1.19 canacar 395: print_fld_str(FLD_MB_IFACE, ifi->name);
396:
397: if (p == -1 && ifi == interfaces) {
1.43 ! dlg 398: print_fld_str(FLD_MB_RING, "mbufs");
1.31 claudio 399: print_fld_uint(FLD_MB_LLOCKS, mcllivelocks_diff);
1.19 canacar 400: print_fld_size(FLD_MB_MSIZE, mbpool.pr_size);
401: print_fld_size(FLD_MB_MALIVE, mbpool.pr_nget - mbpool.pr_nput);
402: print_fld_size(FLD_MB_MHWM, mbpool.pr_hiwat);
403: }
404:
405: if (p >= 0 && p < mclpool_count) {
1.35 dlg 406: struct if_rxring_info *ifr = &ifi->data.ifri_entries[p];
407: struct if_rxring *rxr= &ifr->ifr_info;
1.43 ! dlg 408: print_fld_str(FLD_MB_RING, ifr->ifr_name);
1.35 dlg 409: print_fld_uint(FLD_MB_MSIZE, ifr->ifr_size);
410: print_fld_uint(FLD_MB_MALIVE, rxr->rxr_alive);
411: if (rxr->rxr_lwm)
412: print_fld_size(FLD_MB_MLWM, rxr->rxr_lwm);
413: if (rxr->rxr_hwm)
414: print_fld_size(FLD_MB_MHWM, rxr->rxr_hwm);
415: if (rxr->rxr_cwm)
416: print_fld_size(FLD_MB_MCWM, rxr->rxr_cwm);
1.19 canacar 417: }
1.18 canacar 418:
419: end_line();
1.1 deraadt 420: }