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