1 /*-
2 * SPDX-License-Identifier: BSD-4-Clause
3 *
4 * Copyright (c) 1983, 1988, 1993
5 * The Regents of the University of California.
6 * Copyright (c) 2005 Robert N. M. Watson
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38 #if 0
39 #ifndef lint
40 static char sccsid[] = "@(#)mbuf.c 8.1 (Berkeley) 6/6/93";
41 #endif /* not lint */
42 #endif
43
44 #ifdef FSTACK
45 #include <stdint.h>
46 #endif
47
48 #include <sys/cdefs.h>
49 __FBSDID("$FreeBSD$");
50
51 #include <sys/param.h>
52 #include <sys/mbuf.h>
53 #include <sys/protosw.h>
54 #include <sys/sf_buf.h>
55 #include <sys/socket.h>
56 #include <sys/socketvar.h>
57 #include <sys/sysctl.h>
58
59 #include <err.h>
60 #ifndef FSTACK
61 #include <kvm.h>
62 #endif
63 #include <memstat.h>
64 #include <stdint.h>
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <stdbool.h>
68 #include <string.h>
69 #include <libxo/xo.h>
70 #include "netstat.h"
71
72 /*
73 * Print mbuf statistics.
74 */
75 void
mbpr(void * kvmd,u_long mbaddr)76 mbpr(void *kvmd, u_long mbaddr)
77 {
78 struct memory_type_list *mtlp;
79 struct memory_type *mtp;
80 uintmax_t mbuf_count, mbuf_bytes, mbuf_free, mbuf_failures, mbuf_size;
81 uintmax_t mbuf_sleeps;
82 uintmax_t cluster_count, cluster_limit, cluster_free;
83 uintmax_t cluster_failures, cluster_size, cluster_sleeps;
84 uintmax_t packet_count, packet_bytes, packet_free, packet_failures;
85 uintmax_t packet_sleeps;
86 uintmax_t tag_bytes;
87 uintmax_t jumbop_count, jumbop_limit, jumbop_free;
88 uintmax_t jumbop_failures, jumbop_sleeps, jumbop_size;
89 uintmax_t jumbo9_count, jumbo9_limit, jumbo9_free;
90 uintmax_t jumbo9_failures, jumbo9_sleeps, jumbo9_size;
91 uintmax_t jumbo16_count, jumbo16_limit, jumbo16_free;
92 uintmax_t jumbo16_failures, jumbo16_sleeps, jumbo16_size;
93 uintmax_t bytes_inuse, bytes_incache, bytes_total;
94 int nsfbufs, nsfbufspeak, nsfbufsused;
95 struct sfstat sfstat;
96 size_t mlen;
97 #ifndef FSTACK
98 int error;
99 #endif
100
101 mtlp = memstat_mtl_alloc();
102 if (mtlp == NULL) {
103 xo_warn("memstat_mtl_alloc");
104 return;
105 }
106
107 /*
108 * Use memstat_*_all() because some mbuf-related memory is in uma(9),
109 * and some malloc(9).
110 */
111 if (live) {
112 if (memstat_sysctl_all(mtlp, 0) < 0) {
113 xo_warnx("memstat_sysctl_all: %s",
114 memstat_strerror(memstat_mtl_geterror(mtlp)));
115 goto out;
116 }
117 } else {
118 #ifndef FSTACK
119 if (memstat_kvm_all(mtlp, kvmd) < 0) {
120 error = memstat_mtl_geterror(mtlp);
121 if (error == MEMSTAT_ERROR_KVM)
122 xo_warnx("memstat_kvm_all: %s",
123 kvm_geterr(kvmd));
124 else
125 xo_warnx("memstat_kvm_all: %s",
126 memstat_strerror(error));
127 goto out;
128 }
129 #endif
130 }
131
132 mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_MEM_NAME);
133 if (mtp == NULL) {
134 xo_warnx("memstat_mtl_find: zone %s not found", MBUF_MEM_NAME);
135 goto out;
136 }
137 mbuf_count = memstat_get_count(mtp);
138 mbuf_bytes = memstat_get_bytes(mtp);
139 mbuf_free = memstat_get_free(mtp);
140 mbuf_failures = memstat_get_failures(mtp);
141 mbuf_sleeps = memstat_get_sleeps(mtp);
142 mbuf_size = memstat_get_size(mtp);
143
144 mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_PACKET_MEM_NAME);
145 if (mtp == NULL) {
146 xo_warnx("memstat_mtl_find: zone %s not found",
147 MBUF_PACKET_MEM_NAME);
148 goto out;
149 }
150 packet_count = memstat_get_count(mtp);
151 packet_bytes = memstat_get_bytes(mtp);
152 packet_free = memstat_get_free(mtp);
153 packet_sleeps = memstat_get_sleeps(mtp);
154 packet_failures = memstat_get_failures(mtp);
155
156 mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_CLUSTER_MEM_NAME);
157 if (mtp == NULL) {
158 xo_warnx("memstat_mtl_find: zone %s not found",
159 MBUF_CLUSTER_MEM_NAME);
160 goto out;
161 }
162 cluster_count = memstat_get_count(mtp);
163 cluster_limit = memstat_get_countlimit(mtp);
164 cluster_free = memstat_get_free(mtp);
165 cluster_failures = memstat_get_failures(mtp);
166 cluster_sleeps = memstat_get_sleeps(mtp);
167 cluster_size = memstat_get_size(mtp);
168
169 mtp = memstat_mtl_find(mtlp, ALLOCATOR_MALLOC, MBUF_TAG_MEM_NAME);
170 if (mtp == NULL) {
171 xo_warnx("memstat_mtl_find: malloc type %s not found",
172 MBUF_TAG_MEM_NAME);
173 goto out;
174 }
175 tag_bytes = memstat_get_bytes(mtp);
176
177 mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_JUMBOP_MEM_NAME);
178 if (mtp == NULL) {
179 xo_warnx("memstat_mtl_find: zone %s not found",
180 MBUF_JUMBOP_MEM_NAME);
181 goto out;
182 }
183 jumbop_count = memstat_get_count(mtp);
184 jumbop_limit = memstat_get_countlimit(mtp);
185 jumbop_free = memstat_get_free(mtp);
186 jumbop_failures = memstat_get_failures(mtp);
187 jumbop_sleeps = memstat_get_sleeps(mtp);
188 jumbop_size = memstat_get_size(mtp);
189
190 mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_JUMBO9_MEM_NAME);
191 if (mtp == NULL) {
192 xo_warnx("memstat_mtl_find: zone %s not found",
193 MBUF_JUMBO9_MEM_NAME);
194 goto out;
195 }
196 jumbo9_count = memstat_get_count(mtp);
197 jumbo9_limit = memstat_get_countlimit(mtp);
198 jumbo9_free = memstat_get_free(mtp);
199 jumbo9_failures = memstat_get_failures(mtp);
200 jumbo9_sleeps = memstat_get_sleeps(mtp);
201 jumbo9_size = memstat_get_size(mtp);
202
203 mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_JUMBO16_MEM_NAME);
204 if (mtp == NULL) {
205 xo_warnx("memstat_mtl_find: zone %s not found",
206 MBUF_JUMBO16_MEM_NAME);
207 goto out;
208 }
209 jumbo16_count = memstat_get_count(mtp);
210 jumbo16_limit = memstat_get_countlimit(mtp);
211 jumbo16_free = memstat_get_free(mtp);
212 jumbo16_failures = memstat_get_failures(mtp);
213 jumbo16_sleeps = memstat_get_sleeps(mtp);
214 jumbo16_size = memstat_get_size(mtp);
215
216 xo_open_container("mbuf-statistics");
217
218 xo_emit("{:mbuf-current/%ju}/{:mbuf-cache/%ju}/{:mbuf-total/%ju} "
219 "{N:mbufs in use (current\\/cache\\/total)}\n",
220 mbuf_count + packet_count, mbuf_free + packet_free,
221 mbuf_count + packet_count + mbuf_free + packet_free);
222
223 xo_emit("{:cluster-current/%ju}/{:cluster-cache/%ju}/"
224 "{:cluster-total/%ju}/{:cluster-max/%ju} "
225 "{N:mbuf clusters in use (current\\/cache\\/total\\/max)}\n",
226 cluster_count - packet_free, cluster_free + packet_free,
227 cluster_count + cluster_free, cluster_limit);
228
229 xo_emit("{:packet-count/%ju}/{:packet-free/%ju} "
230 "{N:mbuf+clusters out of packet secondary zone in use "
231 "(current\\/cache)}\n",
232 packet_count, packet_free);
233
234 xo_emit("{:jumbo-count/%ju}/{:jumbo-cache/%ju}/{:jumbo-total/%ju}/"
235 "{:jumbo-max/%ju} {:jumbo-page-size/%ju}{U:k} {N:(page size)} "
236 "{N:jumbo clusters in use (current\\/cache\\/total\\/max)}\n",
237 jumbop_count, jumbop_free, jumbop_count + jumbop_free,
238 jumbop_limit, jumbop_size / 1024);
239
240 xo_emit("{:jumbo9-count/%ju}/{:jumbo9-cache/%ju}/"
241 "{:jumbo9-total/%ju}/{:jumbo9-max/%ju} "
242 "{N:9k jumbo clusters in use (current\\/cache\\/total\\/max)}\n",
243 jumbo9_count, jumbo9_free, jumbo9_count + jumbo9_free,
244 jumbo9_limit);
245
246 xo_emit("{:jumbo16-count/%ju}/{:jumbo16-cache/%ju}/"
247 "{:jumbo16-total/%ju}/{:jumbo16-limit/%ju} "
248 "{N:16k jumbo clusters in use (current\\/cache\\/total\\/max)}\n",
249 jumbo16_count, jumbo16_free, jumbo16_count + jumbo16_free,
250 jumbo16_limit);
251
252 #if 0
253 xo_emit("{:tag-count/%ju} {N:mbuf tags in use}\n", tag_count);
254 #endif
255
256 /*-
257 * Calculate in-use bytes as:
258 * - straight mbuf memory
259 * - mbuf memory in packets
260 * - the clusters attached to packets
261 * - and the rest of the non-packet-attached clusters.
262 * - m_tag memory
263 * This avoids counting the clusters attached to packets in the cache.
264 * This currently excludes sf_buf space.
265 */
266 bytes_inuse =
267 mbuf_bytes + /* straight mbuf memory */
268 packet_bytes + /* mbufs in packets */
269 (packet_count * cluster_size) + /* clusters in packets */
270 /* other clusters */
271 ((cluster_count - packet_count - packet_free) * cluster_size) +
272 tag_bytes +
273 (jumbop_count * jumbop_size) + /* jumbo clusters */
274 (jumbo9_count * jumbo9_size) +
275 (jumbo16_count * jumbo16_size);
276
277 /*
278 * Calculate in-cache bytes as:
279 * - cached straught mbufs
280 * - cached packet mbufs
281 * - cached packet clusters
282 * - cached straight clusters
283 * This currently excludes sf_buf space.
284 */
285 bytes_incache =
286 (mbuf_free * mbuf_size) + /* straight free mbufs */
287 (packet_free * mbuf_size) + /* mbufs in free packets */
288 (packet_free * cluster_size) + /* clusters in free packets */
289 (cluster_free * cluster_size) + /* free clusters */
290 (jumbop_free * jumbop_size) + /* jumbo clusters */
291 (jumbo9_free * jumbo9_size) +
292 (jumbo16_free * jumbo16_size);
293
294 /*
295 * Total is bytes in use + bytes in cache. This doesn't take into
296 * account various other misc data structures, overhead, etc, but
297 * gives the user something useful despite that.
298 */
299 bytes_total = bytes_inuse + bytes_incache;
300
301 xo_emit("{:bytes-in-use/%ju}{U:K}/{:bytes-in-cache/%ju}{U:K}/"
302 "{:bytes-total/%ju}{U:K} "
303 "{N:bytes allocated to network (current\\/cache\\/total)}\n",
304 bytes_inuse / 1024, bytes_incache / 1024, bytes_total / 1024);
305
306 xo_emit("{:mbuf-failures/%ju}/{:cluster-failures/%ju}/"
307 "{:packet-failures/%ju} {N:requests for mbufs denied "
308 "(mbufs\\/clusters\\/mbuf+clusters)}\n",
309 mbuf_failures, cluster_failures, packet_failures);
310 xo_emit("{:mbuf-sleeps/%ju}/{:cluster-sleeps/%ju}/{:packet-sleeps/%ju} "
311 "{N:requests for mbufs delayed "
312 "(mbufs\\/clusters\\/mbuf+clusters)}\n",
313 mbuf_sleeps, cluster_sleeps, packet_sleeps);
314
315 xo_emit("{:jumbop-sleeps/%ju}/{:jumbo9-sleeps/%ju}/"
316 "{:jumbo16-sleeps/%ju} {N:/requests for jumbo clusters delayed "
317 "(%juk\\/9k\\/16k)}\n",
318 jumbop_sleeps, jumbo9_sleeps, jumbo16_sleeps, jumbop_size / 1024);
319 xo_emit("{:jumbop-failures/%ju}/{:jumbo9-failures/%ju}/"
320 "{:jumbo16-failures/%ju} {N:/requests for jumbo clusters denied "
321 "(%juk\\/9k\\/16k)}\n",
322 jumbop_failures, jumbo9_failures, jumbo16_failures,
323 jumbop_size / 1024);
324
325 mlen = sizeof(nsfbufs);
326 if (live &&
327 sysctlbyname("kern.ipc.nsfbufs", &nsfbufs, &mlen, NULL, 0) == 0 &&
328 sysctlbyname("kern.ipc.nsfbufsused", &nsfbufsused, &mlen,
329 NULL, 0) == 0 &&
330 sysctlbyname("kern.ipc.nsfbufspeak", &nsfbufspeak, &mlen,
331 NULL, 0) == 0)
332 xo_emit("{:nsfbufs-current/%d}/{:nsfbufs-peak/%d}/"
333 "{:nsfbufs/%d} "
334 "{N:sfbufs in use (current\\/peak\\/max)}\n",
335 nsfbufsused, nsfbufspeak, nsfbufs);
336
337 if (fetch_stats("kern.ipc.sfstat", mbaddr, &sfstat, sizeof(sfstat),
338 kread_counters) != 0)
339 goto out;
340
341 xo_emit("{:sendfile-syscalls/%ju} {N:sendfile syscalls}\n",
342 (uintmax_t)sfstat.sf_syscalls);
343 xo_emit("{:sendfile-no-io/%ju} "
344 "{N:sendfile syscalls completed without I\\/O request}\n",
345 (uintmax_t)sfstat.sf_noiocnt);
346 xo_emit("{:sendfile-io-count/%ju} "
347 "{N:requests for I\\/O initiated by sendfile}\n",
348 (uintmax_t)sfstat.sf_iocnt);
349 xo_emit("{:sendfile-pages-sent/%ju} "
350 "{N:pages read by sendfile as part of a request}\n",
351 (uintmax_t)sfstat.sf_pages_read);
352 xo_emit("{:sendfile-pages-valid/%ju} "
353 "{N:pages were valid at time of a sendfile request}\n",
354 (uintmax_t)sfstat.sf_pages_valid);
355 xo_emit("{:sendfile-pages-bogus/%ju} "
356 "{N:pages were valid and substituted to bogus page}\n",
357 (uintmax_t)sfstat.sf_pages_bogus);
358 xo_emit("{:sendfile-requested-readahead/%ju} "
359 "{N:pages were requested for read ahead by applications}\n",
360 (uintmax_t)sfstat.sf_rhpages_requested);
361 xo_emit("{:sendfile-readahead/%ju} "
362 "{N:pages were read ahead by sendfile}\n",
363 (uintmax_t)sfstat.sf_rhpages_read);
364 xo_emit("{:sendfile-busy-encounters/%ju} "
365 "{N:times sendfile encountered an already busy page}\n",
366 (uintmax_t)sfstat.sf_busy);
367 xo_emit("{:sfbufs-alloc-failed/%ju} {N:requests for sfbufs denied}\n",
368 (uintmax_t)sfstat.sf_allocfail);
369 xo_emit("{:sfbufs-alloc-wait/%ju} {N:requests for sfbufs delayed}\n",
370 (uintmax_t)sfstat.sf_allocwait);
371 out:
372 xo_close_container("mbuf-statistics");
373 memstat_mtl_free(mtlp);
374 }
375