xref: /freebsd/usr.bin/netstat/mbuf.c (revision 3642298923e528d795e3a30ec165d2b469e28b40)
1 /*
2  * Copyright (c) 1983, 1988, 1993
3  *	The Regents of the University of California.
4  * Copyright (c) 2005 Robert N. M. Watson
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #if 0
37 #ifndef lint
38 static char sccsid[] = "@(#)mbuf.c	8.1 (Berkeley) 6/6/93";
39 #endif /* not lint */
40 #endif
41 
42 #include <sys/cdefs.h>
43 __FBSDID("$FreeBSD$");
44 
45 #include <sys/param.h>
46 #include <sys/mbuf.h>
47 #include <sys/protosw.h>
48 #include <sys/socket.h>
49 #include <sys/sysctl.h>
50 
51 #include <err.h>
52 #include <memstat.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include "netstat.h"
57 
58 #define	YES	1
59 typedef int bool;
60 
61 static struct mbtypenames {
62 	short	mt_type;
63 	const char *mt_name;
64 } mbtypenames[] = {
65 	{ MT_DATA,	"data" },
66 	{ MT_OOBDATA,	"oob data" },
67 	{ MT_CONTROL,	"ancillary data" },
68 	{ MT_HEADER,	"packet headers" },
69 #ifdef MT_SOCKET
70 	{ MT_SOCKET,	"socket structures" },			/* XXX */
71 #endif
72 #ifdef MT_PCB
73 	{ MT_PCB,	"protocol control blocks" },		/* XXX */
74 #endif
75 #ifdef MT_RTABLE
76 	{ MT_RTABLE,	"routing table entries" },		/* XXX */
77 #endif
78 #ifdef MT_HTABLE
79 	{ MT_HTABLE,	"IMP host table entries" },		/* XXX */
80 #endif
81 #ifdef MT_ATABLE
82 	{ MT_ATABLE,	"address resolution tables" },
83 #endif
84 	{ MT_FTABLE,	"fragment reassembly queue headers" },	/* XXX */
85 	{ MT_SONAME,	"socket names and addresses" },
86 #ifdef MT_SOOPTS
87 	{ MT_SOOPTS,	"socket options" },
88 #endif
89 #ifdef MT_RIGHTS
90 	{ MT_RIGHTS,	"access rights" },
91 #endif
92 #ifdef MT_IFADDR
93 	{ MT_IFADDR,	"interface addresses" },		/* XXX */
94 #endif
95 	{ 0, 0 }
96 };
97 
98 /*
99  * Print mbuf statistics extracted from kmem.
100  */
101 void
102 mbpr_kmem(u_long mbaddr, u_long nmbcaddr, u_long nmbufaddr, u_long mbhiaddr,
103     u_long clhiaddr, u_long mbloaddr, u_long clloaddr, u_long pgsaddr,
104     u_long mbpaddr)
105 {
106 	int i, nmbclusters;
107 	short nmbtypes;
108 	size_t mlen;
109 	long *mbtypes = NULL;
110 	struct mbstat *mbstat = NULL;
111 	struct mbtypenames *mp;
112 	bool *seen = NULL;
113 
114 	mlen = sizeof *mbstat;
115 	if ((mbstat = malloc(mlen)) == NULL) {
116 		warn("malloc: cannot allocate memory for mbstat");
117 		goto err;
118 	}
119 
120 	if (kread(mbaddr, (char *)mbstat, sizeof mbstat))
121 		goto err;
122 	if (kread(nmbcaddr, (char *)&nmbclusters, sizeof(int)))
123 		goto err;
124 
125 	if (mbstat->m_mbufs < 0) mbstat->m_mbufs = 0;		/* XXX */
126 	if (mbstat->m_mclusts < 0) mbstat->m_mclusts = 0;	/* XXX */
127 
128 	nmbtypes = mbstat->m_numtypes;
129 	if ((seen = calloc(nmbtypes, sizeof(*seen))) == NULL) {
130 		warn("calloc: cannot allocate memory for mbtypes seen flag");
131 		goto err;
132 	}
133 	if ((mbtypes = calloc(nmbtypes, sizeof(long *))) == NULL) {
134 		warn("calloc: cannot allocate memory for mbtypes");
135 		goto err;
136 	}
137 
138 #undef MSIZE
139 #define MSIZE		(mbstat->m_msize)
140 #undef MCLBYTES
141 #define	MCLBYTES	(mbstat->m_mclbytes)
142 
143 	printf("%lu mbufs in use\n", mbstat->m_mbufs);
144 
145 	for (mp = mbtypenames; mp->mt_name; mp++) {
146 		if (mbtypes[mp->mt_type]) {
147 			seen[mp->mt_type] = YES;
148 			printf("\t  %lu mbufs allocated to %s\n",
149 				mbtypes[mp->mt_type], mp->mt_name);
150 		}
151 	}
152 	for (i = 1; i < nmbtypes; i++) {
153 		if (!seen[i] && mbtypes[i])
154 			printf("\t  %lu mbufs allocated to <mbuf type: %d>\n",
155 			    mbtypes[i], i);
156 	}
157 
158 	printf("%lu/%d mbuf clusters in use (current/max)\n",
159 	    mbstat->m_mclusts, nmbclusters);
160 
161 	printf("%lu KBytes allocated to network\n", (mbstat->m_mbufs * MSIZE +
162 	    mbstat->m_mclusts * MCLBYTES) / 1024);
163 	printf("%lu requests for sfbufs denied\n", mbstat->sf_allocfail);
164 	printf("%lu requests for sfbufs delayed\n", mbstat->sf_allocwait);
165 	printf("%lu requests for I/O initiated by sendfile\n",
166 	    mbstat->sf_iocnt);
167 	printf("%lu calls to protocol drain routines\n", mbstat->m_drain);
168 
169 err:
170 	if (mbtypes != NULL)
171 		free(mbtypes);
172 	if (seen != NULL)
173 		free(seen);
174 	if (mbstat != NULL)
175 		free(mbstat);
176 }
177 
178 /*
179  * If running on a live kernel, directly query the zone allocator for stats
180  * from the four mbuf-related zones/types.
181  */
182 static void
183 mbpr_sysctl(void)
184 {
185 	struct memory_type_list *mtlp;
186 	struct memory_type *mtp;
187 	u_int64_t mbuf_count, mbuf_bytes, mbuf_free, mbuf_failures, mbuf_size;
188 	u_int64_t cluster_count, cluster_bytes, cluster_limit, cluster_free;
189 	u_int64_t cluster_failures, cluster_size;
190 	u_int64_t packet_count, packet_bytes, packet_free, packet_failures;
191 	u_int64_t tag_count, tag_bytes;
192 	u_int64_t bytes_inuse, bytes_incache, bytes_total;
193 	int nsfbufs, nsfbufspeak, nsfbufsused;
194 	struct mbstat mbstat;
195 	size_t mlen;
196 
197 	mtlp = memstat_mtl_alloc();
198 	if (mtlp == NULL) {
199 		warn("memstat_mtl_alloc");
200 		return;
201 	}
202 
203 	/*
204 	 * Use memstat_sysctl_all() because some mbuf-related memory is in
205 	 * uma(9), and some malloc(9).
206 	 */
207 	if (memstat_sysctl_all(mtlp, 0) < 0) {
208 		warnx("memstat_sysctl_all: %s",
209 		    memstat_strerror(memstat_mtl_geterror(mtlp)));
210 		goto out;
211 	}
212 
213 	mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_MEM_NAME);
214 	if (mtp == NULL) {
215 		warnx("memstat_mtl_find: zone %s not found", MBUF_MEM_NAME);
216 		goto out;
217 	}
218 	mbuf_count = memstat_get_count(mtp);
219 	mbuf_bytes = memstat_get_bytes(mtp);
220 	mbuf_free = memstat_get_free(mtp);
221 	mbuf_failures = memstat_get_failures(mtp);
222 	mbuf_size = memstat_get_size(mtp);
223 
224 	mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_PACKET_MEM_NAME);
225 	if (mtp == NULL) {
226 		warnx("memstat_mtl_find: zone %s not found",
227 		    MBUF_PACKET_MEM_NAME);
228 		goto out;
229 	}
230 	packet_count = memstat_get_count(mtp);
231 	packet_bytes = memstat_get_bytes(mtp);
232 	packet_free = memstat_get_free(mtp);
233 	packet_failures = memstat_get_failures(mtp);
234 
235 	mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_CLUSTER_MEM_NAME);
236 	if (mtp == NULL) {
237 		warnx("memstat_mtl_find: zone %s not found",
238 		    MBUF_CLUSTER_MEM_NAME);
239 		goto out;
240 	}
241 	cluster_count = memstat_get_count(mtp);
242 	cluster_bytes = memstat_get_bytes(mtp);
243 	cluster_limit = memstat_get_countlimit(mtp);
244 	cluster_free = memstat_get_free(mtp);
245 	cluster_failures = memstat_get_failures(mtp);
246 	cluster_size = memstat_get_size(mtp);
247 
248 	mtp = memstat_mtl_find(mtlp, ALLOCATOR_MALLOC, MBUF_TAG_MEM_NAME);
249 	if (mtp == NULL) {
250 		warnx("memstat_mtl_find: malloc type %s not found",
251 		    MBUF_TAG_MEM_NAME);
252 		goto out;
253 	}
254 	tag_count = memstat_get_count(mtp);
255 	tag_bytes = memstat_get_bytes(mtp);
256 
257 	printf("%llu/%llu/%llu mbufs in use (current/cache/total)\n",
258 	    mbuf_count + packet_count, mbuf_free + packet_free,
259 	    mbuf_count + packet_count + mbuf_free + packet_free);
260 
261 	printf("%llu/%llu/%llu/%llu mbuf clusters in use "
262 	    "(current/cache/total/max)\n",
263 	    cluster_count - packet_free, cluster_free + packet_free,
264 	    cluster_count + cluster_free, cluster_limit);
265 
266 #if 0
267 	printf("%llu mbuf tags in use\n", tag_count);
268 #endif
269 
270 	mlen = sizeof(nsfbufs);
271 	if (!sysctlbyname("kern.ipc.nsfbufs", &nsfbufs, &mlen, NULL, 0) &&
272 	    !sysctlbyname("kern.ipc.nsfbufsused", &nsfbufsused, &mlen, NULL,
273 	    0) &&
274 	    !sysctlbyname("kern.ipc.nsfbufspeak", &nsfbufspeak, &mlen, NULL,
275 	    0)) {
276 		printf("%d/%d/%d sfbufs in use (current/peak/max)\n",
277 		    nsfbufsused, nsfbufspeak, nsfbufs);
278 	}
279 
280 	/*-
281 	 * Calculate in-use bytes as:
282 	 * - straight mbuf memory
283 	 * - mbuf memory in packets
284 	 * - the clusters attached to packets
285 	 * - and the rest of the non-packet-attached clusters.
286 	 * - m_tag memory
287 	 * This avoids counting the clusters attached to packets in the cache.
288 	 * This currently excludes sf_buf space.
289 	 */
290 	bytes_inuse =
291 	    mbuf_bytes +			/* straight mbuf memory */
292 	    packet_bytes +			/* mbufs in packets */
293 	    (packet_count * cluster_size) +	/* clusters in packets */
294 	    /* other clusters */
295 	    ((cluster_count - packet_count - packet_free) * cluster_size) +
296 	    tag_bytes;
297 
298 	/*
299 	 * Calculate in-cache bytes as:
300 	 * - cached straught mbufs
301 	 * - cached packet mbufs
302 	 * - cached packet clusters
303 	 * - cached straight clusters
304 	 * This currently excludes sf_buf space.
305 	 */
306 	bytes_incache =
307 	    (mbuf_free * mbuf_size) +		/* straight free mbufs */
308 	    (packet_free * mbuf_size) +		/* mbufs in free packets */
309 	    (packet_free * cluster_size) +	/* clusters in free packets */
310 	    (cluster_free * cluster_size);	/* free clusters */
311 
312 	/*
313 	 * Total is bytes in use + bytes in cache.  This doesn't take into
314 	 * account various other misc data structures, overhead, etc, but
315 	 * gives the user something useful despite that.
316 	 */
317 	bytes_total = bytes_inuse + bytes_incache;
318 
319 	printf("%lluK/%lluK/%lluK bytes allocated to network "
320 	    "(current/cache/total)\n", bytes_inuse / 1024,
321 	    bytes_incache / 1024, bytes_total / 1024);
322 
323 #if 0
324 	printf("%llu/%llu/%llu requests for mbufs denied (mbufs/clusters/"
325 	    "mbuf+clusters)\n", mbuf_failures, cluster_failures,
326 	    packet_failures);
327 #endif
328 
329 	mlen = sizeof(mbstat);
330 	if (!sysctlbyname("kern.ipc.mbstat", &mbstat, &mlen, NULL, 0)) {
331 		printf("%lu requests for sfbufs denied\n",
332 		    mbstat.sf_allocfail);
333 		printf("%lu requests for sfbufs delayed\n",
334 		    mbstat.sf_allocwait);
335 		printf("%lu requests for I/O initiated by sendfile\n",
336 		    mbstat.sf_iocnt);
337 		printf("%lu calls to protocol drain routines\n",
338 		    mbstat.m_drain);
339 	}
340 
341 out:
342 	memstat_mtl_free(mtlp);
343 }
344 
345 /*
346  * Print mbuf statistics.
347  */
348 void
349 mbpr(u_long mbaddr, u_long mbtaddr __unused, u_long nmbcaddr, u_long nmbufaddr,
350     u_long mbhiaddr, u_long clhiaddr, u_long mbloaddr, u_long clloaddr,
351     u_long cpusaddr __unused, u_long pgsaddr, u_long mbpaddr)
352 {
353 
354 	if (mbaddr != 0)
355 		mbpr_kmem(mbaddr, nmbcaddr, nmbufaddr, mbhiaddr, clhiaddr,
356 		    mbloaddr, clloaddr, pgsaddr, mbpaddr);
357 	else
358 		mbpr_sysctl();
359 }
360