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