1 /* $OpenBSD: mbufs.c,v 1.44 2020/12/22 06:57:18 dlg Exp $ */
2 /*
3 * Copyright (c) 2008 Can Erkin Acar <canacar@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
18 #include <sys/signal.h>
19 #include <sys/socket.h>
20 #include <sys/sysctl.h>
21 #include <sys/queue.h>
22 #include <sys/mbuf.h>
23 #include <sys/pool.h>
24 #include <net/if.h>
25 #include <sys/sockio.h>
26 #include <sys/ioctl.h>
27
28 #include <err.h>
29 #include <errno.h>
30 #include <ifaddrs.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "systat.h"
35
36 /* pool info */
37 int mbpool_index = -1;
38 int mclpools_index[MCLPOOLS];
39 int mclpool_count = 0;
40 struct kinfo_pool mbpool;
41 u_int mcllivelocks, mcllivelocks_cur, mcllivelocks_diff;
42
43 /* interfaces */
44 static int num_ifs = 0;
45 struct if_info {
46 char name[16];
47 struct if_rxrinfo data;
48 } *interfaces = NULL;
49
50 static int sock;
51
52 void print_mb(void);
53 int read_mb(void);
54 int select_mb(void);
55 static void showmbuf(struct if_info *, int, int);
56
57 /* Define fields */
58 field_def fields_mbuf[] = {
59 {"IFACE", 8, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
60 {"RING", 8, 8, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
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},
68 {"CWM", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
69 };
70
71
72 #define FLD_MB_IFACE FIELD_ADDR(fields_mbuf,0)
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)
82
83
84 /* Define views */
85 field_def *view_mbuf[] = {
86 FLD_MB_IFACE, FLD_MB_RING,
87 FLD_MB_LLOCKS, FLD_MB_MSIZE, FLD_MB_MALIVE, FLD_MB_MLWM, FLD_MB_MHWM,
88 FLD_MB_MCWM, NULL
89 };
90
91 /* Define view managers */
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[] = {
99 {view_mbuf, "mbufs", '4', &mbuf_mgr},
100 {NULL, NULL, 0, NULL}
101 };
102
103
104 int
initmembufs(void)105 initmembufs(void)
106 {
107 struct if_rxring_info *ifr;
108 field_view *v;
109 int i, mib[4], npools;
110 struct kinfo_pool pool;
111 char pname[32];
112 size_t size;
113
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
135 /* go through all pools to identify mbuf and cluster pools */
136
137 mib[0] = CTL_KERN;
138 mib[1] = KERN_POOL;
139 mib[2] = KERN_POOL_NPOOLS;
140 size = sizeof(npools);
141
142 if (sysctl(mib, 3, &npools, &size, NULL, 0) == -1) {
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);
153 if (sysctl(mib, 4, &pname, &size, NULL, 0) == -1) {
154 continue;
155 }
156
157 if (strcmp(pname, "mbufpl") == 0) {
158 mbpool_index = i;
159 continue;
160 }
161
162 if (strncmp(pname, "mcl", 3) != 0)
163 continue;
164
165 if (mclpool_count == MCLPOOLS) {
166 warnx("mbufs: Too many mcl* pools");
167 break;
168 }
169
170 mib[2] = KERN_POOL_POOL;
171 size = sizeof(pool);
172
173 if (sysctl(mib, 4, &pool, &size, NULL, 0) == -1) {
174 err(1, "sysctl(KERN_POOL_POOL, %d)", i);
175 /* NOTREACHED */
176 }
177
178 strlcpy(ifr[mclpool_count].ifr_name, pname,
179 sizeof(ifr[mclpool_count].ifr_name));
180 ifr[mclpool_count].ifr_size = pool.pr_size;
181
182 mclpools_index[mclpool_count++] = i;
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 */
193 read_mb();
194
195 return(1);
196 }
197
198 int
select_mb(void)199 select_mb(void)
200 {
201 num_disp = 0;
202 return (0);
203 }
204
205 int
read_mb(void)206 read_mb(void)
207 {
208 struct kinfo_pool pool;
209 struct ifaddrs *ifap = NULL, *ifa;
210 struct if_info *ifi;
211 struct if_rxring_info *ifr;
212 int mib[4];
213 int i, p, nif, ret = 1, rv;
214 u_int rings;
215 size_t size;
216
217 mib[0] = CTL_KERN;
218 mib[1] = KERN_NETLIVELOCKS;
219 size = sizeof(mcllivelocks_cur);
220 if (sysctl(mib, 2, &mcllivelocks_cur, &size, NULL, 0) == -1 &&
221 errno != EOPNOTSUPP) {
222 error("sysctl(KERN_NETLIVELOCKS)");
223 goto exit;
224 }
225 mcllivelocks_diff = mcllivelocks_cur - mcllivelocks;
226 mcllivelocks = mcllivelocks_cur;
227
228 num_disp = 0;
229 if (getifaddrs(&ifap)) {
230 error("getifaddrs: %s", strerror(errno));
231 return (1);
232 }
233
234 nif = 1;
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 }
242
243 if (num_ifs < nif) {
244 ifi = reallocarray(interfaces, nif, sizeof(*interfaces));
245 if (ifi == NULL) {
246 error("reallocarray: %d interfaces", nif);
247 goto exit;
248 }
249
250 interfaces = ifi;
251 while (num_ifs < nif)
252 memset(&interfaces[num_ifs++], 0, sizeof(*interfaces));
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));
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 }
300
301 ifi++;
302 }
303
304 /* Fill in the "System" entry from pools */
305
306 mib[0] = CTL_KERN;
307 mib[1] = KERN_POOL;
308 mib[2] = KERN_POOL_POOL;
309 mib[3] = mbpool_index;
310 size = sizeof(mbpool);
311
312 if (sysctl(mib, 4, &mbpool, &size, NULL, 0) == -1) {
313 error("sysctl(KERN_POOL_POOL, %d)", mib[3]);
314 goto exit;
315 }
316
317 for (i = 0; i < mclpool_count; i++) {
318 ifr = &interfaces[0].data.ifri_entries[i];
319
320 mib[3] = mclpools_index[i];
321 size = sizeof(pool);
322
323 if (sysctl(mib, 4, &pool, &size, NULL, 0) == -1) {
324 error("sysctl(KERN_POOL_POOL, %d)", mib[3]);
325 continue;
326 }
327
328 ifr->ifr_info.rxr_alive = pool.pr_nget - pool.pr_nput;
329 ifr->ifr_info.rxr_hwm = pool.pr_hiwat;
330 }
331
332 num_disp = 1;
333 ret = 0;
334
335 for (i = 0; i < num_ifs; i++) {
336 struct if_info *ifi = &interfaces[i];
337 int pnd = num_disp;
338 for (p = 0; p < ifi->data.ifri_total; p++) {
339 ifr = &ifi->data.ifri_entries[p];
340 if (ifr->ifr_info.rxr_alive == 0)
341 continue;
342 num_disp++;
343 }
344 if (i && pnd == num_disp)
345 num_disp++;
346 }
347
348 exit:
349 if (ifap)
350 freeifaddrs(ifap);
351 return (ret);
352 }
353
354 void
print_mb(void)355 print_mb(void)
356 {
357 int i, p, n, count = 0;
358
359 showmbuf(interfaces, -1, 1);
360
361 for (n = i = 0; i < num_ifs; i++) {
362 struct if_info *ifi = &interfaces[i];
363 int pcnt = count;
364 int showif = i;
365
366 if (maxprint > 0 && count >= maxprint)
367 return;
368
369 for (p = 0; p < ifi->data.ifri_total; p++) {
370 struct if_rxring_info *ifr = &ifi->data.ifri_entries[p];
371 if (ifr->ifr_info.rxr_hwm == 0)
372 continue;
373 if (n++ >= dispstart) {
374 showmbuf(ifi, p, showif);
375 showif = 0;
376 count++;
377 }
378 }
379
380 if (i && pcnt == count) {
381 /* only print the first line */
382 if (n++ >= dispstart) {
383 showmbuf(ifi, -1, 1);
384 count++;
385 }
386 }
387 }
388 }
389
390
391 static void
showmbuf(struct if_info * ifi,int p,int showif)392 showmbuf(struct if_info *ifi, int p, int showif)
393 {
394 if (showif)
395 print_fld_str(FLD_MB_IFACE, ifi->name);
396
397 if (p == -1 && ifi == interfaces) {
398 print_fld_str(FLD_MB_RING, "mbufs");
399 print_fld_uint(FLD_MB_LLOCKS, mcllivelocks_diff);
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 < ifi->data.ifri_total) {
406 struct if_rxring_info *ifr = &ifi->data.ifri_entries[p];
407 struct if_rxring *rxr= &ifr->ifr_info;
408 print_fld_str(FLD_MB_RING, ifr->ifr_name);
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);
417 }
418
419 end_line();
420 }
421