mbufs.c revision 1.29
1/*	$OpenBSD: mbufs.c,v 1.29 2010/09/23 10:49:55 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#include <sys/param.h>
18#include <sys/types.h>
19#include <sys/socket.h>
20#include <sys/sysctl.h>
21#include <sys/mbuf.h>
22#include <sys/pool.h>
23#include <net/if.h>
24
25#include <err.h>
26#include <errno.h>
27#include <ifaddrs.h>
28#include <stdlib.h>
29#include <string.h>
30
31#include "systat.h"
32
33
34/* pool info for mcl* pools */
35struct mclpool_info {
36	char title[16];
37	int pool_offset;
38	int size;
39} mclpools[MCLPOOLS];
40
41int mclpool_count = 0;
42int mbpool_index = -1;
43struct pool mbpool;
44
45/* interfaces */
46static int num_ifs;
47struct if_info {
48	char name[16];
49	struct if_data data;
50} *interfaces = NULL;
51
52void print_mb(void);
53int read_mb(void);
54int select_mb(void);
55static void showmbuf(struct if_info *, int, int);
56
57
58/* Define fields */
59field_def fields_mbuf[] = {
60	{"IFACE", 8, 16, 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 FIELD_ADDR(x) (&fields_mbuf[x])
73
74#define FLD_MB_IFACE	FIELD_ADDR(0)
75#define FLD_MB_RXDELAY	FIELD_ADDR(1)
76#define FLD_MB_TXDELAY	FIELD_ADDR(2)
77#define FLD_MB_LLOCKS	FIELD_ADDR(3)
78#define FLD_MB_MSIZE	FIELD_ADDR(4)
79#define FLD_MB_MALIVE	FIELD_ADDR(5)
80#define FLD_MB_MLWM	FIELD_ADDR(6)
81#define FLD_MB_MHWM	FIELD_ADDR(7)
82#define FLD_MB_MCWM	FIELD_ADDR(8)
83
84
85/* Define views */
86field_def *view_mbuf[] = {
87	FLD_MB_IFACE,
88#if NOTYET
89	FLD_MB_RXDELAY, FLD_MB_TXDELAY,
90#endif
91	FLD_MB_LLOCKS, FLD_MB_MSIZE, FLD_MB_MALIVE, FLD_MB_MLWM, FLD_MB_MHWM,
92	FLD_MB_MCWM, NULL
93};
94
95/* Define view managers */
96
97struct view_manager mbuf_mgr = {
98	"Mbufs", select_mb, read_mb, NULL, print_header,
99	print_mb, keyboard_callback, NULL, NULL
100};
101
102field_view views_mb[] = {
103	{view_mbuf, "mbufs", '4', &mbuf_mgr},
104	{NULL, NULL, 0, NULL}
105};
106
107
108int
109initmembufs(void)
110{
111	field_view *v;
112	int i, mib[4], npools;
113	struct pool pool;
114	char pname[32];
115	size_t size;
116
117	/* go through all pools to identify mbuf and cluster pools */
118	bzero(mclpools, sizeof(mclpools));
119
120	mib[0] = CTL_KERN;
121	mib[1] = KERN_POOL;
122	mib[2] = KERN_POOL_NPOOLS;
123	size = sizeof(npools);
124
125	if (sysctl(mib, 3, &npools, &size, NULL, 0) < 0) {
126		err(1, "sysctl(KERN_POOL_NPOOLS)");
127		/* NOTREACHED */
128	}
129
130	for (i = 1; i <= npools; i++) {
131		mib[0] = CTL_KERN;
132		mib[1] = KERN_POOL;
133		mib[2] = KERN_POOL_NAME;
134		mib[3] = i;
135		size = sizeof(pname);
136		if (sysctl(mib, 4, &pname, &size, NULL, 0) < 0) {
137			continue;
138		}
139
140		if (strcmp(pname, "mbpl") == 0) {
141			mbpool_index = i;
142			continue;
143		}
144
145		if (strncmp(pname, "mcl", 3) != 0)
146			continue;
147
148		if (mclpool_count == MCLPOOLS) {
149			warnx("mbufs: Too many mcl* pools");
150			break;
151		}
152
153		mib[2] = KERN_POOL_POOL;
154		size = sizeof(struct pool);
155
156		if (sysctl(mib, 4, &pool, &size, NULL, 0) < 0) {
157			err(1, "sysctl(KERN_POOL_POOL, %d)", i);
158			/* NOTREACHED */
159		}
160
161		mclpools[mclpool_count].size = pool.pr_size;
162		mclpools[mclpool_count].pool_offset = i;
163		snprintf(mclpools[mclpool_count].title,
164		    sizeof(mclpools[0].title), "%dk",
165		    pool.pr_size / 1024);
166
167		mclpool_count++;
168	}
169
170	if (mclpool_count != MCLPOOLS)
171		warnx("mbufs: Unable to read all %d mcl* pools", MCLPOOLS);
172
173	/* add view to the engine */
174	for (v = views_mb; v->name != NULL; v++)
175		add_view(v);
176
177
178	/* finally read it once */
179	read_mb();
180
181	return(1);
182}
183
184int
185select_mb(void)
186{
187	num_disp = 0;
188	return (0);
189}
190
191int
192read_mb(void)
193{
194	struct pool pool;
195	struct ifaddrs *ifap, *ifa;
196	struct if_info *ifi;
197	int mib[4];
198	int i, p, nif, ret = 1;
199	size_t size;
200
201	num_disp = 0;
202	if (getifaddrs(&ifap)) {
203		error("getifaddrs: %s", strerror(errno));
204		return (1);
205	}
206
207	nif = 1;
208	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next)
209		if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_LINK)
210			nif++;
211
212	if (interfaces == NULL || num_ifs < nif) {
213		size_t len = sizeof(*ifi) * nif;
214		if (nif > SIZE_MAX / sizeof(*ifi)) {
215			error("overflow allocting %u interfaces", nif);
216			goto exit;
217		}
218
219		ifi = realloc(interfaces, len);
220		if (ifi == NULL) {
221			error("realloc: out of memory allocating %lld bytes",
222			      (long long) len);
223			goto exit;
224		}
225
226		interfaces = ifi;
227		num_ifs = nif;
228	}
229
230	/* Fill in the "real" interfaces */
231	ifi = interfaces + 1;
232
233	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
234		if (ifa->ifa_addr == NULL ||
235		    ifa->ifa_addr->sa_family != AF_LINK)
236			continue;
237
238		strlcpy(ifi->name, ifa->ifa_name, sizeof(ifi->name));
239
240		if (ifa->ifa_data)
241			memcpy(&ifi->data, ifa->ifa_data, sizeof(ifi->data));
242		else
243			bzero(&ifi->data, sizeof(ifi->data));
244		ifi++;
245	}
246
247	/* Fill in the "System" entry from pools */
248	bzero(interfaces, sizeof(interfaces[0]));
249	strlcpy(interfaces[0].name, "System", sizeof(interfaces[0].name));
250
251	mib[0] = CTL_KERN;
252	mib[1] = KERN_POOL;
253	mib[2] = KERN_POOL_POOL;
254	mib[3] = mbpool_index;
255	size = sizeof(struct pool);
256
257	if (sysctl(mib, 4, &mbpool, &size, NULL, 0) < 0) {
258		error("sysctl(KERN_POOL_POOL, %d)", mib[3]);
259		goto exit;
260	}
261
262	for (i = 0; i < mclpool_count; i++) {
263		struct mclpool *mp = &interfaces[0].data.ifi_mclpool[i];
264
265		mib[3] = mclpools[i].pool_offset;
266		size = sizeof(struct pool);
267
268		if (sysctl(mib, 4, &pool, &size, NULL, 0) < 0) {
269			error("sysctl(KERN_POOL_POOL, %d)", mib[3]);
270			continue;
271		}
272
273		mp->mcl_alive = pool.pr_nget - pool.pr_nput;
274		mp->mcl_hwm = pool.pr_hiwat;
275	}
276
277	num_disp = 1;
278	ret = 0;
279
280	for (i = 0; i < num_ifs; i++) {
281		struct if_info *ifi = &interfaces[i];
282		int pnd = num_disp;
283		for (p = 0; p < mclpool_count; p++) {
284			struct mclpool *mp = &ifi->data.ifi_mclpool[p];
285			if (mp->mcl_alive == 0)
286				continue;
287			num_disp++;
288		}
289		if (i && pnd == num_disp)
290			num_disp++;
291	}
292
293 exit:
294	freeifaddrs(ifap);
295	return (ret);
296}
297
298void
299print_mb(void)
300{
301	int i, p, n, count = 0;
302
303	showmbuf(interfaces, -1, 1);
304
305	for (n = i = 0; i < num_ifs; i++) {
306		struct if_info *ifi = &interfaces[i];
307		int pcnt = count;
308		int showif = i;
309
310		if (maxprint > 0 && count >= maxprint)
311			return;
312
313		for (p = 0; p < mclpool_count; p++) {
314			struct mclpool *mp = &ifi->data.ifi_mclpool[p];
315			if (mp->mcl_alive == 0)
316				continue;
317			if (n++ >= dispstart) {
318				showmbuf(ifi, p, showif);
319				showif = 0;
320				count++;
321			}
322		}
323
324		if (i && pcnt == count) {
325			/* only print the first line */
326			if (n++ >= dispstart) {
327				showmbuf(ifi, -1, 1);
328				count++;
329			}
330		}
331
332
333	}
334}
335
336
337static void
338showmbuf(struct if_info *ifi, int p, int showif)
339{
340	if (showif)
341		print_fld_str(FLD_MB_IFACE, ifi->name);
342
343	if (p == -1 && ifi == interfaces) {
344		print_fld_size(FLD_MB_MSIZE, mbpool.pr_size);
345		print_fld_size(FLD_MB_MALIVE, mbpool.pr_nget - mbpool.pr_nput);
346		print_fld_size(FLD_MB_MHWM, mbpool.pr_hiwat);
347	}
348
349#if NOTYET
350	print_fld_uint(FLD_MB_RXDELAY, ifi->data.ifi_rxdelay);
351	print_fld_uint(FLD_MB_TXDELAY, ifi->data.ifi_txdelay);
352	if (ifi->data.ifi_livelocks)
353		print_fld_size(FLD_MB_LLOCKS, ifi->data.ifi_livelocks);
354#endif
355
356	if (p >= 0 && p < mclpool_count) {
357		struct mclpool *mp = &ifi->data.ifi_mclpool[p];
358
359		print_fld_str(FLD_MB_MSIZE, mclpools[p].title);
360		print_fld_uint(FLD_MB_MALIVE, mp->mcl_alive);
361		if (mp->mcl_lwm)
362			print_fld_size(FLD_MB_MLWM, mp->mcl_lwm);
363		if (mp->mcl_hwm)
364			print_fld_size(FLD_MB_MHWM, mp->mcl_hwm);
365		if (mp->mcl_cwm)
366			print_fld_size(FLD_MB_MCWM, mp->mcl_cwm);
367	}
368
369	end_line();
370}
371