]> git.saurik.com Git - apple/network_cmds.git/blob - netstat.tproj/mbuf.c
network_cmds-325.tar.gz
[apple/network_cmds.git] / netstat.tproj / mbuf.c
1 /*
2 * Copyright (c) 2008 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 <stdlib.h>
69 #include <errno.h>
70 #include "netstat.h"
71
72 #define YES 1
73 typedef int bool;
74
75 struct mbstat mbstat;
76
77 static struct mbtypes {
78 int mt_type;
79 char *mt_name;
80 } mbtypes[] = {
81 { MT_DATA, "data" },
82 { MT_OOBDATA, "oob data" },
83 { MT_CONTROL, "ancillary data" },
84 { MT_HEADER, "packet headers" },
85 { MT_SOCKET, "socket structures" }, /* XXX */
86 { MT_PCB, "protocol control blocks" }, /* XXX */
87 { MT_RTABLE, "routing table entries" }, /* XXX */
88 { MT_HTABLE, "IMP host table entries" }, /* XXX */
89 { MT_ATABLE, "address resolution tables" },
90 { MT_FTABLE, "fragment reassembly queue headers" }, /* XXX */
91 { MT_SONAME, "socket names and addresses" },
92 { MT_SOOPTS, "socket options" },
93 { MT_RIGHTS, "access rights" },
94 { MT_IFADDR, "interface addresses" }, /* XXX */
95 { MT_TAG, "packet tags" }, /* XXX */
96 { 0, 0 }
97 };
98
99 int nmbtypes = sizeof(mbstat.m_mtypes) / sizeof(short);
100 bool seen[256]; /* "have we seen this type yet?" */
101
102 mb_stat_t *mb_stat;
103 unsigned int njcl, njclbytes;
104
105 #define KERN_IPC_MB_STAT "kern.ipc.mb_stat"
106 #define KERN_IPC_NJCL "kern.ipc.njcl"
107 #define KERN_IPC_NJCL_BYTES "kern.ipc.njclbytes"
108
109 #define MB_STAT_HDR1 "\
110 class buf active ctotal total cache cached uncached memory\n\
111 name size bufs bufs bufs state bufs bufs usage\n\
112 ---------- ----- -------- -------- -------- ----- -------- -------- ---------\n\
113 "
114
115 #define MB_STAT_HDR2 "\n\
116 class waiter notify purge wretry nwretry failure\n\
117 name count count count count count count\n\
118 ---------- -------- -------- -------- -------- -------- --------\n\
119 "
120
121 static const char *mbpr_state(int);
122 static const char *mbpr_mem(u_int32_t);
123 static int mbpr_getdata(void);
124
125 /*
126 * Print mbuf statistics.
127 */
128 void
129 mbpr(void)
130 {
131 unsigned long totmem = 0, totfree = 0, totmbufs, totused;
132 double totpct;
133 u_int32_t m_msize, m_mbufs = 0, m_clfree = 0, m_bigclfree = 0;
134 u_int32_t m_mbufclfree = 0, m_mbufbigclfree = 0;
135 u_int32_t m_16kclusters = 0, m_16kclfree = 0, m_mbuf16kclfree = 0;
136 int i;
137 struct mbtypes *mp;
138 mb_class_stat_t *cp;
139
140 if (mbpr_getdata() != 0)
141 return;
142
143 m_msize = mbstat.m_msize;
144 cp = &mb_stat->mbs_class[0];
145 for (i = 0; i < mb_stat->mbs_cnt; i++, cp++) {
146 if (cp->mbcl_size == m_msize) {
147 m_mbufs = cp->mbcl_active;
148 } else if (cp->mbcl_size == mbstat.m_mclbytes) {
149 m_clfree = cp->mbcl_total - cp->mbcl_active;
150 } else if (cp->mbcl_size == mbstat.m_bigmclbytes) {
151 m_bigclfree = cp->mbcl_total - cp->mbcl_active;
152 } else if (njcl > 0 && cp->mbcl_size == njclbytes) {
153 m_16kclfree = cp->mbcl_total - cp->mbcl_active;
154 m_16kclusters = cp->mbcl_total;
155 } else if (cp->mbcl_size == (m_msize + mbstat.m_mclbytes)) {
156 m_mbufclfree = cp->mbcl_total - cp->mbcl_active;
157 } else if (cp->mbcl_size == (m_msize + mbstat.m_bigmclbytes)) {
158 m_mbufbigclfree = cp->mbcl_total - cp->mbcl_active;
159 } else if (njcl > 0 && cp->mbcl_size == (m_msize + njclbytes)) {
160 m_mbuf16kclfree = cp->mbcl_total - cp->mbcl_active;
161 }
162 }
163
164 /* adjust free counts to include composite caches */
165 m_clfree += m_mbufclfree;
166 m_bigclfree += m_mbufbigclfree;
167 m_16kclfree += m_mbuf16kclfree;
168
169 cp = &mb_stat->mbs_class[0];
170 for (i = 0; i < mb_stat->mbs_cnt; i++, cp++) {
171 u_int32_t mem;
172
173 mem = cp->mbcl_ctotal * cp->mbcl_size;
174 totmem += mem;
175 totfree += (cp->mbcl_mc_cached + cp->mbcl_infree) *
176 cp->mbcl_size;
177 if (mflag > 1) {
178 if (i == 0)
179 printf(MB_STAT_HDR1);
180
181 if (njcl == 0 &&
182 cp->mbcl_size > (m_msize + mbstat.m_bigmclbytes))
183 continue;
184
185 printf("%-10s %5u %8u %8u %8u %5s %8u %8u %9s\n",
186 cp->mbcl_cname, cp->mbcl_size, cp->mbcl_active,
187 cp->mbcl_ctotal, cp->mbcl_total,
188 mbpr_state(cp->mbcl_mc_state), cp->mbcl_mc_cached,
189 cp->mbcl_infree, mbpr_mem(mem));
190 }
191 }
192
193 cp = &mb_stat->mbs_class[0];
194 for (i = 0; i < mb_stat->mbs_cnt; i++, cp++) {
195 if (mflag > 2) {
196 if (i == 0)
197 printf(MB_STAT_HDR2);
198
199 if (njcl == 0 &&
200 cp->mbcl_size > (m_msize + mbstat.m_bigmclbytes))
201 continue;
202
203 printf("%-10s %8u %8llu %8llu %8u %8u %8llu\n",
204 cp->mbcl_cname, cp->mbcl_mc_waiter_cnt,
205 cp->mbcl_notified, cp->mbcl_purge_cnt,
206 cp->mbcl_mc_wretry_cnt, cp->mbcl_mc_nwretry_cnt,
207 cp->mbcl_fail_cnt);
208 }
209 }
210
211 if (mflag > 1)
212 printf("\n");
213
214 totmbufs = 0;
215 for (mp = mbtypes; mp->mt_name; mp++)
216 totmbufs += mbstat.m_mtypes[mp->mt_type];
217 /*
218 * These stats are not updated atomically in the kernel;
219 * adjust the total as neeeded.
220 */
221 if (totmbufs > m_mbufs)
222 totmbufs = m_mbufs;
223 printf("%lu/%u mbufs in use:\n", totmbufs, m_mbufs);
224 for (mp = mbtypes; mp->mt_name; mp++)
225 if (mbstat.m_mtypes[mp->mt_type]) {
226 seen[mp->mt_type] = YES;
227 printf("\t%u mbufs allocated to %s\n",
228 mbstat.m_mtypes[mp->mt_type], mp->mt_name);
229 }
230 seen[MT_FREE] = YES;
231 for (i = 0; i < nmbtypes; i++)
232 if (!seen[i] && mbstat.m_mtypes[i]) {
233 printf("\t%u mbufs allocated to <mbuf type %d>\n",
234 mbstat.m_mtypes[i], i);
235 }
236 if ((m_mbufs - totmbufs) > 0)
237 printf("\t%lu mbufs allocated to caches\n",
238 m_mbufs - totmbufs);
239 printf("%u/%u mbuf 2KB clusters in use\n",
240 (unsigned int)(mbstat.m_clusters - m_clfree),
241 (unsigned int)mbstat.m_clusters);
242 printf("%u/%u mbuf 4KB clusters in use\n",
243 (unsigned int)(mbstat.m_bigclusters - m_bigclfree),
244 (unsigned int)mbstat.m_bigclusters);
245 if (njcl > 0) {
246 printf("%u/%u mbuf %uKB clusters in use\n",
247 m_16kclusters - m_16kclfree, m_16kclusters,
248 njclbytes/1024);
249 }
250 totused = totmem - totfree;
251 if (totmem == 0)
252 totpct = 0;
253 else if (totused < (ULONG_MAX/100))
254 totpct = (totused * 100)/(double)totmem;
255 else {
256 u_long totmem1 = totmem/100;
257 u_long totused1 = totused/100;
258 totpct = (totused1 * 100)/(double)totmem1;
259 }
260 printf("%lu KB allocated to network (%.1f%% in use)\n",
261 totmem / 1024, totpct);
262
263 printf("%u requests for memory denied\n", (unsigned int)mbstat.m_drops);
264 printf("%u requests for memory delayed\n", (unsigned int)mbstat.m_wait);
265 printf("%u calls to drain routines\n", (unsigned int)mbstat.m_drain);
266
267 free(mb_stat);
268 }
269
270 static const char *
271 mbpr_state(int state)
272 {
273 char *msg = "?";
274
275 switch (state) {
276 case MCS_DISABLED:
277 msg = "dis";
278 break;
279
280 case MCS_ONLINE:
281 msg = "on";
282 break;
283
284 case MCS_PURGING:
285 msg = "purge";
286 break;
287
288 case MCS_OFFLINE:
289 msg = "off";
290 break;
291 }
292 return (msg);
293 }
294
295 static const char *
296 mbpr_mem(u_int32_t bytes)
297 {
298 static char buf[33];
299 double mem = bytes;
300
301 if (mem < 1024) {
302 (void) snprintf(buf, sizeof (buf), "%d", (int)mem);
303 } else if ((mem /= 1024) < 1024) {
304 (void) snprintf(buf, sizeof (buf), "%.1f KB", mem);
305 } else {
306 mem /= 1024;
307 (void) snprintf(buf, sizeof (buf), "%.1f MB", mem);
308 }
309 return (buf);
310 }
311
312 static int
313 mbpr_getdata(void)
314 {
315 size_t len;
316 int error = -1;
317
318 if (nmbtypes != 256) {
319 (void) fprintf(stderr,
320 "netstat: unexpected change to mbstat; check source\n");
321 goto done;
322 }
323
324 len = sizeof(mbstat);
325 if (sysctlbyname("kern.ipc.mbstat", &mbstat, &len, 0, 0) == -1)
326 goto done;
327
328 if (sysctlbyname(KERN_IPC_MB_STAT, NULL, &len, 0, 0) == -1) {
329 (void) fprintf(stderr,
330 "Error retrieving length for %s\n", KERN_IPC_MB_STAT);
331 goto done;
332 }
333
334 mb_stat = calloc(1, len);
335 if (mb_stat == NULL) {
336 (void) fprintf(stderr,
337 "Error allocating %lu bytes for sysctl data\n", len);
338 goto done;
339 }
340
341 if (sysctlbyname(KERN_IPC_MB_STAT, mb_stat, &len, 0, 0) == -1) {
342 (void) fprintf(stderr,
343 "Error %d getting %s\n", errno, KERN_IPC_MB_STAT);
344 goto done;
345 }
346
347 if (mb_stat->mbs_cnt == 0) {
348 (void) fprintf(stderr,
349 "Invalid mbuf class count (%d)\n", mb_stat->mbs_cnt);
350 goto done;
351 }
352
353 len = sizeof (njcl);
354 (void) sysctlbyname(KERN_IPC_NJCL, &njcl, &len, 0, 0);
355 len = sizeof (njclbytes);
356 (void) sysctlbyname(KERN_IPC_NJCL_BYTES, &njclbytes, &len, 0, 0);
357
358 error = 0;
359
360 done:
361 if (error != 0 && mb_stat != NULL)
362 free(mb_stat);
363
364 return (error);
365 }