xref: /openbsd/usr.bin/systat/mbufs.c (revision 898184e3)
1 /*	$OpenBSD: mbufs.c,v 1.32 2011/03/02 06:48:17 jasper 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 */
35 struct mclpool_info {
36 	char title[16];
37 	int pool_offset;
38 	int size;
39 } mclpools[MCLPOOLS];
40 
41 int mclpool_count = 0;
42 int mbpool_index = -1;
43 struct pool mbpool;
44 u_int mcllivelocks, mcllivelocks_cur, mcllivelocks_diff;
45 
46 /* interfaces */
47 static int num_ifs;
48 struct if_info {
49 	char name[16];
50 	struct if_data data;
51 } *interfaces = NULL;
52 
53 void print_mb(void);
54 int read_mb(void);
55 int select_mb(void);
56 static void showmbuf(struct if_info *, int, int);
57 
58 
59 /* Define fields */
60 field_def fields_mbuf[] = {
61 	{"IFACE", 8, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
62 	{"RXDELAY", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
63 	{"TXDELAY", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
64 	{"LIVELOCKS", 5, 10, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
65 	{"SIZE", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
66 	{"ALIVE", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
67 	{"LWM", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
68 	{"HWM", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
69 	{"CWM", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
70 };
71 
72 
73 #define FLD_MB_IFACE	FIELD_ADDR(fields_mbuf,0)
74 #define FLD_MB_RXDELAY	FIELD_ADDR(fields_mbuf,1)
75 #define FLD_MB_TXDELAY	FIELD_ADDR(fields_mbuf,2)
76 #define FLD_MB_LLOCKS	FIELD_ADDR(fields_mbuf,3)
77 #define FLD_MB_MSIZE	FIELD_ADDR(fields_mbuf,4)
78 #define FLD_MB_MALIVE	FIELD_ADDR(fields_mbuf,5)
79 #define FLD_MB_MLWM	FIELD_ADDR(fields_mbuf,6)
80 #define FLD_MB_MHWM	FIELD_ADDR(fields_mbuf,7)
81 #define FLD_MB_MCWM	FIELD_ADDR(fields_mbuf,8)
82 
83 
84 /* Define views */
85 field_def *view_mbuf[] = {
86 	FLD_MB_IFACE,
87 #if NOTYET
88 	FLD_MB_RXDELAY, FLD_MB_TXDELAY,
89 #endif
90 	FLD_MB_LLOCKS, FLD_MB_MSIZE, FLD_MB_MALIVE, FLD_MB_MLWM, FLD_MB_MHWM,
91 	FLD_MB_MCWM, NULL
92 };
93 
94 /* Define view managers */
95 
96 struct view_manager mbuf_mgr = {
97 	"Mbufs", select_mb, read_mb, NULL, print_header,
98 	print_mb, keyboard_callback, NULL, NULL
99 };
100 
101 field_view views_mb[] = {
102 	{view_mbuf, "mbufs", '4', &mbuf_mgr},
103 	{NULL, NULL, 0, NULL}
104 };
105 
106 
107 int
108 initmembufs(void)
109 {
110 	field_view *v;
111 	int i, mib[4], npools;
112 	struct pool pool;
113 	char pname[32];
114 	size_t size;
115 
116 	/* go through all pools to identify mbuf and cluster pools */
117 	bzero(mclpools, sizeof(mclpools));
118 
119 	mib[0] = CTL_KERN;
120 	mib[1] = KERN_POOL;
121 	mib[2] = KERN_POOL_NPOOLS;
122 	size = sizeof(npools);
123 
124 	if (sysctl(mib, 3, &npools, &size, NULL, 0) < 0) {
125 		err(1, "sysctl(KERN_POOL_NPOOLS)");
126 		/* NOTREACHED */
127 	}
128 
129 	for (i = 1; i <= npools; i++) {
130 		mib[0] = CTL_KERN;
131 		mib[1] = KERN_POOL;
132 		mib[2] = KERN_POOL_NAME;
133 		mib[3] = i;
134 		size = sizeof(pname);
135 		if (sysctl(mib, 4, &pname, &size, NULL, 0) < 0) {
136 			continue;
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");
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 
183 int
184 select_mb(void)
185 {
186 	num_disp = 0;
187 	return (0);
188 }
189 
190 int
191 read_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 	mib[0] = CTL_KERN;
201 	mib[1] = KERN_NETLIVELOCKS;
202 	size = sizeof(mcllivelocks_cur);
203 	if (sysctl(mib, 2, &mcllivelocks_cur, &size, NULL, 0) < 0 &&
204 	    errno != EOPNOTSUPP) {
205 		error("sysctl(KERN_NETLIVELOCKS)");
206 		goto exit;
207 	}
208 	mcllivelocks_diff = mcllivelocks_cur - mcllivelocks;
209 	mcllivelocks = mcllivelocks_cur;
210 
211 	num_disp = 0;
212 	if (getifaddrs(&ifap)) {
213 		error("getifaddrs: %s", strerror(errno));
214 		return (1);
215 	}
216 
217 	nif = 1;
218 	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next)
219 		if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_LINK)
220 			nif++;
221 
222 	if (interfaces == NULL || num_ifs < nif) {
223 		size_t len = sizeof(*ifi) * nif;
224 		if (nif > SIZE_MAX / sizeof(*ifi)) {
225 			error("overflow allocting %u interfaces", nif);
226 			goto exit;
227 		}
228 
229 		ifi = realloc(interfaces, len);
230 		if (ifi == NULL) {
231 			error("realloc: out of memory allocating %lld bytes",
232 			      (long long) len);
233 			goto exit;
234 		}
235 
236 		interfaces = ifi;
237 		num_ifs = nif;
238 	}
239 
240 	/* Fill in the "real" interfaces */
241 	ifi = interfaces + 1;
242 
243 	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
244 		if (ifa->ifa_addr == NULL ||
245 		    ifa->ifa_addr->sa_family != AF_LINK)
246 			continue;
247 
248 		strlcpy(ifi->name, ifa->ifa_name, sizeof(ifi->name));
249 
250 		if (ifa->ifa_data)
251 			memcpy(&ifi->data, ifa->ifa_data, sizeof(ifi->data));
252 		else
253 			bzero(&ifi->data, sizeof(ifi->data));
254 		ifi++;
255 	}
256 
257 	/* Fill in the "System" entry from pools */
258 	bzero(interfaces, sizeof(interfaces[0]));
259 	strlcpy(interfaces[0].name, "System", sizeof(interfaces[0].name));
260 
261 	mib[0] = CTL_KERN;
262 	mib[1] = KERN_POOL;
263 	mib[2] = KERN_POOL_POOL;
264 	mib[3] = mbpool_index;
265 	size = sizeof(struct pool);
266 
267 	if (sysctl(mib, 4, &mbpool, &size, NULL, 0) < 0) {
268 		error("sysctl(KERN_POOL_POOL, %d)", mib[3]);
269 		goto exit;
270 	}
271 
272 	for (i = 0; i < mclpool_count; i++) {
273 		struct mclpool *mp = &interfaces[0].data.ifi_mclpool[i];
274 
275 		mib[3] = mclpools[i].pool_offset;
276 		size = sizeof(struct pool);
277 
278 		if (sysctl(mib, 4, &pool, &size, NULL, 0) < 0) {
279 			error("sysctl(KERN_POOL_POOL, %d)", mib[3]);
280 			continue;
281 		}
282 
283 		mp->mcl_alive = pool.pr_nget - pool.pr_nput;
284 		mp->mcl_hwm = pool.pr_hiwat;
285 	}
286 
287 	num_disp = 1;
288 	ret = 0;
289 
290 	for (i = 0; i < num_ifs; i++) {
291 		struct if_info *ifi = &interfaces[i];
292 		int pnd = num_disp;
293 		for (p = 0; p < mclpool_count; p++) {
294 			struct mclpool *mp = &ifi->data.ifi_mclpool[p];
295 			if (mp->mcl_alive == 0)
296 				continue;
297 			num_disp++;
298 		}
299 		if (i && pnd == num_disp)
300 			num_disp++;
301 	}
302 
303  exit:
304 	freeifaddrs(ifap);
305 	return (ret);
306 }
307 
308 void
309 print_mb(void)
310 {
311 	int i, p, n, count = 0;
312 
313 	showmbuf(interfaces, -1, 1);
314 
315 	for (n = i = 0; i < num_ifs; i++) {
316 		struct if_info *ifi = &interfaces[i];
317 		int pcnt = count;
318 		int showif = i;
319 
320 		if (maxprint > 0 && count >= maxprint)
321 			return;
322 
323 		for (p = 0; p < mclpool_count; p++) {
324 			struct mclpool *mp = &ifi->data.ifi_mclpool[p];
325 			if (mp->mcl_alive == 0)
326 				continue;
327 			if (n++ >= dispstart) {
328 				showmbuf(ifi, p, showif);
329 				showif = 0;
330 				count++;
331 			}
332 		}
333 
334 		if (i && pcnt == count) {
335 			/* only print the first line */
336 			if (n++ >= dispstart) {
337 				showmbuf(ifi, -1, 1);
338 				count++;
339 			}
340 		}
341 
342 
343 	}
344 }
345 
346 
347 static void
348 showmbuf(struct if_info *ifi, int p, int showif)
349 {
350 	if (showif)
351 		print_fld_str(FLD_MB_IFACE, ifi->name);
352 
353 	if (p == -1 && ifi == interfaces) {
354 		print_fld_uint(FLD_MB_LLOCKS, mcllivelocks_diff);
355 		print_fld_size(FLD_MB_MSIZE, mbpool.pr_size);
356 		print_fld_size(FLD_MB_MALIVE, mbpool.pr_nget - mbpool.pr_nput);
357 		print_fld_size(FLD_MB_MHWM, mbpool.pr_hiwat);
358 	}
359 
360 #if NOTYET
361 	print_fld_uint(FLD_MB_RXDELAY, ifi->data.ifi_rxdelay);
362 	print_fld_uint(FLD_MB_TXDELAY, ifi->data.ifi_txdelay);
363 #endif
364 
365 	if (p >= 0 && p < mclpool_count) {
366 		struct mclpool *mp = &ifi->data.ifi_mclpool[p];
367 
368 		print_fld_str(FLD_MB_MSIZE, mclpools[p].title);
369 		print_fld_uint(FLD_MB_MALIVE, mp->mcl_alive);
370 		if (mp->mcl_lwm)
371 			print_fld_size(FLD_MB_MLWM, mp->mcl_lwm);
372 		if (mp->mcl_hwm)
373 			print_fld_size(FLD_MB_MHWM, mp->mcl_hwm);
374 		if (mp->mcl_cwm)
375 			print_fld_size(FLD_MB_MCWM, mp->mcl_cwm);
376 	}
377 
378 	end_line();
379 }
380