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