]> git.saurik.com Git - apple/network_cmds.git/blob - netstat.tproj/mbuf.c
network_cmds-596.100.2.tar.gz
[apple/network_cmds.git] / netstat.tproj / mbuf.c
1 /*
2 * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * Copyright (c) 1983, 1988, 1993
30 * The Regents of the University of California. All rights reserved.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 */
60
61
62 #include <sys/param.h>
63 #include <sys/socket.h>
64 #include <sys/mbuf.h>
65 #include <sys/sysctl.h>
66
67 #include <stdio.h>
68 #include <string.h>
69 #include <stdlib.h>
70 #include <errno.h>
71 #include "netstat.h"
72
73 #define YES 1
74 typedef int bool;
75
76 struct mbstat mbstat;
77
78 static struct mbtypes {
79 int mt_type;
80 char *mt_name;
81 } mbtypes[] = {
82 { MT_DATA, "data" },
83 { MT_OOBDATA, "oob data" },
84 { MT_CONTROL, "ancillary data" },
85 { MT_HEADER, "packet headers" },
86 { MT_SOCKET, "socket structures" }, /* XXX */
87 { MT_PCB, "protocol control blocks" }, /* XXX */
88 { MT_RTABLE, "routing table entries" }, /* XXX */
89 { MT_HTABLE, "IMP host table entries" }, /* XXX */
90 { MT_ATABLE, "address resolution tables" },
91 { MT_FTABLE, "fragment reassembly queue headers" }, /* XXX */
92 { MT_SONAME, "socket names and addresses" },
93 { MT_SOOPTS, "socket options" },
94 { MT_RIGHTS, "access rights" },
95 { MT_IFADDR, "interface addresses" }, /* XXX */
96 { MT_TAG, "packet tags" }, /* XXX */
97 { 0, 0 }
98 };
99
100 int nmbtypes = sizeof(mbstat.m_mtypes) / sizeof(short);
101 bool seen[256]; /* "have we seen this type yet?" */
102
103 mb_stat_t *mb_stat;
104 unsigned int njcl, njclbytes;
105 mleak_stat_t *mleak_stat;
106 struct mleak_table table;
107
108 #define KERN_IPC_MB_STAT "kern.ipc.mb_stat"
109 #define KERN_IPC_NJCL "kern.ipc.njcl"
110 #define KERN_IPC_NJCL_BYTES "kern.ipc.njclbytes"
111 #define KERN_IPC_MLEAK_TABLE "kern.ipc.mleak_table"
112 #define KERN_IPC_MLEAK_TOP_TRACE "kern.ipc.mleak_top_trace"
113
114 #define MB_STAT_HDR1 "\
115 class buf active ctotal total cache cached uncached memory\n\
116 name size bufs bufs bufs state bufs bufs usage\n\
117 ---------- ----- -------- -------- -------- ----- -------- -------- ---------\n\
118 "
119
120 #define MB_STAT_HDR2 "\n\
121 class waiter notify purge wretry nwretry failure\n\
122 name count count count count count count\n\
123 ---------- -------- -------- -------- -------- -------- --------\n\
124 "
125
126 #define MB_LEAK_HDR "\n\
127 calltrace [1] calltrace [2] calltrace [3] calltrace [4] calltrace [5] \n\
128 ------------------ ------------------ ------------------ ------------------ ------------------ \n\
129 "
130
131 #define MB_LEAK_SPACING " "
132 static const char *mbpr_state(int);
133 static const char *mbpr_mem(u_int32_t);
134 static int mbpr_getdata(void);
135
136 /*
137 * Print mbuf statistics.
138 */
139 void
140 mbpr(void)
141 {
142 unsigned long totmem = 0, totfree = 0, totmbufs, totused, totreturned = 0;
143 double totpct;
144 u_int32_t m_msize, m_mbufs = 0, m_clfree = 0, m_bigclfree = 0;
145 u_int32_t m_mbufclfree = 0, m_mbufbigclfree = 0;
146 u_int32_t m_16kclusters = 0, m_16kclfree = 0, m_mbuf16kclfree = 0;
147 int i;
148 struct mbtypes *mp;
149 mb_class_stat_t *cp;
150
151 if (mbpr_getdata() != 0)
152 return;
153
154 m_msize = mbstat.m_msize;
155 cp = &mb_stat->mbs_class[0];
156 for (i = 0; i < mb_stat->mbs_cnt; i++, cp++) {
157 if (cp->mbcl_size == m_msize) {
158 m_mbufs = cp->mbcl_active;
159 } else if (cp->mbcl_size == mbstat.m_mclbytes) {
160 m_clfree = cp->mbcl_total - cp->mbcl_active;
161 } else if (cp->mbcl_size == mbstat.m_bigmclbytes) {
162 m_bigclfree = cp->mbcl_total - cp->mbcl_active;
163 } else if (njcl > 0 && cp->mbcl_size == njclbytes) {
164 m_16kclfree = cp->mbcl_total - cp->mbcl_active;
165 m_16kclusters = cp->mbcl_total;
166 } else if (cp->mbcl_size == (m_msize + mbstat.m_mclbytes)) {
167 m_mbufclfree = cp->mbcl_total - cp->mbcl_active;
168 } else if (cp->mbcl_size == (m_msize + mbstat.m_bigmclbytes)) {
169 m_mbufbigclfree = cp->mbcl_total - cp->mbcl_active;
170 } else if (njcl > 0 && cp->mbcl_size == (m_msize + njclbytes)) {
171 m_mbuf16kclfree = cp->mbcl_total - cp->mbcl_active;
172 }
173 }
174
175 /* adjust free counts to include composite caches */
176 m_clfree += m_mbufclfree;
177 m_bigclfree += m_mbufbigclfree;
178 m_16kclfree += m_mbuf16kclfree;
179
180 cp = &mb_stat->mbs_class[0];
181 for (i = 0; i < mb_stat->mbs_cnt; i++, cp++) {
182 u_int32_t mem;
183
184 mem = cp->mbcl_ctotal * cp->mbcl_size;
185 totmem += mem;
186 totreturned += cp->mbcl_release_cnt;
187 totfree += (cp->mbcl_mc_cached + cp->mbcl_infree) *
188 cp->mbcl_size;
189 if (mflag > 1) {
190 if (i == 0)
191 printf(MB_STAT_HDR1);
192
193 if (njcl == 0 &&
194 cp->mbcl_size > (m_msize + mbstat.m_bigmclbytes))
195 continue;
196
197 printf("%-10s %5u %8u %8u %8u %5s %8u %8u %9s\n",
198 cp->mbcl_cname, cp->mbcl_size, cp->mbcl_active,
199 cp->mbcl_ctotal, cp->mbcl_total,
200 mbpr_state(cp->mbcl_mc_state), cp->mbcl_mc_cached,
201 cp->mbcl_infree, mbpr_mem(mem));
202 }
203 }
204
205 cp = &mb_stat->mbs_class[0];
206 for (i = 0; i < mb_stat->mbs_cnt; i++, cp++) {
207 if (mflag > 2) {
208 if (i == 0)
209 printf(MB_STAT_HDR2);
210
211 if (njcl == 0 &&
212 cp->mbcl_size > (m_msize + mbstat.m_bigmclbytes))
213 continue;
214
215 printf("%-10s %8u %8llu %8llu %8u %8u %8llu\n",
216 cp->mbcl_cname, cp->mbcl_mc_waiter_cnt,
217 cp->mbcl_notified, cp->mbcl_purge_cnt,
218 cp->mbcl_mc_wretry_cnt, cp->mbcl_mc_nwretry_cnt,
219 cp->mbcl_fail_cnt);
220 }
221 }
222
223 if (mflag > 1)
224 printf("\n");
225
226 totmbufs = 0;
227 for (mp = mbtypes; mp->mt_name; mp++)
228 totmbufs += mbstat.m_mtypes[mp->mt_type];
229 /*
230 * These stats are not updated atomically in the kernel;
231 * adjust the total as neeeded.
232 */
233 if (totmbufs > m_mbufs)
234 totmbufs = m_mbufs;
235 printf("%lu/%u mbufs in use:\n", totmbufs, m_mbufs);
236 for (mp = mbtypes; mp->mt_name; mp++)
237 if (mbstat.m_mtypes[mp->mt_type]) {
238 seen[mp->mt_type] = YES;
239 printf("\t%u mbufs allocated to %s\n",
240 mbstat.m_mtypes[mp->mt_type], mp->mt_name);
241 }
242 seen[MT_FREE] = YES;
243 for (i = 0; i < nmbtypes; i++)
244 if (!seen[i] && mbstat.m_mtypes[i]) {
245 printf("\t%u mbufs allocated to <mbuf type %d>\n",
246 mbstat.m_mtypes[i], i);
247 }
248 if ((m_mbufs - totmbufs) > 0)
249 printf("\t%lu mbufs allocated to caches\n",
250 m_mbufs - totmbufs);
251 printf("%u/%u mbuf 2KB clusters in use\n",
252 (unsigned int)(mbstat.m_clusters - m_clfree),
253 (unsigned int)mbstat.m_clusters);
254 printf("%u/%u mbuf 4KB clusters in use\n",
255 (unsigned int)(mbstat.m_bigclusters - m_bigclfree),
256 (unsigned int)mbstat.m_bigclusters);
257 if (njcl > 0) {
258 printf("%u/%u mbuf %uKB clusters in use\n",
259 m_16kclusters - m_16kclfree, m_16kclusters,
260 njclbytes/1024);
261 }
262 totused = totmem - totfree;
263 if (totmem == 0)
264 totpct = 0;
265 else if (totused < (ULONG_MAX/100))
266 totpct = (totused * 100)/(double)totmem;
267 else {
268 u_long totmem1 = totmem/100;
269 u_long totused1 = totused/100;
270 totpct = (totused1 * 100)/(double)totmem1;
271 }
272 printf("%lu KB allocated to network (%.1f%% in use)\n",
273 totmem / 1024, totpct);
274 printf("%lu KB returned to the system\n", totreturned / 1024);
275
276 printf("%u requests for memory denied\n", (unsigned int)mbstat.m_drops);
277 printf("%u requests for memory delayed\n", (unsigned int)mbstat.m_wait);
278 printf("%u calls to drain routines\n", (unsigned int)mbstat.m_drain);
279
280 free(mb_stat);
281 mb_stat = NULL;
282
283 if (mleak_stat != NULL) {
284 mleak_trace_stat_t *mltr;
285
286 printf("\nmbuf leak detection table:\n");
287 printf("\ttotal captured: %u (one per %u)\n"
288 "\ttotal allocs outstanding: %llu\n"
289 "\tnew hash recorded: %llu allocs, %llu traces\n"
290 "\thash collisions: %llu allocs, %llu traces\n"
291 "\toverwrites: %llu allocs, %llu traces\n"
292 "\tlock conflicts: %llu\n\n",
293 table.mleak_capture / table.mleak_sample_factor,
294 table.mleak_sample_factor,
295 table.outstanding_allocs,
296 table.alloc_recorded, table.trace_recorded,
297 table.alloc_collisions, table.trace_collisions,
298 table.alloc_overwrites, table.trace_overwrites,
299 table.total_conflicts);
300
301 printf("top %d outstanding traces:\n", mleak_stat->ml_cnt);
302 for (i = 0; i < mleak_stat->ml_cnt; i++) {
303 mltr = &mleak_stat->ml_trace[i];
304 printf("[%d] %llu outstanding alloc(s), "
305 "%llu hit(s), %llu collision(s)\n", (i + 1),
306 mltr->mltr_allocs, mltr->mltr_hitcount,
307 mltr->mltr_collisions);
308 }
309
310 printf(MB_LEAK_HDR);
311 for (i = 0; i < MLEAK_STACK_DEPTH; i++) {
312 int j;
313
314 printf("%2d: ", (i + 1));
315 for (j = 0; j < mleak_stat->ml_cnt; j++) {
316 mltr = &mleak_stat->ml_trace[j];
317 if (i < mltr->mltr_depth) {
318 if (mleak_stat->ml_isaddr64) {
319 printf("0x%0llx ",
320 mltr->mltr_addr[i]);
321 } else {
322 printf("0x%08x ",
323 (u_int32_t)mltr->mltr_addr[i]);
324 }
325 } else {
326 printf(MB_LEAK_SPACING);
327 }
328 }
329 printf("\n");
330 }
331 free(mleak_stat);
332 mleak_stat = NULL;
333 }
334 }
335
336 static const char *
337 mbpr_state(int state)
338 {
339 char *msg = "?";
340
341 switch (state) {
342 case MCS_DISABLED:
343 msg = "dis";
344 break;
345
346 case MCS_ONLINE:
347 msg = "on";
348 break;
349
350 case MCS_PURGING:
351 msg = "purge";
352 break;
353
354 case MCS_OFFLINE:
355 msg = "off";
356 break;
357 }
358 return (msg);
359 }
360
361 static const char *
362 mbpr_mem(u_int32_t bytes)
363 {
364 static char buf[33];
365 double mem = bytes;
366
367 if (mem < 1024) {
368 (void) snprintf(buf, sizeof (buf), "%d", (int)mem);
369 } else if ((mem /= 1024) < 1024) {
370 (void) snprintf(buf, sizeof (buf), "%.1f KB", mem);
371 } else {
372 mem /= 1024;
373 (void) snprintf(buf, sizeof (buf), "%.1f MB", mem);
374 }
375 return (buf);
376 }
377
378 static int
379 mbpr_getdata(void)
380 {
381 size_t len;
382 int error = -1;
383
384 if (nmbtypes != 256) {
385 (void) fprintf(stderr,
386 "netstat: unexpected change to mbstat; check source\n");
387 goto done;
388 }
389
390 len = sizeof(mbstat);
391 if (sysctlbyname("kern.ipc.mbstat", &mbstat, &len, 0, 0) == -1)
392 goto done;
393
394 if (sysctlbyname(KERN_IPC_MB_STAT, NULL, &len, 0, 0) == -1) {
395 (void) fprintf(stderr,
396 "Error retrieving length for %s\n", KERN_IPC_MB_STAT);
397 goto done;
398 }
399
400 mb_stat = calloc(1, len);
401 if (mb_stat == NULL) {
402 (void) fprintf(stderr,
403 "Error allocating %lu bytes for sysctl data\n", len);
404 goto done;
405 }
406
407 if (sysctlbyname(KERN_IPC_MB_STAT, mb_stat, &len, 0, 0) == -1) {
408 (void) fprintf(stderr,
409 "Error %d getting %s\n", errno, KERN_IPC_MB_STAT);
410 goto done;
411 }
412
413 if (mb_stat->mbs_cnt == 0) {
414 (void) fprintf(stderr,
415 "Invalid mbuf class count (%d)\n", mb_stat->mbs_cnt);
416 goto done;
417 }
418
419 /* mbuf leak detection! */
420 if (mflag > 3) {
421 errno = 0;
422 len = sizeof (table);
423 if (sysctlbyname(KERN_IPC_MLEAK_TABLE, &table, &len, 0, 0) ==
424 -1 && errno != ENXIO) {
425 (void) fprintf(stderr, "error %d getting %s\n", errno,
426 KERN_IPC_MLEAK_TABLE);
427 goto done;
428 } else if (errno == ENXIO) {
429 (void) fprintf(stderr, "mbuf leak detection is not "
430 "enabled in the kernel.\n");
431 goto skip;
432 }
433
434 if (sysctlbyname(KERN_IPC_MLEAK_TOP_TRACE, NULL, &len,
435 0, 0) == -1) {
436 (void) fprintf(stderr, "Error retrieving length for "
437 "%s: %d\n", KERN_IPC_MB_STAT, errno);
438 goto done;
439 }
440
441 mleak_stat = calloc(1, len);
442 if (mleak_stat == NULL) {
443 (void) fprintf(stderr, "Error allocating %lu bytes "
444 "for sysctl data\n", len);
445 goto done;
446 }
447
448 if (sysctlbyname(KERN_IPC_MLEAK_TOP_TRACE, mleak_stat, &len,
449 0, 0) == -1) {
450 (void) fprintf(stderr, "error %d getting %s\n", errno,
451 KERN_IPC_MLEAK_TOP_TRACE);
452 goto done;
453 }
454 }
455
456 skip:
457 len = sizeof (njcl);
458 (void) sysctlbyname(KERN_IPC_NJCL, &njcl, &len, 0, 0);
459 len = sizeof (njclbytes);
460 (void) sysctlbyname(KERN_IPC_NJCL_BYTES, &njclbytes, &len, 0, 0);
461
462 error = 0;
463
464 done:
465 if (error != 0 && mb_stat != NULL) {
466 free(mb_stat);
467 mb_stat = NULL;
468 }
469
470 if (error != 0 && mleak_stat != NULL) {
471 free(mleak_stat);
472 mleak_stat = NULL;
473 }
474
475 return (error);
476 }