xref: /openbsd-src/usr.bin/systat/mbufs.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
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 }
418